delay in displaying QStackedWidget Item in qt

1.3k views Asked by At

I am using QStackedWidget item. But for the first time it is taking time and after a while it is working properly.

mymainwindow::mymainwindow() : QMainWindow()
{

    stack = new QStackedWidget();
    list = new QListWidget();
    stack->addWidget(new QLineEdit("Hello U have clicked the first menu"));
    stack->addWidget(new QLineEdit("Second ListWidget Item"));
    stack->addWidget(new QLineEdit("Last Widget Item"));

    widget = new QWidget();
    QLabel *label = new QLabel("Main Window");

    list->addItem("New Item 1");
    list->addItem("New Item 2");
    list->addItem("New Item 3");
    list->setFixedSize(200,100);

    QVBoxLayout *vertical = new QVBoxLayout();
    vertical->addWidget(label);
    vertical->addWidget(list);
    vertical->addWidget(stack);
    stack->hide();

    widget->setLayout(vertical);
    setCentralWidget(widget);
}

void mymainwindow::keyPressEvent(QKeyEvent *event)
{

    switch (event->key()) {

    case Qt::Key_Down:
        connect(list,SIGNAL(currentRowChanged(int)),stack,SLOT(setCurrentIndex(int)));
        break;
    case Qt::Key_Up:
        connect(list,SIGNAL(currentRowChanged(int)),stack,SLOT(setCurrentIndex(int)));
        break;
    case Qt::Key_Enter:
        stack->show();
        break;
    case Qt::Key_Escape:
        stack->hide();
        break;

    }
}
2

There are 2 answers

1
UmNyobe On BEST ANSWER

Well :

  • You are overriding QMainWindow::keyPressEvent(QKeyEvent *event) and completely disregarding the default implementation.
  • Qobject::connect at each key press is a mistake. You seem to have your own interpretation of what it does. read the docs
  • You must not listen to key press of the main window to know items of the listwidget are changing.
  • The proper way of shortcuts is to add a Qaction, and then associate a shortcut to this action. Why? If the widgets inside stack need to receive "Enter" key events (like a QButton), your UI will be completely bogus because you are manipulating the visibility at the same time.

Basically what you want is to move connection to the constructor of your window, and to make sure the key events are always processed

mymainwindow::mymainwindow() : QMainWindow()
{

    stack = new QStackedWidget();
    list = new QListWidget();
    stack->addWidget(new QLineEdit("Hello U have clicked the first menu"));
    stack->addWidget(new QLineEdit("Second ListWidget Item"));
    stack->addWidget(new QLineEdit("Last Widget Item"));

    widget = new QWidget();
    QLabel *label = new QLabel("Main Window");

    list->addItem("New Item 1");
    list->addItem("New Item 2");
    list->addItem("New Item 3");
    list->setFixedSize(200,100);

    QVBoxLayout *vertical = new QVBoxLayout();
    vertical->addWidget(label);
    vertical->addWidget(list);
    vertical->addWidget(stack);
    stack->hide();

    connect(list,SIGNAL(currentRowChanged(int)),stack,SLOT(setCurrentIndex(int)));
    list->setCurrentRow(2);//last, to test 

    widget->setLayout(vertical);
    setCentralWidget(widget);
}


void mymainwindow::keyPressEvent(QKeyEvent *event)
{

    switch (event->key()) {

    case Qt::Key_Enter:
        stack->show();
        break;
    case Qt::Key_Escape:
        stack->hide();
        break;
    }
    QMainWindow::keyPressEvent(event);
}

Still, this is a nightmare.

Edit:
If the focus is on the list widget, changing rows in the list with the keyboard will trigger the signal.

8
László Papp On

I would personally suggest to move the connections from your event to the constructor as per my comments earlier since that would be a cleaner design, although we do not quite get what you are trying to achieve. Hence, as per your request, I am providing some code below, which I guess, you could do:

...
case Qt::Key_Down:
    connect(list,SIGNAL(currentRowChanged(int)),stack,SLOT(setCurrentIndex(int)));
    break;
case Qt::Key_Up:
    connect(list,SIGNAL(currentRowChanged(int)),stack,SLOT(setCurrentIndex(int)));
    break;
...

to:

mymainwindow.h

mymainwindow : public QMainWindow
{
    ...
    QTimer m_timer;
    bool m_ready;
};

mymainwindow.cpp

mymainwindow::mymainwindow()
    : QMainWindow()
    , m_ready(false)
{

    stack = new QStackedWidget();
    list = new QListWidget();
    stack->addWidget(new QLineEdit("Hello U have clicked the first menu"));
    stack->addWidget(new QLineEdit("Second ListWidget Item"));
    stack->addWidget(new QLineEdit("Last Widget Item"));

    widget = new QWidget();
    QLabel *label = new QLabel("Main Window");

    list->addItem("New Item 1");
    list->addItem("New Item 2");
    list->addItem("New Item 3");
    list->setFixedSize(200,100);

    QVBoxLayout *vertical = new QVBoxLayout();
    vertical->addWidget(label);
    vertical->addWidget(list);
    vertical->addWidget(stack);
    stack->hide();

    widget->setLayout(vertical);
    setCentralWidget(widget);

    connect(&m_timer, SIGNAL(timeout()), SLOT(delayEvent()));
    m_timer.setSingleShot(true);
    m_timer.start(5000);
}

void mymainwindow::delayEvent()
{
    m_ready = true;
}


void mymainwindow::keyPressEvent(QKeyEvent *event)
{

    switch (event->key()) {

    case Qt::Key_Down:
        if (m_ready)
             connect(list,SIGNAL(currentRowChanged(int)),stack,SLOT(setCurrentIndex(int)), Qt::UniqueConnection);
        break;
    case Qt::Key_Up:
        if (m_ready)
            connect(list,SIGNAL(currentRowChanged(int)),stack,SLOT(setCurrentIndex(int)), Qt::UniqueConnection);
        break;
    case Qt::Key_Enter:
        stack->show();
        break;
    case Qt::Key_Escape:
        stack->hide();
        break;

    }
}

Then, use this variable for the events to see if you are "ready" or not. Also, you would need to use Qt::UniqueConnection for the fifth parameter when connecting to avoid duplicated connections, or just use the m_ready guard or any other for that purpose.

But really, this sounds like a fishy design.