2013-07-12 14 views
5

Sto provando a visualizzare una casella combinata nella mia tabella, in modo da poter impostare l'indice selezionato dal modello di tabella, come con le altre celle nella tabella. L'ho messo insieme da altri esempi, ma non riesco ancora a capire come funziona l'interazione per impostare l'indice selezionato di QComboBox.PyQt - Come impostare QComboBox in una vista tabella usando QItemDelegate

Questo è l'esempio più semplice che riesco a dimostrare per illustrare il problema. Se qualcuno può dimostrare come impostare automaticamente l'indice dai dati del modello? Inoltre, come utilizzare il segnale 'currentIndexChanged', in quanto sembra che si sprigioni quasi continuamente ogni volta che viene ridipinto? Grazie.

# The following tells SIP (the system that binds Qt's C++ to Python) 
# to return Python native types rather than QString and QVariant 
import sip 
sip.setapi('QString', 2) 
sip.setapi('QVariant', 2) 


from PyQt4 import QtCore, QtGui 

class TableModel(QtCore.QAbstractTableModel): 
    """ 
    A simple 5x4 table model to demonstrate the delegates 
    """ 
    def rowCount(self, parent=QtCore.QModelIndex()): return 5 
    def columnCount(self, parent=QtCore.QModelIndex()): return 4 

    def data(self, index, role=QtCore.Qt.DisplayRole): 
     if not index.isValid(): return None 
     if not role==QtCore.Qt.DisplayRole: return None 
     return "{0:02d}".format(index.row()) 


class ComboDelegate(QtGui.QItemDelegate): 
    """ 
    A delegate that places a fully functioning QComboBox in every 
    cell of the column to which it's applied 
    """ 
    def __init__(self, parent): 

     QtGui.QItemDelegate.__init__(self, parent) 

    def paint(self, painter, option, index): 

     self.combo = QtGui.QComboBox(self.parent()) 
     self.connect(self.combo, QtCore.SIGNAL("currentIndexChanged(int)"), self.parent().currentIndexChanged) 

     li = [] 
     li.append("Zero") 
     li.append("One") 
     li.append("Two") 
     li.append("Three") 
     li.append("Four") 
     li.append("Five") 

     self.combo.addItems(li) 

     if not self.parent().indexWidget(index): 
      self.parent().setIndexWidget(
       index, 
       self.combo 
      ) 

class TableView(QtGui.QTableView): 
    """ 
    A simple table to demonstrate the QComboBox delegate. 
    """ 
    def __init__(self, *args, **kwargs): 
     QtGui.QTableView.__init__(self, *args, **kwargs) 

     # Set the delegate for column 0 of our table 
     # self.setItemDelegateForColumn(0, ButtonDelegate(self)) 
     self.setItemDelegateForColumn(0, ComboDelegate(self)) 

    @QtCore.pyqtSlot() 
    def currentIndexChanged(self, ind): 
     print "Combo Index changed {0} {1} : {2}".format(ind, self.sender().currentIndex(), self.sender().currentText()) 

if __name__=="__main__": 
    from sys import argv, exit 

    class Widget(QtGui.QWidget): 
     """ 
     A simple test widget to contain and own the model and table. 
     """ 
     def __init__(self, parent=None): 
      QtGui.QWidget.__init__(self, parent) 

      l=QtGui.QVBoxLayout(self) 
      self._tm=TableModel(self) 
      self._tv=TableView(self) 
      self._tv.setModel(self._tm) 
      l.addWidget(self._tv) 

    a=QtGui.QApplication(argv) 
    w=Widget() 
    w.show() 
    w.raise_() 
    exit(a.exec_()) 

risposta

17

Si sta utilizzando il metodo paint in modo errato. Dovrebbe essere utilizzato quando si desidera modificare la visualizzazione del comportamento della vista. Inoltre, creare nuovi widget ogni volta che si desidera dipingere è molto costoso. Ma si desidera modificare il comportamento di modifica, quindi è necessario modificare l'intera logica del programma.

Vedere fixed code. Di seguito esporrò le modifiche.

1. Prima di tutto, è necessario rendere modificabile la prima colonna. Puoi farlo da reimplementare QAbstractItemModel::flags:

def flags(self, index): 
    if (index.column() == 0): 
     return QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled 
    else: 
     return QtCore.Qt.ItemIsEnabled 

2. Per impostazione predefinita l'editor elemento viene creato quando l'utente esegue un doppio click sulla voce. Se si desidera visualizzare tutti i comboboxes per impostazione predefinita, è possibile utilizzare openPersistentEditor:

for row in range(0, self._tm.rowCount()): 
    self._tv.openPersistentEditor(self._tm.index(row, 0)) 

Si raccomanda di eseguire gli editor aperto anche per le cellule di nuova creazione (se presenti).

3. Ora torniamo al nostro delegato. Abbiamo bisogno di implementare createEditor metodo che verrà chiamato automaticamente dalla vista quando si richiede un editor per una cella:

def createEditor(self, parent, option, index): 
    combo = QtGui.QComboBox(parent) 
    li = [] 
    li.append("Zero") 
    li.append("One") 
    li.append("Two") 
    li.append("Three") 
    li.append("Four") 
    li.append("Five") 
    combo.addItems(li) 
    self.connect(combo, QtCore.SIGNAL("currentIndexChanged(int)"), 
       self, QtCore.SLOT("currentIndexChanged()")) 
    return combo 

Si noti che è al di sotto connectappend s perché dobbiamo evitare currentIndexChanged segnali su inizializzazione.

4. Implementare setEditorData metodo che verrà chiamato dalla vista quando i dati modello è stato cambiato. Inoltre verrà chiamato una volta quando viene inizializzato un editor.

def setEditorData(self, editor, index): 
    editor.blockSignals(True) 
    editor.setCurrentIndex(int(index.model().data(index))) 
    editor.blockSignals(False) 

Anche in questo caso, vogliamo evitare segnali che non sono causati da parte dell'utente, in modo da usiamo blockSignals.

5. Nello slot abbiamo semplicemente emettiamo commitData segnale che farà sì che la vista per chiamare il setModelData del nostro delegato:

@QtCore.pyqtSlot() 
def currentIndexChanged(self): 
    self.commitData.emit(self.sender()) 

6. Implementare setModelData metodo:

def setModelData(self, editor, model, index): 
    model.setData(index, editor.currentIndex()) 

7. Il modello ha la necessità di supportare il cambiamento dei dati.Quindi dovremmo implementare setData metodo del modello:

def setData(self, index, value, role=QtCore.Qt.DisplayRole): 
    print "setData", index.row(), index.column(), value 
    # todo: remember the data 
+0

Ho aggiunto un follow-up domanda sul modello di dati [qui] (http://stackoverflow.com/questions/17697352/pyqt-implement-a-qabstracttablemodel -for-display-in-qtableview) piuttosto che estendere troppo questa domanda. – drexiya

+0

Un'altra domanda di follow-up [qui] (http://stackoverflow.com/questions/17748546/pyqt-column-of-checkboxes-in-a-qtableview) sull'aggiunta di una colonna di checkbox alla vista. – drexiya

Problemi correlati