2016-08-31 16 views
3

Я хочу получить целое число, хранящееся в [(1, 'cb'), (3, 'cd'), (7, 'ca'), (11, 'aa'), (22, 'bd')], когда я выбираю выпадающий автоматически полный элемент.PyQt QSortFilterProxyModel индекс от неправильной модели передан mapToSource?

Поскольку я использовал QSortFilterProxyModel, при использовании клавиши «вниз» для выбора элемента индекс относится к прокси-модели.

Я прочитал в документации, что я должен использовать mapToSource, чтобы получить индекс в оригинальной модели, но здесь я получил сообщение об ошибке index from wrong model passed to mapToSource и index.row() всегда -1. Что мне не хватает? Благодаря!

Ошибка:

row in proxy model 0 
QSortFilterProxyModel: index from wrong model passed to mapToSource 
row in original model -1 

код:

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


import sys 
import re 
import signal 
signal.signal(signal.SIGINT, signal.SIG_DFL) 


class MyModel(QStandardItemModel): 

    def __init__(self, parent=None): 
     super(MyModel, self).__init__(parent) 

    def data(self, index, role): 

     symbol = self.symbol_data[index.row()] 
     if role == Qt.DisplayRole: 
      return symbol[1] 

     elif role == Qt.UserRole: 
      return symbol[0] 

    def setup(self, data): 
     self.symbol_data = data 
     for line, name in data: 
      item = QStandardItem(name) 
      self.appendRow(item) 


class MyGui(QDialog): 

    def __init__(self, parent=None): 

     super(MyGui, self).__init__(parent) 

     symbols = [(1, 'cb'), (3, 'cd'), (7, 'ca'), (11, 'aa'), (22, 'bd')] 

     model = MyModel() 
     model.setup(symbols) 

     layout = QVBoxLayout(self) 
     self.line = QLineEdit(self) 

     layout.addWidget(self.line) 

     self.setLayout(layout) 

     completer = CustomQCompleter() 

     completer.setModel(model) 
     completer.setCaseSensitivity(Qt.CaseInsensitive) 
     completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion) 
     completer.setWrapAround(False) 

     self.line.setCompleter(completer) 

     self.completer = completer 

     self.completer.highlighted[QModelIndex].connect(self.test) 

     # qApp.processEvents() 
     # QTimer.singleShot(0, self.completer.complete) 
     self.line.textChanged[QString].connect(self.pop) 

    def pop(self, *x): 
     text = x[0] 
     self.completer.splitPath(text) 
     QTimer.singleShot(0, self.completer.complete) 

     self.line.setFocus() 

    def test(self, index): 
     print 'row in proxy model', index.row() 
     print 'row in original model', self.completer.model().mapToSource(index).row() 
     # print 'line in original model:', 
     # self.completer.model().sourceModel().symbol_data[x[0].row()][0] 


class CustomQCompleter(QCompleter): 

    def __init__(self, parent=None): 
     super(CustomQCompleter, self).__init__(parent) 
     self.local_completion_prefix = "" 
     self.source_model = None 
     self.first_down = True 

    def setModel(self, model): 
     self.source_model = model 
     self._proxy = QSortFilterProxyModel(
      self, filterCaseSensitivity=Qt.CaseInsensitive) 
     self._proxy.setSourceModel(model) 
     super(CustomQCompleter, self).setModel(self._proxy) 

    def splitPath(self, path): 
     self.local_completion_prefix = str(path) 
     self._proxy.setFilterFixedString(path) 
     return "" 

    def eventFilter(self, obj, event): 

     if event.type() == QEvent.KeyPress: 
      'This is used to mute the connection to clear lineedit' 
      if event.key() in (Qt.Key_Down, Qt.Key_Up): 
       curIndex = self.popup().currentIndex() 

       if event.key() == Qt.Key_Down: 
        if curIndex.row() == self._proxy.rowCount()-1: 
         print 'already last row', curIndex.row() 
         if self._proxy.rowCount() == 1: 
          pass 
         else: 
          return True 
       else: 
        if curIndex.row() == 0: 
         print 'already first row' 
         return True 

       if curIndex.row() == 0 and self.first_down: 
        print 'already row 0 first' 
        self.popup().setCurrentIndex(curIndex) 
        self.first_down = False 
        return True 

     super(CustomQCompleter, self).eventFilter(obj, event) 
     return False 


if __name__ == '__main__': 

    app = QApplication(sys.argv) 
    gui = MyGui() 
    gui.show() 
    sys.exit(app.exec_()) 

обновление: Это будет решено, спасибо за помощь Авариса в #pyqt. Оказывается, что я могу сделать это, чтобы отобразить индекс исходной модели

proxy_index= self.completer.completionModel().mapToSource(index) 
print 'original row:', self.completer.model().mapToSource(proxy_index).row() 

или даже лучше:

print 'data:', index.data(Qt.UserRole).toPyObject() 

becuase: " completionModel() на самом деле является прокси-модель на .MODEL()

вам не нужно возиться с mapToSource для этого. index.data (Qt.UserRole) должно дать вам этот номер независимо от того, какой индекс возвращается

просто FYI, вам редко приходится использовать mapToSource за пределами (прокси) модели. это в основном для внутреннего использования. надлежащий прокси-сервер должен перенаправить все соответствующие запросы из источника. так что вы можете использовать прокси-сервер, как если вы используете источник один -Avaris "

ответ

1

вставить правильный код здесь для справки

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


import sys 
import re 
import signal 
signal.signal(signal.SIGINT, signal.SIG_DFL) 


class MyModel(QStandardItemModel): 

    def __init__(self, parent=None): 
     super(MyModel, self).__init__(parent) 

    def data(self, index, role): 

     symbol = self.symbol_data[index.row()] 
     if role == Qt.DisplayRole: 
      return symbol[1] 

     elif role == Qt.UserRole: 
      return symbol[0] 

    def setup(self, data): 
     self.symbol_data = data 
     for line, name in data: 
      item = QStandardItem(name) 
      self.appendRow(item) 


class MyGui(QDialog): 

    def __init__(self, parent=None): 

     super(MyGui, self).__init__(parent) 

     symbols = [(1, 'cb'), (3, 'cd'), (7, 'ca'), (11, 'aa'), (22, 'bd')] 

     model = MyModel() 
     model.setup(symbols) 

     layout = QVBoxLayout(self) 
     self.line = QLineEdit(self) 

     layout.addWidget(self.line) 

     self.setLayout(layout) 

     completer = CustomQCompleter() 

     completer.setModel(model) 
     completer.setCaseSensitivity(Qt.CaseInsensitive) 
     completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion) 
     completer.setWrapAround(False) 

     self.line.setCompleter(completer) 

     self.completer = completer 

     self.completer.highlighted[QModelIndex].connect(self.test) 

     # QTimer.singleShot(0, self.completer.complete) 
     self.line.textChanged[QString].connect(self.pop) 

    def pop(self, *x): 
     text = x[0] 
     self.completer.splitPath(text) 
     QTimer.singleShot(0, self.completer.complete) 

     self.line.setFocus() 

    def test(self, index): 
     print 'row in completion model', index.row() 
     print 'data:', index.data(Qt.UserRole).toPyObject() 

class CustomQCompleter(QCompleter): 

    def __init__(self, parent=None): 
     super(CustomQCompleter, self).__init__(parent) 
     self.local_completion_prefix = "" 
     self.source_model = None 
     self.first_down = True 

    def setModel(self, model): 
     self.source_model = model 
     self._proxy = QSortFilterProxyModel(
      self, filterCaseSensitivity=Qt.CaseInsensitive) 
     self._proxy.setSourceModel(model) 
     super(CustomQCompleter, self).setModel(self._proxy) 

    def splitPath(self, path): 
     self.local_completion_prefix = str(path) 
     self._proxy.setFilterFixedString(path) 
     return "" 

    def eventFilter(self, obj, event): 

     if event.type() == QEvent.KeyPress: 
      'This is used to mute the connection to clear lineedit' 
      if event.key() in (Qt.Key_Down, Qt.Key_Up): 
       curIndex = self.popup().currentIndex() 

       if event.key() == Qt.Key_Down: 
        if curIndex.row() == self._proxy.rowCount()-1: 
         print 'already last row', curIndex.row() 
         if self._proxy.rowCount() == 1: 
          pass 
         else: 
          return True 
       else: 
        if curIndex.row() == 0: 
         print 'already first row' 
         return True 

       if curIndex.row() == 0 and self.first_down: 
        print 'already row 0 first' 
        self.popup().setCurrentIndex(curIndex) 
        self.first_down = False 
        return True 

     super(CustomQCompleter, self).eventFilter(obj, event) 
     return False 


if __name__ == '__main__': 

    app = QApplication(sys.argv) 
    gui = MyGui() 
    gui.show() 
    sys.exit(app.exec_())