IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> ?3-The Basics-GUI Design Using Qt Widgets -> 正文阅读

[C++知识库]?3-The Basics-GUI Design Using Qt Widgets

所有的小部件(widgets)都继承自QObjectQWidget是所有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 any
            doThings();
            return true;
        } else  if (ev->type() == QEvent::Show) {
            // complement handling of Show if any
            doThings2();
            QWidget::event(ev);
            return true;
        }
        // Make sure the rest of events are handled
        return 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_NAMESPACE

class 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);
    } // setupUi

    void 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 Ui

QT_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中的一些常见窗口类是QMainWindowQMessageBoxQDialog。主窗口通常遵循桌面应用程序的预定义布局,包括菜单栏、工具栏、中心小部件区域和状态栏。QMainWindow需要一个中心小部件,即使它只是一个占位符。其他组件可以在主窗口中移除。下图显示了QMainWindow的布局结构。我们通常调用show()方法来显示小部件或主窗口。

QMenuBar位于QMainWindow的顶部。你可以添加菜单选项,如文件、编辑、查看和帮助。在下面显示QMenuBar的屏幕截图中,有QToolBarQDockWidget提供了一个小部件,可以停靠在QMainWindow内部,也可以作为顶级窗口浮动。中心窗口小部件是主视图区域,你可以在其中添加表单或子窗口小部件。使用子窗口小部件创建自己的视图区域,然后调用setCentralWidget()

重要提示:
QMainWindow不应与QWindow混淆。QWindow是一个方便的类,表示底层窗口系统中的窗口。通常,应用程序的UI使用QWidgetQMainWindow。但是,如果希望保持最小的依赖关系,可以直接渲染到QWindow

QMessageBox是一种对话框,用于显示信息和警报,或向用户提问。通常,exec()方法用于显示对话框。
可以使用以下代码段创建一个简单的消息框:

QMessageBox messageBox;
messageBox.setText("This is a simple QMessageBox.");
messageBox.exec();
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-05-05 10:59:30  更:2022-05-05 11:00:44 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 22:15:25-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码