QT QLabel(用作图像容器)全屏错误问题

3

在Ubuntu 13.04下的Qt 4.8.5中,我遇到了以下问题(我对Qt不熟悉)。

我有一个应用程序,具有以下结构:

主窗口
-中央小部件
--垂直布局
---选项卡部件
---使用代码创建并添加到布局中的QLabel
---状态栏

在全屏模式下,我隐藏了TabWidget和StatusBar,然后QLabel停止刷新(我有一个线程来进行刷新)。奇怪的是,当我恢复TabWidget或StatusBar时,它可以正常工作。如果将1x1像素标签添加到垂直布局中,它也可以正常工作。

负责GUI更改的槽函数为:

void Mainview::onToggleFullScreen()
{
    if (this->isFullScreen())
    {
        this->showNormal();
        this->statusbar->show();
        this->tabWidget->show();
    }
    else
    {
        this->showFullScreen();
        this->statusbar->hide();
        this->tabWidget->hide();
    }
}

但是我不明白的是,如果我在图像附近放置一个QLabel,它就可以工作,但是如果我在MainWindow构造函数中添加这一行代码,它就停止刷新:

label_10->hide(); //this is the label

有什么想法是问题出在哪里吗?(提前感谢)

你是如何调用 QLabel::setPixmap 的呢:通过信号/槽连接还是在另一个线程中直接调用? - alexisdm
我使用QPainter进行连续渲染,并使用setPixmap进行单个图像的设置。 - András Kovács
setPixmap函数直接被调用,但整个过程通过事件发生/事件接收信号/槽连接进行通信。 - András Kovács
2
请展示负责GUI变更的代码。 - Pavel Strakhov
1个回答

0

你可能以某种错误的方式进行操作,但是你没有展示代码,那我们怎么知道呢?

下面是一个安全的SSCCE示例,展示了如何正确地进行操作。适用于Qt 4.8和5.1。

小问题:状态栏不应该是centralWidget()的一部分! QMainWindow已经为你提供了一个statusBar()

在线程之间传递图像的唯一安全方法是使用QImage。你不能在GUI线程之外使用QPixmap。就这样结束了。

在下面的示例中,所有重要的事情都发生在幕后。 DrawThing QObject存在于另一个线程中。这个QThread的默认实现run()方法会旋转消息循环。这就是为什么计时器可以触发,因为你需要一个旋转的消息循环。

每次生成新图像时,都会通过隐式地向MainWindow发送消息将其传输到GUI线程。Qt事件循环代码接收该消息并重新合成为插槽调用。这样做是因为连接的两端(DrawThingMainWindow实例)位于不同的线程中。
这就是Qt“少写代码,多创造”的设计方法之美 :) 越多地利用Qt为您所做的事情,您就越不需要担心样板文件。

Screenshot

//main.cpp
#include <QMainWindow>
#include <QVBoxLayout>
#include <QStatusBar>
#include <QLabel>
#include <QThread>
#include <QPainter>
#include <QImage>
#include <QApplication>
#include <QBasicTimer>
#include <QPushButton>

class DrawThing : public QObject {
    Q_OBJECT
    int m_ctr;
    QBasicTimer t;
    void timerEvent(QTimerEvent * ev) {
        if (ev->timerId() != t.timerId()) return;
        QImage img(128, 128, QImage::Format_RGB32);
        QPainter p(&img);
        p.translate(img.size().width()/2, img.size().height()/2);
        p.scale(img.size().width()/2, img.size().height()/2);
        p.eraseRect(-1, -1, 2, 2);
        p.setBrush(Qt::NoBrush);
        p.setPen(QPen(Qt::black, 0.05));
        p.drawEllipse(QPointF(), 0.9, 0.9);
        p.rotate(m_ctr*360/12);
        p.setPen(QPen(Qt::red, 0.1));
        p.drawLine(0, 0, 0, 1);
        m_ctr = (m_ctr + 1) % 12;
        emit newImage(img);
    }
public:
    explicit DrawThing(QObject *parent = 0) : QObject(parent), m_ctr(0) { t.start(1000, this); }
    Q_SIGNAL void newImage(const QImage &);
};

class MainWindow : public QMainWindow {
    Q_OBJECT
    QLabel *m_label;
public:
    explicit MainWindow(QWidget *parent = 0, Qt::WindowFlags flags = 0) : QMainWindow(parent, flags) {
        QWidget * cw = new QWidget;
        QTabWidget * tw = new QTabWidget();
        QVBoxLayout * l = new QVBoxLayout(cw);
        l->addWidget(tw);
        l->addWidget(m_label = new QLabel("Label"));
        setCentralWidget(cw);
        QPushButton * pb = new QPushButton("Toggle Status Bar");
        tw->addTab(pb, "Tab 1");
        connect(pb, SIGNAL(clicked()), SLOT(toggleStatusBar()));
        statusBar()->showMessage("The Status Bar");
    }
    Q_SLOT void setImage(const QImage & img) {
        m_label->setPixmap(QPixmap::fromImage(img));
    }
    Q_SLOT void toggleStatusBar() {
        statusBar()->setHidden(!statusBar()->isHidden());
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QThread t;
    DrawThing thing;
    MainWindow w;
    thing.moveToThread(&t);
    t.start();
    w.connect(&thing, SIGNAL(newImage(QImage)), SLOT(setImage(QImage)));
    w.show();
    t.connect(&a, SIGNAL(aboutToQuit()), SLOT(quit()));
    int rc = a.exec();
    t.wait();
    return rc;
}

#include "main.moc"

代码太大了,无法在此处发布,但我会尝试用最小的代码量重现错误。 - András Kovács
这就是问题所在:一旦开始努力减少代码,就会发现错误。我可以很快地补充说,在每种情况下都是如此。这样可以节省大家的时间,因为不必等待其他人解决问题 :) - Kuba hasn't forgotten Monica
你需要一个C++代码文件,如果使用QML,则需要一个或多个QML文件。就这样。不必担心.h文件或其他任何东西。上面的代码基本上只需要将其放入一个文件夹中,运行qmake -project,然后运行qmakemake即可。再简单不过了! - Kuba hasn't forgotten Monica

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接