Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A QLineEdit with a QCompleter won't show the QCompleter's popup menu with an empty text field

Tags:

c++

qt

qt4

I have a QLineEdit, with a QCompleter object associated to it. If the user enters at least one character, the popup menu from the QCompleter is shown, but when the user deletes the last character (thus leaving the field empty) the popup disappears. Is there any way to make it show even when the QLineEdit's text is empty?

like image 566
Andrea Bergia Avatar asked Jan 31 '11 23:01

Andrea Bergia


2 Answers

you should be able to force completer's popup window to get shown once your line edit text is erased by using QCompleter::complete slot:

lineEdit->completer()->complete();

Here's how you can do it:

  • define textChanged slot for your lineedit;
  • override customEvent method for your window;
  • in the textChanged slot send user event to the window whenever lineedit's text has zero length;
  • in the customEvent method show completer whenever user event is received;

Below is an example:

mainwindow.h:

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

protected:
    void customEvent(QEvent * event);

private:
    Ui::MainWindow *ui;

private slots:
    void on_lineEdit_textChanged(QString );
};

mainwindow.cpp:

class CompleteEvent : public QEvent
{
public:
    CompleteEvent(QLineEdit *lineEdit) : QEvent(QEvent::User), m_lineEdit(lineEdit) { }

    void complete()
    {
        m_lineEdit->completer()->complete();
    }

private:
    QLineEdit *m_lineEdit;
};

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    QStringList wordList;
    wordList << "one" << "two" << "three" << "four";

    QLineEdit *lineEdit = new QLineEdit(this);
    lineEdit->setGeometry(20, 20, 200, 30);
    connect(lineEdit, SIGNAL(textChanged(QString)), SLOT(on_lineEdit_textChanged(QString )));

    QCompleter *completer = new QCompleter(wordList, this);
    completer->setCaseSensitivity(Qt::CaseInsensitive);
    completer->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
    lineEdit->setCompleter(completer);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::customEvent(QEvent * event)
{
    QMainWindow::customEvent(event);
    if (event->type()==QEvent::User)
        ((CompleteEvent*)event)->complete();
}

void MainWindow::on_lineEdit_textChanged(QString text)
{
    if (text.length()==0)
        QApplication::postEvent(this, new CompleteEvent((QLineEdit*)sender()));
}

hope this helps, regards

like image 107
serge_gubenko Avatar answered Sep 28 '22 10:09

serge_gubenko


Here is my solution based on serge_gubenko's answer. This class uses QStringListModel, but it can be easily replaced with any other model.

Completer_line_edit.h

#include <QLineEdit>
#include <QStringListModel>
#include <QTimer>

/*! Line edit widget with auto completion based on QStringListModel.
  Modified behaviour: completion list will appear even when contents of
  line edit is empty. Full list of options will be showed when line edit
  has focus and is empty.
  */
class Completer_line_edit : public QLineEdit {
  Q_OBJECT
public:
  explicit Completer_line_edit(QWidget *parent = 0);

  //! Set list of options used for copmletion.
  inline void set_list(QStringList list) { model.setStringList(list); }

private:
  QStringListModel model;
  void focusInEvent(QFocusEvent *e);
  void customEvent(QEvent* e);
  QTimer timer;

private slots:
  void slot_text_edited();
  void slot_call_popup();

};

Completer_line_edit.cpp

#include "Completer_line_edit.h"
#include <QCompleter>
#include <QEvent>
#include <QApplication>

Completer_line_edit::Completer_line_edit(QWidget *parent) :
  QLineEdit(parent)
{
  setCompleter(new QCompleter());
  completer()->setModel(&model);
  completer()->setCompletionMode(QCompleter::PopupCompletion);
  completer()->setCaseSensitivity(Qt::CaseInsensitive);
  connect(this, SIGNAL(textEdited(QString)), this, SLOT(slot_text_edited()));
}

void Completer_line_edit::focusInEvent(QFocusEvent *e) {
  QLineEdit::focusInEvent(e);
  // force completion when line edit is focued in
  completer()->complete();
}

void Completer_line_edit::slot_text_edited() {
  qDebug() << "text edited";
  // force to show all items when text is empty
  completer()->setCompletionMode(text().isEmpty()? QCompleter::UnfilteredPopupCompletion: QCompleter::PopupCompletion);
  if (text().isEmpty()) {
    // completion list will be hidden now; we will show it again after a delay
    timer.singleShot(100, this, SLOT(slot_call_popup()));
  }
}

void Completer_line_edit::slot_call_popup() {
  // apparently, complete() works only in event handler
  QApplication::postEvent(this, new QEvent(QEvent::User));
}

void Completer_line_edit::customEvent(QEvent *e) {
  QLineEdit::customEvent(e);
  // force completion after text is deleted
  completer()->complete();
}
like image 29
Pavel Strakhov Avatar answered Sep 28 '22 09:09

Pavel Strakhov