为什么延迟加载的QWidget会显示但是存储的QWidget不显示?

时间:2015-12-15 03:11:10

标签: c++ qt user-interface qwidget

我有一些小弹出窗口小部件的集合,它们出现在不同的地方,但每次只有一个和一个。对于简单的功能,new-to-show和delete-to-hide是可以的,并且可以像它应该的那样工作,但是当他们开始处理他们自己的数据时,我可以看到内存泄漏。

因为我只需要每种类型中的一种,我想我会在父构造函数中预先创建所有这些,并根据需要显示和隐藏它们。据我所知,这应该有效,但popup-> show()并没有显示出来。此示例所基于的复杂应用程序显示弹出窗口确实存在于正确的位置,并且可以与用户交互...除了它不可见。

这是一个显示的懒惰版本:

#ifndef MAIN_H
#define MAIN_H

#include <QtWidgets>

class Popup : public QLabel
{
    Q_OBJECT
public:
    explicit Popup(int x, int y, int width, int height, QWidget* parent = 0);
};

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MainWindow(QWidget* parent = 0);
    ~MainWindow() {}
    void mousePressEvent(QMouseEvent* ev);
private:
    Popup* popup;
};

#endif // MAIN_H

/***************
*** main.cpp ***
***************/
#include "main.h"
#include <QApplication>

int main(int argc, char* argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}



MainWindow::MainWindow(QWidget* parent)
    : QMainWindow(parent)
{
    popup = 0;

    QWidget* cWidget = new QWidget(this);
    cWidget->setStyleSheet("background-color: lightgray");
    setCentralWidget(cWidget);

    showMaximized();
}

void MainWindow::mousePressEvent(QMouseEvent* ev)
{
    if(popup != 0)
    {
        if(!popup->geometry().contains(ev->x(), ev->y()))
        {
            delete popup;
            popup = 0;
        }
    }
    else
    {
        popup = new Popup(ev->x(), ev->y(), 100, 100, this);
        popup->show();
    }
    ev->accept();
}



Popup::Popup(int x, int y, int width, int height, QWidget* parent) :
    QLabel(parent)
{
    setStyleSheet("background-color: black");
    setGeometry(
                x - (width  / 2),   // Left
                y - (height / 2),   // Top
                width ,             // Width
                height              // Height
                );
}

这是预先创建的版本,但不显示:

#ifndef MAIN_H
#define MAIN_H

#include <QtWidgets>

class Popup : public QLabel
{
    Q_OBJECT
public:
    explicit Popup(QWidget* parent = 0);
    void setup(int x, int y, int width, int height);
};

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MainWindow(QWidget* parent = 0);
    ~MainWindow() {}
    void mousePressEvent(QMouseEvent* ev);
private:
    Popup* popup;
};

#endif // MAIN_H

/***************
*** main.cpp ***
***************/
#include "main.h"
#include <QApplication>

int main(int argc, char* argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}



MainWindow::MainWindow(QWidget* parent)
    : QMainWindow(parent)
{
    popup = new Popup(this);

    QWidget* cWidget = new QWidget(this);
    cWidget->setStyleSheet("background-color: lightgray");
    setCentralWidget(cWidget);

    showMaximized();
}

void MainWindow::mousePressEvent(QMouseEvent* ev)
{
    if(popup->isVisible())
    {
        if(!popup->geometry().contains(ev->x(), ev->y()))
        {
            popup->hide();
        }
    }
    else
    {
        popup->setup(ev->x(), ev->y(), 100, 100);
        popup->show();
    }
    ev->accept();
}



Popup::Popup(QWidget* parent) :
    QLabel(parent)
{
    setStyleSheet("background-color: black");
}

void Popup::setup(int x, int y, int width, int height)
{
    setGeometry(
                x - (width  / 2),   // Left
                y - (height / 2),   // Top
                width ,             // Width
                height              // Height
                );
}

我错过了什么?

2 个答案:

答案 0 :(得分:1)

您永远不会在popup小部件中设置窗口标记(例如Qt :: Popup) 它实际上是MainWindow w的子窗口小部件,应该在某处显示。

在Qt中,没有布局的QWidgets简单地堆叠在彼此之上。外观的z顺序取决于实例化的顺序。这就是为什么懒惰的QLabel是可见的而另一个不是。

实际上它可能足以在cWidget之后实例化弹出窗口:

MainWindow::MainWindow(QWidget* parent)
    : QMainWindow(parent)
{
    // popup = new Popup(this); // not here

    QWidget* cWidget = new QWidget(this);
    cWidget->setStyleSheet("background-color: lightgray");
    setCentralWidget(cWidget);

    popup = new Popup(this); // but here (untested, but should work)

    showMaximized();
}

但是要以Qt的方式执行此操作,您应该避免堆叠小部件,而是为您的popup提供真正的弹出式外观​​:

popup->setWindowFlags(Qt::Popup); // this lets popup have its own window

答案 1 :(得分:0)

Martin提到z-order,我还没有与之建立联系,提示更多googling,很快发现了QWidget :: raise()方法。现在它按照我的意图运作。

实例化顺序确实有效,但如果您动态创建更多小部件则不行。弹出窗口仍将显示在动态窗口小部件下。

我确信有一种方法可以使它工作(这个是我与Qt的第一个项目,所以我完全期望在几年之后把它称为“丑陋”,尽管我尽了最大的努力),但是窗口标志打破了弹出窗口和应用程序已经写入的方式之间的耦合。如果我开始使用窗口标志,我可能会让它工作得很好或者甚至更好,但我没有。

以下是我现在正在做的事情,这有效:

#ifndef MAIN_H
#define MAIN_H

#include <QtWidgets>

class Popup : public QLabel
{
    Q_OBJECT
public:
    explicit Popup(QWidget* parent = 0);
    void setup(int x, int y, int width, int height);
};

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MainWindow(QWidget* parent = 0);
    ~MainWindow() {}
    void mousePressEvent(QMouseEvent* ev);
private:
    Popup* popup;
};

#endif // MAIN_H

/***************
*** main.cpp ***
***************/
#include "main.h"
#include <QApplication>

int main(int argc, char* argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}



MainWindow::MainWindow(QWidget* parent)
    : QMainWindow(parent)
{
    popup = new Popup(this);

    QWidget* cWidget = new QWidget(this);
    cWidget->setStyleSheet("background-color: lightgray");
    setCentralWidget(cWidget);

    showMaximized();
}

void MainWindow::mousePressEvent(QMouseEvent* ev)
{
    if(popup->isVisible())
    {
        if(!popup->geometry().contains(ev->x(), ev->y()))
        {
            popup->hide();
        }
    }
    else
    {
        popup->setup(ev->x(), ev->y(), 100, 100);
        popup->raise();     /*** THIS IS WHAT I WAS MISSING!!! ***/
        popup->show();
    }
    ev->accept();
}



Popup::Popup(QWidget* parent) :
    QLabel(parent)
{
    setStyleSheet("background-color: black");
}

void Popup::setup(int x, int y, int width, int height)
{
    setGeometry(
                x - (width  / 2),   // Left
                y - (height / 2),   // Top
                width ,             // Width
                height              // Height
                );
}