2012-10-24 22 views
5

Tôi bắt đầu học Qt4 Model/View Programming và tôi có câu hỏi mới bắt đầu.Cột ảo trong QTableView?

Tôi có ứng dụng đơn giản mà hiển thị bảng sqlite trong QTableView:

class Model(QtSql.QSqlTableModel): 
    def __init__(self, parent=None): 
     super(Model, self).__init__(parent) 
     self.setEditStrategy(QtSql.QSqlTableModel.OnFieldChange) 

     self.setTable("test") 
     self.select() 

class App(QtGui.QMainWindow): 
    def __init__(self, model): 
     QtGui.QMainWindow.__init__(self) 

     self.ui = Ui_MainWindow() 
     self.ui.setupUi(self) 

     self.ui.tableView.setModel(model) 

if __name__ == "__main__": 
    myDb = QtSql.QSqlDatabase.addDatabase("QSQLITE") 
    myDb.setDatabaseName("test.db") 

    if not myDb.open(): 
     print 'FIXME' 

    model = Model() 

    app = QtGui.QApplication(sys.argv) 
    window = App(model) 
    window.show() 
    sys.exit(app.exec_()) 

đây như thế nào cơ sở dữ liệu trông giống như:

sqlite> create table test (a INTEGER, b INTEGER, c STRING); 
sqlite> insert into test VALUES(1, 2, "xxx"); 
sqlite> insert into test VALUES(6, 7, "yyy"); 

Vì vậy, tôi nhận được một cái gì đó như:

+---+---+-----+ 
| a | b | c | 
+---+---+-----+ 
| 1 | 2 | xxx | 
+---+---+-----+ 
| 6 | 7 | yyy | 
+---+---+-----+ 

Có thể sửa đổi Model để có trong QTableView giống như cột ảo? Ví dụ:

+---+---+-----+-----+ 
| a | b | sum | c | 
+---+---+-----+-----+ 
| 1 | 2 | 3 | xxx | 
+---+---+-----+-----+ 
| 6 | 7 | 13 | yyy | 
+---+---+-----+-----+ 

Hoặc có lẽ tôi nên làm theo cách khác?

Trả lời

4

Có, bạn có thể làm điều đó. Mặc dù @BrtH's answer có liên quan, các mô hình rất phức tạp và rất dễ bị lạc. Vì vậy, tôi nghĩ rằng một trường hợp nhiều hơn trong ví dụ điểm sẽ tốt hơn.

Cá nhân, tôi muốn sử dụng mô hình proxy bắt nguồn từ QAbstractProxyModel. Tuy nhiên, trong trường hợp của bạn reimplementing QSqlTableModel cũng là khả thi. Dưới đây là triển khai cho mục tiêu của bạn. Lưu ý rằng, điều quan trọng là bạn phải biết các khái niệm cơ bản về số Model/View methodology để bạn hiểu được từng phương pháp thực hiện điều gì.

class Model(QtSql.QSqlTableModel): 
    def __init__(self, parent=None): 
     super(Model, self).__init__(parent) 
     self.setEditStrategy(QtSql.QSqlTableModel.OnFieldChange) 

     self.setTable("test") 
     self.select() 


    def columnCount(self, parent=QtCore.QModelIndex()): 
     # this is probably obvious 
     # since we are adding a virtual column, we need one more column 
     return super(Model, self).columnCount()+1 


    def data(self, index, role=QtCore.Qt.DisplayRole): 
     if role == QtCore.Qt.DisplayRole and index.column()==2: 
      # 2nd column is our virtual column. 
      # if we are there, we need to calculate and return the value 
      # we take the first two columns, get the data, turn it to integer and sum them 
      # [0] at the end is necessary because pyqt returns value and a bool 
      # http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/qvariant.html#toInt 
      return sum(self.data(self.index(index.row(), i)).toInt()[0] for i in range(2)) 
     if index.column() > 2: 
      # if we are past 2nd column, we need to shift it to left by one 
      # to get the real value 
      index = self.index(index.row(), index.column()-1) 
     # get the value from base implementation 
     return super(Model, self).data(index, role) 


    def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole): 
     # this is similar to `data` 
     if section==2 and orientation==QtCore.Qt.Horizontal and role==QtCore.Qt.DisplayRole: 
      return 'Sum' 
     if section > 2 and orientation==QtCore.Qt.Horizontal: 
      section -= 1 
     return super(Model, self).headerData(section, orientation, role) 


    def flags(self, index): 
     # since 2nd column is virtual, it doesn't make sense for it to be Editable 
     # other columns can be Editable (default for QSqlTableModel) 
     if index.column()==2: 
      return QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled 
     return QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsEditable 


    def setData(self, index, data, role): 
     # similar to data. 
     # we need to be careful when setting data (after edit) 
     # if column is after 2, it is actually the column before that 
     if index.column() > 2: 
      index = self.index(index.row(), index.column()-1) 
     return super(Model, self).setData(index, data, role) 
+0

Cảm ơn bạn về ví dụ này. Nó hoạt động tốt! – Adam

3

Đó là điều chắc chắn nhất có thể. Dưới đây là ví dụ về một số mã của riêng tôi, được sửa đổi cho dữ liệu của bạn.

import sqlite3 

conn = sqlite3.connect('test.db') 


class MyTreeModel(QAbstractItemModel): 
    def __init__(self, parent=None): 
     super(MyTreeModel, self).__init__(parent) 

     c = conn.cursor() 
     c.execute("SELECT a, b, c FROM 'test'") 
     self.items = c.fetchall() 

     self.columns = ['a', 'b', 'sum', 'c'] 

    def columnCount(self, index): 
     return len(self.columns) 

    def rowCount(self, parent): 
     return len(self.items) 

    def data(self, index, role=Qt.DisplayRole): 
     if index.isValid(): 
      col= index.column() 
      spot = self.items[index.row()] 
      if role == Qt.DisplayRole: 
       if col == 0 or col == 1: 
        return self.items[index.row()][col] 
       elif col == 2: 
        return self.items[index.row()][0] + self.items[index.row()][1] 
       elif col == 3: 
        return self.items[index.row()][2] 

    def headerData(self, section, orientation, role=Qt.DisplayRole): 
     if orientation == Qt.Horizontal and role == Qt.DisplayRole: 
      return self.columns[section] 

    def index(self, row, col, index): 
     if not index.isValid(): 
      return self.createIndex(row, col) 
     else: 
      return QModelIndex() 

    def parent(self, child): 
     return QModelIndex() 

Đây là mô hình cho QTreeView, nhưng tôi nghĩ bạn có thể dễ dàng điều chỉnh nó.
Để biết thêm thông tin về các phương pháp này và mô hình, hãy xem http://srinikom.github.com/pyside-docs/PySide/QtCore/QAbstractItemModel.html.

+0

Tôi đang cố gắng áp dụng Mô hình như trong ví dụ của bạn. Nhưng tôi có vấn đề với 'rowCount'. Nó trả về 0 vì rỗng 'self.items'. 'set_items' không được thực hiện, và tôi cũng không thấy hàm này trong tài liệu. Những gì tôi đang thiếu? – Adam

+0

Bạn không bỏ lỡ bất cứ điều gì, đó là lỗi của tôi. 'set_items' không phải là chức năng 'chính thức', nó chỉ là thứ tôi đã sử dụng vì trong mã của tôi, tôi đã thay đổi dữ liệu vài lần sau khi mô hình được tải. Tôi đã chỉnh sửa câu trả lời để tải dữ liệu trực tiếp từ một cơ sở dữ liệu, nhưng nó đã được một thời gian kể từ khi tôi đã làm những điều cơ sở dữ liệu và tôi đã không kiểm tra bất cứ điều gì, vì vậy nó có thể không hoạt động. – BrtH

+0

Cảm ơn bạn rất nhiều. – Adam

1

Bạn đã xem QSqlQueryModel chưa? Nó cho phép hiển thị kết quả của bất kỳ truy vấn SQL nào. Mã ví dụ của bạn:

class Model(QtSql.QSqlQueryModel): 
    def __init__(self, parent=None): 
     super(Model, self).__init__(parent) 
     self.setQuery("SELECT a, b, a + b, c FROM test") 
     self.setHeaderData(0, QtCore.Qt.Horizontal, "a") 
     self.setHeaderData(1, QtCore.Qt.Horizontal, "b") 
     self.setHeaderData(2, QtCore.Qt.Horizontal, "sum") 
     self.setHeaderData(3, QtCore.Qt.Horizontal, "c") 

Nhưng hãy nhớ:

Mô hình

là chỉ đọc theo mặc định. Để làm cho nó đọc-ghi, bạn phải phân lớp nó và reimplement setData() và flags().

+0

Có, tôi đã đọc về QSqlQueryModel nhưng tôi cũng cần viết quyền truy cập vào cơ sở dữ liệu. Vì vậy, tôi bắt đầu với QSqlTableModel. Nhưng cảm ơn ví dụ này! – Adam

Các vấn đề liên quan