2013-08-05 34 views
10

背景:我找不到QTableView内的组合框的完整工作示例。所以我写了这个代码基于其他几个更人为的例子。但问题是,此示例要求您在组合框启用之前双击组合框,然后再次单击将其放下。这不是非常用户友好的。如果我使用QTableWidget执行非模型/视图事件,则第一次单击时组合框会下降。PyQt - QTableView内组合框的最简单的工作示例

问题:有人可以看看这个,并告诉我需要做什么才能使其响应,就像QTableWidget?此外,如果有什么我没做的事情是不必要的,请指出。例如,是否有必要引用应用程序风格?

import sys 
from PyQt4 import QtGui, QtCore 

rows = "ABCD" 
choices = ['apple', 'orange', 'banana'] 

class Delegate(QtGui.QItemDelegate): 
    def __init__(self, owner, items): 
     super(Delegate, self).__init__(owner) 
     self.items = items 
    def createEditor(self, parent, option, index): 
     self.editor = QtGui.QComboBox(parent) 
     self.editor.addItems(self.items) 
     return self.editor 
    def paint(self, painter, option, index): 
     value = index.data(QtCore.Qt.DisplayRole).toString() 
     style = QtGui.QApplication.style() 
     opt = QtGui.QStyleOptionComboBox() 
     opt.text = str(value) 
     opt.rect = option.rect 
     style.drawComplexControl(QtGui.QStyle.CC_ComboBox, opt, painter) 
     QtGui.QItemDelegate.paint(self, painter, option, index) 
    def setEditorData(self, editor, index): 
     value = index.data(QtCore.Qt.DisplayRole).toString() 
     num = self.items.index(value) 
     editor.setCurrentIndex(num) 
    def setModelData(self, editor, model, index): 
     value = editor.currentText() 
     model.setData(index, QtCore.Qt.DisplayRole, QtCore.QVariant(value)) 
    def updateEditorGeometry(self, editor, option, index): 
     editor.setGeometry(option.rect) 

class Model(QtCore.QAbstractTableModel): 
    def __init__(self): 
     super(Model, self).__init__() 
     self.table = [[row, choices[0]] for row in rows] 
    def rowCount(self, index=QtCore.QModelIndex()): 
     return len(self.table) 
    def columnCount(self, index=QtCore.QModelIndex()): 
     return 2 
    def flags(self, index): 
     return QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable 
    def data(self, index, role): 
     if role == QtCore.Qt.DisplayRole: 
      return self.table[index.row()][index.column()] 
    def setData(self, index, role, value): 
     if role == QtCore.Qt.DisplayRole: 
      self.table[index.row()][index.column()] = value 

class Main(QtGui.QMainWindow): 
    def __init__(self, parent=None): 
     super(Main, self).__init__(parent) 
     self.model = Model() 
     self.table = QtGui.QTableView() 
     self.table.setModel(self.model) 
     self.table.setItemDelegateForColumn(1, Delegate(self, ["apple", "orange", "banana"])) 
     self.setCentralWidget(self.table) 
     self.setWindowTitle('Delegate Test') 
     self.show() 

if __name__ == '__main__': 
    app = QtGui.QApplication(sys.argv) 
    main = Main() 
    app.exec_() 
+0

您可能会发现我的答案为[这个问题](http://stackoverflow.com/questions/17615997/pyqt-how-to-set-qcombobox-in- a-table-view-using-qitemdelegate)有帮助。 –

+1

谢谢,现在我看到'paint'覆盖是不必要的,我需要'openPersistentEditor'。但是如果我需要从模型之外调用'openPersistentEditor',似乎就会打败模型/视图的目的。另外,当你只能一次操作一个组合框时,绘制所有组合框似乎效率低下。有没有办法摆脱双击要求,所以它出现在单元格选择? – user2120303

+0

您不需要从模型中调用它。您可以使用其他对象(例如,您的子类视图或表单)来跟踪模型更改并在必要时调用编辑器。对于第二个问题,将'view-> selectionModel()'的'selectionChanged'信号连接到您的插槽。在此插槽中打开所选单元格中的编辑器,并根据需要关闭以前的编辑器。 –

回答

5

使用QTableWiget.setCellWidget

import sys 
from PyQt4 import QtGui 
app = QtGui.QApplication(sys.argv) 
table = QtGui.QTableWidget(1,1) 
combobox = QtGui.QComboBox() 
combobox.addItem("Combobox item") 
table.setCellWidget(0,0, combobox) 
table.show() 
app.exec() 
+0

该问题要求在QTableView中的组合框,而不是QTableWidget。 – ekhumoro

+0

@ekhumoro是的,我看到了,但我认为他只是想要一种方法来获取表格中的小部件。我可能会删除这个答案。 –

-1

如果有人有兴趣将它设置,下面是修改PyQt5和Python 3的主要更新同样的例子包括:

  • 的Python 3:super().__init__()
  • PyQt5:大多数类是QtWidgets ;不需要用于此实例中
  • Model.setDataQtGui:输入参数顺序改变为:index, value, role,和True返回的None现在内部Main指定
  • 组合框choices和表内容代替;这使得DelegateModel更普遍
from PyQt5 import QtWidgets, QtCore 

class Delegate(QtWidgets.QItemDelegate): 
    def __init__(self, owner, choices): 
     super().__init__(owner) 
     self.items = choices 
    def createEditor(self, parent, option, index): 
     self.editor = QtWidgets.QComboBox(parent) 
     self.editor.addItems(self.items) 
     return self.editor 
    def paint(self, painter, option, index): 
     value = index.data(QtCore.Qt.DisplayRole) 
     style = QtWidgets.QApplication.style() 
     opt = QtWidgets.QStyleOptionComboBox() 
     opt.text = str(value) 
     opt.rect = option.rect 
     style.drawComplexControl(QtWidgets.QStyle.CC_ComboBox, opt, painter) 
     QtWidgets.QItemDelegate.paint(self, painter, option, index) 
    def setEditorData(self, editor, index): 
     value = index.data(QtCore.Qt.DisplayRole) 
     num = self.items.index(value) 
     editor.setCurrentIndex(num) 
    def setModelData(self, editor, model, index): 
     value = editor.currentText() 
     model.setData(index, QtCore.Qt.DisplayRole, QtCore.QVariant(value)) 
    def updateEditorGeometry(self, editor, option, index): 
     editor.setGeometry(option.rect) 

class Model(QtCore.QAbstractTableModel): 
    def __init__(self, table): 
     super().__init__() 
     self.table = table 
    def rowCount(self, parent): 
     return len(self.table) 
    def columnCount(self, parent): 
     return len(self.table[0]) 
    def flags(self, index): 
     return QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable 
    def data(self, index, role): 
     if role == QtCore.Qt.DisplayRole: 
      return self.table[index.row()][index.column()] 
    def setData(self, index, value, role): 
     if role == QtCore.Qt.EditRole: 
      self.table[index.row()][index.column()] = value 
     return True 

class Main(QtWidgets.QMainWindow): 
    def __init__(self, parent=None): 
     super().__init__(parent) 
     # set combo box choices: 
     choices = ['apple', 'orange', 'banana'] 
     # create table data: 
     table = [] 
     table.append(['A', choices[0]]) 
     table.append(['B', choices[0]]) 
     table.append(['C', choices[0]]) 
     table.append(['D', choices[0]]) 
     # create table view: 
     self.model  = Model(table) 
     self.tableView = QtWidgets.QTableView() 
     self.tableView.setModel(self.model) 
     self.tableView.setItemDelegateForColumn(1, Delegate(self,choices)) 
     # make combo boxes editable with a single-click: 
     for row in range(len(table)): 
      self.tableView.openPersistentEditor(self.model.index(row, 1)) 
     # initialize 
     self.setCentralWidget(self.tableView) 
     self.setWindowTitle('Delegate Test') 
     self.show() 

if __name__ == '__main__': 
    import sys 
    app = QtWidgets.QApplication(sys.argv) 
    main = Main() 
    app.exec_()