2013-07-17 4 views
12

Ich möchte einen Pandas-Datenrahmen in einer PyQt-Tabelle anzeigen. Ich habe dabei einige Fortschritte gemacht, konnte aber die Klasse des Tabellenmodells nicht korrekt ableiten. Jede Hilfe mit diesem würde sehr geschätzt werden.PyQt - Implementiere ein QAbstractTableModel zur Anzeige in QTableView

** Hinweis vollständige Beispielcode here **

Ich kämpfe eine gültige QtCore.QAbstractTableModel abgeleitete Klasse zu generieren. Nach einer vorherigen Frage zu QItemDelegates versuche ich ein Tabellenmodell aus einem Pandas DataFrame zu erzeugen, um echte Daten einzufügen. Ich habe Beispielcode here, aber wenn ich mein TableModel durch TableModel2 in der Widget-Klasse (ln 152) ersetze, kann ich die Tabelle nicht anzeigen lassen.

class TableModel2(QtCore.QAbstractTableModel): 
    def __init__(self, parent=None, *args): 
     super(TableModel2, self).__init__() 
     #QtCore.QAbstractTableModel.__init__(self, parent, *args) 
     self.datatable = None 
     self.headerdata = None 
     self.dataFrame = None 
     self.model = QtGui.QStandardItemModel(self) 

    def update(self, dataIn): 
     print 'Updating Model' 
     self.datatable = dataIn 
     print 'Datatable : {0}'.format(self.datatable) 
     headers = dataIn.columns.values 
     header_items = [ 
        str(field) 
        for field in headers 
     ] 
     self.headerdata = header_items 
     print 'Headers' 
     print self.headerdata 

     for i in range(len(dataIn.index.values)): 
      for j in range(len(dataIn.columns.values)): 
       #self.datatable.setItem(i,j,QtGui.QTableWidgetItem(str(df.iget_value(i, j)))) 
       self.model.setItem(i,j,QtGui.QStandardItem(str(dataIn.iget_value(i, j)))) 

    def rowCount(self, parent=QtCore.QModelIndex()): 
     return len(self.datatable.index) 

    def columnCount(self, parent=QtCore.QModelIndex()): 
     return len(self.datatable.columns.values) 

    def data(self, index, role=QtCore.Qt.DisplayRole): 
     if not index.isValid(): 
      return QtCore.QVariant() 
     elif role != QtCore.Qt.DisplayRole: 
      return QtCore.QVariant() 
     #return QtCore.QVariant(self.model.data(index)) 
      return QtCore.QVariant(self.model.data(index)) 

    def headerData(self, col, orientation, role): 
     if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole: 
      return QtCore.QVariant() 
     return QtCore.QVariant(self.headerdata[col]) 

    def setData(self, index, value, role=QtCore.Qt.DisplayRole): 
     print "setData", index.row(), index.column(), value 

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

Ich bin versucht, das Modell zu erstellen und es dann zu der Ansicht hinzufügen, wie folgt aus:

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) 
     cdf = self.get_data_frame() 
     self._tm=TableModel(self) 
     self._tm.update(cdf) 
     self._tv=TableView(self) 
     self._tv.setModel(self._tm) 
     for row in range(0, self._tm.rowCount()): 
      self._tv.openPersistentEditor(self._tm.index(row, 0)) 
     l.addWidget(self._tv) 

    def get_data_frame(self): 
     df = pd.DataFrame({'Name':['a','b','c','d'], 
     'First':[2.3,5.4,3.1,7.7], 'Last':[23.4,11.2,65.3,88.8], 'Class':[1,1,2,1], 'Valid':[True, True, True, False]}) 
     return df 

Vielen Dank für Ihre Aufmerksamkeit!

Hinweis: Bearbeiten 2 Ich habe das QStandardItemModel in TableModel2 integriert. Außerdem wurde die dataFrameToQtTable-Funktion nach dem @ mata-Kommentar gelöscht. Das wird ein bisschen näher, funktioniert aber immer noch nicht.

+0

Pandas hat . https://github.com/pydata/pandas/commits/master/pandas/sandbox/qtpandas.py –

Antwort

10

Ok Ich habe das mit dem obigen Vorschlag und etwas Hilfe aus dem Rapid GUI Buch von Summerfield herausgefunden. Es gibt kein zugrunde liegendes Modell, das in QAbstractTableModel vorhanden ist. Es müssen nur drei Funktionen außer Kraft gesetzt werden, und die Daten können in jedem benutzerdefinierten Format gespeichert werden, solange es im Datenaufruf zurückgegeben wird.

Eine sehr einfache Implementierung könnte sein:

class TableModel(QtCore.QAbstractTableModel): 
    def __init__(self, parent=None, *args): 
     super(TableModel, self).__init__() 
     self.datatable = None 

    def update(self, dataIn): 
     print 'Updating Model' 
     self.datatable = dataIn 
     print 'Datatable : {0}'.format(self.datatable) 

    def rowCount(self, parent=QtCore.QModelIndex()): 
     return len(self.datatable.index) 

    def columnCount(self, parent=QtCore.QModelIndex()): 
     return len(self.datatable.columns.values) 

    def data(self, index, role=QtCore.Qt.DisplayRole): 
     if role == QtCore.Qt.DisplayRole: 
      i = index.row() 
      j = index.column() 
      return '{0}'.format(self.datatable.iget_value(i, j)) 
     else: 
      return QtCore.QVariant() 

    def flags(self, index): 
     return QtCore.Qt.ItemIsEnabled 

Dies ermöglicht es Ihnen, jede compatable Datenrahmen in einer Qt-Ansicht anzuzeigen.

Ich habe die Gist über here

aktualisiert dieses Dies sollten Sie gehen schnell, wenn Sie auch tun müssen.

+0

Leider Spalten- und Indexnamen werden nicht angezeigt? Es wäre schön, wenn Sie das beheben könnten. – working4coins

1

Dies ist wahrscheinlich Ihr Problem:

def rowCount(self, parent=QtCore.QModelIndex()): 
    if type(self.datatable) == pd.DataFrame: 
    ... 


def columnCount(self, parent=QtCore.QModelIndex()): 
    if (self.datatable) == pd.DataFrame: 
    ... 

Sie setzen Ihre datatable auf eine QTableWidget in dataFrameToQtTable, so dass es kein pd.DataFrame sein kann, wird Ihre Methoden immer 0 zurück

Ohne den Typ überprüfen Sie, Sie hätten das Problem sofort bemerkt. Möchten Sie alle Fälle, in denen Ihr Typ nicht übereinstimmt, ignorieren (besser einen Fehler auslösen, wenn er nicht der erwarteten Oberfläche entspricht)? Tychecks sind in most cases unnecessary.

+0

Ja, ich weiß, dass das falsch ist, aber das ist mein Problem. Ich denke nicht, dass es auf ein QTableWidgetItem gesetzt werden sollte. Ich möchte das interne Modell in QAbstractTableModel aktualisieren, aber ich bin nicht sicher, wie das geht - oder finde die Zeilen- oder Spaltenanzahl. Vielen Dank. – drexiya

+0

Ich habe den Beispielcode vereinfacht, um dieses dataFrameToQtTable zu entfernen, hoffentlich wird das Problem klarer. – drexiya

Verwandte Themen