2013-07-17 72 views
12

Tôi muốn hiển thị khung dữ liệu gấu trúc trong bảng PyQt. Tôi đã thực hiện một số tiến bộ với điều này, nhưng đã không thể có được một cách chính xác lấy được các lớp mô hình bảng. Đánh giá rất cao mọi sự giúp đỡ trong trường hợp này.PyQt - Triển khai QAbstractTableModel để hiển thị trong QTableView

** Lưu ý đầy đủ mã ví dụ here **

Tôi đang nỗ lực để tạo ra một QtCore.QAbstractTableModel hợp lệ lớp dẫn xuất. Tiếp theo từ một câu hỏi trước về QItemDelegates Tôi đang cố gắng tạo ra một mô hình bảng từ một khung dữ liệu Pandas để chèn dữ liệu thực. Tôi có mã ví dụ làm việc here, nhưng nếu tôi thay thế TableModel bằng TableModel2 trong lớp Widget (ln 152), tôi không thể hiển thị bảng.

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 

Tôi đang cố gắng để tạo ra các mô hình và sau đó thêm nó vào xem, như thế này:

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 

Cám ơn sự quan tâm của bạn!

Lưu ý: Chỉnh sửa 2 Tôi đã kết hợp QStandardItemModel vào TableModel2. Cũng đã xóa hàm dataFrameToQtTable sau nhận xét của @ mata. Điều này đang tiến gần hơn một chút nhưng vẫn không hoạt động.

+0

Pandas có một bảng ví dụ Qt trong repo của nó . https://github.com/pydata/pandas/commits/master/pandas/sandbox/qtpandas.py –

Trả lời

10

Ok Tôi đã tìm ra điều này với đề xuất ở trên và một số trợ giúp từ sách Giao diện người dùng nhanh của Summerfield. Không có mô hình cơ bản tồn tại trong QAbstractTableModel. Chỉ có ba hàm cần được ghi đè và dữ liệu có thể được lưu trữ ở bất kỳ định dạng do người dùng xác định nào miễn là nó được trả về trong cuộc gọi dữ liệu.

Một thực hiện rất đơn giản có thể là:

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 

này cho phép bạn xem bất kỳ khung dữ liệu tương thích trong một cái nhìn Qt.

Tôi đã cập nhật Gist qua here

này sẽ giúp bạn đi một cách nhanh chóng nếu bạn cũng cần phải làm điều này.

+0

Thật không may tên cột và chỉ mục không hiển thị? Sẽ rất tuyệt nếu bạn có thể khắc phục điều đó. – working4coins

1

Đây có lẽ là vấn đề của bạn:

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


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

Bạn đặt của bạn datatable đến một QTableWidget trong dataFrameToQtTable, vì vậy nó không thể là một pd.DataFrame, phương pháp của bạn sẽ luôn luôn trả 0.

Nếu không có loại kiểm tra, bạn sẽ bắt gặp vấn đề ngay lập tức. Bạn có thực sự muốn âm thầm bỏ qua tất cả các trường hợp loại của bạn không khớp (tốt hơn là để nó tăng lỗi nếu nó không theo cùng giao diện mà bạn mong đợi)? Typechecks là in most cases unnecessary.

+0

Có, tôi biết rằng điều này là sai, nhưng đây là vấn đề của tôi. Tôi không nghĩ rằng nó nên được thiết lập để một QTableWidgetItem. Tôi muốn cập nhật mô hình nội bộ trong QAbstractTableModel, nhưng tôi không chắc chắn làm thế nào để làm điều này - hoặc tìm số hàng hoặc cột. Cảm ơn. – drexiya

+0

Tôi đã đơn giản hóa mã ví dụ để xóa dữ liệu nàyFrameToQtTable hy vọng vấn đề sẽ rõ ràng hơn. – drexiya