添加按钮之前先包含头文件,在widget.h中#include
,第一个字母都是Q。继续在private:下面添加如下代码。
private:
QPushButton b1;//可以直接使用
QPushButton *b2;//不能直接使用。空指针,需要实际的内存。
//按钮进行初始化,实例化,实例化的2种方式。
b2 = new QPushButton("hello,qt");
//b2->setText("hello,qt");
b2->show();
界面如图所示,未达到预期效果,因为窗口2没有依附窗口1。
如果窗口需要依附另外一个窗口,需要给该窗口指定一个父类。让他依附于谁就把窗口类传给他。
b2 = new QPushButton("hello,qt",this);
用第一种方式创建按钮,没有用.show();也出现了
父窗口显示的时候,子窗口也会随之显示。如果有100个窗口还要show100次,但是指定了this这个父类,子类就不需要show了。但是出现了hello qt被覆盖了,于是我们要改变按钮的位置。得出结论,窗口的坐标系原点在左上角,X轴向右递增,Y轴向下递增。
QT中的对象树。析构顺序和构造的顺序相反。QT的内存回收机制:1、使用的类是直接或者间接从QObject的派生。2、类在创建对象的时候指定父对象,在析构的时候首先析构子类对象。
添加新文件不改变参数类型只改变父类对象。并且在头文件中添加析构函数。
析构过程:在widget.h中创建对象,之后运行项目。
运行结果如图所示。
关闭UI界面的时候,默认被释放。
对于类来说,直接按下F1进入帮助文档,对于类的函数来说,指定完成参数之后按下F1进入帮助文档。
设置窗口的标题,在widget下用this指针指向本作用域。也可以在main函数中对窗口标题进行设置,直接用到w.resize(),w.setWindowTitle()函数。
//设置窗口的标题
this->setWindowTitle("环境监测系统");
//设置固定的宽度和高度
this->setFixedSize(200,300);
//设置窗口图标
this->setWindowIcon(QIcon("D:\\1.png"));
点击一下b1按钮关闭对象。函数剖析:
信号和槽都是函数,1、信号只有函数声明没有函数定义。
2、槽函数需要声明也需要定义。只是个回调函数。
//需求 b1 关闭窗口
//connect (b1,发出信号,this,处理槽函数);
connect (&b1,&QPushButton::clicked,this,&Widget::close);
更换需求:当按下b1的时候b2的显示内容改变。
槽函数的特性:
/*自定义槽函数
*1、槽函数在Qt5中可以任意成员函数,全局函数,静态函数 lambda表达式(隐式函数)
*2、槽函数需要与信号对应(返回值和参数)
*3、信号是没有返回值的,槽函数的返回值是:void
*4、void mysig(int,double,qstring);
* void mtslot(int double qstring);
*5、槽函数的信号是为了接收信号传过来的数据。
*6、槽函数的参数是不能够大于信号的参数个数,可以少于信号的参数个数。
*7、槽函数可以重载。
*/
功能实现:在widget中添加声明,之后再在widget.cpp中完成函数实现。
更换需求:仅仅显示一个界面。
重新添加一个subwidget.cpp和subwidget.h。在头文集中声明QpushButton,在CPP文件中实现。在主窗口中包含头文件。子窗口初始化代码:
Subwidget::Subwidget(QWidget *parent) : QWidget(parent)
{
b1 = new QPushButton("中腾",this);
b1->resize(100,100);
setWindowTitle("软件园窗口");
resize(400,600);
}
主窗口头文件包含代码:
QPushButton *b3; //作用显示子窗口
//子窗口的对象
Subwidget subW;
主窗口cpp文件包含代码:
//b3显示子窗口Subwidget --subW
b3 = new QPushButton("软件园",this);
b3->resize(150,150);
b3->move(200,200);
//注意这里是创建的指针类型的b3不需要取地址符。
connect(b3,&QPushButton::clicked,this,&Widget::slotHindMe);
然后从中腾返回主窗口的实现。要发送一个信号回到主窗口。
Subwidget::Subwidget(QWidget *parent) : QWidget(parent)
{
b1 = new QPushButton("中腾",this);
b1->resize(100,100);
setWindowTitle("软件园窗口");
resize(400,600);
//给主窗口发送信号
connect(b1,&QPushButton::clicked,this,&Subwidget::myslot);
}
void Subwidget::myslot()
{
//发送信号
emit sigSub();
}
在主窗口widget中实现:
connect(&subW,&Subwidget::sigSub,this,&Widget::slotShowMe);
void Widget::slotShowMe()
{
//显示自己
show();
//显示软件园
subW.hide();
}
信号槽不仅仅能发送一个信号,可以发送多个信号,发送多个信号的时候要用到函数指针,对多个信号进行重载,其次,还要声明作用域。如果信号和槽发生重载,要定义函数指针显示定义。
void Subwidget::myslot()
{
//发送信号
emit sigSub();
emit sigSub(250,"你是250");
}
connect(b3,&QPushButton::clicked,this,&Widget::slotHindMe);
void (Subwidget::*MySigSub)()=&Subwidget::sigSub;
connect(&subW,MySigSub,this,&Widget::slotShowMe);
void (Subwidget::*MySigPlus)(int ,QString)=&Subwidget::sigSub;
connect(&subW,MySigPlus,this,&Widget::slotSubMag);
拓展:1、信号可以连接信号
2、一个信号可以连接多个槽函数
3、多个信号可以连接一个槽函数
4、槽函数可以使用lambda表达式
[=](){}值传递的方式,可以使用到函数外的参数。[&](){}引用外部的地址。[this](){}可以使用当前类的成员变量。[a](){}值传递的方式,可以传递a的值,大括号只能使用a。
使用lambad表达式作为槽函数。
1、一个Qt程序的组成部分:应用程序类,窗口类
2、应用程序类的个数:有且只有一个,QApplication a;
3、如何查看对应的模块:
光标移动到类上,F1
qmake += 模块的名字
1>在窗口中添加按钮
类名:QPushButton
设置按钮显示的内容:setText
移动按钮的位置:move
按钮设置父窗口:setParent
设置窗口的大小:resize(),resizeFixed()
2>Qt的坐标体系:
坐标原点:左上角
x轴延伸方向:向右
y轴延伸方向:向下
3>Qt的内存回收机制
满足什么条件不需要用户手动释放内存?
1.从QObject类直接或间接派生。
2.从直接或间接派生出的类,指定父对象。
1>.格式:connect(信号发出者对象(指针),&className::clicked,信号接收者对象(指针),&classB::slot);
2>.标准信号槽的使用:
3>.自定义槽函数:
1:返回值void
2:可以重载
3:需要和信号对应,个数<=信号的参数个数
4>.自定义信号
1:返回值void
2:可以重载
3:需要使用一个关键字声明:signals;
4:不需要函数定义
5>.单参数的信号(槽)
1:重载的时候:信号槽发生了重载,需要使用函数指针。
2:Qt4信号槽的使用
SIGNAL(信号的函数名()),SLOT(槽函数名(int,long))
connect 连接 重载过的信号和槽的解决方法。
6>.拓展:
a.信号可以链接信号(参数的对应)。
b.一个信号可以链接多个槽函数
c.多个信号可以链接同一个槽函数
d.槽函数可以使用lambda表达式
1>.菜单栏
2>.工具栏
3>.浮动窗口和核心部件
4>.状态栏
1>.模态对话框
2>.非模态对话框
3>.标准对话框和文件对话框
Me wo;
Beauty sweet;//小红
Beauty sweet1;//小紫
//场景:
1>. 我 看到 美女 之后 ,我直流口水 //自己给自己发信号
connect(&wo,&Me::seeBeauty,&wo,&Me::mouthWatering);
2>.我 调戏 美女 , 美女抽我 //我发信号,其他人接收
connect(&wo,&Me::molestBeauty,&sweet,&Beauty::beatSomebody);
3>.我给两个美女些情书,一个同意,一个拒绝 //槽函数的参数个数<信号的参数个数
//1.信号和槽重载的时候,需要使用到函数指针
//2.同一个信号和槽,可以链接多个槽函数
void (Beauty::*slotAnswer)()=&Beauty::answer;
connect(&wo,&Me::writeLoveLetter,&sweet,slotAnswer);
void (Beauty::*slotAnswer1)(QString)=&Beauty::answer;
connect(&wo,&Me::writeLoveLetter,&sweet,slotAnswer);
4>.我拜托小红把情书给她的双胞胎妹妹小紫,小紫说我只喜欢会Qt的程序猿
//信号链接信号
connect(&wo,&Me::weituoLetter,&sweet1,&Beauty::sendLetter);
connect(&sweet1,&Beauty::sendLetter,&sweet,&Beauty::slotAnswer1);
介绍UI界面,创建UI界面之后,如下:无法改变英文名,点击text输入中文,改变名称。
connect(ui->actionopen,&QAction::triggered,this,[=]()
{
QString name = QFileDialog::getOpenFileName(this,"打开文件","D:\\","Image(*.jpg *.png)");
qDebug() << name;
});
讲解了浮动窗口的应用,如何使用浮动窗口。设置状态为floating,默认状态为浮动。
下面勾选框设置允许停靠的位置。
在项目文件上右击添加新文件,选择天机resource file 添加新文件。添加成功后右击,加入前缀和反斜杠。把资源文件夹复制到工程文件夹下面,之后添加资源图片。
ui->actionSave_as->setIcon(QIcon(":/IMAGE/3.png"));
即可显示出资源图片:
如果项目比较大,可以添加不同的前缀来添加文件。
资源文件的更简单的使用方法:左侧选择中标签,之后在资源管理中找到icon,在normal中添加资源中的图片
模态&非模态对话框
非模态对话框:打开之后可以其他界面进行其他操作。
模态对话框:打开之后不可以其他界面进行其他操作。
connect(ui->actionopen,&QAction::triggered,this,[=]()
{
//显示模态对话框 exec
QDialog log(this);//定义一个父类对象,表示只有这一个窗口
log.exec();//阻塞状态。
QString name = QFileDialog::getOpenFileName(this,"打开文件","D:\\","Image(*.jpg *.png)");
qDebug() << name;
});
connect(ui->actionsave,&QAction::triggered,this,[=]()
{
//非模态对话框要保证在完成之前不被析构掉。只有当主窗口关闭之后才会被析构掉。
QDialog *log =new QDialog(this);
//显示非模态对话框 show()
//设置对话框的属性
log->show(); //非阻塞状态
log->setAttribute(Qt::WA_DeleteOnClose);//让对话框删除。
QString name = QFileDialog::getOpenFileName(this,"打开文件","D:\\","Image(*.jpg *.png)");
qDebug() << name;
});
实现包含的头文件 #include
实现代码:
QMessageBox::about(this,"about","++++++");
实现现象:
四种消息提示符:
如果执行了OK之后会出现的界面情况,最后一个参数为默认按钮,添加成功之后的界面,按下回车,按钮会响应回车按键:
if(QMessageBox::Ok == QMessageBox::critical(this,"error","系统文件错误!!!",QMessageBox::Ok|QMessageBox::Cancel,QMessageBox::Cancel))
{
//显示模态对话框 exec
QDialog log(this);
log.exec();//阻塞
}
所需要包含的头文件:
#include
#include
返回值是QColor 获得颜色对话框。之后打印出红绿蓝的颜色属性。
QColor color = QColorDialog::getColor();
qDebug()<<color.red()<<color.green()<<color.blue();
返回值是QFont 获得字体的对话框,之后打印出字体属性(斜体,字体大小,加粗);
bool ok;
QFont font = QFontDialog::getFont(&ok,QFont("华文彩云"),this,"我的字体设置");
if(ok)
{
qDebug()<<font.family()<<font.italic()<<font.pointSize()<<font.bold();
}
在开始布局之前首先为每一组控件创建一个父窗口。设置完成之后,界面如图所示。
为窗口设定最大宽度、高度和最小宽度、高度,来让界面固定大小。
网格布局:让每行每列的对齐,可以显示当行多列,每一列的宽度是相等的。
美化完成之后,选中对话框可以设置最后的间距大小,可以设置和边界的最后距离。
布局的时候,就是布局套布局,一层层布局下去。
1–PushButton按钮。
首先拖拽一个Button按钮放在UI界面上,在.cpp文件中,按下F1进入帮助文档,查看帮助文档信息,查看父类,在点击Signals。查看可以使用的信号。
每个控件放置在界面内一定要布置布局。
信号操作使用的实例:
connect(ui->radioButton,&QAbstractButton::clicked,this,[=]()
{
QMessageBox::information(this,"打印正确","hhhh");
});
connect(ui->checkBox,&QCheckBox::stateChanged,this,[=](int state)
{
qDebug()<<state;
});
在QListWidget:控件中添加图片和文字。
ui->listWidget->addItem("软件创业园");
ui->listWidget->addItem(new QListWidgetItem(QIcon("D:\\1.png"),"Lufft"));
//1、指定行数
ui->tableWidget->setRowCount(5);
//2、指定列数
ui->tableWidget->setColumnCount(3);
QStringList list;
list<<"姓名"<<"性别"<<"年龄";
ui->tableWidget->setHorizontalHeaderLabels(list);
Tool Box:
就像QQ列表的使用一样,点击一次按钮,就打开一次列表界面,使用效果如下图所示:
栈窗口:Stacked Widget
结果如下图所示:通过按键按钮,然后切换不同的界面。与QTabWidget 的区别是:这个控件和按钮是独立的,而QTabWidget是有联系的。
序号是当前窗口的currentIndex:
connect(ui->musicBtn,&QPushButton::clicked,this,[=]()
{
ui->stackedWidget->setCurrentIndex(0);
});
connect(ui->otherBtn,&QPushButton::clicked,this,[=]()
{
ui->stackedWidget->setCurrentIndex(1);
});
connect(ui->movieBtn,&QPushButton::clicked,this,[=]()
{
ui->stackedWidget->setCurrentIndex(2);
});
connect(ui->comboBox,&QComboBox::currentTextChanged ,this,[=]()
{
ui->stackedWidget->setCurrentIndex(2);
});
在Qt中,QPixmap代表的是一张图片。如何插入图片呢?
首先添加资源文件,在UI界面添加lable控件,之后添加代码:
ui->image->setPixmap(QPixmap(":/IMAGE/3.png"));
为了显示动图:要在头文件添加 #include,之后添加如下代码:
QMovie* movie = new QMovie(":/IMAGE/4.gif");
ui->image->setMovie(movie);
movie->start();
自定义控件:封装一个控件的时候,先对疯转搞的控件进行处理。
首先添加一个文件,在文件中创建一部分控件。紧接着在主窗口把主窗口提升为之前设置的子窗口,默认选择全局包含,这样在之后的创建过程中,其他控件也可以提升为之前的子控件。
在smallwidget中先对里面的控件进行处理,添加如下代码:
void(QSpinBox::*sigValueChange)(int) = &QSpinBox::valueChanged;
connect(ui->spinBox,sigValueChange,ui->horizontalSlider,&QSlider::setValue;
connect(ui->horizontalSlider,&QSlider::valueChanged,ui->spinBox,&QSpinBox::setValue);
小技巧:在使用控件的时候,做错了,重新更改边框,在widget右击变形为。。。
在项目中添加新的C++文件,在C++文件上继承Qlabel,之后重写被保护的虚函数,虚函数的查看,在Qlabel中按下F1。QLabel是从QWidget中派生的。
实际上这些事件都是回调函数,我们只需要对这些函数进行功能实现即可。
//字符串的拼接 QString().arg()
//%1,%2,%3 --占位符
QString str = QString("%3,%2,%1").arg(1).arg("123").arg('a');
#include "mylabel.h"
#include <QMouseEvent>
// QWidget 默认不追踪鼠标事件的
Mylabel::Mylabel(QWidget *parent) : QLabel(parent)
{
//设置窗口追踪鼠标键
this->setMouseTracking(true);
}
//进入和离开都是在边界的那一瞬间完成的。
//鼠标进入
void Mylabel::enterEvent(QEvent *)
{
setText("鼠标进入");
}
//鼠标离开
void Mylabel::leaveEvent(QEvent *)
{
setText("鼠标离开~");
}
//鼠标按下
void Mylabel::mousePressEvent(QMouseEvent *ev)
{
//字符串的拼接 QString().arg()
//%1,%2,%3 --占位符
QString btn;
if(ev->button()==Qt::LeftButton)
{
btn = "LeftButton";
}
else if(ev->button()==Qt::RightButton)
{
btn = "RightButton";
}
else if(ev->button()==Qt::MidButton)
{
btn = "MidButton";
}
QString str = QString("MousePress[%3]:(%1,%2)").arg(ev->x()).arg(ev->y()).arg(btn);
setText(str);
}
//鼠标释放 这是个瞬间的状态
void Mylabel::mouseReleaseEvent(QMouseEvent *ev)
{
//字符串的拼接 QString().arg()
//%1,%2,%3 --占位符
QString btn;
if(ev->button()==Qt::LeftButton)
{
btn = "LeftButton";
}
else if(ev->button()==Qt::RightButton)
{
btn = "RightButton";
}
else if(ev->button()==Qt::MidButton)
{
btn = "MidButton";
}
QString str = QString("MouseRelease[%3]:(%1,%2)").arg(ev->x()).arg(ev->y()).arg(btn);
setText(str);
}
//鼠标移动 移动操作比较特殊 要按位与操作才能捕捉鼠标对象。这是个持续的状态。
void Mylabel::mouseMoveEvent(QMouseEvent *ev)
{
//字符串的拼接 QString().arg()
//%1,%2,%3 --占位符
QString btn;
if(ev->buttons()&Qt::LeftButton)
{
btn = "LeftButton";
}
else if(ev->buttons()&Qt::RightButton)
{
btn = "RightButton";
}
else if(ev->buttons()&Qt::MidButton)
{
btn = "MidButton";
}
QString str = QString("MousePress[%3]:(%1,%2)").arg(ev->x()).arg(ev->y()).arg(btn);
setText(str);
}
使用方法一:
首先包含timerevent 的头文件,其次在窗口的构造函数中启动定时器。id = startTimer(100);参数100代表100ms触发一次。添加代码如下 实现启动定时器。当num>=100的时候关闭定时器。
//每触发一次定时器,就进入一次函数
static int num = 0;
QString str = QString("%1:%2").arg("Time out").arg(num++);
if(num >= 100)
{
//关闭定时器
killTimer(id);
}
使用方法2:
首先包含头文件QTimer,在构造函数中创建一个对象,创建对象完成之后,mylabel构造函数中添加如下代码,启动定时器:
//第二种定时器的使用方式
QTimer *timer = new QTimer(this);
timer->start(100);
connect(timer,&QTimer::timeout,this,[=]()
{
static int number=0;
QString str = QString("%1:%2").arg("Time out").arg(number++);
this->setText(str);
});
首先在widget.cpp中包含头文件“#include ”,如果我们想在当前窗口绘图的话,我们需要重载一个虚函数。
protected:
/*
* 1-回调函数
* 2-此函数不需要用户调用,在刷新的时候回自动调用
* 1.窗口显示的试试
* 2.最大化,最小化
* 3.窗口被遮挡重现显示的试试
* 4.用户强制刷新的时候
* 3-如果想使用画家类画图,操作必须在paintevent完成
*/
void paintEvent(QPaintEvent *event);
void Widget::paintEvent(QPaintEvent *)
{
//创建画家类对象
QPainter p(this); //指定绘图设备,不是父对象
// 创建新画笔 -- 轮廓
QPen pen;
pen.setColor(/*Qt::green*/QColor(0,255,0));
pen.setWidth(10);
pen.setStyle(Qt::DotLine);
//闭合区域使用画刷 -- 填充闭合区域
//QBrush brush(Qt::blue);
QBrush brush(QPixmap(":/IMAGE/3.png"));
p.setBrush(brush);
//将新画笔设置给画家类
p.setPen(pen);
//画背景图
p.drawPixmap(0,0,QPixmap(":/IMAGE/3.png"));
//画直线
p.drawLine(QPoint(100,100),QPoint(300,500));
//画椭圆
p.drawEllipse(QPoint(200,100),100,50);
//画矩形
p.drawRect(400,200,200,200);
//写字
QFont font("华文彩云",48,75,true); //定义字体类
p.setFont(font);//调用字体类
p.drawText(100,400,"我是你哥哥");
}
首先定义变量x;在UI界面添加按键,添加按键之后,创建槽函数。
connect(ui->move,&QPushButton::clicked,this,[=]()
{
//刷新窗口
update();//系统调用paintEvent
});
再完成槽函数之后,在 void Widget::paintEvent(QPaintEvent *)
添加如下代码。
int width = this->width();
int height = this->height();
x+=5;
//提供笑脸
if(x>this->width())
{
x=20;
}
p.drawPixmap(x,100,QPixmap(":/IMAGE/1.png"));
单击按键移动可以实现图片一直向右移动,即使跑出界面,也可以再进入界面。
在widget添加如下代码:
ui->setupUi(this);
QPixmap pix(300,300);//纸的大小
pix.fill(Qt::red);//给纸张填充颜色
QPainter p(&pix);//定义画家类
p.setPen(QPen(Qt::green,10));//设置画笔颜色,粗细
p.drawRect(10,10,280,280);//绘制矩形
p.drawEllipse(150,150,50,50);//绘制圆形
pix.save("D:\\mypixmap.jpg");
//指定绘图设备 1.构造函数中(参数是绘图设备)
//2.begin(参数是绘图设备)
// end;
//在QImage中绘图
QImage img(300,300,QImage::Format_RGB32);//纸的大小
img.fill(Qt::red);//填充为红色
p.begin(&img);//开始绘制图片
p.setPen(QPen(Qt::green,10));
p.drawRect(10,10,280,280);
p.drawEllipse(150,150,50,50);
p.end();//结束绘制图片
img.save("D:\\myimage.jpg");
//在Qpicture中绘图
//1.保存的是绘图步骤 --画家类
//2.不是图片 是二进制文件 (save 保存生成的文件)
//3.不依赖于平台
QPicture pic;//纸的大小
p.begin(&pic);//开始绘制图片
p.setPen(QPen(Qt::green,10));
p.drawRect(10,10,280,280);
p.drawEllipse(150,150,50,50);
p.end();//结束绘制图片
pic.save("D:\\mypic.jpg");
显示picture
void Widget::paintEvent(QPaintEvent *event)
{
QPainter p(this);
QPicture pic;
pic.load("D:\\mypic.jpg");
p.drawPicture(100,100,pic);
}
实现画图功能
#include "widget.h"
#include "ui_widget.h"
#include <QPainter>
#include <QMouseEvent>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//加载图片
pix.load("D:\\3.png");
//去掉边框函数
this->setWindowFlag(Qt::FramelessWindowHint);
//设置背景透明函数
this->setAttribute(Qt::WA_TranslucentBackground);
}
Widget::~Widget()
{
delete ui;
}
void Widget::paintEvent(QPaintEvent *event)
{
//在窗口中把图片画出来
QPainter p(this);
p.drawPixmap(0,0,pix);
}
void Widget::mousePressEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton)
{
//求差值 左键按下的点减去窗口左上角的点的坐标
pq = event->globalPos() - this->frameGeometry().topLeft();
}
else if(event->button() == Qt::RightButton)
{
// close window
this->close();
}
}
void Widget::mouseMoveEvent(QMouseEvent *e)
{
//move x,y 使用屏幕坐标系
//e->x(),e->y() 窗口的坐标系 Widget
this->move(e->globalPos() - pq);
}