基本控件
基本语法
定时器
使用定时器需要引入 #include <QTimer>头文件 不论是
创建定时器:
方法一:在.h文件中声明一个对象,然后在.cpp文件中new一个对象
QTimer * tim ; //在public中声明一个定时器对象
tim = new QTimer();//类中声明后创建对象tim 父类是QWidget
方法二:直接在.cpp的构造函数中生成对象sim
QTimer * sim = new QTimer(this);//直接创建对象 父类this也是QWidget
定时器三个重要函数:
tim->start(50); //调用start()函数并传值50,可以启动tim定时器并50ms发送一次信号tim->stop(); //停止定时器tim->isActive() //判断当前定时器状态,运行返回true否则反之、bool类型
专用信号使用:
[signal] void QTimer::timeout()
每次按照设定的时间间隔发出信号,这是一个专用信号。它可以用于信号连接,但不能由用户发出。
使用方式:
发送者——》tim
信号——》&QTimer::timeout
接收者——》this(父窗口)
槽函数——》lambda表达式 直接计数
connect(tim,&QTimer::timeout,this,[=](){
static int a = 0;
a++;
ui->label->setText(QString::number(a));
});
精度设定:
精度越高定时器越准确,但消耗资源越多
tim->setTimerType(Qt::PreciseTimer); //高精度 毫秒级别
tim->setTimerType(Qt::CoarseTimer); //默认精度 毫秒级别误差5%
tim->setTimerType(Qt::VeryCoarseTimer); //低精度 秒级别
一次性定时器:
QTimer::singleShot(2000, this, [=](){/*直接写要实现的内容*/});
----不用创建对象--- 延时2秒发射信号--
窗口切换
基本容器使用
串口通讯
1.pro工程文件加入串口通讯模块
QT += core gui serialport
2.头文件中加入
#include<QtSerialPort/QSerialPort> //用于提供访问串行端口的功能
#include <QSerialPortInfo> //用于提供关于现有串行端口的信息
3.定义一个串口对象 也可以在函数中直接定义但不如这种好
头文件类中:
public: QSerialPort *M; //声明一个对象
构造函数中:
M = new QSerialPort(this); //实例化一个对象
4. 定义串口参数与打开串口
M->setPortName("COM3"); //串口名称
M->setBaudRate(QSerialPort::Baud9600); //波特率 9600
M->setDataBits(QSerialPort::Data8); //数据位 8位
M->setParity(QSerialPort::NoParity); //校验位 无校验
M->setStopBits(QSerialPort::OneStop); //停止位 1位
M->setFlowControl(QSerialPort::NoFlowControl); //无流控
M->open(QSerialPort::ReadWrite); //打开串口(可读可写方式)
//如果串口打开则返回真,可以用作判断如 if(M->open(QSerialPort::ReadWrite))
//串口的关闭M->close();
5.写命令
M->write(“内容可以是QByteArray类型”); //写命令
6.读命令 //读取数据相对麻烦需要先设置信号槽
信号readyRead():每当缓存区有新数据就发出,不是有数据就发。这个信号会使数据分段所以在第二种方式中用延时的方式和数据缓冲的方式读
读的方法用readAll()全部读取,也有其他方式
//第一种 比较古老不推荐
connect(serialPort,SIGNAL(readyRead()),this,SLOT(ready()));
//第二种 推荐用这个带缓冲的接收数据
connect(mSerialPort,&QSerialPort::readyRead,this,[=](){
Serialtime->start(50); //Serialtime一个定时器 延时100ms
A->append(M->readAll());//用append方法将读到的数据放入缓冲区
//A是一个QByteArray类型对象当缓存用 //M是串口对象
});//连接接收信号槽
//第三种 每当寄存器有新数据就会触发
connect(mSerialPort,&QSerialPort::readyRead,this,&QSerialPort::ready());
接收数据后的处理,如果用第二种连接方式读,别忘了关掉定时器
void Dialog::Serial_receive() //接收数据函数
{
Serialtime->stop(); //延时器停止
QByteArray temp = *A; //提取数据
A->clear(); //清除缓存区
}
数据处理
接收的数据是两个字节用一个qfloat16类型的变量储存,首先要左移动8位高字节,然后在赋值低字节即可。 qfloat16 a6=(uchar)(temp.at(13))<<8 | (uchar)(temp.at(14));
数据不仅需要移位处理,同时需要等比缩放。
void Widget::Serial_receive() //接收数据函数
{
Serialtime->stop(); //延时器停止
QByteArray temp = *A;
A->clear(); //清除缓存区
QString str = temp.toHex();
if(temp.size() == 21){
if(temp.at(0) == 0x01){
qDebug()<<temp<<endl;
qDebug()<<str<<endl;
qfloat16 a1=(uchar)(temp.at(3))<<8 | (uchar)(temp.at(4));
qfloat16 a2=(uchar)(temp.at(5))<<8 | (uchar)(temp.at(6));
qfloat16 a3=(uchar)(temp.at(7))<<8 | (uchar)(temp.at(8));
qfloat16 a4=(uchar)(temp.at(9))<<8 | (uchar)(temp.at(10));
qfloat16 a5=(uchar)(temp.at(11))<<8 | (uchar)(temp.at(12));
qfloat16 a6=(uchar)(temp.at(13))<<8 | (uchar)(temp.at(14));
qfloat16 a7=(uchar)(temp.at(15))<<8 | (uchar)(temp.at(16));
qfloat16 a8=(uchar)(temp.at(17))<<8 | (uchar)(temp.at(18));
qDebug()<<a6<<endl;
a6=a6*0.030525-25;
if(a6<0){
a6=0;
}
qDebug()<<a6<<endl;
ui->label->setText(QString::number(a6,'f',1)+"℃");
}else{
qDebug()<<"地址不正确"<<endl;
}
}else{
qDebug()<<"数据错误"<<endl;
}
}
数据库使用
多线程
QT中主界面----->就是主线程------>有且只有一条----->只负责界面事件的接收和数据的显示即可
其余子线程完成其余的逻辑功能----->通过信号槽机制完成数据传输与功能访问
禁止子线程直接访问主线程控件
线程类 QThread
bool QThread::isFinished() const; //判断线程中的任务是否完成
bool QThread::isRunning() const; //判断子线程是否在执行
如果运用 exec(); 则线程不会结束且一直执行
线程设置优先级
Priority QThread::priority() const; //得到当前线程的优先级 0-7 最高是7
void QThread::setPriority(Priority priority); //设定优先级,不好用,可以在启动时候传参设定
优先级:
QThread::IdlePriority --> 最低的优先级
QThread::LowestPriority
QThread::LowPriority
QThread::NormalPriority
QThread::HighPriority
QThread::HighestPriority
QThread::TimeCriticalPriority --> 最高的优先级
QThread::InheritPriority --> 子线程和其父线程的优先级相同, 默认是这个
信号与槽
[slot] void QThread::quit(); //退出线程
[slot] void QThread::start(Priority priority = InheritPriority); // 启动子线程(参数是线程优先级)
[slot] void QThread::terminate(); // 立即终止函数,不待任务完成,一般不用
[signal] void QThread::finished(); //线程任务完毕发出此信号
[signal] void QThread::started(); // 开始工作之前发出这个信号, 一般不使用
bool QThread::wait(unsigned long time = ULONG_MAX); //等待任务完成退出线程与quit()配合用
静态函数
[static] QThread *QThread::currentThread(); // 返回当前线程指针地址
[static] int QThread::idealThreadCount(); // 当前理想线程数==当前电脑的 CPU 核心数
// 线程休眠函数
[static] void QThread::msleep(unsigned long msecs); // 单位: 毫秒
[static] void QThread::sleep(unsigned long secs); // 单位: 秒
[static] void QThread::usleep(unsigned long usecs); // 单位: 微秒
任务处理函数
[virtual protected] void QThread::run();
//此函数为纯虚函数,需要重写函数功能,将需要运行的线程放置其中,
当执行[slot] void QThread::start(Priority priority = InheritPriority);
函数时即可自动运行此函数。
第一种:继承QThread类并重写虚函数run方法
第一步:创建一个继承C++类,基类为QThread类,需要Add Q_OBJECT,这个可以用信号槽
注意:在mythread.h头文件中引入 #include<QThread> 否则无法使用
第二部:重写run()函数,如果需要与主界面传参还要写信号以供功能传参用
//mythread.h
class mythread : public QThread
{
Q_OBJECT
public:
mythread();
void run() override; //重写run函数
signals:
void isok(int c); //一个自定义信号带参数
};
//widget.h
#include <QWidget>
#include"mythread.h" //引入自定义线程头文件
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private:
Ui::Widget *ui;
mythread * myt1; //声明一个线程类
//mythread.cpp
mythread::mythread()//子线程构造函数
{
qDebug()<<"启动子线程构造函数";
}
void mythread::run() //重写run虚函数
{
int a=5;
int b=10;
int c=0;
c =(a+b);
emit isok(c); //线程结束后发送自定义信号
}
//Widget.cpp
Widget::Widget(QWidget *parent) //在构造函数中进行初始化和定义
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
myt1 = new mythread; //分配空间
//连接线程信号与界面 用信号槽机制
connect(myt1,&mythread::isok,this,[=](int c){
ui->label->setNum(c); //返回信号给的值
});
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_clicked()
{
//启动myt1线程并且设定线程优先级3
myt1->start(QThread::NormalPriority);
}
第三步:执行start()方法,就能启动子线程run()功能,如果子线程完成后需要传参则需要自定义信号isok(int c);的方式用信号槽机制传递给主线程
分析:此种线程方式创建简单,使用清晰但会将所有功能都写死在run函数中不太灵活。比较合适常驻类的功能实现。
第二种:用movToThread函数调用
第一步:创建一个类继承自QObject
class Work:public QObject
{
.......
}
第二部:给这个类加一个公共成员函数 也即是要运行的函数
class Work:public QObject
{
public:
......
void working(); // 函数名自己指定
}
第三步:在主线程创建一个QThread对象和要运行的类对象
QThread* sub = new QThread;
Work* a = new MyWork; // 功能函数的对象不能有父对象
第四步:将公共成员函数用movToThread()方法放到QThread对象中
a->moveToThread(sub); // 移动到子线程中工作
第五步:调用start()函数 启动线程
sub->start(); //线程虽然启动但没有任务执行
第六步:调用功能函数开始运行。
注意:这种方式代码更加灵活但也比较复杂,具有多种功能且一次性功能函数可以用这种方式。
第三种:线程池
线程池用法比较简单,自主回收机制很方便,但不太适合常驻线程。
数据库
QT链接mysql数据库