Как вставить новый столбец в модель QAbstractTable во время выполнения с помощью PYQT

#python #pyqt #qtableview #qabstractitemmodel #qabstracttablemodel

#python #pyqt #qtableview #qabstractitemmodel #qabstracttablemodel

Вопрос:

Я создал класс модели типа QAbstractTableModel, к которому я добавил ряд методов, как показано здесь:

 class resultsModel(QAbstractTableModel):
    def __init__(self, parent, headerData, arraydata, *args):
        QAbstractTableModel.__init__(self, parent, *args)
        self.arraydata = arraydata
        self.headerdata = headerData #['Timestamp', 'Force (N)', 'Diplacement (mm)']
    
    def rowCount(self, parent):
        return len(self.arraydata)

    def columnCount(self, parent):
        if len(self.arraydata) > 0: 
            return len(self.arraydata[0]) 
        return 0
        
    def headerData(self, col, orientation, role):
        if orientation == Qt.Horizontal and role == Qt.DisplayRole:
            return self.headerdata[col]
        return None
    
    #Make table cells non-editable
    def flags(self, index):
        return Qt.ItemIsEnabled | Qt.ItemIsSelectable   

    def data(self, index, role):
        if not index.isValid():
            return None
        value = self.arraydata[index.row()][index.column()]    
        if role == Qt.EditRole:
            return value
        elif role == Qt.DisplayRole:
            return value

    def setData(self, index, value, role):
        if not index.isValid():
            return None
        row = index.row()
        column = index.column()
        self.arraydata[row][column] = value
        self.dataChanged.emit(index, index)
        return True
        
    def setHeaderData(self, col, orientation, value, role):
        if role != Qt.DisplayRole or orientation != Qt.Horizontal:
            return False

        self.headerdata[col] = value
        result = self.headerdata[col]
        if result:
            self.headerDataChanged.emit(orientation, col, col)
        
        return result
 

При запуске приложения я использую QTableView с моделью выше за ним:

 resultsHeaders = ['Timestamp', 'Force (N)', 'Diplacement (mm)']
resultsData = [['','','']]
self.resultsTableModel = resultsModel(self, resultsHeaders, resultsData)
self.resultsTable = QTableView()
self.resultsTable.setModel(self.resultsTableModel)
 

Во время выполнения, если подключено последовательное устройство, я хочу добавить в модель несколько дополнительных столбцов, но у меня возникают трудности с реализацией метода ‘insertColumns’ для модели, прежде чем добавлять новые значения заголовка.

 #insert columns
???
#update header values
for i in range(len(resultsHeaders)):            
    self.resultsTable.model().setHeaderData(i, Qt.Horizontal, str(resultsHeaders[int(i)]), Qt.DisplayRole)
 

Ответ №1:

Должна быть реализована соответствующая функция «вставить столбцы», поскольку модель должна быть правильно обновлена, чтобы отразить фактическое количество столбцов, чтобы новые заголовки также отображались правильно.

Чтобы правильно добавлять столбцы, оба beginInsertColumn() (перед добавлением новых данных столбца) и endInsertColumn() (в конце операции) должны быть правильно вызваны.
Обычно для добавления дополнительных столбцов потребуется реализовать insertColumns() , но, учитывая ситуацию и тот факт, что они все равно будут вызывать оба метода, нет необходимости делатьэто и пользовательская функция будут в порядке.

Следующее вставляет только один столбец, если вы хотите добавить больше столбцов сразу, просто убедитесь, что третий аргумент beginInsertColumns правильно отражает это ( newColumn len(columnsToAdd) ) и что данные заголовка и новые пустые значения для массива соответствуют новому количеству столбцов.

 class ResultsModel(QAbstractTableModel):
    # ...
    def addColumn(self, name):
        newColumn = self.columnCount()
        self.beginInsertColumns(QModelIndex(), newColumn, newColumn)
        self.headerdata.append(name)
        for row in self.arraydata:
            row.append('')
        self.endInsertColumns()

# ...
class Whatever(QWidget):
    # ...
    def addColumn(self):
        name = 'New column {}'.format(self.resultsTableModel.columnCount())
        self.resultsTableModel.addColumn(name)
 

Обратите внимание, что:

  1. оба rowCount() и columnCount() должны иметь parent аргумент ключевого слова по умолчанию, как это делает базовая реализация (принятая практика предполагает parent=QModelIndex() );
  2. имена классов всегда должны быть с заглавной буквы, поэтому вам следует переименовать свой класс модели в R esultsModel; подробнее об этом читайте в официальном руководстве по стилю для кода Python;