问题:如何将某些按钮冻结一段特定的时间



我正试图用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,而是尝试了我在这个问题上看到的这个解决方案(我如何使用Qt创建暂停/等待函数?):

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

尽管我删除了这一行:QCoreApplication::processEvents(QEventLoop::AllEvents, 100);,因为这会导致主线程不会冻结,按钮仍然可以点击。

但使用这种方法,每当用户点击第二个瓦片时,如果没有匹配,则图像甚至不会显示,即使在上面的代码之前调用了我的showImage()方法,我也不确定为什么会这样。所以用户知道没有匹配,因为1秒后瓦片会回到初始状态,但他们永远无法在第二个按钮上看到图像。

作为另一种方法,我还考虑禁用所有按钮,然后在单次QTimer超时后,只重新启用尚未匹配的按钮。但这将需要额外的逻辑来跟踪哪些瓦片已经匹配。所以现在我坚持

有更清洁的解决方案吗?也许有办法让QTimer冻结主线程直到超时?

启用/禁用整个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();
}

最新更新