adding dynamic data to sublcassed QAbstractTableModel

2

for testing purposes a have function that asks for input and displays it in a QListView display data. this works fine with one dim.data
I want to extend the script to display two-dimensional data

the incoming data should be inserted in the first row till column 3, and proceeds on the next rows (same operation) so the model contains the data in this form

 input_values = [[1,2],
                 [1,2]]....

so far I implemented that the input_data is added into the first row, but the script stops running before it starts adding the data into the second row. I just get this info

Process finished with exit code -1073740791 (0xC0000409)

What is cousing this behavior and how to fix that ?

    def thread_data_add(self, data):
        if len(self.model.input_data[0]) <= 1:
            self.model.input_data[0].append(data)
            self.model.layoutChanged.emit()

        elif len(self.model.input_data[0]) > 1:
            self.model.input_data.append([])
            self.model.input_data[1].append(data) #crashes here !!! need crash report
            self.model.layoutChanged.emit()


full code

#!/usr/bin/env python

"""


"""


import threading
import sys
import logging

from PyQt5 import QtWidgets as qtw
from PyQt5 import QtCore as qtc
from PyQt5 import QtGui as qtg


class ViewModel(qtc.QAbstractTableModel):


    def __init__(self, input_data=None):
        super().__init__()
        self.input_data = input_data or [[]]
        #


    def data(self, index, role): # parameter index, role are needed !
        """

        :param index: Instance of QModelIndex Class  / set automatically
        Model indexes refer to items in models,
         contain all the information required to specify their locations in those models

        :param role: what type should be returned
        :return: data as a string
        """
        if role == qtc.Qt.DisplayRole:
            row = index.row()
            column = index.column()
            text = self.input_data[row][column] 
            return text



    def rowCount(self, index):
        return len(self.input_data)

    def columnCount(self, index):
        return len(self.input_data[0])


    def getData(self):
        print(self.input_data)
        # todo how to show list data





class MainWindow(qtw.QWidget):

    core_signal = qtc.pyqtSignal(str)


    def __init__(self):
        super().__init__()

        # View
        table_view = qtw.QTableView()
        self.model = ViewModel()
        table_view.setModel(self.model)

        # widgets
        self.start_thread_button = qtw.QPushButton("start Thread")
        self.test_button = qtw.QPushButton("display data")

        # layout
        qvboxlayout = qtw.QVBoxLayout()
        qvboxlayout.addWidget(table_view)

        qvboxlayout.addWidget(self.start_thread_button)
        qvboxlayout.addWidget(self.test_button)
        self.setLayout(qvboxlayout)
        self.show()


        # self.logger = self.default_logger()


        # function

        self.start_thread_button.clicked.connect(self.start)
        self.test_button.clicked.connect(self.model.getData)


    def lambda_thread_data_add(self, data):
        if len(self.model.input_data[0]) <= 1:
            self.model.input_data[0].append(data)
            self.model.layoutChanged.emit()
            # self.model.input_data.append([])
        elif len(self.model.input_data[0]) > 1:
            self.model.input_data.append([])
            self.model.input_data[1].append(data) #crashes here !!! need crash report
            self.model.layoutChanged.emit()



    def thread_data_add(self, data):
        if len(self.model.input_data[0]) <= 1:
            self.model.input_data[0].append(data)
            self.model.layoutChanged.emit()
            # self.model.input_data.append([])
        elif len(self.model.input_data[0]) > 1:
            self.model.input_data.append([])
            self.model.input_data[1].append(data) #crashes here !!! need crash report
            self.model.layoutChanged.emit()



    def start(self):
        # starts thread
        # Setting thread.daemon = True will allow the main program to exit before thread is killed.
        threading.Thread(target=self._execute, daemon=True).start()
        self.core_signal.connect(self.thread_data_add)


    def _execute(self):
        while True:
            user_input = input("type in: ")
            self.core_signal.emit(user_input) # transmit data


    def default_logger(self,level=logging.DEBUG, save_path='beispiel.log'):
    # create logger
        custom_logger = logging.getLogger(__name__)
        custom_logger.setLevel(level)

        # was reingegeben werden soll
        formatter = logging.Formatter('%(asctime)s;%(message)s;%(filename)s;%(lineno)d', "%Y-%m-%d %H:%M:%S")
        file_handler = logging.FileHandler(save_path)
        file_handler.setFormatter(formatter)
        custom_logger.addHandler(file_handler)

        stream_handler = logging.StreamHandler()
        custom_logger.addHandler(stream_handler)

        return custom_logger

if __name__ == '__main__':
    app = qtw.QApplication(sys.argv)
    w = MainWindow()
    sys.exit(app.exec_())






python
pyqt
pyqt5
asked on Stack Overflow Apr 20, 2020 by Sator • edited Apr 22, 2020 by Sator

1 Answer

2

The issue you are getting is an IndexError since the data is not being added uniformly (whole row at a time), it is being added one column, or cell, at a time. As a result, when starting the next row with the 3rd input, there is no data for the 2nd column in that row yet. You don't necessarily have to change the way you are inserting data, just catch the error and supply an empty string or None value.

def data(self, index, role):
    if role == qtc.Qt.DisplayRole:
        try:
            text = self.input_data[index.row()][index.column()]
        except IndexError:
            text = None
        return text

Additionally, make sure you are accessing the correct index of input_data in thread_data_add(), which would be the last index [-1] since you are appending data.

def thread_data_add(self, data):
    if len(self.model.input_data[-1]) < 2:
        self.model.input_data[-1].append(data)
    else:
        self.model.input_data.append([data])
    self.model.layoutChanged.emit()
answered on Stack Overflow Apr 24, 2020 by alec

User contributions licensed under CC BY-SA 3.0