2012-10-24 5 views
5

私はQt4 Model/View Programmingの学習を始めました。私は初心者の質問があります。QTableViewの仮想列ですか?

私はQTableViewにsqliteのテーブルを表示する簡単なアプリケーションがあります。ここでは、データベースがどのように見えるか

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_()) 

を:

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

:だから私のようなものを取得しています

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"); 

Modelをに変更することは可能ですか仮想列のようなもの?以下のような例何かについて:

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

それとも私はいくつかの他の方法でそれを行う必要がありますか?

答えて

4

はい、できます。 @BrtH's answerは関連していますが、モデルはやりにくく、紛失しやすいです。だから私は、ポイントの例でもっと良いケースがあると思った。

個人的には、QAbstractProxyModelから派生したプロキシモデルを使用します。しかし、あなたのケースではQSqlTableModelを再実装することも可能です。以下はあなたの目標の実装です。 Model/View methodologyの基礎を理解することが不可欠であり、それぞれの方法が何であるかを理解する必要があります。

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

ありがとうございます。それはうまく動作します! – Adam

3

最も確かに可能です。以下はあなたのデータのために修正された私自身のコードの例です。

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() 

これはQTreeViewのモデルですが、簡単に変更できると思います。
これらの方法とモデルの詳細については、http://srinikom.github.com/pyside-docs/PySide/QtCore/QAbstractItemModel.htmlを参照してください。

+0

私はあなたの例のようにModelを採用しようとしています。しかし、私は 'rowCount'に問題があります。空の 'self.items'のために0を返します。 'set_items'は実行されません。また、この関数はドキュメントには表示されません。私は何が欠けているのですか? – Adam

+0

あなたは何かを逃していない、それはちょっと私のせいです。 'set_items'は公式の関数ではありません。私のコードでは、モデルをロードした後にデータを数回変更したので、これはちょうど私が使用したものです。私はデータベースから直接データをロードする答えを編集しましたが、データベースの作業をしてから何もテストしていないので、しばらく時間がかかりました。 – BrtH

+0

ありがとうございます。 – Adam

1

QSqlQueryModelを見ましたか? これは、任意のSQLクエリの結果を表示することができます。あなたの例のためのコード:

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") 

しかし、心の中で取る:

モデルは読み取り専用ですデフォルトで。読み書き可能にするには、サブクラス化してsetData()とflags()を再実装する必要があります。

+0

はい、QSqlQueryModelについて読んでいましたが、データベースへの書き込みアクセス権も必要です。だから私はQSqlTableModelを使い始めました。しかし、この例のおかげで! – Adam

関連する問題