2017-12-29 17 views
1

주어진 QTableView 내의 셀 (헤더 제외)을 수정하고 싶습니다. 내가 QTableView 내에서 세포를 수정하는 방법에 대한 몇 가지 기사를 읽고 하나의 모델이 아닌보기를 수정할 필요가 있다는 것을 발견했다QTableView PYQT5에서 셀 수정

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_()) 

: 여기에 아래의 변경을 허용하지 않는 내 원래의 코드입니다. 따라서 코드의이 비트의 추가는 세포를 편집 할 수 있습니다 :

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 방법을 통해 수행해야합니다.

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 
을 : 또 다른 문제는 PyQt4 변경 내용을 통지하기 위해, 당신이 docs에서 볼 수 Qt5에 새로운 필드를 추가하기 위해 새로운 구문을 더한 dataChanged 신호를 사용해야 올바른 방법을 사용하고 있다는 점이다

플러스 : 당신이 질문 How to display a Pandas data frame with PyQt5

+0

에서 볼 수 있듯이 나는 또한 이전에 팬더를 사용하여 모델을 생성하는 클래스를 구현 한

추천/도움에 감사드립니다. 나는 float()을 제거하고 작동한다. – New2Python