Qt的父母是什么?

时间:2015-05-20 15:32:33

标签: qt parent qtwidgets

几乎每个QtWidgets类都可以拥有父级。通常,在对象初始化时设置父级是可选的。例如,如果我创建一个继承Widget::Widget(QWidget* parent): QWidget(parent) { hbox = new QHBoxLayout(this); yes_button = new QPushButton("&Yes"); no_button = new QPushButton("&No", this); cancel_button = new QPushButton("&Cancel", hbox); } 类的类,我将在构造函数上执行以下操作:

cancel_button

我可以设置或不设置父级。我可以将hbox设为cancel_button的孩子。我也可以将yes_button设为QWidget的孩子,但我认为这样做很糟糕。

这是什么意思?并且,是否真的有必要为我创建的每个基于Panel PanelToCover = new Panel(); public Overlay(Panel paneltocover) { PanelToCover = paneltocover; this.StartPosition = FormStartPosition.Manual; this.AutoScaleMode = AutoScaleMode.None; this.Location = paneltocover.PointToScreen(Point.Empty); this.ClientSize = paneltocover.ClientSize; paneltocover.LocationChanged += PanelCover_LocationChanged; paneltocover.ClientSizeChanged += PanelCover_ClientSizeChanged; this.Show(paneltocover); paneltocover.Focus(); } private void PanelCover_LocationChanged(object sender, EventArgs e) { this.Location = PanelToCover.PointToScreen(Point.Empty); } private void PanelCover_ClientSizeChanged(object sender, EventArgs e) { // This works without an issue this.ClientSize = PanelToCover.ClientSize; } 的类设置父级?

2 个答案:

答案 0 :(得分:15)

除了帮助GUI对象中的绘制顺序外,它还有助于内存管理,因此当您销毁QObject时,它的所有子节点也会被销毁。有关详细信息,请参阅http://doc.qt.io/qt-4.8/objecttrees.html。当父母中的某些内容发生变化时(例如调整大小时),它也可以通知其子女自己更新。

要回答你的问题,你不需要为所有东西设置父级(毕竟这就是为什么它是一个可选参数),但大部分时间最好正确设置它。

答案 1 :(得分:8)

首先,QWidgetQObject,而QObjectQObject树中的节点。子节点由父节点进行内存管理,除非您在父节点有机会之前解除分配它们。因此,内存管理是小部件或任何其他QObject s拥有父级的一个原因。

其次,可见的无父小部件总是顶级窗口。相反,使用无父级的非顶级窗口小部件是不可能的。当您显示无父窗口小部件时,它会获取自己的窗口。相反的情况不一定如此 - 可以为子窗口小部件提供一个Qt::Window标记,它也可以成为顶级窗口。

推论是其他小部件中包含的任何小部件父级 - 否则它就是顶级窗口。您可能不会明确设置此父级,但它仍会设置。

我认为您的问题可以改为:我什么时候需要明确地给小部件构造函数一个父级?答案是:

  1. 每当窗口小部件是您打算拥有父窗口的顶级窗口时。这样的窗口不受布局管理的限制,因此没有机制为您设置该父窗口。顶级临时对话框需要父项,以便它们相对于父窗口正确定位。

  2. 每当您的子窗口小部件不受布局管理的影响时。

  3. 在插入布局时,受布局管理影响的小部件是父级的:

    int main(int argc, char ** argv) {
      QApplication app(argc, argv);
      QWidget window;
      QVBoxLayout layout(&window);
      QLabel label("Hello");
      QPushButton button("Goodbye");
      layout.addWidget(&label);
      layout.addWidget(&button);
      QObject::connect(&button, &QPushButton::clicked, [&app]{ app.quit(); });
      window.show();
      return app.exec();
    }
    

    最后,并非所有小部件或QObject都需要在堆上显式创建。由于Qt中的所有QObject派生类(以及许多其他类也是如此!)使用PIMPL习惯用法,当您在堆上单独分配它们时,您实际上正在进行堆分配两次< / em>的。首先分配类的实例 - 有时实例与指针一样小 - 然后类的构造函数分配其PIMPL。显式堆分配是过早悲观化的一种情况。

    为避免这种悲观情绪,您的Widget应如下所示:

    class Widget : public QWidget {
      Q_OBJECT
      QHBoxLayout m_layout;
      QPushButton m_yesButton, m_noButton, m_cancelButton;
    public:
      Widget(QWidget * parent = 0);
    };
    
    Widget::Widget(QWidget * parent) : 
      QWidget(parent),
      m_layout(this),
      m_yesButton("&Yes"),
      m_noButton("&No"),
      m_cancelButton("&Cancel")
    {
      m_layout.addWidget(&m_yesButton);
      m_layout.addWidget(&m_noButton);
      m_layout.addWidget(&m_cancelButton);
    }
    

    如果你想使用the PIMPL idiom,你也可以这样做:

    // Widget.h - Interface
    class WidgetPrivate;
    class Widget : public QWidget {
    {
      Q_OBJECT
      Q_DECLARE_PRIVATE(Widget)
      QScopedPointer<WidgetPrivate> const d_ptr;
    public:
      Widget(QWidget * parent = 0);
      ~Widget();
    };
    
    // Widget.cpp - Implementation 
    class WidgetPrivate {
      Q_DISABLE_COPY(WidgetPrivate)
      Q_DECLARE_PUBLIC(Widget)
      Widget * const q_ptr;
      QHBoxLayout layout;
      QPushButton yesButton, noButton, cancelButton;
    public:
      WidgetPrivate(Widget * q);
    };
    
    WidgetPrivate::WidgetPrivate(Widget * q) {
      q_ptr(q),
      layout(q),
      yesButton("&Yes"),
      noButton("&No"),
      cancelButton("&Cancel")
    {
      layout.addWidget(&yesButton);
      layout.addWidget(&noButton);
      layout.addWidget(&cancelButton);
    }
    
    Widget::Widget(QWidget * parent) :
      QWidget(parent),
      d_ptr(new WidgetPrivate(this))
    {}
    
    Widget::~Widget() {}
    // necessary, since WidgetPrivate is unknown to the interface!
    

    当然,您应该使用QDialogButtonBox而不是所有这些:)