一、编译方式
1、Qt内部编码方式:unicode编码
可以表示所有常见的文件,提供世界上几乎所有的文字的唯一编码方式。具有通用性;具有两字节和四字节标准。
但是我们在编写代码时,不能采用unicode编码,因为unicode编码每个字符都采用两个字符表示,但是char类型只有一个字节。多余的用0表示,但是字符串的结束标志就是空,所以不能用unicode编码方式来写代码。
查看QString帮助,可以看到,它也是提供的unicode编码。在QT中所有字符串都要转换成QString来存储,而字符是QChar(即unicode)
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnLwUzN4QzN3EDMx0iNwETMzgjMyAzNwgDM5EDMy0CN5cTN2ITMvwFOwkTMwIzLcRTO3UjNyEzLcd2bsJ2Lc12bj5ycn9Gbi52YugTMwIzZtl2Lc9CX6MHc0RHaiojIsJye.png)
如果在不同的系统中,不经过编码转换将会发生乱码。
例:
将设置虚拟机与宿主机的共享文件夹,将QT下昨天编写的源文件拷贝到Linux的共享文件夹下,用在Windows下用记事本打开,再点击另存为,可以看到默认的编码方式默认为UTF-8,将其修改为ANSI(GBK编码),保存并替换,此时编码方式已经改变为GBK编码。回到Linux将共享文件替换原来的源文件。再编译将出现执行可执行程序,将出现乱码现象。GBK的编码使用fromUtf8()函数无法完成正常转换。
![]()
QT-编码方式,信号和槽,容器窗口与事件同步,面向对象的QT编程(day2)
注意:
不同的编码方式,对中文的影响较大,因为中文的字符个数较多。但是英文基本不受编码方式影响。
2、手动编码方式转换
(1)QTextCodec类(最后一个字母是转换的缩写,即文本编码转换)
(2)实例
...表示当前编辑器默认的编码方式,这里为KOI8-R。也可以直接将字符串放在第三行的参数中
第二句表示获取一个KOI8-R的对象
第三句表示将这种编码的字符串转换为unicode编码
如果是想将GBK编码转换为unicode编码,只需将KOI8-R替换为GBK即可。
在QT5中,QString内部可以通过类型转换构造函数,将utf8编码自动转换成unicode编码。其他编码需要手动转换为unicode。
二、信号和槽
1、基本概念
信号和槽是QT自行定义的一种通信机制,实现对象之间的数据交互。如:实现点击按钮,关闭标签。
其本质就是函数的调用,一个信号发出,连接到该信号的槽函数将被执行。
2、定义方式
class xx{
Q_OBJECT//元对象编译器,使不符合标准C++的语法转换成符合标准C++的语法
signals://QT中定义的关键字
void sig_func(..);//信号函数,信号函数只能被声明,不能被定义,因为他是执行时动态调用槽函数。
public slots://slots为QT中定义的关键字
void sig_func(...);//槽函数
};
3、建立信号和槽的连接
使用如下的函数,它是一个静态成员函数。信号连接发生在运行期间,这一点需要注意。
注意:
信号函数和槽函数是字符串,即函数签名,不是函数的指针。即按字符串形式处理。
QT提供两个宏可以将信号函数或者槽函数转换为const char*指针:
SIGNAL(信号函数);//将信号函数转换为const char*
SLOT(槽函数);//将槽函数转换为const char*
参数:
sender:信号发送的指针
signal:信号函数
receiver:信号接收的对象指针
method:槽函数
#include<QApplication>
#include<QLabel>
#include<QPushButton>
#include<QObject>
int main(int arg,char* argv[]){
QApplication app(argc,argv);
QLabel label("Hello QT!");
QPushButton button("关闭标签");
label.show();
button.show();
//连接信号和槽函数
QObject::connect(&button,SIGNAL(clicked()),&label,SLOT(close()));
return app.exec();
}
练习:
实现点击按钮,关闭应用
思路:在帮助文档中查找QApplication及其基类相关可以退出或者关闭的函数,可以查找到:
void closeAllWindows();
和上一层基类中的
void quit();
#include<QApplication>
#include<QLabel>
#include<QPushButton>
#include<QObject>
int main(int arg,char* argv[]){
QApplication app(argc,argv);
QLabel label("Hello QT!");
QPushButton button("关闭标签");
label.show();
button.show();
//连接信号和槽函数
QObject::connect(&button,SIGNAL(clicked()),&app,SLOT(closeAllWindows()));
// QObject::connect(&button,SIGNAL(clicked()),&app,SLOT(quit()));
return app.exec();
}
4、信号和槽函数连接的语法要求
1)一般信号和槽函数参数顺序和类型要相同
QObject::connect(&button,SIGNAL(sig_func(int)),&app,SLOT(slot_func(int)));//ok
QObject::connect(&button,SIGNAL(sig_func(int)),&app,SLOT(slot_func(int,string)));//error
2)信号函数和槽函数可带有缺省参数
QObject::connect(&button,SIGNAL(sig_func(int)),&app,SLOT(slot_func(int,string="")));//ok
3)信号函数的参数可以多于槽函数
QObject::connect(&button,SIGNAL(sig_func(int,string)),&app,SLOT(slot_func(int)));//ok多于的参数将被忽略
4)一个信号可以连接到多个槽函数,信号发生时,都会被执行
QObject::connect(&button,SIGNAL(sig_func(int)),&app1,SLOT(slot_func1(int)));//ok
QObject::connect(&button,SIGNAL(sig_func(int)),&app2,SLOT(slot_func2(int)));//ok
5)多个信号可以对应同一个槽函数,无论谁发了信号,槽函数都会被执行
QObject::connect(&button1,SIGNAL(sig_func1(int)),&app,SLOT(slot_func(int)));//ok
QObject::connect(&button2,SIGNAL(sig_func2(int)),&app,SLOT(slot_func(int)));//ok
三、滑块类(QSlider)、微调框/选值框(QSpinbox)
1、<案例>事件同步
(1)滑块类
构造函数
槽函数
setRange(int min,int max);//设置滑动范围
setRange(int);//设置滑块位置
信号函数
valueChanged(int value);//滑块滑动时发送位置信号
(2)微调框/选值框(QSpinbox)
构造函数:
QSpinbox(QWidget* parent=0);
其他:
setRange(int minimum,int maxmum);//设置选值的范围
槽函数:
setValue(int val);
信号函数:
valueChanged(int i);发送值改变的信号
valueChanged(const QString& text);
#include<QApplication>
#include<QSlider>
#include<QSpinbox>
int main(int arg,char* argv[]){ QApplication app(argc,argv);
//创建滑块组件,并设置其属性
QSlider slider(Qt::Horizontal);//设置为水平滑块
slider.setRange(0,100);//设置范围
slider.show()
//创建选值框
QSpinbox spin;
spin.setRange(0,100);
spin.show();
//连接信号和槽函数,相互连接
QObject::connect(&slider,SIGNAL(valueChanged(int)),&spin,SLOT(setValue(int)));
QObject::connect(&spin,SIGNAL(valueChanged(int)),&slider,SLOT(setValue(int)));
return app.exec();
}
因为信号发送和槽函数接收是动态的,所以在它们出现拼写错误时,编译不会报错,执行时才会出现问题。如果执行时出现问题可以考虑是否是这个问题造成的。
三、容器窗口(父窗口)与事件同步
1、父窗口
如果一个组件在创建时指定了父窗口,那么他就会停靠在父窗口上面,如果不指定,就会游离在外部形成独立的窗体。
(1)常用的父窗口类
QWidget(绝大多数图形组件的基类,它的成员函数子类都可以使用)、QMainWindow(QWidget的子类,一般是主界面使用此类)、QDialog(也是QWidget的子类,一般对话框就是用这个类)是比较常用的父窗口类
在实际的开发中,一般使用后两者比较多。
(2)QWidget基类中两个常用的成员函数
resize(int x,int y);调整大小,单位为分辨率
move(int x,int y);//调整位置
注意:
对于父窗口对象,起始位置是相对于屏幕左上角,如果是父窗口中的停靠组件,则相对的是父窗口的左上角。
#include<QApplication>
#include<QLabel>
#include<QPushButton>
#include<QObject>
#include<QWidget>//默认左上角显示,也可以使用QDialog(默认居中显示,没有最大化,最小化)和QMianWindow(默认左上角显示)类
int main(int arg,char* argv[]){
QApplication app(argc,argv);
//创建一个父窗口对象
QWidget parent;
//设置父窗口大小,200*200像素
parent.resize(200,200);
//调节父窗口位置
parent.move(300,300);
//创建lable和button时指针停靠在parent父窗口
QLabel label("Hello QT!",&parent/*指定父窗口*/);
label.move(0,100);//垂直方向不变,水平方向向右移动100像素
QPushButton button("关闭标签",&parent);
button.move(100,100);//移动按钮
//label.show();
//button.show();
//显示父窗口,它所包含的组件也会一起显示
parent.show();//主窗口必须显示
//连接信号和槽函数
QObject::connect(&button,SIGNAL(clicked()),&app,SLOT(closeAllWindows()));
// QObject::connect(&button,SIGNAL(clicked()),&app,SLOT(quit()));
return app.exec();
}
补充:使用付窗口的优点
(1)布局看起来更为美观,更容易管理
(2)因为有时候会动态分配内存,但是可能忘记释放。使用父窗口可以不用担心这个问题,因为主窗口的析构函数会调用所有组件的析构函数,进行内存释放。
四、面向对象的QT编程
1、基于对象的QT编程
因为我们是使用QT已经封装好的类,但是只能在外部使用其公有的成员,限制较大,不推荐。例如前面的的所有案例都是基于对象的编程。
2、面向对象的QT编程
<案例>实现加法计算器
思路:
封装一个类:
class CalculatorDialog:public QDialog{
行为:
构造函数;初始化图形界面(UI)
槽函数:当输入左右操作数时,使能等号按钮
槽函数:点击等号按钮时调用,计算结果
属性:
QLineEdit
QPushButton
QLabel
};
int main(int argc,char** argv){
QApplication app(argc,argv);
CalculatorDialog cal;
cal.show()
return app.exec();
}
实现代码:
//CalculatorDialog.h文件
#ifndef __CalculatorDialog__
#define __CalculatorDialog__
#include<QDialog>
#include<QLineEdit>
#includeQ<PushButton>
#include<QLabel>
//水平布局器,用于自动调整组件的大小和位置
#include<QHBoxLayout>
//验证器,输入组件只能输入数字
#include<QDoubleValidator>
class CalculatorDialog:public Dialog{
Q_OBJECT //元对象,使用MOC编译器声明QT语法转换为标准C++
public:
CalculatorDialog(void);
private slots:
//使能等号按钮
void enbleCalculation(void);
//计算结果
calcClicked();
private:
QLineEdit* m_editX;//左操作数
QLineEdit* m_editY;//右操作数
QPushButton* m_btnCalc;//等号按钮
QLineEdit* m_edit;//保存结果
};
#endif
扩展:
使用元对象编译器可以生成moc开头的文件,再将这些文件通过标准C++编译器编译。
//CalculatorDialog.cpp文件
#include "CalculatorDialog.h"
//构造函数
CalculatorDialog::CalculatorDialog(void){
//设置标题
setWindowTitle("计算器");
//创建编辑框(左右操作数)
m_editX =new QLineEdit(this);//this指向计算机父窗口
//设置对齐方式
m_editX->setAlignment(Qt::AlignRignt);//设置右对齐
//设置验证器,让其只能输入数字
m_editX->setValidator(new QDoubleValidator(this));
m_editY =new QLineEdit(this);
//设置对齐方式
m_editY->setAlignment(Qt::AlignRignt);//设置右对齐
//设置验证器,让其只能输入数字
m_editY->setValidator(new QDoubleValidator(this));
m_editZ =new QLineEdit(this);
//设置对齐方式
m_editZ->setAlignment(Qt::AlignRignt);//设置右对齐
//输出结果只读
m_editZ->setReadOnly(true);
//创建等号
m_btnCalc=new QPushButton("=",this)
//设置默认属性为禁用
m_btnCalc->setEnanled(false);
//创建水平布局器,将所有的组件从左至右添加到布局器中,它将自动调节每个组件的大小和位置
QHBoxLayout* layout =new QHBoxLayout(this);
//为水平布局器添加组件
layout->addWidget(m_editX);//左操作数
layout->addWidget(new QLabel('+'));//加号
layout->addWidget(m_editY);//右操作数
layout->addWidget(m_btnCalc);//等号
layout->addWidget(m_editZ);//结果(只读)
//设置启用布局器
setLayout(layout);
//QLineEdit组件中输入时,将发送信号:textChanged
connect(m_editX,SIGNAL(textChanged(const string&)),this,SLOT(enableCalcButton()));
connect(m_editX,SIGNAL(textChanged(const string&)),this,SLOT(enableCalcButton()));
//点击=号按钮发送clicked信号
connect(m_btnCalc,SIGNAL(clicked()),this,SLOT(calcClicked()));
}
//使能等号按钮的槽函数
void CalculatorDialog::enableCalcButton(void){
//检查左右操作数是否为有效数字
bool bXOk;
bool bYOk;
//text():获取QLineEdit输入的数据,返回值是QString类型
//toDouble():将QString类型转换成double类型,参数是值结果参数,表示转换是否成功
m_editX->text().toDouble(&bXOk);
m_editX->text().toDouble(&bXOk);
//设置=号按钮
m_btnCalc->setEnabled(bXOk&&bYOk);
}
//计算结果的槽函数
void CalculatorDialog::calcClicked(void){
//转换为double并计算
double res=m_editX->text().toDouble()+m_editY->text().toDouble();
//将double转换为字符串文本
QString str=QString::number(res,'g',15);
//显示文本
m_editZ->serText(str);
}
//Calculator.cpp主函数文件
#include<QApplication>
#include"CalculatorDialog.h"
int main(int argc,char** argv){
QApplication app(argc,argv);
CalculatorDialog calc;
calc.show()
return app.exec();
}