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?
可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
回答1:
you should be able to force completer's popup window to get shown once your line edit text is erased by using QCompliter::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
回答2:
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();
}