2013-08-05 14 views
10

Sfondo: Non riesco a trovare un esempio funzionante completo di una casella combinata all'interno di QTableView. Così ho scritto questo codice basato su molti altri esempi più elaborati là fuori. Il problema è, tuttavia, che in questo esempio è necessario fare doppio clic sulla combobox prima che venga abilitato, quindi è necessario fare nuovamente clic per rilasciarlo. Non è molto user-friendly. Se eseguo la non-model/view-thing usando QTableWidget, la casella combinata scende al primo clic.PyQt - esempio di funzionamento più semplice di una casella combinata all'interno di QTableView

Domanda: Qualcuno può guardare questo e dirmi cosa deve essere fatto per farlo rispondere come QTableWidget? Inoltre, se c'è qualcosa che sto facendo che non è necessario, si prega di indicare anche questo. Ad esempio, è assolutamente necessario fare riferimento allo stile dell'applicazione?

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

Si possono trovare la mia risposta a [questa domanda] (http://stackoverflow.com/questions/17615997/pyqt-how-to-set-qcombobox-in- a-table-view-using-qitemdelegate) utile. –

+1

Grazie, ora vedo che l'override di 'paint' non è necessario, e ho bisogno di' openPersistentEditor'. Ma chiamare 'openPersistentEditor' sembra sconfiggere lo scopo del modello/vista se devo chiamarlo dall'esterno del modello. Inoltre, sembra inefficiente disegnare tutte quelle caselle combinate quando puoi operare solo una alla volta. C'è un modo per eliminare il requisito del doppio clic in modo che appaia sulla selezione delle celle? – user2120303

+0

Non è necessario chiamarlo dal modello. Puoi utilizzare un altro oggetto (ad es. La tua vista o forma sottoclasse) per tracciare la modifica del modello e richiamare l'editor se necessario. Per la seconda domanda, collega il segnale 'selectionChanged' di' view-> selectionModel() 'allo slot. In questo slot aprire l'editor nella cella selezionata e chiudere gli editor precedenti se necessario. –

risposta

5

Utilizzando 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

La domanda richiede una casella combinata in un QTableView, non un QTableWidget. – ekhumoro

+0

@ekhumoro sì, l'ho visto ma pensavo volesse solo un modo per ottenere un widget in un tavolo. Probabilmente cancellerò questa risposta. –

1

Se si sta tentando di regolare quando la vista visualizza l'editor, è necessario cambiare la modifica grilletto come definito nel QAbstractItemView. L'impostazione predefinita è edit su doubleClick, ma penso che quello che stai cercando è QAbstractItemView.CurrentChanged. Impostare chiamando myView.setEditTrigger()

-1

Se qualcuno è interessato, qui di seguito è lo stesso esempio modificato per PyQt5 e Python 3. aggiornamenti chiave includono:

  • Python 3: super().__init__()
  • PyQt5: la maggior parte delle classi sono in QtWidgets ; QtGui non è necessario per questo esempio
  • Model.setData: ingresso ordine degli argomenti cambiato in: index, value, role e True restituito anziché None
  • Casella combinata choices e tabella contenuti specificati ora all'interno Main; questo rende Delegate e Model più generale
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_() 
Problemi correlati