Results 1 to 16 of 16

Thread: How does QComboBox uses/calls QCompleter ?

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Join Date
    Jun 2016
    Posts
    19
    Thanks
    10
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Windows

    Default How does QComboBox uses/calls QCompleter ?

    I would like to implemet custom completion (multi world matching e.g,) completer on item list from a qcombobox.

    The docs for QComboBox show setcompleter(QCompleter *) member.

    I figure I need to subclass QCompleter and pass it to QComboBox::setCOmplter()

    I looked at QCompleter docs and I dont see many virtual functions, for which I figure I would have to override with my own code.

    I am lost/confused,
    How does QComboBox would use/call my own custom completer ?
    Which members would QComboBox call ? connect to which slot/signals ?

    In theory, I would imagine QComboBox would call my completer; e.g, complete(QString phrase); passing phrase that was typed in the edit box of combo box.

    Could somone please explain how is QComboBox interacting with QComplter passed to combo box using setCompleter() member ?

    cheers

  2. #2
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,316
    Thanks
    314
    Thanked 870 Times in 857 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: How does QComboBox uses/calls QCompleter ?

    In general, you do not derive from QCompleter to create a custom completer. You instead derive from QAbstractItemModel and set that on your QCompleter as the model it uses to find completions for a partial phrase. The combo box and completer handle the interaction between them and you don't need to care how that works, just what your model does when asked.

    If your completions can be simplified to a list of strings, then you can use the version of QCompleter that accepts a QStringList argument, and internally QCompleter will insert that into a QStringListModel.

    If your completions are more complex, then you may need to implement your own model. In this case, you have almost total control over how QCompleter searches your model for completions. For example, if you have a table model, you can tell it which column to use for completions, which model role to use to retrieve candidates, and so forth.

    The QCompleter example in the docs will help. There is a more advanced example as well. In both cases, note that they use a plain old QCompleter and customize it using models.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  3. The following user says thank you to d_stranz for this useful post:

    boo9 (1st July 2016)

  4. #3
    Join Date
    Jun 2016
    Posts
    19
    Thanks
    10
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: How does QComboBox uses/calls QCompleter ?

    I examined above examples but I dont think they answer my question,

    Let me be more specific
    I need a completer that will complete on many words, e.g, user types in "aa bb" into QEditBox edit, and completer should complete a list where each item on the complete list matches (not just begins with) "aa" and "bb".
    that is, the completion for "aa bb" filter from a list {aaa_a, aaa_bbb, aabb, bbb_a}, should be {aaa_bbb, aabb}.

    I managed to do that but I needed to sublcass both qeditbox and qcompleter.
    Is there any way to accomplish that w/o subclassing QEditBox ?

  5. #4
    Join Date
    Jun 2016
    Posts
    19
    Thanks
    10
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: How does QComboBox uses/calls QCompleter ?

    I subclassed QCompleter

    Qt Code:
    1. class mySearchFilterComplter : public QCompleter
    2. {
    3. Q_OBJECT
    4. public:
    5. mySearchFilterComplter(QObject * parent) : QCompleter(parent), m_model()
    6. {
    7. setModel(&m_model);
    8. }
    9. public slots:
    10. void update(const QString & text)
    11. {
    12. QDebug() << "update";
    13. m_model.setStringList(QStringList() << "one" << "two" << "three");
    14. complete();
    15. popup()->setCurrentIndex(completionModel()->index(0, 0));
    16. }
    17. private:
    18. };
    To copy to clipboard, switch view to plain text mode 

    then connected combo box editTextChanged() signal to my completer update() slot.

    Qt Code:
    1. mySearchFilterComplter * cc = new mySearchFilterComplter(this);
    2. ui->comboBox->setComplter(cc)
    3. connect(ui->comboBox, SIGNAL(editTextChanged(QString)), cc, SLOT(update(QString)));
    To copy to clipboard, switch view to plain text mode 

    The update() gets called with each keystroke in combo box line edit but there is no popup ?
    What am I doing wrong ?
    I have similar code with subsclassed QLineEdit and subclassed QCompleter and the completer popup works. (but the completer::update() is called from keyPressedEvent() though)

    Qt Code:
    1. class MyCompleter : public QCompleter
    2. {
    3. Q_OBJECT;
    4. public:
    5. inline MyCompleter(const QStringList& words, QObject * parent) :
    6. QCompleter(parent), m_model()
    7. {
    8. setModel(&m_model);
    9. }
    10. inline void update(QString word)
    11. {
    12. m_model.setStringList(QStringList() << "one" << "two" << "three");
    13. complete();
    14. }
    15. private:
    16. QStringList m_list;
    17. };
    18.  
    19. class MyLineEdit : public QLineEdit
    20. {
    21. Q_OBJECT;
    22. public:
    23. MyLineEdit(QWidget *parent = 0);
    24. ~MyLineEdit();
    25. void setCompleter(MyCompleter *c);
    26. MyCompleter *completer() const;
    27. protected:
    28. void keyPressEvent(QKeyEvent *e);
    29. private slots:
    30. void insertCompletion(const QString &completion);
    31. private:
    32. MyCompleter *c;
    33. };
    34.  
    35. MyLineEdit::MyLineEdit(QWidget *parent)
    36. : QLineEdit(parent), c(0)
    37. {
    38. }
    39.  
    40. MyLineEdit::~MyLineEdit()
    41. {
    42. }
    43.  
    44. void MyLineEdit::setCompleter(MyCompleter *completer)
    45. {
    46. if (c)
    47. QObject::disconnect(c, 0, this, 0);
    48.  
    49. c = completer;
    50.  
    51. if (!c)
    52. return;
    53.  
    54. c->setWidget(this);
    55. connect(completer, SIGNAL(activated(const QString&)), this, SLOT(insertCompletion(const QString&)));
    56. }
    57.  
    58. MyCompleter *MyLineEdit::completer() const
    59. {
    60. return c;
    61. }
    62.  
    63. void MyLineEdit::insertCompletion(const QString& completion)
    64. {
    65. setText(completion);
    66. selectAll();
    67. }
    68. void MyLineEdit::keyPressEvent(QKeyEvent *e)
    69. {
    70. if (c && c->popup()->isVisible())
    71. {
    72. // The following keys are forwarded by the completer to the widget
    73. switch (e->key())
    74. {
    75. case Qt::Key_Enter:
    76. case Qt::Key_Return:
    77. case Qt::Key_Escape:
    78. case Qt::Key_Tab:
    79. case Qt::Key_Backtab:
    80. e->ignore();
    81. return; // Let the completer do default behavior
    82. }
    83. }
    84.  
    85. bool isShortcut = (e->modifiers() & Qt::ControlModifier) && e->key() == Qt::Key_E;
    86. if (!isShortcut)
    87. QLineEdit::keyPressEvent(e); // Don't send the shortcut (CTRL-E) to the text edit.
    88.  
    89. if (!c)
    90. return;
    91.  
    92. bool ctrlOrShift = e->modifiers() & (Qt::ControlModifier | Qt::ShiftModifier);
    93. if (!isShortcut && !ctrlOrShift && e->modifiers() != Qt::NoModifier)
    94. {
    95. c->popup()->hide();
    96. return;
    97. }
    98.  
    99. c->update(text());
    100. c->popup()->setCurrentIndex(c->completionModel()->index(0, 0));
    101. }
    102.  
    103. MainWindow::MainWindow(QWidget *parent)
    104. : QMainWindow(parent)
    105. {
    106. MyLineEdit * te = new MyLineEdit();
    107.  
    108.  
    109. MyCompleter * completer = new MyCompleter(QStringList() << "112233" << "223344" << "334455", this);
    110. completer->setCaseSensitivity(Qt::CaseInsensitive);
    111. te->setCompleter(completer);
    112.  
    113. QVBoxLayout * layout = new QVBoxLayout;
    114. layout->addWidget(te);
    115. QWidget *centralWidget = new QWidget;
    116. centralWidget->setLayout(layout);
    117. setCentralWidget(centralWidget);
    118. }
    119.  
    120. MainWindow::~MainWindow()
    121. {
    122.  
    123. }
    To copy to clipboard, switch view to plain text mode 

  6. #5
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,316
    Thanks
    314
    Thanked 870 Times in 857 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: How does QComboBox uses/calls QCompleter ?

    If you are fixated on subclassing QCompleter, I can't help you.

    You could probably accomplish what you want without subclassing by using a combination of a QSortFilterProxyModel, QStringListModel, and QRegExp to set a filter on the completion strings returned by the string list model. Then all of these behavioral problems you are battling with should magically disappear because you are using a wheel that already works rather than trying to invent your own.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  7. The following user says thank you to d_stranz for this useful post:

    boo9 (2nd July 2016)

  8. #6
    Join Date
    Jun 2016
    Posts
    19
    Thanks
    10
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: How does QComboBox uses/calls QCompleter ?

    > You could probably accomplish what you want without subclassing by using a combination of a QSortFilterProxyModel, QStringListModel, and QRegExp

    You mean to disable default completer on qcombobox and filter items in the combobox directly ?
    e.g, on each combobox::editTextChanged() notification, programatically rebuild new combo box item list ?
    when user enters "aa bb cc" into combobox edit, then leave only items in the combobox list that contain "aa" and "bb" and "cc" ?

  9. #7
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,316
    Thanks
    314
    Thanked 870 Times in 857 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: How does QComboBox uses/calls QCompleter ?

    ou mean to disable default completer on qcombobox and filter items in the combobox directly ?
    No. The "chain of command" is like this: combo box has a completer, completer has a proxy model, proxy model has the string list model with *all* strings and a regular expression that matches a subset (or none) of the strings.

    You create your complete string model instance and populate it with strings. You also create the proxy model instance and give it the pointer to the string model as its source model. When you call setModel() on the completer, you would give it the pointer to the proxy model. The completer has no idea it is looking at a proxy instead of the full model; the interfaces and interactions are identical, it's just that the proxy is doing some magic to return only a part of the full model to the completer.

    The proxy model does what your manual code does now - it takes the full list of possibilities, applies some logic to select out the matching subset, and passes that to the completer. The "logic" in this case is defined by a QRegExp regular expression.

    You will probably have to create your regular expressions on the fly to match what the user is typing, and it will change with every keystroke. So when the user types "a" and you want to match every string that starts with an "a", then your regular expression is "^a[a-z]*[ _]{0,1}[a-z]*" In English this says, "match any string that starts with lowercase 'a', followed by zero or more lowercase letters of any type, followed by 0 or 1 spaces or underscores, followed by zero or more lowercase letters".

    When the user types "aa bb", then you need "^aa[a]*[ _]{0,1}bb[b]*" which says, match any string starting with two or more lowercase 'a', followed by zero or one underscore or blank space, followed by two or more 'b' characters."

    In essence, you are letting the QRegExp do the filtering for you by changing the rules it uses for filtering. These "rules" would probably be very similar to the "rules" you would be coding by hand, except these are expressed in regular expression syntax rather than a bunch of if / else / endif logic.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  10. The following user says thank you to d_stranz for this useful post:

    boo9 (3rd July 2016)

  11. #8
    Join Date
    Jun 2016
    Posts
    19
    Thanks
    10
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: How does QComboBox uses/calls QCompleter ?

    Thank you for detailed explanation, however RE will not make it in general case.
    For simple searches with two tokens, "aa bb" query means aa followed by bb OR bb followed by aa. One can express that in simple RE
    aa.*bb|bb.*aa

    However when there is more tokens e.g, "aa bb cc dd" permuting all sequences of aa,bb,cc is not feasable.

    3 tokens => 3! = 6 permutations
    4 tokens => 4! = 24 permutations

    cheers

  12. #9
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,316
    Thanks
    314
    Thanked 870 Times in 857 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: How does QComboBox uses/calls QCompleter ?

    I guess I have no idea what you are trying to do with your completer or what the use case might be.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  13. The following user says thank you to d_stranz for this useful post:

    boo9 (6th July 2016)

  14. #10
    Join Date
    Jun 2016
    Posts
    19
    Thanks
    10
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: How does QComboBox uses/calls QCompleter ?

    > I guess I have no idea what you are trying to do with your completer

    I have a list with 100 items.
    Each list item is a text of 10-50 characters, 2-10 words
    When I type in "aa" I would like only items that contain "aa" filtered
    When I type in "aa bb" I would like only items that contain "aa" AND "bb" filtered, "aa bb" does not mean that bb follows aa, it only means that list item must contain "aa" and "bb" anywhere in the item text.
    When I type in "aa bb cc" I would like only items that contain "aa" AND "bb" AND "cc" filtered, aa,bb,cc can appear at any position in the item text.

  15. The following user says thank you to boo9 for this useful post:

    d_stranz (7th July 2016)

  16. #11
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,316
    Thanks
    314
    Thanked 870 Times in 857 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: How does QComboBox uses/calls QCompleter ?

    I have a list with 100 items.
    Each list item is a text of 10-50 characters, 2-10 words
    OK... can you please give an example with some of the real strings that you have in your list, and what the user might type? "aa bb cc" is just too abstract for me to understand how you might be using this in a real application.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

Similar Threads

  1. QComboBox with QCompleter
    By cic in forum Qt Programming
    Replies: 1
    Last Post: 27th September 2013, 19:21
  2. spectrogram calls
    By marc2050 in forum Qwt
    Replies: 1
    Last Post: 5th August 2011, 08:52
  3. Paint() calls
    By alitoh in forum Newbie
    Replies: 1
    Last Post: 10th May 2011, 02:05
  4. How to use IOCTL calls with QT?
    By augusbas in forum Qt Programming
    Replies: 3
    Last Post: 15th November 2010, 07:55
  5. Replies: 1
    Last Post: 12th October 2008, 08:21

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
  •  
Qt is a trademark of The Qt Company.