开发者

Qt: how to make it so that only one of QCompleter::activated() or QLineEdit::returnPressed() gets emitted?

开发者 https://www.devze.com 2023-02-01 08:47 出处:网络
I have a QLineEdit with a QCompleter. I want a slot myslot() ca开发者_如何学Golled when either of the signals QCompleter::activated(const QString) or QLineEdit::returnPressed() get emitted.

I have a QLineEdit with a QCompleter. I want a slot myslot() ca开发者_如何学Golled when either of the signals QCompleter::activated(const QString) or QLineEdit::returnPressed() get emitted.

Also, I want this slot to be called directly after the completion is made if the user used the QCompleter to enter data (ie., I do not want the user to have to press Enter if he already clicked on the QCompleter).

This works fine if the user does not use the completer, or uses the mouse to click on the completer. However, if he uses the enter key on the QCompleter's popup, both of the signals get emitted, and myslot() gets called twice.

How to make it so that it is called only once, no matter the situation?


I recommend making a wrapper class for QCompleter in which you reimplement eventFilter(). The wrapper class can either emit the signal only for the mouse click or it can eat the return pressed event. Clear documentation can be found in the Qt manual. An online copy is here: http://doc.qt.io/archives/4.6/qobject.html#eventFilter

There are other ways but this one is rather strait forward.


You could try to ensure that you are connected to only one signal as appropriate. If the completer is visible then connect to its signal and disconnect from the line edit. When the completer does away then connect back up to the line edit. Here's a one file sample that works the way you want it to.

#include <QAbstractItemView>
#include <QApplication>
#include <QCompleter>
#include <QDebug>
#include <QLineEdit>

class MyLineEdit : public QLineEdit
{
Q_OBJECT
public:
    MyLineEdit() : m_completer( new QCompleter( QStringList( "foo" ) ) )
    {
        setCompleter( m_completer );
        m_completer->popup()->installEventFilter( this );
        connectReturnPressed();
    }

    virtual bool eventFilter( QObject* watched, QEvent* e )
    {
        if ( e->type() == QEvent::Show )
        {
            connectCompleterActivated();
        }
        else if ( e->type() == QEvent::Hide )
        {
            connectReturnPressed();
        }

        return QLineEdit::eventFilter( watched, e );
    }

private slots:
    void myslot() { qDebug() << "myslot"; }

private:
    void connectReturnPressed()
    {
        disconnect( m_completer, SIGNAL( activated( const QString& ) )
                  , this, SLOT( myslot() ) );
        connect( this, SIGNAL( returnPressed() )
                     , SLOT( myslot() ) );
    }
    void connectCompleterActivated()
    {
        disconnect( this, SIGNAL( returnPressed() )
                  , this, SLOT( myslot() ) );
        connect( m_completer, SIGNAL( activated( const QString& ) )
               , SLOT( myslot() ) );
    }

    QCompleter*const m_completer;
};

#include "main.moc"

int main( int argc, char** argv )
{
    QApplication qapp( argc, argv );

    MyLineEdit*const edit = new MyLineEdit;
    edit->show();

    return qapp.exec();
}


I solved this; it's not particularly clean, but it works. Here's my handler for both signals. If the signal comes from the QCompleter, caller is set to COMPLETER, otherwise it's set to ENTER_PRESSED.

void myClass::handler(char caller)
{
  if ((caller == COMPLETER && lineedit->text().length() != 0) || (caller == ENTER_PRESSED))
  {
    // do stuff here
    lineedit->clear();
  }
}

By cleaning the helpline after it does the work it needs to do, it can then ignore the second signal (the one from the completer), since it doesn't make sense for the QCompleter to complete an empty string.

Furthermore, I need this behavior (ie, not just ignoring the signal if the helpline->text().length() is 0), because in my app it is valid for the user just to press enter with an empty string.

0

精彩评论

暂无评论...
验证码 换一张
取 消