文章目录
0x00 前言
本文档为个人边学习边记录的Qt笔记,非教程。虽然在记录时会尽量保证笔记的准确性,但是有些知识点小结为当时的体会与理解,可能并不准确,会有出现内容存在舛误或遗漏的地方,仅供参考。
另外笔记中会存在引用他人文章内容的部分,被引用的原文不会被特殊标记出来,但会在参考文档中给出原文链接,需要注意。
Qt版本:Qt Creator 3.5.0
Based on Qt 5.4.2 (GCC 5.2.1 20151010, 32 bit)
Qt编译链版本:Qt4.8.6
0x01 Qt简介
1.1 Qt是什么
Qt使用C++开发的可以跨平台的图形用户界面应用程序框架,通常被用来开发图形界面应用程序。除了开发图形应用程序也可以在支持嵌入式开发,比如汽车工业、航空航天、仪器仪表等。在智能手机领域,Qt支持 Android、iOS、WinPhone 等智能机操作系统。
另外Qt也具有多线程、访问数据库、图像处理、音视频处理、网络通信、文件操作等功能。
小结一下,Qt主要用来对桌面程序开发以及嵌入式开发、移动设备开发。
1.2 Qt发展史
·1991年由挪威Eirik Chambe-Eng 和 Haavard Nord 开发
·1994年3月4日Eirik Chambe-Eng 和 Haavard Nord正式成立奇趣科技公司Trolltech)
·1995年5月Trolltech首次发布Qt的第一个正式版本
·1996年进入商业领域
·1997年Qt被用来开发Linux桌面环境KDE,大获成功
·2000年奇趣科技公司为开源社区发布了遵循GPL许可证的开源文件
·2006年Trolltech首次在奥斯陆证券交易所公开募股
·2008年诺基亚收购奇趣科技公司,并增加LGPL授权模式
·2011年3月被芬兰Diage IT服务公司收购
·2012年Digia从诺基亚收购了Qt软件技术和业务
·2014年Digia宣布成立Qt Company全资子公司,独立运营Qt商业授权业务
·2016年Qt 公司独立于Digia,并在纳斯达克赫尔辛基独立上市 Helsinki
·2017年Qt公司筹集了1500万欧元的股权资助增长投资
……
1.3 Qt支持的平台
Windows:Windows - 95、98、NT4.0、ME、2000、XP 、Vista、Win7、win8、win2008、win10
Linux:SunSolaris、HP-UX、CompaqTru64 UNIX、IBMAIX、SGI IRIX、FreeBSD、BSD/OS和其它很多X11平台
Macintosh – Mac OS X
Embedded – 有帧缓冲支持的嵌入式Linux平台,Windows CE
1.4 使用Qt开发的软件
1.暴雪战网客户端
2.Skype
3.VirtualBox
4.YY语言
5.虾米音乐
6.WPS
7.豆瓣电台
8.梅赛德斯奔驰A-Class 2019 车载信息娱乐系统
……
1.5 Qt的优点
·Qt可以和python、prel、ruby等语言绑定,使用这些脚本语言来开发Qt应用程序。
·优良的跨平台特性
·面向对象
·丰富的API,包含多达2500个C++类
·支持2D/3D图形渲染,支持OPenGl
·大量的开发文档
·支持 XML
1.6 其它
Qt官网中文地址:https://www.qt.io/cn
Qt的中文官方博客已经登录到CSDN上,地址:https://qt-china.blog.csdn.net/
Qt官方公众号:
·Qt开源社区:https://www.qter.org/
0x02 创建Qt项目
2.1 使用向导新建一个简单的Qt程序
打开Qt Creator 界面选择New Project或者打开“文件”->“新建文件或项目”;
选择Qt Widget Application,填写项目名称,设置保存路径,本例中项目名为“01FirstProject”,选择默认编译套件;
向导会默认添加一个继承与QMainWindow的类,可以类信息中修改类的名字和基类,基类有QMainWindow、QWidget、QDialog,本例中类名为“myWidget”,选择基类为“QWidget”(一个不带UI的界面);
完成后系统会新建main.cpp、mywidget、mywidget.h和一个.pro:
QMainWindow、QWidget、QDialog区别:
QWidget是所有用户界面元素的基类。窗口和控件都是直接或间接继承自QWidget;
QMainWindow窗口包含菜单栏、工具栏、状态栏、标题栏等,是最常见的窗口形式,可以作为GUI程序的主窗口;
QDialog是对话框窗口的基类。对话框主要是用来执行短期任务,或与用户进行互动,它可以是模态或非模态的。QDialog没有菜单栏、工具栏、状态栏等。
QMainWindow、QWidget、QDialog选用原则:
如果需要嵌入到其他窗体中,则基于QWidget创建。
如果是顶级对话框,则基于QDialog创建。
如果是主窗体,则基于QMainWindow创建。
2.2 pro文件
.pro为工程文件(project),为qmake自动生成的用于生产maikefile的配置文件:
解释:
·“#”为注释
·greaterThan(QT_MAJOR_VERSION, 4): QT += widgets:
如果QT_MAJOR_VERSION版本大于4则需要增加widgets模块
·TARGET = myWidget:
指定生成的应用程序名
·TEMPLATE = app:
建立一个应用程序的makefile
·SOURCES += main.cpp\mywidget.cpp:
项目工程中包含的源文件
·HEADERS += mywidget.h:
工程中的头文件
2.3 一个简单的qt程序
1.按钮的创建
main.c:
#include "mywidget.h"
#include <QApplication> //包含一个应用程序类的头文件
//main 入口地址 argc命令行变化的数量,argv命令行变量的数组
int main(int argc, char *argv[])
{
//a应用程序对象,应用程序对象,有且只有一个
QApplication a(argc, argv);
//窗口对象 mywidget父类 ->QWidget
myWidget w;
//窗口对象,默认不会显示,必须要调用show方法显示窗口
w.show();
//让应用程序对象进入消息循环机制,代码堵塞到当前行
return a.exec();
}
mywidget.cpp:
//创建第二个按钮 按照控件大小创建窗口
QPushButton *btn2 = new QPushButton("second button", this);
//移动btn2大小
btn2->move(100, 0);
//重置窗口大小
//resize(600, 400);
//设置固定窗口大小
setFixedSize(600, 400);
//设置窗口标题
setWindowTitle("First window");
}
myWidget::~myWidget()
{
}
mywidget.h:
#ifndef MYWIDGET_H
#define MYWIDGET_H
#include <QWidget>//包含头文件 QWidget 窗口类
class myWidget : public QWidget
{
Q_OBJECT //Q_OBJECT宏,允许类中使用信号和槽机制
public:
myWidget(QWidget *parent = 0);//构造函数
~myWidget(); //析构函数
};
#endif // MYWIDGET_H
运行结果:
2.对象模型(对象树)
1)QObject
Qt创建对象时通常需要传入一个名为parent的对象指针参数(QObject类型参数),即创建一个QObject对象时其QObject构造函数会接收一个QObject指针作为参数。另外,创建的该QObject对象会被自动添加到其父对象parent的children()列表(QObjectList类型列表),QObject类如下:
每一个QObject对象仅有一个父对象,但可以有多个子对象。 当一个QObject对象有多个子对象,子对象又有多个子对象,那么按照这种排列会形成类似一个树的形状。
当父对象析构的时候,QObjectList列表中的所有对象也会被析构。当子对象被析构时,会从该QObjectList列表中自动删除(该父对象并未集成意义的父类)
这种机制在GUI程序中比较实用,例如,当一个窗口new多个控件后可以不用delete,因为父控件在被应用程序销毁时子控件以及布局管理器对象会被一并销毁。或者当一个按钮有一个快捷键(QShortcut)对象作为其子对象,当按钮删除时,这个快捷键也会被删除。
2)QWidget
QWidget是在窗口显示一切组件的父类。QWidget继承自QObject,因此也继承对象树关系。 一个对象会自动的成为父组件的子组件。当父组件关闭时,子组件也会被关闭。例如当关闭一个对话框时,应用程序除了将对话框界面删除,还会将对话框上的按钮、图标一并删除。
我们也可以自己主动删除子对象,它们会自动从父对象列表中删除。
3)对象树的意义
·对象树在一定程度上解决了内存问题。
·当一个QObject对象在堆上创建时,Qt会为其创建一个对象树,但对象树中的对象没有排列顺序,没有顺序意味着销毁这些对象也没有顺序定义。
·对象树中QObject对象被删除时,若该对象有parent,则从其parent中的QObjectList列表中删除;若该对象QObjectList列表非空,则自动delete列表中每个子对象。
Qt保证每个QObject只会被delete一次。
注意:局部对象的析构顺序应该按照其创建顺序的相反过程。 C++中不允许调用两次析构函数,如果先创建父对象然后创建子对象,那么在代码超出作用域时,子对象会先析构,并会将其从父对象QObjectList列表中删除,然后父对象析构时因为子对象不在列表中,所以不会发生析构两次的问题。但是如果先创建子对象,然后创建父对象,那么在代码超出作用域时,父对象QObjectList列表会将里面的所有子对象析构,父对象析构完成后,当轮到子对象时子对象会被再次析构,导致程序崩溃。
示例:
先创建父对象,再创建子对象,析构正确:
int main(int argc, char *argv[])
{
//a应用程序对象,应用程序对象,有且只有一个
QApplication a(argc, argv);
//窗口对象 mywidget父类 ->QWidget
myWidget w;
//新增按钮
QPushButton btn("button");
btn.setParent(&w);
//窗口对象,默认不会显示,必须要调用show方法显示窗口
w.show();
//让应用程序对象进入消息循环机制,代码堵塞到当前行
return a.exec();
}
先创建子对象,再创建父对象,析构错误:
int main(int argc, char *argv[])
{
//a应用程序对象,应用程序对象,有且只有一个
QApplication a(argc, argv);
//新增按钮
QPushButton btn("button"); //子对象在父对象前创建,错误!
//窗口对象 mywidget父类 ->QWidget
myWidget w;
btn.setParent(&w);
//窗口对象,默认不会显示,必须要调用show方法显示窗口
w.show();
//让应用程序对象进入消息循环机制,代码堵塞到当前行
return a.exec();
}
3.Qt窗口坐标系
以左上角为原点(0,0),X向右增加,Y向下增加。 对于嵌套的窗口,其坐标是相对于父窗口的:
0x03 Qt4版本的信号和槽机制
信号槽(Signal & Slots)是Qt的编程基础,也是Qt特色之一。有了信号和槽的机制,使得Qt中各个组件的交互会变得简单和直观。
信号(Signal ):
当特定情况下,某个事件发生之后,它会发出一个信号(signal),是类中一个具有特殊的声明的成员函数。信号没有指定的接收方,类似于广播报文。例如鼠标点击界面上的一个按钮这个事件发生后,该事件会发出一个信号。信号具有以下特点:
·信号的返回值是void类型
·信号只能声明不能定义
·信号必须使用signals关键字进行声明
·信号的访问属性自动被设置为protected
·只能通过emit关键字调用信号(发射信号)
槽(Slots):
当信号发出后,若有对象对这个信号有响应,则对应的响应函数称为槽或槽函数(Slot)。槽可以定义在类的任何部分(public、private、protected)。通常使用connect()函数将要响应的信号和槽关联在一起。所以当事件的信号发出时,被连接的槽会被connect()回调。槽一旦有参数,其参数个数,类型,顺序必须要和对应的信号保持一致。在使用信号与槽的类中,必须在类的定义中加入宏 Q_OBJECT。
信号和槽的模式类似于观察者模式:当某个关心的事件发生时,对应的操作就会被触发执行。
3.1系统自带信号和槽
1.概念
信号与槽的绑定用 QObject::connect() 函数实现的,基本格式是:
QObject::connect(sender, SIGNAL(signal()), receiver, SLOT(slot()));
sender:发出信号的对象
signal:发送对象发出的信号,带括号
receiver:接收信号的对象
slot:接收对象在接收到信号之后所需要调用的函数(槽函数),带括号
信号和槽的使用规则如下:
信号可以连接多个槽:
连接的槽会一个接一个的被调用,但是它们的调用顺序是不确定的,当一个信号发出时,与其关联的槽函数通常会立即执行,就像正常调用一个函数一样。当信号关联的所有槽函数执行完毕后,才会执行发射信号处后面的代码:
connect(btn, SIGNAL(clicked(bool)) , this, SLOT(classIsOver()));
SIGNAL(clicked(bool)) , this, SLOT(updateStatus(int)));
多个信号可以连接同一个槽:
connect(ui->rBtnBlue,SIGNAL(clicked()),this,SLOT(setTextFontColor()));
connect(ui->rBtnRed,SIGNAL(clicked()),this,SLOT(setTextFontColor()));
connect(ui->rBtnBlack,SIGNAL(clicked()),this,SLOT(setTextFontColor()));
一个信号可以连接另外一个信号:
connect(btn, SIGNAL(clicked()) , zt , SIGNAL(teachersignal()));
connect(zt , SIGNAL(teachersignal()) , this, SLOT(classIsOver()));
信号槽可以断开:
利用disconnect()函数:
disconnect(btn, SIGNAL(clicked(bool)) , this, SLOT(classIsOver()));
槽可以被取消链接:
当一个对象delete之后,Qt自动取消所有连接到这个对象上面的槽。
2.一个信号和槽的例子
rxclass.h:
#ifndef RXCLASS_H
#define RXCLASS_H
#include<QDebug>
#include <QObject>
class RxClass:public QObject
{
Q_OBJECT
protected slots:
void mySlot(int v)
{
qDebug()<<"void myslot(int v)";
qDebug()<<"Sender:"<<sender()->objectName();
qDebug()<<"Receiver:"<<this->objectName();
qDebug()<<"Value:"<<v;
qDebug()<<endl;
}
};
#endif // RXCLASS_H
testsignal.h:
#ifndef TESTSIGNAL_H
#define TESTSIGNAL_H
#include <QObject>
class TestSignal:public QObject //只有Qt类才能定义信号
{
Q_OBJECT
public:
void send(int i)
{
emit testSignal(i); //通过emit关键字发送信号
}
signals:
void testSignal(int v);//信号只能声明不能定义
};
#endif // TESTSIGNAL_H
main.cpp:
#include "widget.h"
#include <QApplication>
#include<QDebug>
#include"rxclass.h"
#include"testsignal.h"
void emit_signal()
{
qDebug()<<"emit_signal()"<<endl;
TestSignal t;
RxClass r;
t.setObjectName("t");
r.setObjectName("r");
QObject::connect(&t, SIGNAL(testSignal(int)), &r, SLOT(mySlot(int)));
for(int i=0; i<3; i++)
{
t.send(i);
}
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
emit_signal();
return a.exec();
}
运行结果:
3.2 Lambda表达式
(待补充)
0x04 QMainWindow
一个主窗口提供构件应用程序的用户界面框架,该主窗口由QMainWindow以及相关类来管理。
QMainWindow 提供工具栏(toolbars)、菜单栏(menubar)以及多个铆接部件(dock widgets)、状态栏(statusbar)、中心部件(central widget)等的主应用程序窗口。
4.1 菜单栏(menu bar)
一个主窗口最多只有一个菜单栏。 菜单栏可以位于主窗口顶部或者二主窗口标题栏下。
·创建菜单栏,通过QMainWindow类的menubar()含糊获取主窗口菜单栏指针:
QMenuBar * menuBar() const;
·创建菜单,调用QMenu成员函数addMenu()添加:
QAction *addMenu(QMenu *menu);
QAction *addMenu(const QString &title);
QAction *addMenu(const QIcon &icon, const Qstring &title);
·创建菜单项,调用QMenu类成员函数addAction()添加:
QAction *activeAction() const;
QAction *addAction(const QString &text);
QAction *addAction(const QIcon &icon, const QString &text);
QAction *addAction(const QString &text, const QObject *receiver, const char *member, const QKeySequence & shortcut = 0);
QAction *addAction(const QIcon &icon, const QString &text, const QObject *receiver, const char *member, const QKeySequence & shortcut = 0);
Qt没有专门的菜单项类,只是使用一个QAction类抽象出公共的动作。当QAction对象添加到菜单便显示成一个菜单项,添加到工具栏,显示成一个工具按钮。用户通过点击菜单栏、工具栏按钮等来 激活这个动作。
4.2 工具栏(tool bars)
主窗口工具栏可以有多个工具栏。通常采用一个菜单对应一个工具条的方式或者根据需要对工具条进行划分。
·直接调用QMainWindow类的addToolBar()函数获取主窗口的工具条对象,每增加一个工具条则调用一次该函数:
void addToolBar(Qt::ToolBarArea area, QToolBar * toolbar);
void addToolBar(QToolBar * toolbar);
QToolBar *addToolBar(const QString & title);
工具条是一个可移动的窗口,它的停靠区由QToolBar类的addToolBar()以及setAllowedAreas()决定。停靠位置由Qt::ToolBarArea area枚举决定:
enum ToolBarArea {
LeftToolBarArea = 0x1, //停靠在左侧
RightToolBarArea = 0x2,//停靠在右侧
TopToolBarArea = 0x4, //停靠在顶部
BottomToolBarArea = 0x8,//停靠在底部
ToolBarArea_Mask = 0xf,
AllToolBarAreas = ToolBarArea_Mask, //四个位置 都可以停靠
NoToolBarArea = 0 //任何位置都不能停靠
};
·通过QToolBar类的addAction()插入属于工具条的动作,即在工具条上进行内容设置操作(注意和4.1节的addAction()函数相同但是不属于同一类):
QAction *addAction(const QString & text);
QAction *addAction(const QIcon & icon, const QString & text);
void addAction(QAction * action);
QAction *addAction(const QString & text, const QObject * receiver, const char * member);
QAction *addAction(const QIcon & icon, const QString & text, const QObject * receiver, const char * member);
使用QToolBar类setAllowedAreas()指定停靠区域。使用QToolBar类setMoveable()设定工具栏的是否可以移动。
4.3 状态栏(status bar)
状态栏也只能有一个。
void addWidget(QWidget *widget, int stretch = 0);//添加部件
int insertWidget(int index, QWidget *widget, int stretch = 0);//插入部件
void removeWidget(QWidget *widget);//删除部件
4.4 铆接部件(dock widgets)
铆接部件也称为浮动窗口,可以有多个:
QDockWidget *dock = new QDockWidget("标题", this);
addDockWidget(Qt::LeftDockWidgetArea, dock);
dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea | Qt::TopDockWidgetArea);
4.5 中心部件(central widget)
中心部件只能有一个。除了以上部件,中心显示的部件都可以作为核心部件,例如 一个记事本文件,可以利用QTextEdit作为中心部件。
QTextEdit *edit = new QTextEdit(this);
setCentralWidget(edit);
示例代码:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QMenuBar>
#include<QToolBar>
#include<QDebug>
#include<QPushButton>
#include<QStatusBar>
#include<QLabel>
#include<QDockWidget>
#include<QTextEdit>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
//ui->setupUi(this);
//重置窗口大小
resize(600, 400);
//菜单栏最多只能有一个
//菜单栏创建
QMenuBar *bar = menuBar();
//将菜单栏放入到窗口中
setMenuBar(bar);
//创建菜单
QMenu *fileMenu = bar->addMenu("File");
QMenu *editMenu = bar->addMenu("Edit");
QMenu *helpMenu = bar->addMenu("Help");
//创建菜单项
QAction *newAction = fileMenu->addAction("new");
//添加分隔符
fileMenu->addSeparator();
QAction *openAction = fileMenu->addAction("open");
//工具栏 可以有多个,Qt中所有枚举值用Qt::形式
QToolBar *toolBar = new QToolBar(this);
addToolBar(Qt::LeftToolBarArea,toolBar);
//后期设置 只允许左右停靠
toolBar->setAllowedAreas(Qt::LeftToolBarArea | Qt::RightToolBarArea);
//设置浮动
toolBar->setFloatable(false);
//设置移动(总开关)
toolBar->setMovable(false);
//工具栏中可以设置内容
toolBar->addAction(newAction);
toolBar->addSeparator();
toolBar->addAction(openAction);
//工具栏重添加控件
QPushButton *btn = new QPushButton("aa", this);
toolBar->addWidget(btn);
//状态栏 最多有一个
QStatusBar *stBar = statusBar();
//设置到窗口中
setStatusBar(stBar);
//放一些标签控件
QLabel *label = new QLabel("NOTICE", this);
stBar->addWidget(label);
QLabel *label2 = new QLabel("RIGHT NOTICE", this);
stBar->addPermanentWidget(label2);
//铆接部件(浮动窗口)可以有多个
QDockWidget *dockWidget = new QDockWidget("float", this);
addDockWidget(Qt::BottomDockWidgetArea, dockWidget);
//设置中心部件 只能有一个
QTextEdit *edit = new QTextEdit(this);
setCentralWidget(edit);
//设置后期停靠区域,只允许上下
dockWidget->setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea);
}
MainWindow::~MainWindow()
{
delete ui;
}
运行结果:
4.6 添加资源文件
Qt资源系统是一个跨平台的资源机制,用于将程序运行时需要的资源以二进制的形式存储于可执行文件内部。
若需将特定资源(图标、文本等)添加到程序中,则可以将资源以资源文件形式存储,则当程序编译后可以将资源编译到可执行文件内部。
在工程文件中,右键项目工程,选择“添加新文件”,找到Qt分类下的“Qt Resource File”:
点击“choose”按钮,选择需要添加的资源的路径和名称:
单击下一步直至完成,此时会看到QtCreator左侧文件列表会出现“资源文件”文件夹,里面有res.qrc是我们新建的资源文件:
此时界面右下方有一个“添加”,下拉添加,选择添加前缀,然后取名例如“/new/prefix1”,然后选择这个前缀,点击添加文件,选择需要添加资源文件完成添加:
需要添加的文件:
添加完成后效果:
添加Qt资源: :+ 前缀名 + 文件名
//添加Qt资源“: + 前缀名 + 文件名 ”
ui->actionNew->setIcon(QIcon(":/new/prefix1/image/Luffy.png"));
ui->actionOpen->setIcon(QIcon(":/new/prefix1/image/OnePiece.png"));
运行效果:
完整示例代码:
main.cpp:
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//添加Qt资源“: + 前缀名 + 文件名 ”
ui->actionNew->setIcon(QIcon(":/new/prefix1/image/Luffy.png"));
ui->actionOpen->setIcon(QIcon(":/new/prefix1/image/OnePiece.png"));
}
MainWindow::~MainWindow()
{
delete ui;
}
mainwindow.ui:
0x05 对话框QDialog
对话框时GUI程序中不可或缺的组成部分。Qt为应用程序设计提供 了一些常用的标准对话框,打开文件对话框,信息提示框、选择确认对话框、标准输入对话框等。对话框通常回事一个顶层窗口,出现在程序最上层,用于实现短期任务或者完成用户交互。
Qt中使用QDialog类实现对话框。和主窗口一样,会存在一个类继承QDialog。QDialog及其子类对于其parent指针都有额外含义:若parent为NULL则该对话框会作为一个顶层窗口,顶层窗口在任务栏会有自己的位置;若parent非空则作为其父组件的子对话框。
5.1模态对话框与非模态对话框
模态对话框:弹出时会阻塞同一应用程序中其他窗口的输入。
存在两种级别的模态对话框:
1)应用程序级别模态:
该模态对话框出现时,用户必须首先对对话框进行交互,直到关闭对话库昂,然后才能访问程序中其他的对话框。
2)窗口级别模态:
该模态仅仅阻塞与对话框有关联的窗口,但是依然允许用户与程序中其他窗口进行交互。窗口级别的模态尤其适用于多窗口模式。
一般程序默认的是应用级别的模态。
调用方法:
QDialog dialog;
……
dialog.exec();
代码示例:
main.cpp:
#include "mainwindow.h"
#include <QApplication>
#include <QTextCodec>
int main(int argc, char *argv[])
{
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include"QDialog"
#include"QDebug"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//点击新建按钮,弹出对话框
connect(ui->actionNew,SIGNAL(triggered(bool)), this, SLOT(Dialogshow()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::Dialogshow()
{
//模态创建
QDialog dlg(this);
dlg.exec();
qDebug() << "模态对话框弹出";
}
mainwindow.ui:
非模态对话框:可以在弹出时可以对同一应用中其他窗口进行操作。
调用方法:
QDialog *dialog = new QDialog;
dialog->setAttribute(Qt::WA_DeleteOnClose);
……
dialog.show();
main.cpp:
#include "mainwindow.h"
#include <QApplication>
#include <QTextCodec>
int main(int argc, char *argv[])
{
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include"QDialog"
#include"QDebug"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//点击新建按钮,弹出对话框
connect(ui->actionNew,SIGNAL(triggered(bool)), this, SLOT(Dialogshow()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::Dialogshow()
{
QDialog *dlg2 = new QDialog(this);//防止一闪而过
dlg2->setAttribute(Qt::WA_DeleteOnClose);//关闭时释放对象
dlg2->show();
qDebug() << "非模态对话框弹出";
}
mainwindow.ui:
5.2 消息对话框
错误对话框 :
#include<QMessageBox>
QMessageBox::critical(this, "critical ", "错误");
信息对话框(图略):
#include<QMessageBox>
QMessageBox::Information(this , "info", "信息");
提问对话框(图略):
#include<QMessageBox>
QMessageBox::question(this, "question", "提问");
警告对话框(图略):
#include<QMessageBox>
QMessageBox::warning(this, "waring", "警告");
0x06 界面布局
0x07 控件
1.1标准控件
main.cpp:
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
widget.h:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include<QDebug>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private:
Ui::Widget *ui;
private slots:
void PRINTwoman(void){
qDebug() << "woman";
}
void PRINTprice(){
qDebug() << "price";
}
};
#endif // WIDGET_H
widget.cpp:
#include "widget.h"
#include "ui_widget.h"
#include<QRadioButton>
#include<QCheckBox>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
//设置按钮默认选项
ui->RBMan->setChecked(true);
//选中后,打印信息
QObject::connect(ui->RBWoman, SIGNAL(clicked()), this,SLOT(PRINTwoman()));
QObject::connect(ui->price, SIGNAL(clicked()), this,SLOT(PRINTprice()));
}
Widget::~Widget()
{
delete ui;
}
widget.ui:
运行效果:
1.2 自定义控件封装
在搭建一个Qt项目时,项目会有很多窗口,有些窗口或模块会被重复使用,遇到这种情况通常会将窗口和模块独立出一个窗口类,以备重复使用。
在Qt中使用ui搭建界面,工具栏提供控件有时候不能满足自己的需要,此时需要自己定义控件。
一种实现方法是从QWidget派生出一个SmallWidget类,在该类中实现自定义控件,例如:
1.新建一个Qwidget项目;
2.添加新文件:Qt->设计师界面类:
界面模板选择widget,类名命名为smallwidget:
3.在smallwidget.ui中设计QSpinBox和QSlider两个控件:
4.在Widget.ui中拖拽widget,点击提升为,点击添加,添加名为smallwidget,点击提升;拖拽两个pushbutton:
5.实现功能,通过改变数字使滑动条移动,通过按钮改变及获取数字值,使用信号和槽监听:
smallwidget.cpp:
#include "smallwidget.h"
#include "ui_smallwidget.h"
smallwidget::smallwidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::smallwidget)
{
ui->setupUi(this);
//QSpinBox移动 QSlider跟着移动
QObject::connect(ui->spinBox, SIGNAL(valueChanged(int)), ui->horizontalSlider, SLOT(setValue(int)));
//QSlider移动 QSpinBox跟着移动
QObject::connect(ui->horizontalSlider, SIGNAL(valueChanged(int)), ui->spinBox, SLOT(setValue(int)));
}
void smallwidget::setNum(int num)
{
ui->spinBox->setValue(num);
}
int smallwidget::getNum()
{
return ui->spinBox->value();
}
smallwidget::~smallwidget()
{
delete ui;
}
widget.cpp:
#include "widget.h"
#include "ui_widget.h"
#include<QTextCodec>
#include<QDebug>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
QTextCodec::setCodecForCStrings( QTextCodec::codecForName("UTF-8"));
//点击获取当前值
QObject::connect(ui->btn_get, SIGNAL(clicked(bool)),this,SLOT(GetValue()));
//设置一半值
QObject::connect(ui->btn_set_half, SIGNAL(clicked(bool)),this,SLOT(SetValue()));
}
void Widget::GetValue()
{
qDebug() << ui->widget->getNum();
}
void Widget::SetValue()
{
ui->widget->setNum(50);
}
Widget::~Widget()
{
delete ui;
}
运行效果:
0x08 Qt消息机制
1.1 事件
事件(event)是由系统或者Qt本身在不同时刻发出的。当用户按下鼠标或键盘都会触发一个相应的事件。一些事件在对用户操作做出响应时发出,一些事件由系统自动发出,例如计时器。
当事件发生时,Qt将创建一个事件对象,Qt中所有的事件类都继承于QEvent。 事件对象创建完毕后,Qt将这个事件对象 传递给 QObject的event()事件。event()函数不直接处理事件,而是按照时间对象的类型分派给特定的事件处理函数(event handler)。
在所有组件的父类QWidget中,定义了很多事件处理的回调函数,如:
keyPressEvent()
keyReleaseEvent()
mouseDoubleClickEvent()
mouseMoveEvent()
mousePressEvent()
mouseReleaseEvent()
这些函数都是 protected virtual 的,也就是说,我们可以在子类中重新实现这些函数。
新建Qt widget项目,然后添加新文件,类型为C++ ->C++class,命名为mylabel.cpp,然后ui界面拖拽lable,提升为mylabel:
#include "mylabel.h"
#include<QDebug>
#include<QLabel>
#include<QMouseEvent>
#include<QString>
mylabel::mylabel(QWidget *parent) : QLabel(parent)
{
//设置鼠标追踪状态
setMouseTracking(true);
}
//鼠标进入事件
void mylabel::enterEvent(QEvent *event)
{
//qDebug()<<"in";
}
//鼠标离开事件
void mylabel::leaveEvent(QEvent*)
{
//qDebug()<<"out";
}
//鼠标按下
void mylabel::mousePressEvent(QMouseEvent *ev)
{
//鼠标左键按下 提示信息
// if(ev->button() == Qt::LeftButton)
// {
QString str = QString("Press:press x=%1 y=%2").arg(ev->x()).arg(ev->y());
qDebug()<<str;
// }
}
//鼠标释放
void mylabel::mouseReleaseEvent(QMouseEvent *ev)
{
qDebug()<<"Release";
}
//鼠标移动
void mylabel::mouseMoveEvent(QMouseEvent *ev)
{
// if(ev->buttons() & Qt::LeftButton)
// {
QString str = QString("Move:press x=%1 y=%2").arg(ev->x()).arg(ev->y());
qDebug()<<str;
// }
}
运行效果:
1.2 定时器
1.利用事件void timerEvent(QTimerEvent *);
2.启动定时器startTimer(1000);
3.timerEvent()的返回值是定时器唯一标识,可以和ev->timerId()比较。
对1.1中程序修改:
widget.h:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
//重写定时器事件
void timerEvent(QTimerEvent *);
int id1;// 定时器1唯一标识
int id2;// 定时器2唯一标识
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
widget.cpp:
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
//启动定时器
id1 = startTimer(1000);//参数1 间隔 单位是毫秒
id2 = startTimer(2000);//参数1 间隔 单位是毫秒
}
void Widget::timerEvent(QTimerEvent *ev)
{
if(ev->timerId() == id1)
{
//每隔1秒
static int num = 1;
ui->label_2->setText(QString::number(num++));
}
if(ev->timerId() == id2)
{
//每隔2秒
static int num2 = 1;
ui->label_3->setText(QString::number(num2++));
}
}
Widget::~Widget()
{
delete ui;
}
运行效果:
也可以利用定时器类QTimer:
1.创建定时器对象QTimer * timer = new QTimer(this);
2.启动定时器timer->start(毫秒);
3.间隔一定时间发送信号timeout;
4.暂停timer->stop。
以上。
参考文档
0x01节:
1.https://www.bilibili.com/video/BV1g4411H78N?p=2
2.http://c.biancheng.net/view/1792.html
3.https://www.cryfeifei.cn/2020/06/28/guan-yu-qt-de-li-shi/
0x02节:
1.Qt基础教程V2.0
2.https://blog.csdn.net/qq_34139994/article/details/105391611
3.https://www.bilibili.com/video/BV1g4411H78N?p=6
4.https://www.bilibili.com/video/BV1g4411H78N?p=7
5.https://blog.csdn.net/liang19890820/article/details/50533262
0x03节:
1.Qt基础教程V2.0
2.http://c.biancheng.net/view/1823.html
3.https://blog.csdn.net/small_prince_/article/details/96106202
4.https://www.bilibili.com/video/BV1g4411H78N?p=10
5.https://www.bilibili.com/video/BV1g4411H78N?p=12
0x04节:
1.Qt基础教程V2.0
2.https://www.bilibili.com/video/BV1g4411H78N?p=17
3.https://www.bilibili.com/video/BV1g4411H78N?p=18
0x05节:
1.Qt基础教程V2.0
2.http://c.biancheng.net/view/1870.html
3.https://www.bilibili.com/video/BV1g4411H78N?p=19
4.https://www.bilibili.com/video/BV1g4411H78N?p=20
5.https://www.bilibili.com/video/BV1g4411H78N?p=21
6.https://www.bilibili.com/video/BV1g4411H78N?p=22
7.https://www.bilibili.com/video/BV1g4411H78N?p=23
0x06节:
1.Qt基础教程V2.0
2.https://www.bilibili.com/video/BV1g4411H78N?p=24
0x07节:
1.Qt基础教程V2.0
2.https://www.bilibili.com/video/BV1g4411H78N?p=24
3.https://www.bilibili.com/video/BV1g4411H78N?p=25
4.https://www.bilibili.com/video/BV1g4411H78N?p=26
5.https://www.bilibili.com/video/BV1g4411H78N?p=27
6.https://www.bilibili.com/video/BV1g4411H78N?p=28
7.https://www.bilibili.com/video/BV1g4411H78N?p=29
8.https://www.bilibili.com/video/BV1g4411H78N?p=30