I would like to modify any cell (except header) within given QTableView. Here below is my original code that does not allow for any changes:
import sys
import csv
from datetime import datetime, timedelta
import calendar
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import sqlite3
from pandas import DataFrame
class TBWindow(QMainWindow):
def __init__(self, parent=None):
super(TBWindow, self).__init__(parent)
sql = "select * from stock"
args = []
conn = sqlite3.connect('DataBase.db')
c = conn.cursor()
c.execute(sql,args)
data = c.fetchall()
names = list(map(lambda x: x[0], c.description))
c.close()
conn.close()
data = DataFrame(data, columns = names)
MenuBar = self.menuBar()
saveFile = QAction("&Save File", self)
saveFile.setShortcut("Ctrl+S")
saveFile.setStatusTip('Save File')
saveFile.triggered.connect(self.file_save)
MenuBar.addAction(saveFile)
self.setWindowTitle('Aplikace Princezna Pampeliska')
self.centralwidget = QWidget(self)
self.lineEdit = QLineEdit(self.centralwidget)
self.view = QTableView(self.centralwidget)
self.comboBox = QComboBox(self.centralwidget)
self.label = QLabel(self.centralwidget)
self.gridLayout = QGridLayout(self.centralwidget)
self.gridLayout.addWidget(self.lineEdit, 0, 1, 1, 1)
self.gridLayout.addWidget(self.view, 1, 0, 1, 3)
self.gridLayout.addWidget(self.comboBox, 0, 2, 1, 1)
self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
self.setCentralWidget(self.centralwidget)
self.label.setText("Filter")
self.model = PandasModel(data)
self.proxy = QSortFilterProxyModel(self)
self.proxy.setSourceModel(self.model)
self.view.setModel(self.proxy)
for column in range(self.view.horizontalHeader().count()):
self.view.resizeColumnToContents(column)
for i in (0,1,3):
self.view.horizontalHeader().setSectionResizeMode(i, QHeaderView.Stretch)
self.comboBox.addItems(list(data.columns.values))
self.lineEdit.textChanged.connect(self.on_lineEdit_textChanged)
self.comboBox.currentIndexChanged.connect(self.on_comboBox_currentIndexChanged)
self.horizontalHeader = self.view.horizontalHeader()
def file_save(self):
newModel = self.view.model()
data = []
for row in range(newModel.rowCount()):
rowRes = []
for column in range(newModel.columnCount()):
index = newModel.index(row, column)
item = newModel.data(index)
if item != '':
rowRes.append(item)
data.append(rowRes)
dataFrame = DataFrame(data)
options = QFileDialog.Options()
options |= QFileDialog.DontUseNativeDialog
fileName, fEnd = QFileDialog.getSaveFileName(self, "Save File", "", ".csv")
if fileName:
address = fileName+fEnd
dataFrame.to_csv(address, index=False, header=False)
@pyqtSlot(str)
def on_lineEdit_textChanged(self, text):
search = QRegExp(text, Qt.CaseInsensitive, QRegExp.RegExp)
self.proxy.setFilterRegExp(search)
@pyqtSlot(int)
def on_comboBox_currentIndexChanged(self, index):
self.proxy.setFilterKeyColumn(index)
class PandasModel(QAbstractTableModel):
def __init__(self, data, parent=None):
QAbstractTableModel.__init__(self, parent)
self._data = data
def rowCount(self, parent=None):
return self._data.shape[0]
def columnCount(self, parent=None):
return self._data.shape[1]
def data(self, index, role=Qt.DisplayRole):
if index.isValid():
if role == Qt.DisplayRole:
return str(self._data.iloc[index.row(), index.column()])
return None
def headerData(self, col, orientation, role):
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return self._data.columns[col]
return None
if __name__ == '__main__':
app = QApplication(sys.argv)
main = TBWindow()
main.showMaximized()
sys.exit(app.exec_())
I have read some articles about modifying cells within QTableView and found out that one needs to modify the model not the view. Hence the addition of this bit of code makes the cells editable:
def flags(self, index):
flags = super(self.__class__,self).flags(index)
flags |= Qt.ItemIsEditable
flags |= Qt.ItemIsSelectable
flags |= Qt.ItemIsEnabled
flags |= Qt.ItemIsDragEnabled
flags |= Qt.ItemIsDropEnabled
return flags
However, the changes do not persist, they disappear right after I click elsewhere. I tried to add function setData() in this manner with no success:
def setData(self, index, value, role=Qt.EditRole):
row = index.row()
col = index.column()
self._data[row][name] = value
self.emit(SIGNAL('dataChanged()'))
return True
The program exits with some key error. Any suggestions what should be changed? Thanks!