2013-08-05 59 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_()