Fail to clear QLineEdit after selecting item from

2019-04-15 08:46发布

问题:

using PopupCompletion mode when you select an item (using arrow keys) and press return - lineEdit should become empty (i clear lineEdit when return is pressed), but lineEdit does not become empty. (If you press 'Enter' again it will empty the lineEdit). So i think pressing return does clear lineEdit, but pressing return also tells QCompleter to insert selected item into lineEdit, so it seems like nothing happens.

But, if you click the item insted of selecting it with arrows - everything works fine.

I tried to find the solution on the internet, but i found only one person that had the same problem: http://lists.trolltech.com/qt-interest/2006-10/thread00985-0.html . Sadly there are no answers. Please read his question because it will help understand my problem.

How can I clean LineEdit after QCompleter inserted selected item? (catching activated signal does not help)

回答1:

The issue here is that the completer actually contains a pop-up, which is actually a separate QAbstractItemView widget (refer to the QCompleter::popup() documentation). As such, when you press 'Enter' on the QCompleter, the key event actually goes to the pop-up and not the line edit.

There are two different ways to resolve your issue:

Option 1

Connect the completer's activated signal to the line edit's clear slot, but do it as a QueuedConnection:

QObject::connect(completer, SIGNAL(activated(const QString&)),
                 lineEdit, SLOT(clear()),
                 Qt::QueuedConnection);

The reason why using a direct connection doesn't work is because your are essentially dependent on the order in which slots get called from a signal. Using a QueuedConnection gets around this. From a code maintenance standpoint, I don't really prefer this solution because it isn't clear what your intention is just by looking at the code.

Option 2

Write an event filter around the pop-up to filter out the 'Enter' key to clear the line edit explicitly. Your event filter would end up looking something like this:

class EventFilter : public QObject
{
   Q_OBJECT
public:
   EventFilter(QLineEdit* lineEdit, QObject* parent = NULL)
      :QObject(parent)
      ,mLineEdit(lineEdit)
   { }
   virtual ~EventFilter()
   { }

   bool eventFilter(QObject* watched, QEvent* event)
   {
      QAbstractItemView* view = qobject_cast<QAbstractItemView*>(watched);
      if (event->type() == QEvent::KeyPress)
      {
         QKeyEvent* keyEvent = dynamic_cast<QKeyEvent*>(event);
         if (keyEvent->key() == Qt::Key_Return || 
             keyEvent->key() == Qt::Key_Enter)
         {
            mLineEdit->clear();
            view->hide();
            return true;
         }
      }
      return false;
   }

private:
   QLineEdit* mLineEdit;
};

You would then install the event filter on the completer's pop-up:

EventFilter* filter = new EventFilter(lineEdit);
completer->popup()->installEventFilter(filter);

This option is more work, but it's clearer as to what you are doing. Moreover, you can perform additional customization this way, if you prefer.