创建第一个QT项目
1、工程名无特殊符号和中文
2、路径无中文
3、
QMainWindow 带菜单栏的的窗口
QWidget 空白窗口
QDialog 对话框窗口
4、创建类的类名要大写
Qt项目框架及文件介绍
QT += core gui //包含模块
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets //大于Qt4版本才有此模块
.pro文件 工程文件,是qmake自动生成,用于生成makefile的配置文件
//应用程序对象,在QT中,应用程序对象 有且仅有一个
//整个后台管理的命脉,处理应用程序的初始化和结束,事件处理调度,注意不管有多少窗口,一个QApplication
QApplication a(argc, argv);
//让应用程序对象进入消息循环
//让代码阻塞到这行,主事件循环,在exec函数中,Qt接受并处理用户和系统的事件并且将他们传递给适当的窗口
return a.exec();
确定代码书写位置
.pro:用于生成可执行文件
main.cpp:主函数
widget.cpp:类的函数
一般情况,窗口的属性和添加控件和对控件的操作都会在类的构造函数中书写
优点:可以让主程序中无多余代码,程序阅读也方便
widget.h:类和头文件
帮助手册
对应的类
类的头文件、组件、基类、派生类
//修改窗口的标题(第一个窗口)
this->setWindowTitle("")
//设置窗口的大小,设置完成可以拉伸
this->resize(int w,int h);
//设置固定大小,不可拉伸
this->setFixedSize(int w,int h);
按钮
头文件
#include <QPushButton>
QT += Widgets
QPushButton *button = new QPushBotton;
//设置按钮的父对象为窗口
button->setParent(this);
设置按钮属性
//设置按钮内容
button->setText("第一个按钮");
//设置按钮的显示位置
button->move(100,100);
//设置按钮的大小
button-> setFixedSize(400,400);
创建按钮方式
QPushButton *button = new QPushBotton("第二个按钮",this);
对象树
概念:Qt对象间的父子关系
解决问题:在一定程度上解决了内存问题,简化内存回收
构件会指向它的父亲
当父亲析构的时候,就会先析构children构建
使用注意:
栈一般先构造后析构
该段代码无问题:
QWidget window;
QPushButton button = QPushButton ("退出",&window);
该段代码无问题:(重复析构)
下面的程序先虚构window,析构window及window子对象quit,然后析构quit
QPushbutton quit("quit");
QWidget window;
quit.setParent(&window);
Qt窗口坐标体系
嵌套窗口是基于父窗口来说
信号与槽
connect函数
connect(信号发出者,信号,信号接受者,接收到信号执行任务(槽函数))
帮助手册中的 类中的Public Slots 和 Signals
信号:
槽函数:
close()等
自定义信号与槽
分析场景
小哥敲门 家人开门
添加所需要的类
信号一般写在signals中,返回值一般为void, 参数可以存在,仅声明不需要实现,可以重载
槽函数一般写在slots/public/全局中,返回值一般为void, 参数可以存在,声明并需要实现,可以重载
连接信号与槽后,需要去触发信号
发送信号 emit xiaoge->qiaodoor();
重载自定义信号与槽
步骤1:重写信号声明(带参数)
void qiaodoor(QString name);
步骤2:重写槽函数声明与定义(带参数)
void treat(QString name);
void family::treat(QString name)
{
qDebug().nospace()<<"开门,我的"<<name.toUtf8().data();
}
步骤3:由于函数重载了,所以需要利用函数指针指向
void (Waimai::*qiao)(QString name) = &Waimai::qiaodoor;
void (family::*treat_)(QString name) = &family::treat;
connect(xiaoge,qiao,mother,treat_);
将QString ->(toUtf8) QByteArray ->(data) char *
注意事项
1、发送者与接受者需要时QObject的子类(槽函数全局变量,lambda除外)
2、信号和槽函数返回值都是void
3、信号需要声明,不需要定义实现,槽函数需要声明也需要定义实现。
4、槽函数是普通的成员函数,作为成员函数,会受到public/private/protected的影响
5、使用emit在恰当的位置发送信号
6、使用connect()函数连接信号和槽
7、任何成员函数、static函数、全局函数和Lambda表达式都可以作为槽函数
8、信号槽要求信号和槽的参数一致,所谓一致,是参数类型一致。
如果信号和槽的函数不一致,允许的情况是,槽函数的参数可以比信号的少,即便如此,槽函数存在的那些参数的顺序也必须和信号前面几个一致起来。因为,可以在槽函数中选择忽略信号传来的数据(也就是槽函数的参数比信号的少)
举例:
signal(QString) 和 slot(QString) √
signal(QString,QString) 和 slot(QString) √
signal(QString) 和 slot(QString,QString) ×
signal(QString,QString,int) 和 slot(QString,QString) √
signal(QString,QString,int) 和 slot(QString,int) √
扩展:
1、信号与槽可以一对一,一对多(发出信号,槽函数一个一个执行,顺序不确定),多对一(任意信号发出,槽函数都会执行 )
2、信号可以连接信号
3、槽可以被断开连接(disconnect),槽也可以被取消连接(当一个对象delete了,取消这个对象上的槽)
4、使用lambda表达式
Lambda表达式
概念:C++11中的Lambda表达式用于定义并创建匿名的函数对象
语法
[capture](parameters) mutable -> return-type {statement}
[]是引出符,capture是捕获列表,捕获的是那些定义Lambda为止时Lambda所在作用范围内可见的局部变量
空 没有使用任何函数对象参数
= 函数体内可以使用Lambda所在作用范围内所有可见的局部变量,值传递
& 函数体内可以使用Lambda所在作用范围内所有可见的局部变量,引用传递
a 将a按值进行传递
&a 将a按引用进行传递
this 函数体内可以使用Lambda所在类中的成员变量
a,&b 将a按值进行传递,b按引用进行传递
=,&a,&b 除a和b按引用进行传递外,其他参数都按值进行传递
&,a,b 除a和b按值进行传递外,其他参数都按引用进行传递
(parameters) 参数列表,与普通函数的参数列表一致的。
mutable可修改标示符,按值传递函数对象参数时,加上mutable修饰后,可以修改按值传递进来的拷贝
->return-type 返回值类型
(statement) 函数体,内容跟普通函数一致
1、[]标识一个Lambda的开始,这部分必须存在,不能省略
2、()参数列表,如果不需要传递参数的话,()可以一同省略
3、如果使用mutable,参数列表()不能省略的即使参数为空;如果使用mutable,修改拷贝,而不是值本身
4、返回值类型,如果不需要,->return-type 都可以省略。
5、{函数体},可以使用参数列表,也可以使用捕获列表
使用
int m = 10;
auto fun = [m](int a,int b)mutable{
qDebug() << "lambda is runnig";
m = 300;
return a * b;
}
int sum = fun(100, 200);
qDebug()<<sum;
如果没有 mutable 的话,不能对m(值传递)的值进行修改
槽函数一般可用lambda表达式
QMainWindow
包含一个菜单栏(menu bar)、多个工具栏(tool bars)、多个铆接部件(dock widgets)、一个状态栏(status bar)及一个中心部件(central widget)
菜单栏
菜单栏类QMenuBar:
菜单类QMenu:
QAction:充当子菜单(菜单项)
//创建菜单栏
QMenuBar *menubar = new QMenuBar(this);
this -> setMenuBar(menubar);
//创建菜单
QMenu *menu1 = new QMenu("文件");
QMenu *menu2 = new QMenu("编辑");
QMenu *menu3 = new QMenu("构建");
menubar->addMenu(menu1);
menubar->addMenu(menu2);
menubar->addMenu(menu3);
//创建菜单项
QAction *act1 = new QAction("打开文件");
QAction *act2 = new QAction("另存为");
QAction *act3 = new QAction("关闭文件");
menu1->addAction(act1);
menu1->addAction(act2);
menu1->addAction(act3);
另外一种创建菜单栏的方式(成员函数)
QMenuBar *menubar = menubar();
点击菜单项,实现对应的功能
connect(act3,&QAction::triggered,this,&QMainWindow::close);
工具栏
//创建工具栏
QToolBar *toolBar = new QToolBar(this);
this->addToolBar(toolBar);
QAction *act4 = new QAction("工具");
toolBar->addAction(act1);
toolBar->addAction(act2);
toolBar->addAction(act3);
toolBar->addAction(act4);
//修改工具栏不可以移动(默认可上下左右移动)
toolBar -> setMovable(false);
//修改工具栏可以停靠的区域
toolBar->setAllowedAreas(Qt::LeftToolBarArea|Qt::RightToolBarArea);
//设置工具栏的浮动状态
toolBar->setFloatable(false);
状态栏
//创建状态栏
QStatusBar *statusbar = statusBar();
//QStatusBar *statusbar = new QStatusBar(this);
this -> setStatusBar(statusbar);
信息分为临时信息、正式信息和永久信息
//增加临时信息
statusbar -> showMessage("页面显示成功", 3000);
//增加正式信息(一般位于状态栏左侧)
QLabel *label1 = new QLabel("打开文件",this);
statusbar -> addWidget(label1);
//增加永久信息(一般位于状态栏右侧)
QLabel *label2 = new QLabel("Ysk",this);
statusbar -> addPermanentWidget(label2);
铆接部件(浮动窗口)
铆接部件QDockWidget:
//创建铆接部件
QDockWidget *dockWidget = new QDockWidget("first",this);
this -> addDockWidget(Qt::RightDockWidgetArea,dockWidget);
核心部件(中心部件)
//创建记事本作为核心部件
QTextEdit *edit = new QTextEdit("文本编辑器",this);
this -> setCentralWidget(edit);
资源文件
加载图片
步骤1:新增资源文件(右键工程新增资源文件)
步骤2:给资源文件添加前缀
步骤3:给资源文件增加资源(图片)
步骤4:起别名(选用)
1、给菜单栏加载图片
//给菜单栏增加图片
//创建图片控件
QPixmap pix;
//选择图片
pix.load(":/icon/download.png");
//给菜单项设置图片
act1->setIcon(QIcon(pix));
2、增加背景图
this->setFixedSize(800,600);
this->setAutoFillBackground(true);
//创建图片控件
QPixmap pix1 = QPixmap(":/icon/add.png").scaled(this->size());
//pix1.load(":/icon/add.png")
QPalette palette;//调色板类
palette.setBrush(QPalette::Background,QBrush(pix1));
this->setPalette(palette);
UI
ui功能:绘制界面(通过拖拽使用)
Layouts 布局
Spacers 固定弹簧
Buttons 按钮
Item Views(Model-Based) 列表视窗/窗
Item Widgets(Item-Based)
Containers 容器
Input Widgets 输入窗
Display Widgets 显示窗
QDialog
对话框:很多不能或者不适合放入主窗口的功能组件都必须放在对话框中设置
分类:
模态对话框:阻塞同一应用程序中其他窗口的输入
非模态对话框:不阻塞同一应用程序中其他窗口的输入
自定义QDialog对话框
模态对话框:
QDialog dialog;
dialog.setWindowTitle("Hello dialog!");
dialog.exec();//或者用 open()
非模态对话框:
QDialog *dialog = new QDialog;
dialog->setWindowTitle(tr("Hello,dialog!"));
dialog->show();
对话框要创建在堆上,在栈上会一闪而过
由于对话框的特性,可以设置对话框关闭 自动销毁对话框
标准对话框:
内置对话框,不用重复造轮子
QColorDialog 选择颜色
QFileDialog 选择文件或目录
QFontDialog 选择字体
QInputDialog 允许用户输入一个值,并将其值返回
QMessageBox 模态对话框,用于显示信息、询问问题等
QPageSetupDialog 为打印机提供纸张相关的选项
QPrintDialog 打印机配置
QPrintPreviewDialog 打印预览
QProgressDialog 显示操作过程
文件对话框
//打开一个文件
QString filename = QFileDialog::getOpenFileName(this,tr("打开文件"),"./",tr("Images(*.png,*.xpm,*.jpg);;Text(*.txt)"));
if(!filename.isEmpty())
ui->plainTextEdit->appendPlainText(filename);
//打开多个文件
QStringList filename =QFileDialog::getOpenFileNames(this,tr("打开文件"),"./",tr("Images(*.png,*.xpm,*.jpg);;Text(*.txt)"));
for(int i = 0; i <filename.size(); ++ i )
ui->plainTextEdit->appendPlainText(filename.at(i));
总结:
1、文件对话框使用,参考帮助文档
2、getOpenFileName,getOpenFileNames参数:父类对象指针,文件对话框的标题,打开文件路径,文件过滤器
3、文件过滤器写法:
"Images(*.png, *.xpm, *.jpg)"
"Images(*.png, *.xpm, *.jpg);;Text( *.txt)"
颜色对话框
QColorDialog::getColor 生成颜色对话框
//生成颜色对话框,设置颜色,设置编辑器字体颜色
QPalette pal = ui->plainTextEdit->palette();//获取现有palettle
QColor initColor = pal.color(QPalette::Text);//现有文字颜色
QColor color = QColorDialog::getColor(initColor,this,"选择颜色");
//判断选择颜色是否有效,如果有效设置编辑器字体颜色
if(color.isValid())
{
pal.setColor(QPalette::Text,color);
ui->plainTextEdit->setPalette(pal);
}
总结:
1、颜色对话框使用,参考帮助文档
2、getColor生成颜色对话框,返回值是一个颜色变量,如果在颜色对话框选择取消,返回值无效,反之有效
字体对话框
QFontDialog::getFont 生成选择字体的对话框
bool flag;
QFont initFont = ui->plainTextEdit->font();
QFont font = QFontDialog::getFont(&flag,initFont,this);
if(flag)
{
ui->plainTextEdit->setFont(font);
}
总结:
1、选择字体对话框使用,参考帮助文档。
2、getFont生成选择字体对话框,返回值不能判断有效,一般是根据getFont的第一个参数逻辑变量是否为true
消息对话框
//错误弹窗
QMessageBox::critical(this,"错误消息对话框","error");
//警告弹窗
QMessageBox::warning(this,"警告消息对话框","warning");
//消息弹窗
QMessageBox::information(this,"消息对话框","app is running",QMessageBox::Ok,QMessageBox::No);
//消息选择弹窗
QMessageBox::StandardButton result;
result = QMessageBox::question(this,"选择消息框","文件已修改,是否保存",QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel,QMessageBox::NoButton);
if(result == QMessageBox::Yes)
qDebug()<<"文件已保存";
else if(result == QMessageBox::No)
qDebug()<<"文件未保存";
else
qDebug()<<"取消操作";
输入对话框
QInputDialog:: 输入文本/整型数据/浮点型数据对话框
//生成输入文字对话框
bool ok;
QString text = QInputDialog::getText(this,"输入文字对话框","请输入文字",QLineEdit::Normal,"demo",&ok);
if(ok && !text.isEmpty())
{
ui->plainTextEdit->appendPlainText(text);
}
布局
Qt提供了两种组件定位机制:绝对定位和布局定位
绝对定位:需要提供组件的长高,坐标值。
布局定位:需要指定使用哪种布局(垂直、水平、网状、表格)
布局分类:
系统自带的四种布局,一般不使用。
widget中的四种布局,一般使用。
使用
登录页面绘制
登录页面->主页面 and 主页面->登录页面
this->mainwindows = new Mainwindows;
connect(ui->pushButton,&QPushButton::clicked,[=](){
this->hide();
this->mainwindows->show();
});
connect(this->mainwindows,&Mainwindows::back,this,[=](){
this->mainwindows->hide();
this->show();
});
QLabel
创建标签:
代码
QLabel *label = new QLabel(this);
UI
直接拖拽
显示文字/html
label->setText("这是代码创建的标签");
ui->label->setText("hahahahaha");
ui->label->setText("<h1><a href=\"https://www.gxu.edu.cn\">广西大学</a></h1>");
ui->label->setOpenExternalLinks(true);
显示图片
QPixmap pixmap;
pixmap.load(":/image/111.jpg");
ui->label_image->setPixmap(pixmap);
显示动图
QMovie *move = new QMovie(":/image/scan.gif");
ui->label_gif->setMovie(move);
move->start();
connect(ui->pushButton,&QPushButton::clicked,[=](){
move->stop();
});
QLineEdit(编辑框)
创建QLineEdit
代码
QLineEdit *lineEdit = new QLineEdit(this);
UI
拖拽生成
设置内容
lineEdit->setText("代码创建的编辑框");
ui->lineEdit->setText("UI创建的编辑框");
获取内容
QString str = ui->lineEdit->text();
qDebug()<<str.toUtf8().data();
设置显示模式(显示,不显示,密码)
ui->lineEdit->setEchoMode(QLineEdit::Password);
设置显示的文本与输入框上下左右边界的间隔的像素数
ui->lineEdit->setTextMargins(100,0,0,0);
自定义控件
重复性使用的窗口或窗口中的模块
将自定义控件提升为全局
其他控件:
spinBox 整型数字
horizontalSlider 滑动条
栈容器
可以进行翻页
事件描述
事件:
由系统或Qt本身在不同的时刻发出的
事件经过以下阶段:事件派发->事件过滤器->事件分发->事件处理
事件循环开始:exec()函数
重写窗口关闭/窗口重新设置大小事件
新增一个类继承于QWidget(新建工程)
子类.h中声明重写事件函数
void closeEvent(QCloseEvent *event);
void resizeEvent(QResizeEvent *event);
子类.cpp中去实现函数
void Widget::closeEvent(QCloseEvent *event)
{
int res = QMessageBox::question(this,"提示","您确定要关闭窗口吗?");
if(res == QMessageBox::Yes)
event -> accept();
else event -> ignore();
}
void Widget::resizeEvent(QResizeEvent *event)
{
qDebug()<<"Oldsize = "<<event->oldSize();
qDebug()<<"Newsize = "<<event->size();
}
鼠标按下、释放、移动
新建label类继承QLabel(新建工程,ui绘制label,新增c++类继承QWidget,代码修改继承QLabel,ui绘制label提升新创建label类)
在myLabel.h声明事件函数
void mouseMoveEvent(QMouseEvent *ev);
void mousePressEvent(QMouseEvent *ev);
void mouseReleaseEvent(QMouseEvent *ev);
在myLabel.cpp实现事件函数
void myLabel::mouseMoveEvent(QMouseEvent *ev)
{
qDebug()<<"鼠标在标签中移动了 ("<<ev->x()<<","<<ev->y()<<")"
<<"全局位置:("<<ev->globalX()<<","<<ev->globalY()<<")";
QString str;
str.sprintf("<center><h1>(%d,%d)</h1><center>",ev->x(),ev->y());
this->setText(str);
}
void myLabel::mousePressEvent(QMouseEvent *ev)
{
if(ev->button() == Qt::LeftButton )
qDebug()<<"鼠标左键按下";
else if(ev->button() == Qt::RightButton)
qDebug()<<"鼠标右键按下";
else
qDebug()<<"鼠标其他键按下";
}
void myLabel::mouseReleaseEvent(QMouseEvent *ev)
{
qDebug()<<"鼠标在标签中被释放了";
}
重写事件分发函数
.h声明函数
bool event(QEvent *event);
.cpp实现event
bool Widget::event(QEvent *event)
{
//判断事件类型
if(event->type() == QEvent::KeyPress)
{
//将QEvent类型的event转换类型为QKeyEvent
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if(keyEvent->key() == Qt::Key_Tab)
{
qDebug()<<"Tab被按下";
return true;
}
}
return QWidget::event(event);
}
注意:
1、事件分发函数的返回值bool。
2、处理了自己所需要处理的对象后返回true,其他事件,则需要调用父类的event()函数继续转发,否则这个组件就只能处理我们定义的事件。
事件总结
事件处理有以下四个过程:
事件处理:重写鼠标按下事件、鼠标释放事件,这个是最简单的形式及功能。
事件分发:重新event函数。
事件过滤:重写eventFilter,过滤特定对象的事件,或者所有对象的所有事件(QCoreApp/lication::instance)。
事件派发:QCoreApp/lication::notify
画笔
QPainter:画笔
QPainterDevice:绘图设备(纸张、墙壁)
QPaintEngine:画笔(QPainter)在不同的设备上进行绘制的统一的接口(一般不考虑)
void Widget::paintEvent(QPaintEvent *event)//页面加载,update
{
qDebug()<<"11111";
QPainter painter(this);
painter.drawLine(20,20,400,400);
painter.setPen(Qt::green);
painter.drawRect(10,10,100,400);
painter.setPen(QPen(Qt::blue,5));
painter.drawEllipse(0,0,400,200);//(起点x,y,长,宽)
}
绘图设备QPainterDevice
常见的绘图设备:
QPixmap专门为图像在屏幕上的显示做了优化
QBitmap是QPixmap的一个子类,它的色深限定为1,可以使用QPixmap的isQBitmap()函数来确定这个QPixmap是不是一个QBitmap
QImage专门为图像的像素级访问做了优化
QPicture则可以记录和重新QPainter的各条命令