1

投稿されたコードは、singe を作成しますModel/Proxy QTableView。複数選択機能が有効になっています。

ここに画像の説明を入力

全部で4つのアイテムがあります。そのうちの 2 つは文字「A」を含みます。他の 2 つは、「アイテム」名に文字「B」が含まれています。

QPushButton押されたときにclicked()メソッドが呼び出されます。このメソッドが呼び出されると、最初に にProxy Model接続された を照会しQTableViewます。

proxyModel=self.tableview.model()

次に、メソッドはproxyModel行の総数を返すように a に要求します。

rows=proxyModel.rowCount()

QTabelView各行を反復する のモデル内の行数を知る。まず、行インデックスをクエリしています。

index=proxyModel.index(row, 0)

それを知ると、前のステップで照会された a (ここでは変数) とフラグを提供するメソッドを呼び出して、変数にindex格納されている値を要求することになります。self.itemsdata()QModelIndexindexRole

item=proxyModel.data(index, Qt.DisplayRole).toPyObject()

「toPyObject()」は、.data()メソッドから受け取ったデータを「通常の」Python 変数に変換するために使用されます。

最後に、受信した文字列に文字 " B " があるかどうかをチェックします。その場合、次を使用して QTableView 行を選択します。

self.tableview.selectRow(row)

今私が望むのは、filterAcceptsRow()可能であれば、プロキシモデルの範囲内から同じ選択機能を取得することです。

それが不可能な場合は、他の方法があるかどうか知りたいです...使用する必要がありますQItemSelectionModelか? ではどうやって?

from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys

class Model(QAbstractTableModel):
    def __init__(self, parent=None, *args):
        QAbstractTableModel.__init__(self, parent, *args)
        self.items = ['Item_A_001','Item_A_002','Item_B_001','Item_B_002']

    def rowCount(self, parent=QModelIndex()):
        return len(self.items)       
    def columnCount(self, parent=QModelIndex()):
        return 1

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

        row=index.row()
        if row<len(self.items):
            return QVariant(self.items[row])
        else:
            return QVariant()

class Proxy(QSortFilterProxyModel):
    def __init__(self):
        super(Proxy, self).__init__()

    def filterAcceptsRow(self, row, parent):
        return True

class MyWindow(QWidget):
    def __init__(self, *args):
        QWidget.__init__(self, *args)

        tableModel=Model(self)               

        proxyModel=Proxy()
        proxyModel.setSourceModel(tableModel)

        self.tableview=QTableView(self) 
        self.tableview.setModel(proxyModel)
        self.tableview.horizontalHeader().setStretchLastSection(True)
        self.tableview.setSelectionMode(QAbstractItemView.MultiSelection)

        button=QPushButton(self)
        button.setText('Select Items with B')
        button.clicked.connect(self.clicked)

        layout = QVBoxLayout(self)
        layout.addWidget(self.tableview)
        layout.addWidget(button)
        self.setLayout(layout)

    def clicked(self, arg):
        proxyModel=self.tableview.model()

        self.tableview.clearSelection()
        rows=proxyModel.rowCount()
        for row in range(rows):
            index=proxyModel.index(row, 0)
            item=proxyModel.data(index, Qt.DisplayRole).toPyObject()
            if '_B_' in item:
                self.tableview.selectRow(row)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = MyWindow()
    w.show()
    sys.exit(app.exec_())
4

1 に答える 1

3

filterAcceptsRow()プロキシ モデルのメソッド内で選択を行うことができますが、そのためには次のことが必要になります。

  1. プロキシ モデル (またはソース モデル) にQTableViewインスタンスへの参照が含まれていること。
  2. プロキシ モデルに、アクティブかどうかを示す属性が含まれていること。これは、ボタンがクリックされたときにのみテーブル行を選択したいがfilterAcceptsRow()、プロキシ モデルによって自動的に呼び出されるためです。したがって、selectRow()ボタンがクリックされるまでビューのメソッドを呼び出さないようにする必要があります。

#1 を達成するには、プロキシ モデル クラスで単純なセッター メソッドを定義できます。

def setView(self, view):
    self._view = view

MyWindowもちろん、クラスのコンストラクター内でそのセッターを呼び出す必要もあります。

proxyModel.setView(self.tableview)

#2 を達成するには、プロキシ モデル クラスのコンストラクターでこの属性を作成するだけです。

self.filterActive = False

クラスの準備ができたので、目的の動作を実装できます。再実装では、次の行が含まれていて、フィルターがアクティブである (つまり、ボタンがクリックされた)filterAcceptsRow()場合にのみ、行を選択する必要があります。'_B_'

def filterAcceptsRow(self, row, parent):
    if self.filterActive and '_B_' in self.sourceModel().data(self.sourceModel().index(row, 0), Qt.DisplayRole).toPyObject():
        self._view.selectRow(row)
    return True

最後に、ボタンがクリックされたときにこれらの条件が満たされていることを確認したいので、 clicked() メソッドでproxyModelfilterActive属性を Trueに設定し、QSortFilterProxyModelクラスのinvalidateFilter()メソッドを呼び出して既存のフィルターが無効であるため、filterAcceptsRow()再度呼び出す必要があります。

def clicked(self, arg):
    proxyModel=self.tableview.model()
    self.tableview.clearSelection()
    proxyModel.filterActive = True
    proxyModel.invalidateFilter()

したがって、新しいコード全体は次のとおりです。

from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys

class Model(QAbstractTableModel):
    def __init__(self, parent=None, *args):
        QAbstractTableModel.__init__(self, parent, *args)
        self.items = ['Item_A_001','Item_A_002','Item_B_001','Item_B_002']

    def rowCount(self, parent=QModelIndex()):
        return len(self.items)       
    def columnCount(self, parent=QModelIndex()):
        return 1

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

        row=index.row()
        if row<len(self.items):
            return QVariant(self.items[row])
        else:
            return QVariant()

class Proxy(QSortFilterProxyModel):
    def __init__(self):
        super(Proxy, self).__init__()
        self.filterActive = False

    def setView(self, view):
        self._view = view

    def filterAcceptsRow(self, row, parent):
        if self.filterActive and '_B_' in self.sourceModel().data(self.sourceModel().index(row, 0), Qt.DisplayRole).toPyObject():
            self._view.selectRow(row)
        return True

class MyWindow(QWidget):
    def __init__(self, *args):
        QWidget.__init__(self, *args)

        tableModel=Model(self)               

        proxyModel=Proxy()
        proxyModel.setSourceModel(tableModel)

        self.tableview=QTableView(self) 
        self.tableview.setModel(proxyModel)
        self.tableview.horizontalHeader().setStretchLastSection(True)
        self.tableview.setSelectionMode(QAbstractItemView.MultiSelection)

        proxyModel.setView(self.tableview)

        button=QPushButton(self)
        button.setText('Select Items with B')
        button.clicked.connect(self.clicked)

        layout = QVBoxLayout(self)
        layout.addWidget(self.tableview)
        layout.addWidget(button)
        self.setLayout(layout)

    def clicked(self, arg):
        proxyModel=self.tableview.model()
        self.tableview.clearSelection()
        proxyModel.filterActive = True
        proxyModel.invalidateFilter()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = MyWindow()
    w.show()
    sys.exit(app.exec_())

以上のことから、 の目的は、 のサブクラスで独自のカスタムフィルタリングfilterAcceptsRow()を実装できるようにすることです。したがって、より典型的な実装 (目的のルールに従う) は次のようになります。QSortFilterProxyModel

def filterAcceptsRow(self, row, parent):
    if not self.filterActive or '_B_' in self.sourceModel().data(self.sourceModel().index(row, 0), Qt.DisplayRole).toPyObject():
        return True
    return False

それでも、フィルタリングは正規表現で実行できるため、再実装filterAcceptsRow()する必要さえありません。proxyModel.setFilterRegExp(QRegExp("_B_", Qt.CaseInsensitive, QRegExp.FixedString))とを呼び出すだけproxyModel.setFilterKeyColumn(0)で、フィルターごとに同じことを達成できます。

それが役立つことを願っています!

于 2015-01-23T15:51:50.483 に答える