2

我在扫雷游戏中使用QPushButton

从简单模式更改为困难模式后,QPushButton的数量应该从 9x9 更改为 30x16。

因此,我在MainWindow的构造函数中将具有最大数字(硬模式)的QPushButton添加到GridLayout

btnArr = new QPushButton[HARD_WIDTH * HARD_HEIGHT]; // member element
int index = 0;
for (int i = 0; i < HARD_HEIGHT; ++i) {
    for (int j = 0; j < HARD_WIDTH; ++j) {
        ui->mainGrid->addWidget(&btnArr[index], i, j, 1, 1,
                                Qt::AlignCenter);
        ++index;
    }
}

然后如果用户改变模式(例如:简单模式到困难模式),resetBtn(HARD_WIDTH, HARD_HEIGHT);将被调用。

void MainWindow::resetBtn(const int width, const int height)
{
    int index = 0;
    for (int i = 0; i < HARD_HEIGHT; ++i) {
        for (int j = 0; j < HARD_WIDTH; ++j) {
            if (j < width && i < height) {
                btnArr[index].setVisible(true);
            } else {
                btnArr[index].setVisible(false);
            }
            ++index;
        }
    }
}

问题是似乎每次setVisible调用小部件都会重新绘制。所以在困难模式的情况下,它会被调用 30x16 次,这会产生如下奇怪的效果: 在此处输入图像描述

那么如何在此循环期间设置小部件不重绘?

提前致谢。

4

5 回答 5

2

我认为您正在尝试解决错误的问题。您不应该像这样更新小部件。如果您必须这样做,那么在更改之前隐藏布局的父小部件并在之后再次显示它应该可以工作。

更好的方法是使用QStackedWidget并首先准备好所有电路板。然后,切换到不同的板只是切换活动小部件的问题。

于 2012-06-02T07:09:42.650 回答
1

您可以在进行这些“大规模”更改之前尝试调用setUpdatesEnabled(false)父小部件,并在所有操作完成后重新启用它。

于 2012-05-22T05:48:59.620 回答
1

也许我错了,但据我所知,Qt 不会在调用 setVisible() 后立即呈现小部件。渲染是“渲染”事件的结果,除非您手动调用 render()。

来自官方 Qt 文档(http://qt-project.org/doc/qt-4.8/qwidget.html#paintEvent):

Qt 还试图通过将多个绘制事件合并为一个来加速绘制。当 update() 被多次调用或窗口系统发送多个绘制事件时,Qt 将这些事件合并为一个具有更大区域的事件(参见 QRegion::united())。repaint() 函数不允许这种优化,因此我们建议尽可能使用 update()。

我的直觉告诉我,这不是绘画问题,而是布局问题(没有足够的空间以“硬模式”显示每个按钮)。此外,我认为在将按钮添加到布局时不应使用 Qt::AlignCenter,它会尝试将布局中的每个按钮居中。您应该将布局的父小部件居中(如果您没有创建一个并将其居中)并正确设置大小策略(QWidget setSizePolicy)。

但是正如@Mat 建议的那样,如果这真的是一个绘画问题,您可以使用 setUpdatesEnabled(false/true) (如果 setUpdatesEnabled 解决了您的问题,请接受@Mat 的解决方案)

于 2012-05-23T10:12:44.483 回答
1

总数QPushButton真的很大:30x16 = 480!!!我不习惯让人们改变他们的编程逻辑,但在这种情况下,我认为使用QPushButtons 并不是更好的方法。布局在添加对象时尝试移动对象的时间肯定很糟糕,并且您可能在刷新时间方面达到了一些内部限制,以便重新绘制布局。

我会做的是一个带有自定义paintEvent方法的自定义小部件。在那里,您可以将其宽度和高度划分为您希望的列数和行数,并在玩游戏时用像素图绘制单元格。

对于鼠标交互,最好的方法是mousePressEvent使用自定义逻辑来覆盖 ,该逻辑计算鼠标在网格中的位置并调用相应的方法或发出指示事件位置的信号。不是很难编码。您还可以使用该event->buttons()方法了解按下了哪个鼠标按钮,并根据需要发出不同的信号。

我不习惯回答说最好改变你的整个程序,但在这种情况下,我认为你正在走“艰难的道路”。我知道这不是您正在寻找的答案,但请考虑这种可能性。

于 2012-06-06T05:20:27.637 回答
0

尝试启用/禁用而不是可见/不可见:

void MainWindow::resetBtn(const int width, const int height)
{
    int index = 0;
    for (int i = 0; i < HARD_HEIGHT; i++)
        for (int j = 0; j < HARD_WIDTH; j++)
            btnArr[index++].setEnabled(j < width && i < height);
}
于 2012-06-02T08:22:19.907 回答