PyQT5 - QTableView.setModel crashes the program

Sabari Girish Janakiraman jsgirish at gmail.com
Mon Apr 27 16:20:18 BST 2020


Hello Experts,
I am Sabari Girish and I joined this mailer list just today. Hence, this is
my first query in this forum. Also, I am fairly new to PyQT5.

*What I am trying to do*
I am trying to build a desktop application in Python to analyze and
generate performance reports on a Stock Market Swing Trading Strategy by
downloading end of the day data from our Indian Stock Market Exchange (NSE)
and using this data to analyze our trading strategy which we have put in an
excel.
I have a tabbed view and in each tabs I am trying to display some data in
tabular format using QTableView and TableModel.
As of now, I have 3 tables:
(1) NSE Data Table - Data changes dynamically based on a date selected from
a combo box.
(2) Swing Data Table - Data changes dynamically based on a date selected
from a combo box.
(3) Swing Filter Data Table - Data changes dynamically based on a date
selected from a combo box.

*My Issue:*
(1) NSE Data Table works fine without issues
(2) Swing Data Table - Program crashes while setting the model.

self._view.swingmaindata_table.setModel(self._view.swingmain_model)

The program abruptly crashes here with the following message:
Process finished with exit code -1073740791 (0xC0000409)


*My Environment*

Python 3.7.2

PyCharm IDE

PyQT5

I am looking for help to see where the below issues are and how I can fix
them:
(1) setModel crashing the program
(2) How to dynamically update data in a table? (Replace entire data with a
different set of data)

*Code Snip*
I am trying to use the MVC architecture.

class DbtMain(QMainWindow):
    # DBT's View (GUI) Initializer
    def __init__(self):
        super().__init__()

        # Set main window properties
        self.__set_main_window_properties__()

        # Set the central widget, layout
        self.__set_central_widget_and_layout__()

        # Set Tabs in the layout
        self.__set_tabs_in_layout__()

    '''
    Set main window properties
    '''
    def __set_main_window_properties__(self):
        self.title = 'DELIVERY BASED SWING TRADING'
        self.left = 0
        self.top = 0
        self.width = 1300
        self.height = 700
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

    '''
    Set central widget and layout
    '''
    def __set_central_widget_and_layout__(self):
        self.layout = QVBoxLayout(self)
        self._dbt = QWidget(self)
        self.setCentralWidget(self._dbt)
        self._dbt.setLayout(self.layout)

    '''
    Set tabs in layout.
    Create and add tabs to the DBT central widget layout.
    1. DBT App configuration tab
    2. NSE Data downloader and view tab
    3. Swing file upload tab
    4. Charts tab
    '''
    def __set_tabs_in_layout__(self):
        # Main tab widget
        self.tabs = QTabWidget()
        self.tabs.resize(1000, 600)

        # Create configure tab and add to main tab widget
        self._configure_ui()

        # Create NSE data download and view tab and add to main tab widget
        self._nsedata_ui()

        # Create swing file upload tab and add to main tab widget
        self._upload_swing_ui()

        # Add tabs to main DBT layout
        self.layout.addWidget(self.tabs)

    def label(self, lbl, text, y, x):
        lbl.setText(text)
        lbl.move(y, x)

    def format_text(self, txt):
        txt = f"<P><b><FONT COLOR='#ff0000' FONT SIZE = 4>{txt}</b></P></br>"
        return txt

    def _nsedata_ui(self):
        # Create the NSE data tab
        self.nsedata_tab = QWidget()
        self.tabs.addTab(self.nsedata_tab, "NSE EoD Data")

        # Add the drop down box
        self.dc_label = QLabel(self.nsedata_tab)
        txt = self.format_text("NSE data available dates")
        # txt = "<P><b><FONT COLOR='#ff0000' FONT SIZE = 4>NSE data
available dates</b></P></br>"
        self.label(self.dc_label, txt, 5, 20)
        self.nsedata_dates = QComboBox(self.nsedata_tab)
        self.nsedata_dates.addItems(NseData.data.keys())
        self.nsedata_dates.move(10, 50)

        # Add the QTableView
        self.nsetbl_label = QLabel(self.nsedata_tab)
        self.nsedata_table = QTableView(self.nsedata_tab)
        self.nsedata_table.resize(1050, 550)
        self.nsedata_table.move(200, 50)

    def _configure_ui(self):
        self.configure_tab = QWidget()
        self.tabs.addTab(self.configure_tab, "Configuration")

    def _upload_swing_ui(self):
        self.swingdata_tab = QWidget()
        self.tabs.addTab(self.swingdata_tab, "Swing File Upload")

        # Add the drop down box
        self.swing_dc_label = QLabel(self.swingdata_tab)
        txt = self.format_text("Swing data available dates")
        self.label(self.swing_dc_label, txt, 5, 20)
        self.swingdata_dates = QComboBox(self.swingdata_tab)
        self.swingdata_dates.addItems(SwingFile.data.keys())
        self.swingdata_dates.move(10, 50)

        # Add the QTableView for Main swing data
        self.swingmaintbl_label = QLabel(self.swingdata_tab)
        self.swingmain_table = QTableView(self.swingdata_tab)
        self.swingmain_table.resize(1050, 250)
        self.swingmain_table.move(200, 50)

        # Add the QTableView for Filter swing data
        self.swingfiltertbl_label = QLabel(self.swingdata_tab)
        self.swingfilter_table = QTableView(self.swingdata_tab)
        self.swingfilter_table.resize(1050, 250)
        self.swingfilter_table.move(200, 400)

class DbtController:
    # Controller initializer
    def __init__(self, view):
        self._view = view

        # Default to 1st date of download
        self._show_nse_data(self._view.nsedata_dates.currentText())

        # Connect signals and slots
        self._connect_signals()

    def _refresh_nse_data(self, i):
        self._show_nse_data(self._view.nsedata_dates.currentText())

    def _show_nse_data(self, dt=datetime.date.today().strftime("%d-%b-%Y")):
        self._view.nsedata_model = TableModel(NseData.data[dt])
        self._view.nsedata_table.setModel(self._view.nsedata_model)
        txt = f"<P><b><FONT COLOR='#ff0000' FONT SIZE = 4>NSE Data for
{dt}</b></P></br>"
        self._view.label(self._view.nsetbl_label, txt, 300, 20)

    def _refresh_swing_data(self, i):
        print(f"REFRESH SWING - {i},
{self._view.swingdata_dates.currentText()}")
        # self._show_swing_data(self._view.swingdata_dates.currentText())
        self._view.swingmain_model.update(self._view.swingdata_dates.currentText())

    def _show_swing_data(self, dt=datetime.date.today().strftime("%d-%b-%Y")):
        if dt == datetime.date.today().strftime("%d-%b-%Y"):
            dt = max(SwingFile.datesobj).strftime("%d-%b-%Y")

        print(f"SHOW SWING - {dt}")
        self._view.swingmain_model = TableModel(SwingFile.data[dt]['main'])
        print(SwingFile.data[dt]['main'])
        print("MOD-1")
        self._view.swingmaindata_table.setModel(self._view.swingmain_model)
    # <--- *PROGRAM CRASHES HERE*
        print("MOD-1.1")
        txt = f"<P><b><FONT COLOR='#ff0000' FONT SIZE = 4>Swing Main
Data for {dt}</b></P></br>"
        self._view.label(self._view.swingmaintbl_label, txt, 300, 20)

        self._view.swingfilter_model = TableModel(SwingFile.data[dt]['filter'])
        print("MOD-2")
        self._view.swingfilterdata_table.setModel(self._view.swingfilter_model)
        print("MOD-2.1")
        txt = f"<P><b><FONT COLOR='#ff0000' FONT SIZE = 4>Swing Filter
Data for {dt}</b></P></br>"
        self._view.label(self._view.swingfiltertbl_label, txt, 300, 400)

    '''
    Connect "Choose date from drop down box signal" with respective slots
    '''
    def _connect_signals(self):
        self._view.nsedata_dates.activated.connect(partial(self._refresh_nse_data))
        self._view.swingdata_dates.activated.connect(partial(self._refresh_swing_data))
        # self._view.buttons['Update'].clicked.connect(self._refresh_nse_data)

class TableModel(QtCore.QAbstractTableModel):
    def __init__(self, data):
        super(TableModel, self).__init__()
        self._data = data
        self.header_labels = data[0]
        print(data[0])
        self._data.remove(data[0])

    def headerData(self, section, orientation, role=Qt.DisplayRole):
        if role == Qt.DisplayRole and orientation == Qt.Horizontal:
            return self.header_labels[section]
        return QAbstractTableModel.headerData(self, section, orientation, role)

    def update(self, datain):
        self._data = datain

    def data(self, index, role):
        if role == Qt.DisplayRole:
            # See below for the nested-list data structure.
            # .row() indexes into the outer list,
            # .column() indexes into the sub-list
            return self._data[index.row()][index.column()]

    def rowCount(self, index):
        # The length of the outer list.
        return len(self._data)

    def columnCount(self, index):
        # The following takes the first sub-list, and returns
        # the length (only works if all rows are an equal length)
        return len(self._data[0])

Thanks all in advance.

J.S.Girish
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20200427/43bb0c93/attachment-0001.htm>


More information about the PyQt mailing list