元对象系统
元对象系统是一个基于 标准 C++的扩展 ,为 Qt 提供了信号与槽机制、实时类型信息,动态属性系统元对象系统的三个基本条件:类必须继承自 QObject、类声明 Q_OBJECT 宏(默认私有有)、元对象编译器 moc。class ExamDialog : public QDialog
{
Q_OBJECT//支持信号与槽的宏public:
信号与槽机制
信号和槽机制是 QT 的核心机制: 信号和槽是一种高级接口,应用于对象之间的通信,
它是 QT 的核心特性,信号和槽是 QT 自行定义的一种通信机制,它独立于标准的 C/C++ 语言,要正确的处理信号和槽,必须借助一个称为 moc(Meta-Object Compiler),也就是“元对象编译器”。,它为高层次的事件处理自动生成所需要的必要代码。Qt 程序在交由标准编译器编译之前,先要使用 moc 分析 C++ 源文件。如果 moc 发现在一个类头文件中包含了宏 Q_OBJECT,则会生成以 moc_className.cpp(自定义类名)的.cpp 文件。这个源文件中 包含了 Q_OBJECT 宏的实现代码。新的文件同样将进入编译系统,与原文件一起参与编译。构建生成的.o 文件包含 moc 生成的 cpp 文件。
信号与槽的实例
信号(Signal)就是在特定情况下被发射的事件,例如 PushButton 最常见的信号就是鼠标单击时发射的 clicked() 信号 。发射信号使用 Qt 的 emit 关键字 。QT 的 signals 关键字指出进入了信号声明区,随后即可声明自己的信号
槽声明:
槽(Slot)就是对信号响应的函数。槽就是一个函数,与一般的 C++函数是一样的,可以声明在类的任何部分(public、private 或 protected),可以具有任何参数,也可以被直接调用。槽函数与一般的函数不同的是:槽函数可以与一个信号关联,当信号被发射时,关联的槽函数被自动执行。private slots:
void on_whbtn_clicked();//on_对象名_信号名;
void on_zgbtn_clicked();
void on_sjbtn_clicked();
void connectGuy(QString &str);
槽方法:
void MainWindow::on_whbtn_clicked()
{
QString str = "武汉加油";
emit conn(str); //发射信号
}
// QTC_TEMP
void MainWindow::on_zgbtn_clicked()
{
QString str = "中国加油";
emit conn(str);
}
// QTC_TEMP
void MainWindow::on_sjbtn_clicked()
{
QString str = "世界加油";
emit conn(str);
}void MainWindow::connectGuy(QString &str)
{
qDebug() << QString(str);
}
信号声明:
signals:
void conn(QString &str); //信号不能也不需要实现
这两种信号与槽连接方式效果一样:推荐后者:
QObject::connect(this, SIGNAL(conn(QString &)), this, SLOT(connectGuy(QString &)));
QObject::connect(this, &MainWindow::conn, this, &MainWindow::connectGuy);
发送信号和信号接收的参数只能是参数类型,不能是参数实体,信号接受者的参数个数要小于等于信号发送者
QObject::connect(this, SIGNAL(conn()), this, SLOT(connectGuy(QString &))); //错误的
信号与槽的链接:
信号与槽关联是用 QObject::connect() 函数实现:QMetaObject::Connection QObject:: connect (const QObject * sender , //信号发送者const char * signal , //发送的信号const QObject * receiver , //信号接收者const char * method , //表示与信号连接的方式的字符串,可以是槽或信号Qt::ConnectionType type = Qt::AutoConnection //连接方式,默认自动连接 )常用格式:connect(sender, SIGNAL(signal()), receiver, SLOT(slot()),connectType);
1 一个信号连接一个槽:connect(sender, SIGNAL(single1()), receiver, SLOT(slotFun()));如:2 一个信号连接一个信号:connect(sender, SIGNAL(single1()), receiver, SIGNAL(single2()));如:3 一个信号连接多个槽,关联信号的槽函数按照建立连接时的顺序依次执行:connect(sender, SIGNAL(single1()), receiver1, SLOT(slotFun()));connect(sender, SIGNAL(single1()), receiver2, SLOT(slotFun()));connect(sender, SIGNAL(single1()), receiver3, SLOT(slotFun()));4: 多个信号一个槽connect(sender1, SIGNAL(single1()), receiver, SLOT(slotFun()));connect(sender2, SIGNAL(single2()), receiver, SLOT(slotFun()));connect(sender3, SIGNAL(single3()), receiver, SLOT(slotFun()));
断开信号与槽的连接
void MainWindow::on_pushButton_clicked()
{
qDebug() << "断开conn与connectChina的连接";
//disconnect(this, &MainWindow::conn, this, &MainWindow::connectChina);
//QMetaObject::Connection m_this;//头文件的private添加成员
//m_this = QObject::connect(this, &MainWindow::conn, this, &MainWindow::connectChina);
disconnect(m_this);
}void MainWindow::on_pushButton_2_clicked()
{
qDebug() << "断开conn信号的所有连接";
disconnect(this, &MainWindow::conn, 0, 0);
}void MainWindow::on_pushButton_3_clicked()
{
qDebug() << "断开一个接收者的所有关联";
disconnect(this, 0, this, 0);
}void MainWindow::on_pushButton_4_clicked()
{
qDebug() << "断开一个发送者的所有关联";
disconnect(this, 0, 0, 0);
}
动态属性系统
学了C++,你就通俗的把这个理解为把父类的指针指向子类,然后调用子类的方法
class MyProperityClass : public QObject
{
Q_OBJECT
Q_PROPERTY(QString m_mask READ getMask WRITE setMask NOTIFY maskChange)
public:
explicit MyProperityClass(QObject *parent = nullptr);
QString getMask() const; //读read
void setMask(QString maskNum);signals:
void maskChange(QString str);private:
QString m_mask; //保存属性值
};
QString MyProperityClass::getMask() const
{
return m_mask;
}void MyProperityClass::setMask(QString maskNum)
{
m_mask = maskNum;
emit maskChange(maskNum); //改变了就发送出去
}
MyProperityClass *myProperity = new MyProperityClass;
MyProperityClass *myProperity1 = new MyProperityClass;
connect(myProperity, &MyProperityClass::maskChange, this, &Widget::maskChange);
myProperity->setMask("100000亿个口罩");
qDebug() << "当前口罩库存" << myProperity->getMask();//基类类型指针操作属性
QObject *obj = myProperity;
qDebug() << "obj进行属性读取" << obj->property("getMask").toString();
obj->setProperty("myProperity", "2000000亿个口罩");
qDebug() << "obj第二次进行属性读取" << obj->property("m_mask").toString();
qDebug() << "myProperity1读取口罩库存" << myProperity1->getMask();
}void Widget::maskChange(QString str)
{
qDebug() << "新的口罩库存" << str;
}
QT对象树
Qt 提供了对象树机制,能够自动、有效的组织和管理继承自 QObject 的 Qt 对象.每个继承自 QObject 类的对象通过它的对象链表(QObjectList)来管理子类对象,当用户创建一个子对象时,其对象链表相应更新子类对象信息,对象链表可通过 children()获取。 当父对象析构的时候,其对象链表中的所有(子)对象也会被析构 ,父对象会 自动将其 从父对象列表中删除。Qt 保证没有对象会被 delete 两次。 开发中手动回收资源时 建议使用deleteLater 代替 delete,因 deleteLater 多次是安全的 ,而 delete 多次是不安全的。
在程序结束之后会自动进行析构
#ifndef MYLABLE_H
#define MYLABLE_H
#include "QLabel"class MyLable : public QLabel
{
public:
MyLable(QWidget *parent = 0);
~MyLable();
};#endif // MYLABLE_H
#include "mylable.h"
#include "QDebug"
MyLable::~MyLable()
{
qDebug() << "MLable析构了" << this;
}MyLable::MyLable(QWidget *parent)
: QLabel(parent)
{
qDebug() << "MLable构造了" << this;
}
MyLable *lable = new MyLable(&w);
MyPushButton *button = new MyPushButton(&w);
MyRadioButton *radio = new MyRadioButton(&w);
MyQLayout *layout = new MyQLayout(&w);
lable->setText("文本标签");
button->setText("push按钮");
radio->setText("单选按钮");
layout->addWidget(lable, 0, 0);
layout->addWidget(button, 1, 0);
layout->addWidget(radio, 2, 0);
w.setLayout(layout);
w.show();
const QObjectList list = w.children();
qDebug() << "children是:";
foreach (QObject *obj, list)
qDebug() << obj;
手动析构:
他执行了之后就会析构(析构这个父类所有的子类)
Widget w;
MyLable *lable = new MyLable(&w);
MyPushButton *button = new MyPushButton(&w);
MyRadioButton *radio = new MyRadioButton(&w);
MyQLayout *layout = new MyQLayout(&w);
//孙子类
MyQLayout *sunlayout = new MyQLayout(lable);
MyPushButton *sunbutton1 = new MyPushButton();
MyPushButton *sunbutton2 = new MyPushButton();
MyPushButton *sunbutton3 = new MyPushButton();
sunbutton1->setText("孙标签1");
sunbutton2->setText("孙标签2");
sunbutton3->setText("孙标签3");
sunlayout->addWidget(sunbutton1);
sunlayout->addWidget(sunbutton2);
sunlayout->addWidget(sunbutton3);
lable->setLayout(sunlayout);
//父类
lable->setText("文本标签");
button->setText("push按钮");
radio->setText("单选按钮");
layout->addWidget(lable, 0, 0);
layout->addWidget(button, 1, 0);
layout->addWidget(radio, 2, 0);
w.setLayout(layout);
w.show();
const QObjectList list = w.children(); //基类的孩子
qDebug() << "W的children是:";
foreach (QObject *obj, list)
qDebug() << obj;
const QObjectList list1 = lable->children(); //父类的孩子
qDebug() << "lable的children是:";
foreach (QObject *obj1, list1) {
qDebug() << obj1;
}
lable->deleteLater();
QT窗口布局
QT 提供的默认部件基类包括 QMainWindow、QWidget、和 QDialog 这三种,这三个部件基类也是用的最多的。
QMainWindow 是带有菜单栏、工具栏、状态栏的主窗口类,它有自己单独的布局。
布局有一个中心区域,通常是标准的 Qt 部件,也可以是定制部件,且必须有一个中心小部件.setCentralWidget()方法可设置中心部件
QWidget 类是所有部件对象的基类
被称为基础窗口部件, 继承关系详看 QWidget 类关系 图, Qt::WindowFlagsQt::WindowType 枚举值的组合,用来设置窗口的属性,f = 0 表默认为Qt::Widget 风格,其余窗口属性详见 附件表一。 setWindowState()可设置窗体的状态,参数Qt::WindowStates 枚举值指定
查看windowsflags:
这个是无边框的属性
QWidget widget;
widget.setWindowTitle("widget窗体");
widget.show();
QWidget widget1(0, Qt::FramelessWindowHint | Qt::Dialog);
widget1.setWindowTitle("widget无边框窗体");
widget1.show();
查看windowstate
默认状态
最小窗体,最大窗体,铺满屏幕,窗体活动
设置最大窗体状态
QWidget widget;
widget.setWindowTitle("widget窗体");
widget.setWindowState(Qt::WindowMaximized);//设置最大窗体,标题会保留,铺满就是没标题了
widget.show();
widget.resize(QSize(600,400));//||widget.resize(600,400)//设置窗体指定大小 (宽高)
widget.move(QPoint(60,40));//||widget.move(60,40)//初始化时,窗体的显示位置(x,y坐标)
qDebug() << widget.geometry(); //获取窗体的尺寸信息
Qwidget设计模式的的属性
enabled 启用或禁用 widget,默认启用(设置窗体内部部件是否可以用)。
geometry widget 的位置和尺寸。sizePolicy 设置 widget 在水平和垂直方向的伸缩策略以及伸缩因子(Stretch Factors),所谓伸缩策略实际就是 widget 对待部件大小提示的策 略, 需结合布局管理器一起使用垂直伸展和水平伸展就是等比例伸展
属性值
|
作用
|
Fixed
|
尺寸不能改变,尺寸为 sizeHint 大小
|
Minimum
|
尺寸可以拉伸,尺寸可变范围:≥sizeHint
|
Maximum
|
尺寸可以缩小,尺寸可变范围:minimumSizeHint ~ sizeHint
|
Preferred
|
可以变大缩小,尺寸可变范围:≥minimumSizeHint
|
Expanding
|
可以变大缩小,尺寸可变范围:≥minimumSizeHint,且
部件有优先扩展权
(注:优先扩展权表部件将尽可能多的占用空间,如
Preferred 与 Expanding 同时存在则优先分配空间给 Expanding
)
|
MinimumExpanding
|
尺寸可以拉伸,尺寸可变范围:≥minimumSizeHint,且部件有优先扩展权
|
Ignored
|
任意变大缩小,尺寸可变范围:≥minimumSizeHint(若 minimumSizeHint 为 0,
则可缩小至 0,此时部件不可见)
|
minimumSize 设置部件的最小尺寸,伸缩时不可继续缩小。
maximumSize 设置部件的最大尺寸,伸缩时不可继续变大。palette 画板,设置部件的基本样式。mouseTracking 鼠标跟踪,鼠标离开部件范围后,部件仍可以接收到 mousemove 等事件。tabletTracking 平板或手机的陀螺仪、加速度传感器跟踪。focusPolicy 焦点策略,按钮可以通过 NoFocus 使虚线消失,lineedit 这类文本编辑框必须能获得焦点。
属性值 | 作用 |
NoFocus
|
无法通过点击和键盘获得焦点
|
TabFocus
|
鼠标无法获得焦点,Tab 键获得焦点
|
ClickFocus
|
鼠标点击获得焦点,Tab 键无法获得焦点
|
StrongFocus
|
鼠标和 Tab 键都可以获得焦点
|
WheelFocus
|
通过滚轮获得焦点
|
contextMenuPolicy 上下文菜单策略,指定菜单的显示方式。
属性值 | 作用 |
NoContextMenu
|
部件无菜单,菜单处理延迟到部件父亲
|
PreventContextMenu
|
部件无菜单,菜单处理不延迟到父亲,而是传递到本身。
|
DefaultContextMenu
|
调用部件的 contextMenuEvent 方法,默认处理方式为忽略上下文事件。
|
ActionsContextMenu
|
部件菜单由 actions 定义构成
|
CustomContextMenu
|
部件菜单自定义,发送 customContextMenuRequested 信号
|
acceptDrops 设置部件是否接受拖拽事件,默认启用。
windowOpacity: 设置窗体透明度
toolTip 设置部件的提示,鼠标悬浮时会显示。toolTipDuration 设置 widgettoolTip 的显示持续时间,毫秒为单位,默认为-1,会一直显示。statusTip 设置部件的状态提示,当窗口有 statusBar 时会显示在上面。whatsThis 某些窗口会有 whatsThis 按钮,选中后点击其他按钮会显示帮助信息accessibleName 辅助功能客户端应用程序所使用的控件名称。accessibleDescription 主要用来为视力较差或盲人用户,提供更大的上下文,也可以使用上下文搜索或其他应用程序。layoutDirection widget 布局的方向,LeftToRight,RightToLeft,LayoutDirectionAuto,字面意思autoFillBackground 设置 widget 背景是否被画板颜色自动填充,默认不勾选styleSheet 设置 widget 的 qss 样式表locale 设置 widget 的区域和语言,在将时间等信息转成字符串后,年月日几个字会显示不同语言inputMethodHint 设置 widget 输入时的屏幕键盘模式,有纯数字、纯字母等多种模式,用在手机端
QDialog 是各种对话框的基类,
其继承自 QWidget,对话框有两种表现形式:模态对话 框、非模态对话框。setWindowModality
模态对话框就是阻塞同一应用程序中其它可视窗口的输入的对话框。用户必须完成当前对话框中的交互操作并且关闭窗口后才能操作应用程序中的其它窗口对话框有它们自己的本地事件循环。 exec()方法可使窗口以模态方式运行。当用户关闭这个对话框,exec()将提供一个可用的 返回值并且这时流程控制继续从调用 exec()的地方进行。通常,我们连接默认按钮,例如“OK”到 accept()槽并且把“Cancel”连接到 reject()槽,来使对话框关闭并且返回适当的值。另外我们 也可以连接done()槽,传递给它 Accepted或Rejected。
模态的三种调用方式(以三种模态形式的其中一种作为例子)QDialog dlg;w1.setWindowModality(Qt::ApplicationModal);//继承的父类的模态方法
w1.setModal(true); //属于dialog的模态方法dlg.exec();//这个会有一个返回值,1为accepted,0位rejected
w.setWindowTitle("窗口1");
w.show();
Widget w1;
w1.setWindowTitle("窗口2");
w1.setWindowModality(Qt::NonModal);
w1.show();
Widget w2;
w2.setWindowTitle("窗口3");
w2.show();
阻塞方式
|
阻塞效果
|
Qt::ApplicationModal
|
阻塞应用程序的所有窗口//无法操作其他窗口
|
Qt::WindowModal
|
阻塞阻塞父窗口、祖先窗口及它们的子窗口
|
Qt::NoModal
|
不阻塞,默认值
|
QLabel
常用来显示文本、数字、图片、gif 动图。
QFrame
所有边框部件的基类
QLine Edit
接收用户输入。Line Edit的部件
进行隐式的字符转换
获取输入的信息
connect(ui->lineEdit, &QLineEdit::returnPressed, this, &Widget::showInput);
void Widget::showInput()
{
qDebug() << ui->lineEdit->text() //用户的输入
<< ui->lineEdit->displayText(); //界面的显示
}
QPushButton
按钮类,常用显示文字、图标。
QCheckBox
ui->study->setTristate(true);
或者勾选下方复选框才回有三种状态
setWindowTitle("Label属性设置");
ui->name->setText("派蒙");
ui->num->setNum(12);
ui->image->setScaledContents(true);
ui->image->setPixmap(QPixmap("./image.jpg"));
//设置动图
QMovie *movie = new QMovie("./BigGood.gif");
ui->gif->setMovie(movie);
ui->gif->setScaledContents(true); //设置图片填充
movie->start();
ui->radioButton_3->setChecked(true);
qDebug() << "女是否选择:" << ui->radioButton_3->isChecked();
}void Widget::on_radioButton_2_clicked(bool checked)
{
qDebug() << "男是否选择:" << checked;
}void Widget::on_study_stateChanged(int arg1)
{
// Qt::Unchecked
// Qt::PartiallyChecked
// Qt::Checked
ui->study->setTristate(true);
if (arg1 == Qt::Unchecked) {
qDebug() << "直接开始摆烂:";
} else if (arg1 == Qt::PartiallyChecked) {
qDebug() << "学习处于崩溃边缘状态";
} else {
qDebug() << "已经在学习了";
}
}
QLayout
#include <QApplication>
#include "QFormLayout" //设置表单
#include "QHBoxLayout" //设置水平布局
#include "QLabel"
#include "QLineEdit"
#include "QPushButton"
#include "QRadioButton"
#include "QSpacerItem" //设置间隙
#include "QVBoxLayout" //设置垂直布局
#include "widget.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
//添加标签
QLabel *nameLabel = new QLabel("姓名(&a)");
QLabel *ageLabel = new QLabel("年龄(&b)");
QLabel *emailLabel = new QLabel("邮箱(&c)");
QLabel *numLabel = new QLabel("门派号码:"); //这个不需要设置伙伴
//设置编辑框lineEdit
QLineEdit *nameLineEdit = new QLineEdit;
QLineEdit *ageLineEdit = new QLineEdit;
QLineEdit *emailLineEdit = new QLineEdit;
QLineEdit *numLineEdit = new QLineEdit;
//设置伙伴关系(快捷键)
nameLabel->setBuddy(nameLineEdit);
ageLabel->setBuddy(ageLineEdit);
emailLabel->setBuddy(emailLineEdit);
//用表单设置水平布局
QFormLayout *fromLayout = new QFormLayout();
fromLayout->addRow(nameLabel, nameLineEdit);
fromLayout->addRow(ageLabel, ageLineEdit);
fromLayout->addRow(emailLabel, emailLineEdit);
fromLayout->addRow(numLabel, numLineEdit);
//单独给性别设置水平布局
QLabel *sex = new QLabel("性别:");
QRadioButton *mBtn = new QRadioButton;
QRadioButton *wBtn = new QRadioButton;
mBtn->setText("男");
wBtn->setText("女");
QHBoxLayout *sexLayout = new QHBoxLayout;
sexLayout->addWidget(sex);
sexLayout->addWidget(mBtn);
sexLayout->addWidget(wBtn);
QSpacerItem *space = new QSpacerItem(300, 20);
QPushButton *okBtn = new QPushButton("确定"); //在最下面添加一个确定按钮
//将上述两个布局添加入垂直布局
QVBoxLayout *mainLayout = new QVBoxLayout(&w);
mainLayout->addLayout(fromLayout); //将表单布局加入垂直布局
mainLayout->addLayout(sexLayout); //将水平布局加入垂直布局
mainLayout->addItem(space);
mainLayout->addWidget(okBtn);
mainLayout->setMargin(10);
mainLayout->setSpacing(10);
w.setLayout(mainLayout);
w.show();
return a.exec();
}