I have implemented a QTableView with QAbstractTableModel along with QSortFilterProxyModel
After adding the QSortFilterProxyModel, I am not able to print the Model's data. I am adding the code below.
In the below code I have added comments like "with proxy model" and "without proxy model"
If you comments the lines "with proxy model" and uncomment "without proxy model", run the code and click on "Export" button, then the data in the model in printed in the terminal
But if you uncomments the lines "with proxy model" and comment "without proxy model", run the code and click on "Export" button then error message shown as
line 235, in export_tv self.tableview.model().print_arraydata() AttributeError: 'QSortFilterProxyModel' object has no attribute 'print_arraydata'
I want export feature to work along with the QSortFilterProxyModel
Add / Delete button also does not work with QSortFilterProxyModel. What am I missing here?
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QMessageBox
from datetime import datetime
import traceback
import sys
class Utils:
@staticmethod
def showMsgOnScreen(pFunctionName, pErrorMessage):
try:
msg = QMessageBox()
msg.setIcon(QMessageBox.Critical)
msg.setText(pFunctionName)
msg.setInformativeText(pErrorMessage)
msg.setWindowTitle("Error")
msg.exec_()
except Exception as e:
errmsg = "".join(traceback.format_exception(type(e), e, e.__traceback__))
raise Exception(f"Function: Utils.showMsgOnScreen\n{errmsg}")
class Model(QtCore.QAbstractTableModel):
ActiveRole = QtCore.Qt.UserRole + 1
def __init__(self, datain, columnHeaders, columnDataType, columneditlist, parent=None):
try:
super().__init__()
self._data = datain
self._cols = columnHeaders
self.r = len(self._data)
self.c = len(self._data[0])
self.columnDataType = columnHeaders
self.columneditlist = columneditlist
except Exception as e:
Utils.showMsgOnScreen("Model.__init__", "".join(traceback.format_exception(type(e), e, e.__traceback__)))
def headerData(self, column, orientation, role):
try:
if role == QtCore.Qt.DisplayRole:
if orientation == QtCore.Qt.Horizontal:
return QtCore.QVariant(self._cols[column])
else:
return super().headerData(column, orientation, role)
return QtCore.QVariant()
except Exception as e:
Utils.showMsgOnScreen("Model.headerData", "".join(traceback.format_exception(type(e), e, e.__traceback__)))
def rowCount(self, parent=QtCore.QModelIndex()):
try:
if parent.isValid(): return 0
return len(self._data)
except Exception as e:
Utils.showMsgOnScreen("Model.rowCount", "".join(traceback.format_exception(type(e), e, e.__traceback__)))
def columnCount(self, parent=QtCore.QModelIndex()):
try:
if parent.isValid(): return 0
if len(self._data) > 0:
return len(self._data[0])
return 0
except Exception as e:
Utils.showMsgOnScreen("Model.columnCount", "".join(traceback.format_exception(type(e), e, e.__traceback__)))
def flags(self, index):
try:
if self.columneditlist[index.column()] == False:
return QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled
elif self.columneditlist[index.column()] == True:
return QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsEnabled
except Exception as e:
Utils.showMsgOnScreen("Model.flags", "".join(traceback.format_exception(type(e), e, e.__traceback__)))
def data(self, index, role):
try:
if not index.isValid():
return QtCore.QVariant()
if index.isValid():
col = index.column()
if role == QtCore.Qt.DisplayRole or role == QtCore.Qt.EditRole:
if self.columnDataType[col] == "INT":
return QtCore.QVariant(int(self._data[index.row()][index.column()]))
else:
return QtCore.QVariant(self._data[index.row()][index.column()])
elif role == QtCore.Qt.TextAlignmentRole:
if self.columnDataType[col] == "INT":
return int(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
if self.columnDataType[col] == "STR":
return int(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
if self.columnDataType[col] == "COMBOBOX":
return int(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
elif role == QtCore.Qt.BackgroundRole:
if self.columneditlist[index.column()] == False:
return QtCore.QVariant(QtGui.QColor(QtCore.Qt.gray))
elif role != QtCore.Qt.DisplayRole:
return QtCore.QVariant()
return QtCore.QVariant(self._data[index.row()][index.column()])
except Exception as e:
Utils.showMsgOnScreen("Model.data", "".join(traceback.format_exception(type(e), e, e.__traceback__)))
def setData(self, index, value, role=QtCore.Qt.EditRole):
try:
if role == QtCore.Qt.EditRole:
self._data[index.row()][index.column()] = value
self.dataChanged.emit(index, index, (QtCore.Qt.DisplayRole,))
return True
return False
except Exception as e:
Utils.showMsgOnScreen("Model.setData", "".join(traceback.format_exception(type(e), e, e.__traceback__)))
def print_arraydata(self):
try:
print()
for rownum in range(len(self._data)):
print(self._data[rownum])
except Exception as e:
Utils.showMsgOnScreen("Model.print_arraydata", "".join(traceback.format_exception(type(e), e, e.__traceback__)))
def insert_row(self, position, rows=1):
try:
self.beginInsertRows(QtCore.QModelIndex(), position, (position+1) + rows - 1)
prevrowdata = self._data[position].copy()
self._data.insert(position+1, prevrowdata)
self.endInsertRows()
return True
except Exception as e:
Utils.showMsgOnScreen("Model.insert_row", "".join(traceback.format_exception(type(e), e, e.__traceback__)))
def remove_row(self, position, rows=1):
try:
self.beginRemoveRows(QtCore.QModelIndex(), position, position + rows - 1)
self._data = self._data[:positio] + self._data[position + rows:]
self.endRemoveRows()
return True
except Exception as e:
Utils.showMsgOnScreen("Model.remove_row", "".join(traceback.format_exception(type(e), e, e.__traceback__)))
def append_row(self, crow):
try:
self.insert_row(crow)
except Exception as e:
Utils.showMsgOnScreen("Model.append_row", "".join(traceback.format_exception(type(e), e, e.__traceback__)))
class Main(QtWidgets.QMainWindow):
def __init__(self, parent=None):
try:
super().__init__(parent)
self.get_table_data()
self.tableview, self.proxymodel = self.createTable()
self.tableview.model().rowsInserted.connect(lambda: QtCore.QTimer.singleShot(0, self.tableview.scrollToBottom))
# Set the maximum value of row to the selected row
self.selectrow = self.tableview.model().rowCount()
# create buttons
self.addbtn = QtWidgets.QPushButton("Add")
self.addbtn.clicked.connect(self.insert_row)
self.deletebtn = QtWidgets.QPushButton("Delete")
self.deletebtn.clicked.connect(self.remove_row)
self.exportbtn = QtWidgets.QPushButton("Export")
self.exportbtn.clicked.connect(self.export_tv)
self.computebtn = QtWidgets.QPushButton("Compute")
self.enablechkbox = QtWidgets.QPushButton("Completed")
# create label
self.searchbar = QtWidgets.QLineEdit()
self.searchbar.setFont(QtGui.QFont("Arial", 10))
self.searchbar.textChanged.connect(self.proxymodel.setFilterFixedString)
# create gridlayout
grid_layout = QtWidgets.QGridLayout()
grid_layout.addWidget(self.exportbtn, 2, 2, 1, 1)
grid_layout.addWidget(self.computebtn, 2, 3, 1, 1)
grid_layout.addWidget(self.addbtn, 2, 4, 1, 1)
grid_layout.addWidget(self.deletebtn, 2, 5, 1, 1)
grid_layout.addWidget(self.enablechkbox, 2, 6, 1, 1, QtCore.Qt.AlignCenter)
grid_layout.addWidget(self.tableview, 1, 0, 1, 7)
grid_layout.addWidget(self.searchbar, 0, 3, 1, 1, QtCore.Qt.AlignCenter)
# initializing layout
self.title = "Data Visualization Tool"
self.setWindowTitle(self.title)
self.setGeometry(0, 0, 1024, 576)
self.showMaximized()
self.centralwidget = QtWidgets.QWidget()
self.centralwidget.setLayout(grid_layout)
self.setCentralWidget(self.centralwidget)
except Exception as e:
Utils.showMsgOnScreen("Main.__init__", "".join(traceback.format_exception(type(e), e, e.__traceback__)))
def get_table_data(self):
try:
self.tabledata = [
[1, 'type_1', 21, 'RESOLVED', 'Jack', '2023-01-01'],
[2, 'type_2', 22, 'UNRESOLVED', 'Roger', '2023-01-02'],
[3, 'type_3', 55, 'XYZ', 'Ethan', '2023-01-03'],
[4, 'type_4', 66, 'abc', 'Ivan', '2023-01-04'],
[5, 'type_5', 111, 'abc', 'Rob', '2023-01-05'],
[6, 'type_6', 60, 'abc', 'Rachel', '2023-01-06'],
[7, 'type_7', 12, 'abc', 'Stacie', '2023-01-07']
]
except Exception as e:
Utils.showMsgOnScreen("Main.get_table_data", "".join(traceback.format_exception(type(e), e, e.__traceback__)))
def createTable(self):
try:
tv = QtWidgets.QTableView()
datadict = {
"columnheaders": ['SRNO', 'TYPE', 'ID', 'STATUS', 'NAME', 'START_DATE'],
"columndatatype": ['INT', 'COMBOBOX', 'INT', 'STR', 'STR', 'DATE'],
"columnedittype": [False, True, True, True, True, True]
}
tablemodel = Model(self.tabledata,
datadict['columnheaders'],
datadict['columndatatype'],
datadict['columnedittype'],
self)
proxy_model = QtCore.QSortFilterProxyModel()
proxy_model.setFilterKeyColumn(-1) # with proxy model
proxy_model.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive) # with proxy model
proxy_model.setSourceModel(tablemodel) # with proxy model
proxy_model.sort(0, QtCore.Qt.AscendingOrder) # with proxy model
tv.setModel(proxy_model) # with proxy model
# tv.setModel(tablemodel) # without proxy model
tv.resizeRowsToContents()
return tv, proxy_model
except Exception as e:
Utils.showMsgOnScreen("Main.createTable", "".join(traceback.format_exception(type(e), e, e.__traceback__)))
def export_tv(self):
try:
self.tableview.model().print_arraydata()
except Exception as e:
Utils.showMsgOnScreen("Main.export_tv", "".join(traceback.format_exception(type(e), e, e.__traceback__)))
def remove_row(self):
try:
currrow = self.tableview.currentIndex().row()
if currrow != -1:
self.tableview.model().remove_row(currrow)
except Exception as e:
Utils.showMsgOnScreen("Main.remove_row", "".join(traceback.format_exception(type(e), e, e.__traceback__)))
def insert_row(self):
try:
currrow = self.tableview.currentIndex().row()
if currrow != -1:
self.tableview.model().append_row(currrow)
except Exception as e:
Utils.showMsgOnScreen("Main.insert_row", "".join(traceback.format_exception(type(e), e, e.__traceback__)))
if __name__ == '__main__':
try:
app = QtWidgets.QApplication(sys.argv)
main = Main()
main.show()
sys.exit(app.exec_())
except Exception as e:
errmsg = "".join(traceback.format_exception(type(e), e, e.__traceback__))
errorstring = f"Function: __main__\n{str(errmsg)}"
print("Error Message!", f"{errorstring}", "Critical")