Thứ nhất, QWidget
là QObject
và QObject
s là các nút trong một cây QObject
. Các nút con được bộ nhớ quản lý bởi cha mẹ, trừ khi bạn deallocate chúng trước khi cha mẹ có cơ hội để làm như vậy. Vì vậy, quản lý bộ nhớ là một trong những lý do cho các widget, hoặc bất kỳ một số khác của QObject
s, để có một phụ huynh.
Thứ hai, tiện ích con không nhìn thấy được là luôn là cửa sổ cấp cao nhất. Ngược lại, không thể có tiện ích con cấp cao không có cha mẹ. Khi bạn hiển thị một tiện ích không có cha mẹ, nó sẽ có cửa sổ riêng. Điều ngược lại không nhất thiết phải đúng - có thể cung cấp cho tiện ích con một cờ Qt::Window
và nó cũng trở thành một cửa sổ cấp cao nhất.
Hệ quả là bất kỳ tiện ích nào chứa trong các tiện ích khác có cha mẹ - nếu không nó sẽ là cửa sổ cấp cao nhất. Phụ huynh này có thể không được thiết lập rõ ràng bởi bạn, nhưng nó đã được thiết lập.
Tôi nghĩ rằng câu hỏi của bạn có thể được lặp lại như sau: Khi nào tôi cần phải cung cấp một cách rõ ràng cho hàm tạo phụ tùng? Câu trả lời là:
Bất cứ khi nào tiện ích là cửa sổ cấp cao nhất bạn định có cha/mẹ. Các cửa sổ như vậy không chịu sự quản lý bố cục, do đó không có cơ chế để đặt bố mẹ đó cho bạn. Các hộp thoại tạm thời cấp cao nhất cần phải có các bậc cha mẹ để chúng được định vị chính xác liên quan đến cửa sổ chính.
Bất cứ khi nào bạn có tiện ích con không phải quản lý bố cục.
Widgets chịu sự quản lý bố trí được độ gốc khi chèn vào một bố cục:
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();
}
Cuối cùng, không phải tất cả các widget hoặc QObject
s cần phải được tạo ra một cách rõ ràng trên heap. Vì tất cả các lớp học QObject
đã tham gia trong Qt (và nhiều lớp khác nữa!) sử dụng thành ngữ PIMPL, khi bạn phân bổ chúng riêng lẻ trên heap, bạn thực sự đang thực hiện phân bổ đống hai lần. Trước tiên, bạn cấp phát cá thể của lớp - đôi khi cá thể là nhỏ như một con trỏ hoặc hai - và sau đó hàm tạo của lớp phân bổ PIMPL của nó. Phân bổ heap rõ ràng là một trường hợp bi quan sớm.
Để tránh pessimization này, Widget
của bạn sẽ giống như sau:
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);
}
Nếu bạn muốn sử dụng the PIMPL idiom, bạn có thể làm điều đó, quá:
// 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!
Tất nhiên, bạn nên có sử dụng QDialogButtonBox
thay vì tất cả điều này :)
Bạn có nhận thấy rằng 'QWidget' có nguồn gốc từ 'QObject' không? – cmannett85
Vâng, tất nhiên rồi. Nhưng, tôi thực sự không thể hiểu được quan điểm của mối quan hệ cha mẹ này. –