Qt父机制

2024-01-04

有一个QPushButton in a QWidget, click该按钮应该打开另一个QWidget,如下编码:

项目.pro

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = untitled
TEMPLATE = app

CONFIG(debug, debug|release) {
    DESTDIR = debug
} else {
    DESTDIR = release
}

INCLUDEPATH += ..

SOURCES += ../main.cpp\
           ../widget.cpp \
           ../secondwidget.cpp

HEADERS  += ../widget.h \
            ../secondwidget.h

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = 0);
    ~Widget();
};

#endif // WIDGET_H

小部件.cpp

#include "widget.h"

#include <QVBoxLayout>
#include <QPushButton>

#include "secondwidget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    resize(400, 300);
    QVBoxLayout *vLayout = new QVBoxLayout(this);
    QPushButton *bt = new QPushButton("Open 2nd Widget");
    vLayout->addWidget(bt, 1, Qt::AlignRight);

    SecondWidget *secondWidget = new SecondWidget();
//    SecondWidget *secondWidget = new SecondWidget(this);
    connect(bt, &QPushButton::clicked, secondWidget, &SecondWidget::show);
}

Widget::~Widget()
{

}

第二个小部件.h

#ifndef SECONDWIDGET_H
#define SECONDWIDGET_H

#include <QWidget>

class SecondWidget : public QWidget
{
    Q_OBJECT
public:
    explicit SecondWidget(QWidget *parent = 0);

signals:

public slots:
};

#endif // SECONDWIDGET_H

第二个小部件.cpp

#include "secondwidget.h"

SecondWidget::SecondWidget(QWidget *parent) : QWidget(parent)
{
    setAttribute( Qt::WA_QuitOnClose, false );
}

Passing this为了SecondWidget构造函数(如注释行中所示)会在某些时候打破我的逻辑。所以SecondWidget单击按钮后不再显示。

这是怎么回事?


除了析构函数和构造函数的问题(以及由于第二个而导致的内存泄漏)以及这里的项目文件之外,您可能还需要了解一些内容,以便了解整个父级情况:

你不需要通过this。分配父级的目的是能够简化清理过程QObject实例(包括所有继承自QObject班级)。 Qt 父子模型遵循 C++ 标准,即析构函数以相反的顺序调用构造函数。简单来说,这意味着以下内容:

想象你创造小部件 A、B 和 C。使用您分配的父属性B and C成为...的孩子A。所以这里我们有创建的顺序:

  1. 家长)
  2. B、C(儿童)

现在在某个时候您想要销毁您的小部件(例如:关闭应用程序)。标准 C++ 方法是按以下顺序(与构造相反)销毁它们:

  1. B、C(儿童)
  2. 家长)

如果我们首先寻找父母,这确实会发生。然而,我们在这里处理的是 Qt,因此我们必须考虑该库提供的一项附加功能 - 槽和信号。

每当一个QObject被摧毁时会发出信号。根据对象在父子关系中扮演的角色,结果是以下之一:

  • 只有QObject被摧毁的被摧毁- 这就是当我们销毁其父级之前子级被销毁时会发生的情况
  • 那个的所有孩子 QObject 首先被摧毁,然后是被摧毁 QObject itself- 这就是当父母被摧毁时会发生的情况。发出的信号会被所有子级捕获,而这些子级也会被消除。

然而指定父母并不是强制性的。您可以自己手动进行清理。阅读有关亲子模型的更多信息Qt 文档 http://doc.qt.io/qt-4.8/objecttrees.html.

除此之外,所有权转移(一个小部件成为另一个小部件的子部件)通常会自动发生,因此无需显式指定小部件的父部件。再次把东西从Qt 文档 http://doc.qt.io/qt-4.8/layout.html#tips-for-using-layouts这里有一个例外。如果将小部件添加到布局中,所有权不会转移到布局本身,而是转移到QWidget它是的一部分。

最后,还有一个重要的情况,如果不指定父级,事情就会变得非常非常不同。这里我要引用Qt 文档 http://doc.qt.io/qt-4.8/qobject.html#QObject on QObject:

将parent 设置为0 将构造一个没有父对象的对象。如果该对象是一个小部件,它将成为一个顶级窗口。

所以如果你有一个QWidget并且不要将其添加到某些布局中(以及间接添加到QWidget具有该布局)例如它将自动成为一个单独的窗口。


EDIT:检查你的构造函数,特别是你使用你的构造函数的方式secondWidget目的。正如我上面提到的,如果您不想将其分配给父小部件you需要注意清洁。

您为其动态分配内存

    SecondWidget *secondWidget = new SecondWidget();

甚至将它连接到您的按钮

    connect(bt, &QPushButton::clicked, secondWidget, &SecondWidget::show);

但是你永远不会使用释放分配的内存delete或者将其分配给父小部件,父小部件将自动处理它。因此你会造成内存泄漏。连接一个QObject通过信号和槽与所有权转移没有任何关系。

我个人认为你实际上想要一个secondWidget成为屏幕上显示的额外窗口。在这种情况下,您需要创建一个类型的类成员SecondWidget

SecondWidget *secondWidget;

然后在你的构造函数中分配它并连接你想要的任何插槽和信号

Widget::Widget(QWidget *parent) : QWidget(parent)
{
  //...
  secondWidget = new SecondWidget();
  connect(bt, &QPushButton::clicked, secondWidget, &SecondWidget::show);
}

最后释放构造函数中的内存:

Widget::~Widget()
{
  delete secondWidget;
}

否则,正如我所说,您基本上是在创建对内存块的引用,并且在您离开构造函数之后,该引用就会被销毁,因为它超出了范围。


EDIT 2:

这是一个小例子,如果您愿意,如何做到这一点secondWidget作为主小部件的子项:

main.cpp

#include "widget.h"
#include <QApplication>

int main(int argc, char *argv[])
{
  QApplication a(argc, argv);
  Widget w;
  w.show();

  return a.exec();
}

小部件.hpp

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include "secondwidget.h"

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
  Q_OBJECT

public:
  explicit Widget(QWidget *parent = 0);
  ~Widget();

private:
  Ui::Widget *ui;
};

#endif // WIDGET_H

小部件.cpp

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent) :
  QWidget(parent),
  ui(new Ui::Widget)
{
  ui->setupUi(this);
  SecondWidget *secondWidget = new SecondWidget(this); # secondWidget is now officially adopted by Widget
  # If you skip the parent assignment inside SecondWidget you can call secondWidget->setParent(this) here
  connect(ui->pushButton, SIGNAL(clicked(bool)), secondWidget, SLOT(show()));
}

Widget::~Widget()
{
  delete ui;
}

第二个小部件.hpp

#ifndef SECONDWIDGET_H
#define SECONDWIDGET_H

#include <QObject>
#include <QDialog>

class SecondWidget : public QDialog
{
  Q_OBJECT
public:
  explicit SecondWidget(QWidget *parent = 0);
  ~SecondWidget();
};

#endif // SECONDWIDGET_H

第二个小部件.cpp

#include "secondwidget.h"
#include <QFormLayout>
#include <QLabel>

SecondWidget::SecondWidget(QWidget *parent) : QDialog(parent)
{
  # If you don't call the constructor of your superclass you can still assign a parent by invoking setParent(parent) here
  QFormLayout *layout = new QFormLayout();
  QLabel *label = new QLabel("SecondWidget here");
  layout->addWidget(label); # Transfer ownership of label to SecondWidget
  setLayout(layout);
}

SecondWidget::~SecondWidget()
{

}

请注意setParent(parent)在 - 的里面SecondWidget的构造函数。您要么必须调用超类构造函数(就像您所做的那样),要么手动调用setParent(parent). If you don't do that your第二个小部件will not be assigned as a child to your main widget where you create it and thus you will produce a memory leak. You can also invoke在主窗口小部件的构造函数中使用 secondaryWidget->setParent(this)` 来设置父窗口。

以下是检查父子层次结构是否正常的方法:

  • To each QObject你有(QWidget, QLayout等等都是以下的子类QObject)使用分配对象名称QObject::setObjectName("some name")

  • 在两个构造函数的末尾添加:

    for(int i = 0; i < this->children().count(); i++)
      std::cout << this->children()[i]->objectName().toStdString() << std::endl; // Add #include <iostream> to get the output
    

    基本上遍历了所有的孩子this (Widget or SecondWidget)并显示其子项。就我而言,我得到了

        label              // Printing out children of SecondWidget
        formLayout         // Printing out children of SecondWidget
        gridLayout         // Printing out children of Widget
        pushButton         // Printing out children of Widget
        main second widget // Printing out children of Widget
    

一旦我启动了我的应用程序。

EDIT 3:啊,我没注意到你正在打电话QWidget(parent) in you SecondWidget构造函数。这也可以解决问题,所以你不需要setParent(parent)。我改变了我的第二次编辑。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Qt父机制 的相关文章

  • OpenCV 旋转图像而不裁剪澄清

    我想扩展这个主题 参考用户 Lars Schillingmann 给出的这个 SO 问题和接受的答案 在 C 中的 OpenCV 中旋转图像而不裁剪 https stackoverflow com questions 22041699 ro
  • "/>

    Error 5 expected Css test css gt gt 我需要给吗 在这里 因为我的解决方案仍然无法正常工作 它开始给出一些其他错误 您需要添加一个等号 如下所示 Css test css gt gt 解释 块将整个语句或块
  • CMake source_group() 无法在分层项目设置中正常工作

    在进行更改以使 CMake 项目具有分层文件夹管理后 source group 似乎不再正常工作 CMake 只是将所有内容转储到默认过滤器中 我尝试了各种正则表达式来从父级获取每个源文件的相对文件路径 甚至对父级 CMakeLists t
  • 使用MVVM Light的Messenger在视图模型之间传递值

    有人可以帮我解释一下 MVVM Light 的 Messenger 吗 我正在阅读 StackOverflow 上的一篇文章 MVVM 在视图模型之间传递值 https stackoverflow com questions 6392854
  • 使用 Protobuf-net 序列化 object[]

    我想序列化和反序列化存储在对象数组中的一些值 public class Sample public object Data 我知道在运行时数组中期望什么类型 实际上 我想将 Sample 内部的数据视为消息流 就个人而言 我知道我可以使用S
  • 如何存储指向将 Callable 对象作为其参数之一的函数模板的指针

    考虑以下示例 template
  • iTextSharp 从一页模板高效批量生成 PDF

    我正在使用 ITextSharp 生成多页 PDF 每个页面都有相同的模板 问题是 PDF 的物理大小会随着模板的大小而增长 I HAVE to use 阿克罗菲尔德 我怎么能够reduce最终文件大小 这是 pdf 处理程序的代码片段 p
  • Qt:不完整类型和前向声明的使用无效

    我有一些误解 A h ifndef A H define A H include B h class A public B Q OBJECT public A endif A cpp include A h A A B ui gt blan
  • 显示与 C# 生成的表单相邻的另一种表单

    如何产生一种新形式 例如Form2 from Form1 但要确保Form2毗邻于Form1 例如 就像是 button click handler method Form2 child new Form2 child Location n
  • 给定 X 在三次贝塞尔曲线上求 Y?

    我需要一种方法 允许我在给定 x 坐标的情况下找到三次贝塞尔曲线上的 Y 坐标 我遇到过很多地方告诉我将其视为三次函数 然后尝试找到根 我理解这一点 然而 三次贝塞尔曲线的方程是 对于 x 坐标 X t 1 t 3 X0 3 1 t 2 t
  • PyQt4 QPalette 不工作

    btn QtGui QPushButton Button self palettes btn palette palettes setColor btn backgroundRole QtCore Qt green btn setPalet
  • 将渲染后效果应用于 XNA 中的 SpriteBatch

    在 XNA 框架中 有没有一种方法可以使用典型的 SpriteBatch 方法渲染 2D 场景 然后在渲染该帧后将效果应用于整个图像 例如 模糊 棕褐色甚至使整个事情看起来像旧电影胶片 带有颗粒 灰尘 线条等 是的 您要做的就是将渲染目标设
  • extern "C" 默认参数是否有效?

    From Here https stackoverflow com questions 1472138 c default argumentsC 似乎不支持默认参数 我在导出的库中有以下方法 extern C declspec dllexp
  • 在 C# 中创建我的对称密钥

    一直在审查一些对称加密方法 我看到了很多在类中硬编码私有静态变量的示例 通常类似于 string key THISISYOURENCRYPTIONKEY 然后在更远的地方 代码使用它来加密 解密 抛开正确的实现 算法 策略以及存储它的位置
  • static_assert 有什么作用,你会用它做什么?

    你能举个例子吗static assert C 11 会优雅地解决手头的问题吗 我熟悉运行时assert 我应该选择什么时候static assert 超过常规assert 另外 在boost有一种东西叫做BOOST STATIC ASSER
  • 如何在 IDictionary 中存储多个项目?

    我有这个IDictionary宣言 IDictionary
  • 我可以以编程方式更改 Xamarin.Forms 中的 styles.xml 吗?

    我们有一个可自定义颜色的应用程序 这使得列表视图中所选项目的橙色 Android 默认值有时看起来很糟糕 我们想要更改列表视图所选项目的颜色 我知道如何在我们页面的后台代码 xaml cs 中执行此操作 并且我知道您可以在 styles x
  • 为什么我们从 MultiByte 转换为 WideChar?

    我习惯于处理 ASCII 字符串 但现在使用 UNICODE 我对一些术语感到非常困惑 什么是多字节字符以及什么是widechar有什么不同 多字节是指在内存中包含多个字节的字符吗 widechar只是一个数据类型来表示吗 为什么我们要从M
  • C# 4.0 动态对象和 WinAPI 接口,如 IShellItem(无需在 C# 源代码中定义它们)

    是否可以 使用 C 4 0 中的新动态关键字 使用接口 如 IShellItem 或其他 WinAPI 接口 而无需在 C 源代码中定义它们 或者至少不定义接口成员 我正在尝试类似的事情 const string IShellItemGui
  • 查找文本中所有关键字的有效算法

    我有很多字符串 其中包含许多不同拼写的文本 我通过搜索关键字来标记这些字符串 如果找到关键字 我将使用该关键字的关联文本 假设搜索字符串可以包含文本 schw schwa 和 施瓦茨 我有三个关键字 全部解析为文本 schwarz 现在我正

随机推荐

  • 无法在 Windows 10 上构建 Docker 映像

    Windows 10 专业版 1909泊坞窗 2 2 0 4 43472 Dockerfile 的开头是这样的 FROM debian stable 20191118 这是唯一有效的部分 或任何其他类似的Linux ubuntu 18 04
  • Javascript 中带有多个括号的闭包

    任何人都可以解释一下 当传递更多的括号参数时 该函数如何发出警报 我无法清楚地理解它 function sum a var sum a function f b sum b return f f toString function retu
  • ASP.NET 4.5 异步等待和 Response.Redirect

    有什么办法可以重定向Page Load 或任何其他 ASP NET 事件 使用时async await 当然Redirect throws ThreadAbortException但即使我抓住它try catch它最终会出现一个错误页面 如
  • Hadoop - 全局排序平均值以及 MapReduce 中何时发生

    我在用Hadoop 流 JAR for 字数 我想知道我怎样才能得到全局排序 根据SO中另一个问题的回答 我发现当我们使用只需一台减速机我们可以得到全局排序 但在我的结果中numReduceTasks 1 一个减速器 它不是排序的 例如 我
  • 核心数据关系可以有属性吗

    我正在将 MySQL 数据库移植到 Mac OS 应用程序的 Core Data 我的数据库中有两个多对多表 除了包含外键之外 还有一些数据列 是否可以向核心数据中的多对多关系添加属性 对我来说看起来不像 我的后备方法是复制核心数据中的链接
  • 选择每组中具有最大值的行

    在每个主题都有多个观察值的数据集中 对于每个主题 我想选择具有最大值 pt 的行 例如 使用以下数据集 ID lt c 1 1 1 2 2 2 2 3 3 Value lt c 2 3 5 2 5 8 17 3 5 Event lt c 1
  • 当变量调用别名时如何调用别名

    我添加了一个别名 alias anyalias echo kallel 如果我执行 anyalias kallel 它执行echo命令没有任何问题 现在 如果我以这种方式定义一个变量 var anyalias 然后用这样的方式执行 var
  • 是否有更简单的方法使用 ActiveAdmin 创建/选择相关数据?

    假设我有以下模型 class Translation lt ActiveRecord Base has many localizations end class Localization lt ActiveRecord Base belon
  • 访问 Linkedin 私人可播放流的权限 - 500 或 403 错误

    我在使用 Linked In API V2 时遇到了下一个问题 curl X GET header Accet application json header Authorization Bearer
  • 获取iframe的内容

    我正在尝试获取的内容从另一页 另一个页面是另一个网站 我登录了该网站 获取其内容并将其存储在 我如何获取其中的内容进入当前窗口 简短的回答 你做不到 浏览器使用以下限制限制来自不同网站的内容之间的交互同源政策 http en wikiped
  • 如何在flutter中为image.asset添加onClick?

    我在单击时使用了三个图像 这些图像将导航到其他页面 那么我应该如何在这些图像上使用 onClick 我的代码如下 Row children Expanded child Column children
  • 将 spin.js 微调器插入 div 中?

    刚刚发现 spin js 它似乎是一个救星 问题是如何将微调器插入到我的 div 中 我有一个关注按钮 单击该按钮时 我会删除背景图像并当前替换为 loader gif 我怎样才能用 spin js 做同样的事情 我举了一个 jsfiddl
  • ::-ms-thumb 出现在 MS Edge 中的轨道后面

    我创建了一个滑块 In chrome everything is working fine See image below But in MS Edge thumb appears behind track See image below
  • 无法销毁 codeigniter 中的会话

    我想要实现的是一个简单的登录页面 如果用户登录成功 则重定向到主页 否则保留登录页面 我有 1 个名为login 和 1 个型号名为main 当用户单击登录按钮时 将调用login login send
  • 从大字典中替换 DataFrame 中的值的更好方法

    我编写了一些代码 使用字典将 DataFrame 中的值替换为另一个帧中的值 并且它正在工作 但我在一些大文件上使用它 其中字典可能会变得很长 几千双 当我使用这段代码时 它运行速度非常慢 而且在某些地方还出现了内存不足的情况 我有些确信我
  • Box2D 中的 ChainShape

    最近开始学习libgdx 遇到Box2D的CainShape的问题 我的第一个目标是简单地创建一个带有 ChainShape 的盒子 为了实现这一点 我将四个 Vector2 添加到一个数组中 并使用它们创建一个循环 结果取决于数组中的排列
  • Nunit 运行每个测试两次

    我通过 NUnit 运行测试时遇到问题 我不知道为什么 但每个测试运行两次 问题是 在另一台笔记本电脑上 它通常只运行一次 有没有人遇到同样的问题并且知道如何处理 我有同样的问题 就我而言 我同时拥有Visual Studio 扩展 htt
  • 使用 markdown 时如何正确地将多行 xml 片段粘贴到 github wiki

    我正在尝试为我的项目创建一个 github wiki 但我无法将 Spring beans xml 文件中的片段格式化到此 wiki 中 正确的做法是什么 我尝试使用pre tag code但要么它根本不显示 要么它在同一行中显示所有内容
  • 在 Laravel 5 中间件中获取 cookie

    我正在尝试从 Laravel 5 3 中的中间件检索 cookie 但 request gt cookie language 似乎是空的 我猜它只是在中间件运行后设置的 我在某处读到我应该使用 Cookie queued language
  • Qt父机制

    有一个QPushButton in a QWidget click该按钮应该打开另一个QWidget 如下编码 项目 pro QT core gui greaterThan QT MAJOR VERSION 4 QT widgets TAR