Добрый день,
Я изучаю PyQt5 и имею следующую проблему:
Я хочу отобразить pandas Датафрейм на экране. Пользователь просматривает данные и дважды щелкает по ячейкам, чтобы вручную установить значение. Последний бит вызывает у меня проблемы.
from PyQt5 import QtCore, QtWidgets
import pandas as pd
import sys
#Code snippet from SO.
class DataFrameModel(QtCore.QAbstractTableModel):
DtypeRole = QtCore.Qt.UserRole + 1000
ValueRole = QtCore.Qt.UserRole + 1001
def __init__(self, df=pd.DataFrame(), parent=None):
super(DataFrameModel, self).__init__(parent)
self._dataframe = df
def setDataFrame(self, dataframe):
self.beginResetModel()
self._dataframe = dataframe.copy()
self.endResetModel()
def dataFrame(self):
return self._dataframe
dataFrame = QtCore.pyqtProperty(pd.DataFrame, fget=dataFrame, fset=setDataFrame)
@QtCore.pyqtSlot(int, QtCore.Qt.Orientation, result=str)
def headerData(self, section: int, orientation: QtCore.Qt.Orientation, role: int = QtCore.Qt.DisplayRole):
if role == QtCore.Qt.DisplayRole:
if orientation == QtCore.Qt.Horizontal:
return self._dataframe.columns[section]
else:
return str(self._dataframe.index[section])
return QtCore.QVariant()
def rowCount(self, parent=QtCore.QModelIndex()):
if parent.isValid():
return 0
return len(self._dataframe.index)
def columnCount(self, parent=QtCore.QModelIndex()):
if parent.isValid():
return 0
return self._dataframe.columns.size
def data(self, index, role=QtCore.Qt.DisplayRole):
if not index.isValid() or not (0 <= index.row() < self.rowCount() \
and 0 <= index.column() < self.columnCount()):
return QtCore.QVariant()
row = self._dataframe.index[index.row()]
col = self._dataframe.columns[index.column()]
dt = self._dataframe[col].dtype
val = self._dataframe.iloc[row][col]
if role == QtCore.Qt.DisplayRole:
return str(val)
elif role == DataFrameModel.ValueRole:
return val
if role == DataFrameModel.DtypeRole:
return dt
return QtCore.QVariant()
def roleNames(self):
roles = {
QtCore.Qt.DisplayRole: b'display',
DataFrameModel.DtypeRole: b'dtype',
DataFrameModel.ValueRole: b'value'
}
return roles
Класс работает нормально при отображении данных.
class Main_Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
QtWidgets.QWidget.__init__(self, parent=None)
vLayout = QtWidgets.QVBoxLayout(self)
hLayout = QtWidgets.QHBoxLayout()
self.pathLE = QtWidgets.QLineEdit(self)
hLayout.addWidget(self.pathLE)
self.loadBtn = QtWidgets.QPushButton("Select File", self)
hLayout.addWidget(self.loadBtn)
vLayout.addLayout(hLayout)
self.pandasTv = QtWidgets.QTableView(self)
vLayout.addWidget(self.pandasTv)
self.loadBtn.clicked.connect(self.loadFile)
self.pandasTv.setSortingEnabled(True)
self.setGeometry (100,100,600,1000)
self.pandasTv.doubleClicked.connect(self.on_click) #
def loadFile(self):
fileName, _ = QtWidgets.QFileDialog.getOpenFileName(self, "Open File", "", "CSV Files (*.csv)");
self.pathLE.setText(fileName)
tmp = pd.read_csv(fileName, sep=None, engine='python', iterator=True)
sep = tmp._engine.data.dialect.delimiter
tmp.close()
df = pd.read_csv(fileName, sep=sep, dtype = object)
model = DataFrameModel(df)
self.pandasTv.setModel(model)
def on_click(self, signal):
row, col = signal.row(), signal.column() # Row, col of DoubleClick
tmp = self.pandasTv.model().index(row, col).data() #Gets the data
text, res = QtWidgets.QInputDialog.getText(self, 'input', tmp , QtWidgets.QLineEdit.Normal,tmp) #manual user input
print(text)
#self.pandasTv.[set_value(row,col)= text]
И стандарт:
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
На этом этапе мне нужно сделать что-то вроде:
self.pandasTv.set_value (row, col) = текст, но это кажется ... неуловимым.
После этого. Данные должны быть либо сохранены, либо переданы в основную программу.
Есть мысли, как поступить? Спасибо