Results 1 to 9 of 9

Thread: How to change completion rule of QCompleter

  1. #1
    Join Date
    Aug 2009
    Posts
    2
    Thanked 1 Time in 1 Post
    Qt products
    Platforms
    Unix/X11 Windows

    Question How to change completion rule of QCompleter

    The standard QCompleter classs uses completionPrefix to search for all completions, so all the completions have the same prefix which is completionPrefix, what i want to achieve is this:if the string in the completion model contains the chars under the cursor,it should appear in the completion, and i also want to use different rules to decide which should appear in the completions.

    For example:
    the completion model:QListModel<<"manual"<<"anual"
    When i type 'nual', i want both "manual" and "anual" appear in the completion, because they both contains "nual",so how can i achieve this?

    I don't know how to change the completion rule,it seems that the standard QCompleter use prfix matching to find completions.

    Any suggestions?

  2. #2
    Join Date
    Jul 2009
    Posts
    139
    Thanks
    13
    Thanked 59 Times in 52 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: How to change completion rule of QCompleter

    Using this QCompleter example and this custom QCompleter example, I implemented what you want.

    Header:
    Qt Code:
    1. #ifndef LINEEDIT_H
    2. #define LINEEDIT_H
    3.  
    4. #include <QLineEdit>
    5. #include <QStringList>
    6. #include <QStringListModel>
    7. #include <QString>
    8. #include <QCompleter>
    9.  
    10. class MyCompleter : public QCompleter
    11. {
    12. Q_OBJECT
    13.  
    14. public:
    15. inline MyCompleter(const QStringList& words, QObject * parent) :
    16. QCompleter(parent), m_list(words), m_model()
    17. {
    18. setModel(&m_model);
    19. }
    20.  
    21. inline void update(QString word)
    22. {
    23. // Do any filtering you like.
    24. // Here we just include all items that contain word.
    25. QStringList filtered = m_list.filter(word, caseSensitivity());
    26. m_model.setStringList(filtered);
    27. m_word = word;
    28. complete();
    29. }
    30.  
    31. inline QString word()
    32. {
    33. return m_word;
    34. }
    35.  
    36. private:
    37. QStringList m_list;
    38. QString m_word;
    39. };
    40.  
    41. class MyLineEdit : public QLineEdit
    42. {
    43. Q_OBJECT
    44.  
    45. public:
    46. MyLineEdit(QWidget *parent = 0);
    47. ~MyLineEdit();
    48.  
    49. void setCompleter(MyCompleter *c);
    50. MyCompleter *completer() const;
    51.  
    52. protected:
    53. void keyPressEvent(QKeyEvent *e);
    54.  
    55. private slots:
    56. void insertCompletion(const QString &completion);
    57.  
    58. private:
    59. MyCompleter *c;
    60. };
    61.  
    62. #endif // LINEEDIT_H
    To copy to clipboard, switch view to plain text mode 

    CPP:
    Qt Code:
    1. MyLineEdit::MyLineEdit(QWidget *parent)
    2. : QLineEdit(parent), c(0)
    3. {
    4. }
    5.  
    6. MyLineEdit::~MyLineEdit()
    7. {
    8. }
    9.  
    10. void MyLineEdit::setCompleter(MyCompleter *completer)
    11. {
    12. if (c)
    13. QObject::disconnect(c, 0, this, 0);
    14.  
    15. c = completer;
    16.  
    17. if (!c)
    18. return;
    19.  
    20. c->setWidget(this);
    21. connect(completer, SIGNAL(activated(const QString&)), this, SLOT(insertCompletion(const QString&)));
    22. }
    23.  
    24. MyCompleter *MyLineEdit::completer() const
    25. {
    26. return c;
    27. }
    28.  
    29. void MyLineEdit::insertCompletion(const QString& completion)
    30. {
    31. setText(completion);
    32. selectAll();
    33. }
    34.  
    35.  
    36. void MyLineEdit::keyPressEvent(QKeyEvent *e)
    37. {
    38. if (c && c->popup()->isVisible())
    39. {
    40. // The following keys are forwarded by the completer to the widget
    41. switch (e->key())
    42. {
    43. case Qt::Key_Enter:
    44. case Qt::Key_Return:
    45. case Qt::Key_Escape:
    46. case Qt::Key_Tab:
    47. case Qt::Key_Backtab:
    48. e->ignore();
    49. return; // Let the completer do default behavior
    50. }
    51. }
    52.  
    53. bool isShortcut = (e->modifiers() & Qt::ControlModifier) && e->key() == Qt::Key_E;
    54. if (!isShortcut)
    55. QLineEdit::keyPressEvent(e); // Don't send the shortcut (CTRL-E) to the text edit.
    56.  
    57. if (!c)
    58. return;
    59.  
    60. bool ctrlOrShift = e->modifiers() & (Qt::ControlModifier | Qt::ShiftModifier);
    61. if (!isShortcut && !ctrlOrShift && e->modifiers() != Qt::NoModifier)
    62. {
    63. c->popup()->hide();
    64. return;
    65. }
    66.  
    67. c->update(text());
    68. c->popup()->setCurrentIndex(c->completionModel()->index(0, 0));
    69. }
    To copy to clipboard, switch view to plain text mode 

    Usage:
    Qt Code:
    1. MyLineEdit * te = new MyLineEdit;
    2. MyCompleter * completer = new MyCompleter(QStringList() << "oneone" << "Twotwo", this);
    3. completer->setCaseSensitivity(Qt::CaseInsensitive);
    4. te->setCompleter(completer);
    To copy to clipboard, switch view to plain text mode 

  3. The following 2 users say thank you to numbat for this useful post:

    akiross (17th April 2011), viet.nguyentien (13th September 2011)

  4. #3
    Join Date
    Aug 2009
    Posts
    2
    Thanked 1 Time in 1 Post
    Qt products
    Platforms
    Unix/X11 Windows

    Default Re: How to change completion rule of QCompleter


    Many thanks,numbat,i just translated your code into Python,it works fine.
    Qt Code:
    1. from PyQt4.QtCore import *
    2. from PyQt4.QtGui import *
    3. import sys
    4.  
    5. class TextEdit(QTextEdit):
    6.  
    7. def __init__(self,parent=None):
    8. super(TextEdit,self).__init__(parent)
    9. self.cmp=None
    10.  
    11. def setCompleter(self,completer):
    12. if self.cmp:
    13. self.disconnect(self.cmp,0,0)
    14. self.cmp=completer
    15. if (not self.cmp):
    16. return
    17. self.cmp.setWidget(self)
    18. self.cmp.setCompletionMode(QCompleter.PopupCompletion)
    19. self.cmp.setCaseSensitivity(Qt.CaseInsensitive)
    20. self.connect(self.cmp,SIGNAL('activated(QString)'),self.insertCompletion)
    21.  
    22. def completer(self):
    23. return self.cmp
    24.  
    25. def insertCompletion(self,string):
    26. tc=self.textCursor()
    27. tc.movePosition(QTextCursor.StartOfWord,QTextCursor.KeepAnchor)
    28. tc.insertText(string)
    29. self.setTextCursor(tc)
    30.  
    31. def textUnderCursor(self):
    32. tc=self.textCursor()
    33. tc.select(QTextCursor.WordUnderCursor)
    34. return tc.selectedText()
    35.  
    36. def keyPressEvent(self,e):
    37. print(e.text())
    38. if (self.cmp and self.cmp.popup().isVisible()):
    39. if e.key() in (Qt.Key_Enter,Qt.Key_Return,Qt.Key_Escape,Qt.Key_Tab,Qt.Key_Backtab):
    40. e.ignore()
    41. return
    42. isShortcut=((e.modifiers() & Qt.ControlModifier) and e.key()==Qt.Key_E)
    43. if (not self.cmp or not isShortcut):
    44. super().keyPressEvent(e)
    45.  
    46. ctrlOrShift = e.modifiers() & (Qt.ControlModifier | Qt.ShiftModifier)
    47. if (not self.cmp or (ctrlOrShift and e.text().isEmpty())):
    48. return
    49.  
    50. eow=QString("~!@#$%^&*()_+{}|:\"<>?,./;'[]\\-=")
    51. hasModifier = (e.modifiers() != Qt.NoModifier) and not ctrlOrShift
    52. completionPrefix = self.textUnderCursor()
    53. if (not isShortcut and (hasModifier or e.text().isEmpty() or completionPrefix.length()<2
    54. or eow.contains(e.text().right(1)))):
    55. self.cmp.popup().hide()
    56. return
    57. self.cmp.update(completionPrefix)
    58. self.cmp.popup().setCurrentIndex(self.cmp.completionModel().index(0, 0))
    59.  
    60. cr = self.cursorRect()
    61. cr.setWidth(self.cmp.popup().sizeHintForColumn(0)
    62. + self.cmp.popup().verticalScrollBar().sizeHint().width())
    63. self.cmp.complete(cr)
    64.  
    65. class Completer(QCompleter):
    66. def __init__(self,stringlist,parent=None):
    67. super(Completer,self).__init__(parent)
    68. self.stringlist=stringlist
    69. self.setModel(QStringListModel())
    70.  
    71. def update(self,completionText):
    72. filtered=self.stringlist.filter(completionText,Qt.CaseInsensitive)
    73. self.model().setStringList(filtered)
    74. self.popup().setCurrentIndex(self.model().index(0, 0))
    75.  
    76.  
    77. app=QApplication(sys.argv)
    78. li<<'The'<<'that'<<'Red'<<'right'<<'what'
    79. cmp=Completer(li)
    80. window=QMainWindow()
    81. edit=TextEdit()
    82. edit.setCompleter(cmp)
    83. window.setCentralWidget(edit)
    84. window.show()
    85.  
    86. app.exec_()
    To copy to clipboard, switch view to plain text mode 

  5. The following user says thank you to freud for this useful post:

    medved6 (10th December 2010)

  6. #4
    Join Date
    Sep 2009
    Posts
    2
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: How to change completion rule of QCompleter

    After a lot of studying up on how this works, I've finally figured it out. I've implemented my own version as well, but I have a question.

    My problem is that when the first letter entered into the editable combobox is actually the first letter of an entry, that entry is automatically selected. This bypasses completion of a single letter.

    For example. The list is:
    chicken broth
    cinnamon
    boneless chicken breast

    I want "c" to show all of these as possible completions. However, "c" will cause the combobox to select "chicken broth" instead. I've looked, but I can't figure out how to disable this behavior. Any suggestions?

    Thanks
    Bill

    edit: btw, hitting "c" will make the edittext read "chicken broth." And hitting backspace will remove all but the "c." Then it completes like i want it to. Obviously, I don't want to have to hit backspace every time.
    Last edited by jungle; 26th September 2009 at 21:41.

  7. #5
    Join Date
    Sep 2009
    Posts
    2
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: How to change completion rule of QCompleter

    I'll just give this one bump to see if anyone missed it. I have looked into the issue more, and I still can't figure out exactly what is setting the text. But it definitely happens without any completer attached.

    bill

  8. #6
    Join Date
    Dec 2009
    Posts
    50
    Thanks
    9
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: How to change completion rule of QCompleter

    Thank you.
    Ir was usefull for me as well

  9. #7
    Join Date
    Nov 2011
    Posts
    1
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: How to change completion rule of QCompleter

    There is a way of config the space between lines in the popup list?
    I don find a way to choose the row height.

    Thanks,
    Urbano

  10. #8
    Join Date
    Sep 2011
    Posts
    1,245
    Thanks
    3
    Thanked 127 Times in 126 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: How to change completion rule of QCompleter

    make your own thread instead of digging up old, relatively un-connected threads.
    If you have a problem, CUT and PASTE your code. Do not retype or simplify it. Give a COMPLETE and COMPILABLE example of your problem. Otherwise we are all guessing the problem from a fabrication where relevant details are often missing.

  11. #9
    Join Date
    Jul 2021
    Posts
    1
    Qt products
    Qt Jambi PyQt3 PyQt4
    Platforms
    Windows

    Default Re: How to change completion rule of QCompleter

    Quote Originally Posted by numbat View Post
    Using this QCompleter example and this employee monitoring, I implemented what you want.

    Header:
    Qt Code:
    1. #ifndef LINEEDIT_H
    2. #define LINEEDIT_H
    3.  
    4. #include <QLineEdit>
    5. #include <QStringList>
    6. #include <QStringListModel>
    7. #include <QString>
    8. #include <QCompleter>
    9.  
    10. class MyCompleter : public QCompleter
    11. {
    12. Q_OBJECT
    13.  
    14. public:
    15. inline MyCompleter(const QStringList& words, QObject * parent) :
    16. QCompleter(parent), m_list(words), m_model()
    17. {
    18. setModel(&m_model);
    19. }
    20.  
    21. inline void update(QString word)
    22. {
    23. // Do any filtering you like.
    24. // Here we just include all items that contain word.
    25. QStringList filtered = m_list.filter(word, caseSensitivity());
    26. m_model.setStringList(filtered);
    27. m_word = word;
    28. complete();
    29. }
    30.  
    31. inline QString word()
    32. {
    33. return m_word;
    34. }
    35.  
    36. private:
    37. QStringList m_list;
    38. QString m_word;
    39. };
    40.  
    41. class MyLineEdit : public QLineEdit
    42. {
    43. Q_OBJECT
    44.  
    45. public:
    46. MyLineEdit(QWidget *parent = 0);
    47. ~MyLineEdit();
    48.  
    49. void setCompleter(MyCompleter *c);
    50. MyCompleter *completer() const;
    51.  
    52. protected:
    53. void keyPressEvent(QKeyEvent *e);
    54.  
    55. private slots:
    56. void insertCompletion(const QString &completion);
    57.  
    58. private:
    59. MyCompleter *c;
    60. };
    61.  
    62. #endif // LINEEDIT_H
    To copy to clipboard, switch view to plain text mode 

    CPP:
    Qt Code:
    1. MyLineEdit::MyLineEdit(QWidget *parent)
    2. : QLineEdit(parent), c(0)
    3. {
    4. }
    5.  
    6. MyLineEdit::~MyLineEdit()
    7. {
    8. }
    9.  
    10. void MyLineEdit::setCompleter(MyCompleter *completer)
    11. {
    12. if (c)
    13. QObject::disconnect(c, 0, this, 0);
    14.  
    15. c = completer;
    16.  
    17. if (!c)
    18. return;
    19.  
    20. c->setWidget(this);
    21. connect(completer, SIGNAL(activated(const QString&)), this, SLOT(insertCompletion(const QString&)));
    22. }
    23.  
    24. MyCompleter *MyLineEdit::completer() const
    25. {
    26. return c;
    27. }
    28.  
    29. void MyLineEdit::insertCompletion(const QString& completion)
    30. {
    31. setText(completion);
    32. selectAll();
    33. }
    34.  
    35.  
    36. void MyLineEdit::keyPressEvent(QKeyEvent *e)
    37. {
    38. if (c && c->popup()->isVisible())
    39. {
    40. // The following keys are forwarded by the completer to the widget
    41. switch (e->key())
    42. {
    43. case Qt::Key_Enter:
    44. case Qt::Key_Return:
    45. case Qt::Key_Escape:
    46. case Qt::Key_Tab:
    47. case Qt::Key_Backtab:
    48. e->ignore();
    49. return; // Let the completer do default behavior
    50. }
    51. }
    52.  
    53. bool isShortcut = (e->modifiers() & Qt::ControlModifier) && e->key() == Qt::Key_E;
    54. if (!isShortcut)
    55. QLineEdit::keyPressEvent(e); // Don't send the shortcut (CTRL-E) to the text edit.
    56.  
    57. if (!c)
    58. return;
    59.  
    60. bool ctrlOrShift = e->modifiers() & (Qt::ControlModifier | Qt::ShiftModifier);
    61. if (!isShortcut && !ctrlOrShift && e->modifiers() != Qt::NoModifier)
    62. {
    63. c->popup()->hide();
    64. return;
    65. }
    66.  
    67. c->update(text());
    68. c->popup()->setCurrentIndex(c->completionModel()->index(0, 0));
    69. }
    To copy to clipboard, switch view to plain text mode 

    Usage:
    Qt Code:
    1. MyLineEdit * te = new MyLineEdit;
    2. MyCompleter * completer = new MyCompleter(QStringList() << "oneone" << "Twotwo", this);
    3. completer->setCaseSensitivity(Qt::CaseInsensitive);
    4. te->setCompleter(completer);
    To copy to clipboard, switch view to plain text mode 
    Thank you, Numbat
    It`s works for me

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.