Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Completion problem with QLineEdit and QItemDelegate
QtWS25 Last Chance

Completion problem with QLineEdit and QItemDelegate

Scheduled Pinned Locked Moved Solved General and Desktop
2 Posts 1 Posters 1.1k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    Matthieu 0
    wrote on last edited by
    #1

    Hello,

    I'm trying to implement the QCompleter example we can find in the widgets/tools/customcompleter sources.
    What I want is when I'm typing some text, if there is some matches, the first completion line available is selected so if I hit the return key (and only if I hit it), the completion is done.

    But in my code here, the line is never selected. I think my problem is located in the keyPressEvent. It is a minimal example, written in pyqt5.

    Any help is very appreciated :)

    import sys
    
    from PyQt5.QtCore import QAbstractTableModel, Qt, QVariant
    from PyQt5.QtWidgets import (QApplication, QCompleter, QItemDelegate,
                                 QLineEdit, QMainWindow, QTableView)
    
    
    class MyLineEdit(QLineEdit):
    
        def __init__(self, parent=None, completer=None):
            super().__init__(parent)
            if completer:
                self.setCompleter(completer)
    
        def setCompleter(self, completer):
            if completer:
                completer.setWidget(self)
                completer.setCompletionMode(QCompleter.PopupCompletion)
                completer.setCaseSensitivity(Qt.CaseInsensitive)
                completer.setModelSorting(
                    QCompleter.CaseSensitivelySortedModel)
                completer.setMaxVisibleItems(15)
                completer.activated.connect(self.insertCompletion)
    
            super().setCompleter(completer)
    
        def insertCompletion(self, completion):
            completer = self.completer()
            if completer and completer.widget() == self:
                completer.widget().setText(completion)
    
        def keyPressEvent(self, event):
    
            completer = self.completer()
    
            if event.key() in (Qt.Key_Return, Qt.Key_Enter,
                               Qt.Key_Tab, Qt.Key_Backtab):
                self.returnPressed.emit()
                if completer and completer.popup().isHidden():
                    return
    
            super().keyPressEvent(event)
            input_text = self.text()
    
            if completer:
    
                if not event.text():
                    completer.popup().hide()
                    return
    
                if input_text and input_text != completer.completionPrefix():
                    completer.setCompletionPrefix(input_text)
                    completer.popup().setCurrentIndex(
                        completer.completionModel().index(0, 0))
    
    
    class MyDelegate(QItemDelegate):
    
        def __init__(self, parent):
            super().__init__(parent)
    
        def createEditor(self, parent, option, index):
            strings = ('tata', 'tete', 'titi', 'toto', 'tutu')
            completer = QCompleter(strings)
            editor = MyLineEdit(parent)
            editor.setCompleter(completer)
            editor.editingFinished.connect(self.commitAndCloseEditor)
            editor.returnPressed.connect(self.commitAndCloseEditor)
            return editor
    
        def commitAndCloseEditor(self):
            editor = self.sender()
            self.commitData.emit(editor)
            self.closeEditor.emit(editor)
    
        def setEditorData(self, editor, index):
            if editor:
                editor.setText(index.model().data[0])
    
        def setModelData(self, editor, model, index):
            if editor:
                model.setData(index, editor.text(), Qt.EditRole)
    
    
    class Model(QAbstractTableModel):
    
        def __init__(self):
            super().__init__()
            self.data = ['hello']
    
        def rowCount(self, parent=None):
            return 1
    
        def columnCount(self, parent=None):
            return 1
    
        def data(self, index, role):
            if not index.isValid():
                return QVariant()
    
            if role in (Qt.DisplayRole, Qt.EditRole):
                return self.data[0]
    
            return QVariant()
    
        def setData(self, index, value, role):
            if role == Qt.EditRole:
                self.data[0] = value
    
                top_left = self.index(0, 0)
                bottom_right = self.index(
                    self.rowCount() + 1, self.columnCount())
                self.dataChanged.emit(top_left, bottom_right,
                                      [Qt.DisplayRole])
                return True
    
            return False
    
        def flags(self, index):
            return Qt.ItemIsEditable | super().flags(index)
    
    
    class MainWindow(QMainWindow):
    
        def __init__(self):
            super().__init__()
            self.model = Model()
            self.table = QTableView()
            self.table.setModel(self.model)
            delegate = MyDelegate(self.table)
            self.table.setItemDelegateForColumn(0, delegate)
    
        def initUI(self):
            self.show()
    
            self.setCentralWidget(self.table)
    
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
    
        mw = MainWindow()
        mw.initUI()
    
        sys.exit(app.exec_())
    
    

    Best regards

    1 Reply Last reply
    0
    • M Offline
      M Offline
      Matthieu 0
      wrote on last edited by
      #2

      Finally found a solution. I used a QTextEdit, it does not work with QLineEdit, I don't know why. I still have a small problem, I can't close the completion popup when I hit the return key, so I must hit return key, twice. Not a big problem.

      import sys
      
      from PyQt5.QtCore import QAbstractTableModel, Qt, QVariant, pyqtSignal
      from PyQt5.QtGui import QTextCursor, QTextOption
      from PyQt5.QtWidgets import (QAbstractItemDelegate, QApplication, QCompleter,
                                   QItemDelegate, QMainWindow, QTableView, QTextEdit)
      
      
      class MyLineEdit(QTextEdit):
      
          returnPressed = pyqtSignal()
      
          def __init__(self, parent=None):
              super().__init__(parent)
              self.setAcceptRichText(False)
              self.setWordWrapMode(QTextOption.NoWrap)
              self.setUndoRedoEnabled(False)
              self.setTabChangesFocus(True)
              self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
              self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
              self.completer = None
              self.textChanged.connect(self.textHasChanged)
      
          def setCompleter(self, completer):
              if completer:
                  completer.setWidget(self)
                  completer.setCompletionMode(QCompleter.PopupCompletion)
                  completer.setCaseSensitivity(Qt.CaseInsensitive)
                  completer.setModelSorting(
                      QCompleter.CaseSensitivelySortedModel)
                  completer.setMaxVisibleItems(15)
                  completer.activated.connect(self.insertCompletion)
                  self.completer = completer
      
          def insertCompletion(self, completion):
              print('>>> insertCompletion')
              if self.completer and self.completer.widget() == self:
                  self.completer.widget().setPlainText(completion)
                  self.completer.widget().moveCursor(QTextCursor.EndOfLine)
                  self.completer.widget().ensureCursorVisible()
      
          def focusInEvent(self, event):
              print('>>> focusInEvent')
              if self.completer:
                  self.completer.setWidget(self)
              super().focusInEvent(event)
      
          def keyPressEvent(self, event):
              print('>>> keyPressEvent')
      
              if self.completer and self.completer.popup().isVisible():
      
                  if event.key() in (Qt.Key_Return, Qt.Key_Enter,
                                     Qt.Key_Tab, Qt.Key_Backtab, Qt.Key_Escape):
                      event.ignore()
                      return
              else:
                  if event.key() in(Qt.Key_Return, Qt.Key_Enter):
                      self.returnPressed.emit()
                      return
      
              super().keyPressEvent(event)
      
              if not self.toPlainText():
                  self.completer.popup().hide()
                  return
      
              self.completer.setCompletionPrefix(self.toPlainText())
              self.completer.popup().setCurrentIndex(
                  self.completer.completionModel().index(0, 0))
              self.completer.complete()
      
          def textHasChanged(self):
              # remove new lines and strip left blank characters
              self.blockSignals(True)
              cursor = self.textCursor()
              self.setPlainText(' '.join(self.toPlainText().splitlines()).lstrip())
              self.setTextCursor(cursor)
              self.ensureCursorVisible()
              self.blockSignals(False)
      
      
      class MyDelegate(QItemDelegate):
      
          def __init__(self, parent):
              super().__init__(parent)
      
          def createEditor(self, parent, option, index):
              strings = ('tata', 'tada', 'tadam', 'tete', 'titi', 'toto', 'tutu')
              completer = QCompleter(strings)
              editor = MyLineEdit(parent)
              editor.setCompleter(completer)
              editor.returnPressed.connect(self.commitAndCloseEditor)
              return editor
      
          def commitAndCloseEditor(self):
              print('>>> commitAndCloseEditor')
              editor = self.sender()
              self.commitData.emit(editor)
              self.closeEditor.emit(editor)
      
          def setEditorData(self, editor, index):
              if editor:
                  editor.setText(index.model().data[0])
                  editor.selectAll()
      
          def setModelData(self, editor, model, index):
              if editor:
                  model.setData(index, editor.toPlainText(), Qt.EditRole)
      
      
      class Model(QAbstractTableModel):
      
          def __init__(self):
              super().__init__()
              self.data = ['hello']
      
          def rowCount(self, parent=None):
              return 1
      
          def columnCount(self, parent=None):
              return 1
      
          def data(self, index, role):
              if not index.isValid():
                  return QVariant()
      
              if role in (Qt.DisplayRole, Qt.EditRole):
                  return self.data[0]
      
              return QVariant()
      
          def setData(self, index, value, role):
              if role == Qt.EditRole:
                  self.data[0] = value
      
                  top_left = self.index(0, 0)
                  bottom_right = self.index(
                      self.rowCount() + 1, self.columnCount())
                  self.dataChanged.emit(top_left, bottom_right,
                                        [Qt.DisplayRole])
                  return True
      
              return False
      
          def flags(self, index):
              return Qt.ItemIsEditable | super().flags(index)
      
      
      class MainWindow(QMainWindow):
      
          def __init__(self):
              super().__init__()
              self.model = Model()
              self.table = QTableView()
              self.table.setModel(self.model)
              delegate = MyDelegate(self.table)
              self.table.setItemDelegateForColumn(0, delegate)
      
          def initUI(self):
              self.show()
      
              self.setCentralWidget(self.table)
      
      
      if __name__ == '__main__':
          app = QApplication(sys.argv)
      
          mw = MainWindow()
          mw.initUI()
      
          sys.exit(app.exec_())
      
      1 Reply Last reply
      1

      • Login

      • Login or register to search.
      • First post
        Last post
      0
      • Categories
      • Recent
      • Tags
      • Popular
      • Users
      • Groups
      • Search
      • Get Qt Extensions
      • Unsolved