2015-01-21 3 views
0

Опубликованный код создает сингл Model/ProxyQTableView. Для него была включена функция множественного выбора.Как выбрать индекс QTableView или строку изнутри модели

enter image description here

Есть всего четыре пункта. Два из них включают символ «A». Другие два включают символ «B» в именах «item».

QPushButton при нажатии вызовов для метода clicked(). При вызове этого метода первых запросов в Proxy Model подключен к QTableView:

proxyModel=self.tableview.model() 

Тогда метод просит proxyModel возвращать общее количество строк:

rows=proxyModel.rowCount() 

Зная, сколько строк в QTabelView ' s она выполняет итерацию каждой строки. Сначала он запрашивает индекс строки:

index=proxyModel.index(row, 0) 

Зная index она протекает с просьбой значением, хранящимся в self.items переменной посредством вызова data() метод подачи его с опрошена в предыдущей стадии а QModelIndex (переменная index здесь) и a Role флаг.

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

ответ

2

Вы можете достичь выбора внутри 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() вам необходимо установить атрибут для True, и вам необходимо вызвать методкласса 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), чтобы добиться того же, по-фильтровальному.

Надеюсь, что это поможет!

+0

Хорошая работа! Благодаря ! – alphanumeric

Смежные вопросы