Qt:如何在特定时间内冻结某些按钮?

时间:2019-01-04 20:09:07

标签: c++ qt qtimer

我正在尝试使用Qt 5.11.1和C ++构建一个简单的内存游戏,您会在屏幕上看到一些图块,并且必须单击两个图块并尝试匹配它们显示的图像。

我的图块被实现为QPushButtons。每次单击一个图像都会显示一个图像(通过调用showImage()方法来更改按钮背景)。单击第二个磁贴时,如果存在匹配项,则会禁用两个按钮,因此您无法再次单击它们(您会获得更高的分数)。但是,如果没有找到匹配项,则您刚刚单击的两个图块将在1秒后返回其初始状态(不显示图像)(这使用户可以“记住”每个图块上显示的图像)

每当您单击“平铺”(按钮)时,它就会被禁用(button->setEnabled(false))。如果在单击第二个图块之后没有匹配项,则将两个图块都转回,然后再次setEnabled(true)。我正在使用单次QTimer调用将回退磁贴的方法:

QTimer::singleShot(1000, this, SLOT(turnTilesBack()));
firstTile->setEnabled(true);
secondTile->setEnabled(true);

一切都按预期工作,除了一件事:当QTimer在其自己的线程中运行(或者据我了解,我读到的东西),所有可用的磁贴在经过1000毫秒后仍保持启用状态,从而允许用户继续单击在他们。但是,当没有匹配项时,我想“冻结”按钮,直到QTimer超时为止,以便用户无法继续播放,直到磁贴变回原处为止。

因此,我没有使用QTimer,而是尝试了这个问题(How do I create a pause/wait function using Qt?)上看到的解决方案:

QTime dieTime= QTime::currentTime().addSecs(1);
while (QTime::currentTime() < dieTime)
    turnTilesBack();

尽管我删除了以下行:QCoreApplication::processEvents(QEventLoop::AllEvents, 100);,因为这将导致主线程不冻结,并且按钮仍可单击。

但是使用这种方法,每当用户单击第二个图块时,即使没有匹配,也不会显示图像,即使在上面的代码之前调用了我的showImage()方法,我也不会确定为什么会这样。因此用户知道没有匹配项,因为1秒钟后磁贴返回到其初始状态,但是他们再也没有看到第二个按钮上的图像。

作为另一种方法,我也禁用了所有按钮,然后在单次拍摄QTimer超时后,仅重新启用了尚未匹配的按钮。但这需要附加的逻辑来跟踪已匹配的图块。所以现在我坚持

是否有更清洁的解决方案?也许有一种方法可以使QTimer冻结主线程直到其超时?

1 个答案:

答案 0 :(得分:3)

启用/禁用整个QPushButtons组的一种简单方法是将它们放在中间小部件上(在下面的示例中,我使用了QFrame

如果要禁用所有QPushButtons,只需禁用框架,所有子控件都将被禁用。

当您要重新启用它们时,请启用框架。

重新启用框架后,框架内 中已禁用的任何小部件都不会启用,因此您不会在单个按钮上失去启用/禁用状态

这是一个简单的例子。请注意,我使用了显式的启用/禁用按钮,它们充当计时器的代理。

#include <QApplication>
#include <QMainWindow>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QPushButton>
#include <QFrame>

int main(int argc, char** argv)
{
    QApplication* app = new QApplication(argc, argv);
    QMainWindow*  window = new QMainWindow();
    window->setFixedSize(1024, 200);

    QWidget* widget = new QWidget();
    QHBoxLayout layout(widget);

    QPushButton* enable  = new QPushButton("enable");
    QPushButton* disable = new QPushButton("disable");
    QFrame*      frame   = new QFrame();

    layout.addWidget(enable);
    layout.addWidget(disable);
    layout.addWidget(frame);

    QVBoxLayout frame_layout(frame);
    for (int i = 0; i < 5; ++i)
        frame_layout.addWidget(new QPushButton("click"));

    // this shows that an already disabled button remains disabled
    QPushButton* already_chosen = new QPushButton("click");
    frame_layout.addWidget(already_chosen);
    already_chosen->setEnabled(false);

    QObject::connect(enable,  &QPushButton::clicked, [&]{ frame->setEnabled(true); });
    QObject::connect(disable, &QPushButton::clicked, [&]{ frame->setEnabled(false); });

    window->setCentralWidget(widget);
    window->show();
    return app->exec();
}