我正在尝试使用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冻结主线程直到其超时?
答案 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();
}