✿3
所有的小部件(widgets)都继承自QObject。QWidget是所有UI wdigets的父类,它包含绝大多数去描述一个小部件的属性,如geometry、color、mouse、keyboard、tooltips。
所有继承自QObject的对象都有一个父子关系,这种关系让开发者更便利,如:
- 当一个部件销毁时,所有它的子类都会被销毁。这避免了内存泄露。
- 你可以查找一个给定的QWidget类,通过findChild()和findChildren。
- 在一个QWidget里的子部件自动地包含于它的父部件里。
QObject
QObject是Qt对象模型的心脏。该模型的核心功能是一种非常强大的无缝对象通信机制,称为信号和插槽(signals and slots)。可以使用connect()将信号连接到插槽,并使用disconnect()销毁连接。为了避免永无止境的通知循环,你可以使用blockSignals()临时阻止信号。受保护的函数connectNotify()和disconnectNotify()使跟踪连接成为可能。
QoObject在对象树中组织自己。当你以另一个对象作为父对象创建QObject时,该对象将自动将自己添加到父对象的children()列表中。父对象拥有该对象的所有权;例如,它将在析构函数中自动删除其子级。可以按名称查找对象,也可以选择使用findChild()或findChildren()。
template <typename T> T
QObject::findChild(const QString &name = QString(), Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
下面示例返回名为“button1”的parentWidget的子QPushButton,即使该按钮不是父对象的直接子对象:
QPushButton *button = parentWidget->findChild<QPushButton *>("button1");
下面示例返回parentWidget的QListWidget子级:
QListWidget *list = parentWidget->findChild<QListWidget *>();
下面示例返回名为“button1”的parentWidget(其直接父对象)的子QPushButton:
QPushButton *button = parentWidget->findChild<QPushButton *>("button1", Qt::FindDirectChildrenOnly);
下面示例返回parentWidget的QListWidget子级,即其直接父级:
QListWidget *list = parentWidget->findChild<QListWidget *>(QString(), Qt::FindDirectChildrenOnly);
每个对象都有一个objectName(),其类名可以通过相应的metaObject()找到(参见QMetaObject::className())。可以使用inherits()函数确定对象的类是否继承QObject继承层次结构中的另一个类。
QObject *obj = new QPushButton;
obj->metaObject()->className(); // returns "QPushButton"QPushButton::staticMetaObject.className(); // returns "QPushButton"
QTimer *timer = new QTimer; // QTimer inherits QObject
timer->inherits("QTimer"); // returns true
timer->inherits("QObject"); // returns true
timer->inherits("QAbstractButton"); // returns false// QVBoxLayout inherits QObject and QLayoutItem
QVBoxLayout *layout = new QVBoxLayout;
layout->inherits("QObject"); // returns true
layout->inherits("QLayoutItem"); // returns true (even though QLayoutItem is not a QObject)
当一个对象被删除,它会触发destroyed()信号。你可以捕捉这个信号,以避免挂起对QoObject的引用。
QObjects可以接收通过event()并过滤其他对象的事件。可以重新实现方便的处理程序childEvent(),以捕获子事件。
bool QObject::event(QEvent *e)
此虚函数接收对象的事件,如果识别并处理了事件e,则应返回true。
可以重新实现event()函数来自定义对象的行为。
请确保为所有未处理的事件调用父事件类实现。
class MyClass : public QWidget {
Q_OBJECT
public:MyClass(QWidget *parent = nullptr);~MyClass();bool event(QEvent* ev) override {if (ev->type() == QEvent::PolishRequest) {// overwrite handling of PolishRequest if anydoThings();return true;} else if (ev->type() == QEvent::Show) {// complement handling of Show if anydoThings2();QWidget::event(ev);return true;}// Make sure the rest of events are handledreturn QWidget::event(ev);}
};
最后但并非最不重要的一点是,QObject在Qt中提供了基本的计时器支持。
QTimer *timer = new QTimer(this);connect(timer, &QTimer::timeout, this, QOverload<>::of(&AnalogClock::update));timer->start(1000);// one second (1000 millisecond)
请注意,对于任何实现信号、插槽或属性的对象,Q_OBJECT宏都是必需的。你还需要在源文件上运行元对象编译器。我们强烈建议在QObject的所有子类中使用此宏,无论它们是否实际使用信号、插槽和属性,因为如果不这样做,可能会导致某些函数表现出奇怪的行为。
所有Qt widgets都继承自QObject。便利函数isWidgetType()返回一个对象是否实际上是一个小部件,它比qobject_cast<QWidget *>(obj)或obj->inherits(“QWidget”)更快速。
一些OObject函数,如children()返回一个QObjectList。QObjectList是一个QList<QObject*>的类型定义。
使用QLabel展示一个简单的文本:
#include <QApplication>
#include <QLabel>
int main(int argc, char* argv[]) {QApplication app(argc, argv);QLabel myLabel;myLabel.setText("Hello World");myLabel.show();return app.exec();
}
要记得将下面语句添加到.pro文件中,以便启用Qt Widgets模块:
QT += widgets
一旦你更改了.pro文件,你需要运行qmake!
你可以通过C++代码动态地添加一个垂直布局:
QWidget *widget = new QWidget;
QPushButton *pushBtn1 = new QPushButton("Push Button 1");
QPushButton *pushBtn2 = new QPushButton("Push Button 2");
QPushButton *pushBtn3 = new QPushButton("Push Button 3");
QPushButton *pushBtn4 = new QPushButton("Push Button 4");
QVBoxLayout *verticalLayout = new QVBoxLayout(widget);
verticalLayout->addWidget(pushBtn1);
verticalLayout->addWidget(pushBtn2);
verticalLayout->addWidget(pushBtn3);
verticalLayout->addWidget(pushBtn4);
widget->show ();
记住,QWidget实例将会成为应用程序的主窗口。上例中布局被设置为主布局顶层。如果你在构造函数中没有设置父窗口,你得使用QWidget::setLayout()在之后安装布局并重新设置小部件实例的父窗口。
Tools->C+±>Inspect C++ Code Model…->Working Copy
ui_mainwindow.h
#include <QtCore/QVariant>
#include <QtWidgets/QAction>
#include <QtWidgets/QApplication>
#include <QtWidgets/QButtonGroup>
#include <QtWidgets/QHeaderView>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QMenuBar>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QStatusBar>
#include <QtWidgets/QToolBar>
#include <QtWidgets/QVBoxLayout>
#include <QtWidgets/QWidget>QT_BEGIN_NAMESPACEclass Ui_MainWindow {
public:QWidget *centralWidget;QWidget *widget;QVBoxLayout *verticalLayout;QPushButton *pushButton;QPushButton *pushButton_2;QPushButton *pushButton_3;QPushButton *pushButton_4;QMenuBar *menuBar;QToolBar *mainToolBar;QStatusBar *statusBar;void setupUi(QMainWindow *MainWindow) {if (MainWindow->objectName().isEmpty())MainWindow->setObjectName(QStringLiteral("MainWindow"));MainWindow->resize(400, 300);centralWidget = new QWidget(MainWindow);centralWidget->setObjectName(QStringLiteral("centralWidget"));widget = new QWidget(centralWidget);widget->setObjectName(QStringLiteral("widget"));widget->setGeometry(QRect(130, 50, 82, 74));verticalLayout = new QVBoxLayout(widget);verticalLayout->setSpacing(6);verticalLayout->setContentsMargins(11, 11, 11, 11);verticalLayout->setObjectName(QStringLiteral("verticalLayout"));verticalLayout->setContentsMargins(0, 0, 0, 0);pushButton = new QPushButton(widget);pushButton->setObjectName(QStringLiteral("pushButton"));pushButton->setCheckable(false);verticalLayout->addWidget(pushButton);pushButton_2 = new QPushButton(widget);pushButton_2->setObjectName(QStringLiteral("pushButton_2"));verticalLayout->addWidget(pushButton_2);pushButton_3 = new QPushButton(widget);pushButton_3->setObjectName(QStringLiteral("pushButton_3"));verticalLayout->addWidget(pushButton_3);pushButton_4 = new QPushButton(widget);pushButton_4->setObjectName(QStringLiteral("pushButton_4"));verticalLayout->addWidget(pushButton_4);MainWindow->setCentralWidget(centralWidget);menuBar = new QMenuBar(MainWindow);menuBar->setObjectName(QStringLiteral("menuBar"));menuBar->setGeometry(QRect(0, 0, 400, 17));MainWindow->setMenuBar(menuBar);mainToolBar = new QToolBar(MainWindow);mainToolBar->setObjectName(QStringLiteral("mainToolBar"));MainWindow->addToolBar(Qt::TopToolBarArea, mainToolBar);statusBar = new QStatusBar(MainWindow);statusBar->setObjectName(QStringLiteral("statusBar"));MainWindow->setStatusBar(statusBar);retranslateUi(MainWindow);QMetaObject::connectSlotsByName(MainWindow);} // setupUivoid retranslateUi(QMainWindow *MainWindow) {MainWindow->setWindowTitle(QApplication::translate("MainWindow", "MainWindow", Q_NULLPTR));pushButton->setText(QApplication::translate("MainWindow", "PushButton1", Q_NULLPTR));pushButton_2->setText(QApplication::translate("MainWindow", "PushButton2", Q_NULLPTR));pushButton_3->setText(QApplication::translate("MainWindow", "PushButton3", Q_NULLPTR));pushButton_4->setText(QApplication::translate("MainWindow", "PushButton4", Q_NULLPTR));} // retranslateUi
};namespace Ui {class MainWindow: public Ui_MainWindow {};
} // namespace UiQT_END_NAMESPACE
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui { class MainWindow; }class MainWindow: public QMainWindow {Q_OBJECT
public:explicit MainWindow(QWidget *parent = 0);~MainWindow();
private:Ui::MainWindow *ui;
};
#endif
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui->setupUi(this);
}MainWindow::~MainWindow() {delete ui;
}
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[]) {QApplication a(argc, argv);MainWindow w;w.show();return a.exec();
}
创建自定义小部件
我们修改mylabel.h,添加头文件#include,在类声明前添加一个宏QDESIGNER_WIDGET_EXPORT,这样可确保类会正确的导出到DDL(dynamic-link library)或共享库。你的自定义小部件可能在没有这个宏时可以正常的工作,但添加这个宏是一个好的实践。
你得更新myframe.h和mylabel.h头文件如下,以避免depressed warning:
#include <QtUiPlugin/QDesignerCustomWidgetInterface>
在mylabelplugin.h中,实现group()函数:
QString MyFramePlugin::group() const {return QLatin1String("My Containers");
}
为了创建一个自定义geometry或其他属性的小部件,你可以实现domXml()函数:
QString MyLabelPlugin::domXml() const {return QLatin1String("<widget class='MyLabel' name='myLabel'>\n""<property name='geometry'>\n""<rect>\n""<x>0</x>\n""<y>0</y>\n""<width>100</width>\n""<height>16</height>\n""</rect>\n""</property>\n""<property name='text'>\n""<string>MyLabel</string>\n""</property>\n""</widget>\n");
}
在Release模式下,Build。然后,可以手动将新生成的文件夹里的release目录下的mywidgetcollectionplugin.dll复制到D:\Qt\Qt5.9.0\5.9\mingw53_32\plugins\designer路径下。这个路径及文件扩展名依不同操作系统而异。如果不做这样的拷贝操作,就无法在designer.exe窗口看到我们自定义的插件。
在D:\Qt\Qt5.9.0\5.9\mingw53_32\bin目录下,双击designer.exe。
单击“创建”按钮,将MyLabel拖到MyFrame里面。
创建Qt样式表和自定义主题
Qt Style Sheet语法和HTML/CSS语法是一致的。
QPushButton { background-color: rgb(193, 255, 216); border-width: 2px; border-radius: 6; border-color: lime; border-style: solid; padding: 2px; min-height: 2.5ex; min-width: 10ex;
}
QPushButton:hover { background-color: rgb(170, 255, 127);
}
QPushButton:pressed { background-color: rgb(170, 255, 127); font: bold;
}
在前面的示例中,只有按钮将获得样式表中描述的样式,而所有其他小部件将具有本机样式。还可以为每个按钮创建不同的样式,并通过在样式表中提及按钮的对象名称,将样式应用于各个按钮:QPushButton#pushButtonID
CSS选择符主要有3种:HTML选择符、class选择符 和 id选择符。
1.HTML选择符:以HTML标签作为选择符。如:h1 {text-align: center; color: blue}<h1>一级标题居中蓝色</h1>
2.class选择符:使用HTML标签的class属性值作为选择符。定义class选择符时,前面要加“.”标志。如:
.title {text-align: center; color: blue}<p class="title">蓝色的段落</p> <h1 class="title">蓝色的标题</h1>
3.id选择符:使用HTML标签的id属性值作为选择符。定义id选择符时,前面要加“#”标志。如:
#red {color:red;} #green {color:green;}<p id="red">这个段落是红色</p> <p id="green">这个段落是绿色</p>
使用QSS文件
可以创建扩展名为.qss的新样式表文件,然后将其添加到资源文件(.qrc)中。
你可以应用样式表给小部件:
MyWidget::MyWidget(QWidget* parent): QWidget(parent) {setStyleSheet("QWidget {background-color: green}");
}
你也可以应用样式表给整个应用程序:
#include "mywidget.h"
#include <QApplication>
#include <QFile>
int main(int argc, char *argv[]) { QApplication app(argc, argv); QFile file(":/qss/default.qss"); file.open(QFile::ReadOnly); QString styleSheet = QLatin1String(file.readAll()); app.setStyleSheet(styleSheet); Widget mywidget; mywidget.show(); return app.exec();
}
Qt提供了几个QStyle子类,它们模拟Qt支持的不同平台的样式。这些样式在Qt GUI模块中很容易获得。你可以构建自己的自定义样式,并将其导出为插件。Qt使用QStyle呈现Qt小部件,以确保它们的外观和感觉与本机小部件相同。
你可以对单独的小部件设置样式,使用QWidget::setStyle()函数。
通过创建自定义样式,可以自定义GUI的外观。创建自定义样式有两种不同的渠道。在静态渠道中,可以对QStyle类进行子类化,并重新实现虚函数以提供所需的行为,或者从头重写QStyle类。QCommonStyle通常用作基类,而不是QStyle。在动态渠道中,可以将QProxyStyle子类化,并在运行时修改系统样式的行为。你还可以通过使用诸如drawPrimitive()、drawItemText()和drawControl()等QStyle函数来开发支持样式的自定义小部件。
有几种方法可以在Qt应用程序中应用自定义样式。最简单的方法是在创建QApplication对象之前调用QApplication::setStyle()静态函数,如下所示:
#include "customstyle.h"
int main(int argc, char *argv[]) { QApplication::setStyle(new CustomStyle); QApplication app(argc, argv); Widget helloworld; helloworld.show(); return app.exec();
}
小部件是可以在屏幕上显示的GUI元素。这可能包括标签、按钮、列表视图、窗口、对话框等。所有小部件都在屏幕上向用户显示特定信息,其中大多数小部件允许用户通过键盘或鼠标进行交互。
窗口是没有其他父窗口小部件的顶级窗口小部件。通常,除非指定了任何窗口标志,否则窗口都有标题栏和边框。窗口样式和某些策略由底层窗口系统决定。Qt中的一些常见窗口类是QMainWindow、QMessageBox和QDialog。主窗口通常遵循桌面应用程序的预定义布局,包括菜单栏、工具栏、中心小部件区域和状态栏。QMainWindow需要一个中心小部件,即使它只是一个占位符。其他组件可以在主窗口中移除。下图显示了QMainWindow的布局结构。我们通常调用show()方法来显示小部件或主窗口。
QMenuBar位于QMainWindow的顶部。你可以添加菜单选项,如文件、编辑、查看和帮助。在下面显示QMenuBar的屏幕截图中,有QToolBar。QDockWidget提供了一个小部件,可以停靠在QMainWindow内部,也可以作为顶级窗口浮动。中心窗口小部件是主视图区域,你可以在其中添加表单或子窗口小部件。使用子窗口小部件创建自己的视图区域,然后调用setCentralWidget()。
重要提示:
QMainWindow不应与QWindow混淆。QWindow是一个方便的类,表示底层窗口系统中的窗口。通常,应用程序的UI使用QWidget或QMainWindow。但是,如果希望保持最小的依赖关系,可以直接渲染到QWindow。
QMessageBox是一种对话框,用于显示信息和警报,或向用户提问。通常,exec()方法用于显示对话框。
可以使用以下代码段创建一个简单的消息框:
QMessageBox messageBox;
messageBox.setText("This is a simple QMessageBox.");
messageBox.exec();
更多推荐
✿3
发布评论