我想修改给定QTableView中的任何单元格(标头除外).以下是我的原始代码,不允许进行任何更改:
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_())
我已经阅读了一些有关在QTableView中修改单元格的文章,发现需要修改模型而不是视图.因此,这部分代码的添加使单元格可编辑:
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
但是,更改不会持久存在,在我单击其他位置后它们会立即消失.我试图以这种方式添加函数setData(),但没有成功:
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
程序退出并出现一些关键错误.有什么建议应该改变吗?谢谢!
解决方法:
您的代码有2个错误:
>第一种是由于不良的编程习惯引起的:您不应使用与其他变量,函数或类一起使用的名称来调用变量.在您的情况下,标志是方法的名称,因此您不应在变量的名称中使用它:
def flags(self, index):
fl = super(self.__class__,self).flags(index)
fl |= Qt.ItemIsEditable
fl |= Qt.ItemIsSelectable
fl |= Qt.ItemIsEnabled
fl |= Qt.ItemIsDragEnabled
fl |= Qt.ItemIsDropEnabled
return fl
>第二个错误是由于未使用正确的方法访问和分配熊猫中的数据而引起的,这必须通过iloc方法来完成.另一个问题是,您正在使用PyQt4的有效方法来通知更改,您必须使用新语法加上dataChanged信号在Qt5中添加新字段,如在docs中所见:
def setData(self, index, value, role=Qt.EditRole):
if index.isValid():
row = index.row()
col = index.column()
self._data.iloc[row][col] = float(value)
self.dataChanged.emit(index, index, (Qt.DisplayRole, ))
return True
return False
加:
我先前还实现了一个使用大熊猫创建模型的类,如您在问题How to display a Pandas data frame with PyQt5中所见