这里写目录标题
- 1.软件下载
- 2 新建工程
- 3.信号与槽
- 4.使用子线程
- 5 实战:计算器实现
- 6 定时器
- 7.图片显示
- 8. QMainWindow 和 文件操作
- 9 . 事件
- 10.TCP
- 11.窗口跳转![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/65efb63262801f1fe4a857121733e36a.png)
- 12.多线程
- 13.自定义信号
- 14. 数据库
- 15. QTableView
- 16. QCustomPlot使用
- 17. 结构体的互引用
- 18. 项目移植到新电脑后注意事项
- 19. 关于QPainterPath的一个问题
- 20. 鼠标单击、双击问题解决
- 21. SIGSEGV错误
- 22.由于结构体中使用了QByteArray数据,导致程序崩溃
- 23. ui界面自动生成connect函数的机制
- 24. toolbutton显示问题
- snap7通信
1.软件下载
https://blog.csdn.net/weixin_42214237/article/details/131997396
安装使用教程
2 新建工程
(1)
(2)选择分类
QMAINWINDOW
带菜单栏
QWIGET
不带菜单栏
QDIALOG
对话框
(3)选择工具库
(4)选择编译工具
qmake
才会产生 .pro文件
3.信号与槽
打开槽函数:
(1)右键控件,转到槽
(2)连接函数
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//连接信号与槽:谁发出信号,什么信号,谁处理,怎么处理
connect(ui->lineEdit,SIGNAL(returnPressed()),this,SLOT(on_commitButton_clicked()));
}
(3)第二种连接函数写法
取地址法
connect(ui->cancelButton,&QPushButton::clicked,this, &Widget::on_cancelButton_clicked);
(4)基于lamda的连接函数
connect(ui->browseButton,&QPushButton::clicked,[this]()
{
QMessageBox::information(this,"信息","点击浏览");
});
4.使用子线程
(1) .h文件添加包
#include
(2)创建process对象,并根据进程名执行
//创建process对象
QProcess *myProcess = new QProcess(this);
myProcess->start(program); //运行一个子进程,根据进程名
5 实战:计算器实现
使用栈,添加头文件
#include<QStack>
使用
QStack<char> stk;
stack.push('a');
6 定时器
(1)QObject: startTimer killTimer
xx.cpp
myTimerid =this->startTimer(TIMEOUT);//开启定时器,返回当前定时器编号
this->killTimer(myTimerid);//关闭定时器
//定时器事件定义
void Widget::timerEvent(QTimerEvent *event)
{
if(event->timerId()!=myTimerid){
return;
}
xxx
}
xx.h
声明虚函数
virtual void timerEvent(QTimerEvent *event); //定时器结束时触发的事件虚函数
(2)QTimer:
xx.cpp
timer = new QTimer; //初始化定时器
timer->start(TIMEOUT); //开启定时器,参数为定时时长(ms)
timer->stop();//结束定时
触发函数
void Widget::timeoutSlot()
{
xxx
}
//连接器:定时器时间结束信号与处理槽
connect(timer,&QTimer::timeout,this,&Widget::timeoutSlot);
QTimer::singleShot(1000,this,SLOT(timeoutSlot())); //单次计时
xxx.h
private:
Ui::Widget *ui;
QTimer *timer; //指针对象
int picID;
//槽函数的固定写法
private slots:
void on_startBT_clicked();
void timeoutSlot();
void on_endBt_clicked();
void on_pushButton_clicked();
7.图片显示
(1)
QImage img;
img.load("F:\\qtProject\\pic\\0.jpg");
ui->label->setPixmap(QPixmap::fromImage(img));
(2)
QPixmap pix("E:\\Desktop\\pic\\0.jpg");
ui->label->setPixmap(pix);
8. QMainWindow 和 文件操作
编辑窗口占满全屏
编辑菜单栏:&操作可以添加快捷键,使用 alt+字母选中
窗体预览
alt+shift+R
窗体菜单层次
菜单栏 > 菜单 > 动作
文件操作
9 . 事件
event是事件的总入口
内部函数是斜体
xx.h中声明事件函数
void keyPressEvent(QKeyEvent *k); //声明键盘事件虚函数
void mousePressEvent(QMouseEvent *m); //声明鼠标事件虚函数
xx.cpp中定义事件函数
// 重写事件虚函数
void MainWindow::keyPressEvent(QKeyEvent *k)
{
if (k->modifiers() == Qt::ControlModifier && k->key()== Qt::Key_S) //ctrl+s
{
//QMessageBox::information(this,"提示","键盘生效");
saveFileSlot();
}
}
void MainWindow::mousePressEvent(QMouseEvent *m)
{
QPoint pt = m->pos(); //获取鼠标位置
qDebug()<<pt;
if(m->button() == Qt::LeftButton) //左键被按下
{
qDebug()<<"左键被按下";
}
else if(m->button() ==Qt::RightButton)
{
qDebug()<<"右键被按下";
}
}
设置自动补全
10.TCP
LINUX TCP模型
添加网络库
客服端发起的一次连接:
socket->connectToHost(QHostAddress(ip), port.toShort());
服务端发起的永久连接:
QTcpSocket *socket = server->nextPendingConnection();
发送与接收消息
发送数据
QString text = ui->lineEdit->text();
QByteArray ba;
ba.append(text);
socket->write(ba); //发送 QByteArray类型 的数据
接收数据
绑定接收信号与槽
connect(socket,&QTcpSocket::readyRead,this,&Chat::receivInfoSlot);
槽函数进行接收
ui->receiveEdit->setText(QString(socket->readAll()));
11.窗口跳转
12.多线程
(1) 首先创建线程类,继承QThread
(2).h文件中加上 Q_OBJECT对象
(3)线程类中重写 run() 函数,处理实际的业务
(4)调用函数中开启线程
mythread *t = new mythread(socket); //创建线程对象
t->start(); //开始线程
无法单独运行QT生成的exe文件
在环境变量中添加qt程序的安装路径
13.自定义信号
ui对象只能在当前类中操作,其他类无法操作
在需要自定义信号的类中声明信号(函数)
signals:
void sendToWidget(QByteArray b); //自定义的信号,信号可以带参数
使用emit关键字发出信号
emit sendToWidget(ba); //发送信号
在接受信号的类中就可以信号与槽了
其中,对象就是声明了信号的对象,信号类型就是信号函数,槽函数可以定义为有参函数,接受信号中的参数
connect(t,&mythread::sendToWidget,this,&Widget::threadSlot);//信号与槽
14. 数据库
mysql数据库的安装
navicat安装
首先需要添加sql外部库
解决报错:QMYSQL driver not loadedQSqlDatabase: available drivers xxx
==>链 接 点 这 里
配置文件
[mysql.pro]
TARGET = qsqlmysql
HEADERS += $$PWD/qsql_mysql_p.h
SOURCES += $$PWD/qsql_mysql.cpp $$PWD/main.cpp
#QMAKE_USE += mysql
OTHER_FILES += mysql.json
PLUGIN_CLASS_NAME = QMYSQLDriverPlugin
include(../qsqldriverbase.pri)
INCLUDEPATH += "C:/Program Files/MySQL\MySQL Server 5.7/include"
LIBS += "C:/Program Files/MySQL/MySQL Server 5.7/lib/libmysql.lib"
DESTDIR = D:\Qt\5.15.2\Src\qtbase\src\plugins\sqldrivers\mysql\lib\
[qsqldriverbase.pri]
QT = core core-private sql-private
# For QMAKE_USE in the parent projects.
#include($$shadowed($$PWD)/qtsqldrivers-config.pri)
include(./configure.pri)
PLUGIN_TYPE = sqldrivers
load(qt_plugin)
DEFINES += QT_NO_CAST_TO_ASCII QT_NO_CAST_FROM_ASCII
15. QTableView
16. QCustomPlot使用
17. 结构体的互引用
18. 项目移植到新电脑后注意事项
(1)项目路径不能有中文
(2)构建路径设置
19. 关于QPainterPath的一个问题
在QT 5.13之前的版本,QPainterPath类没有 clear( ) 函数;可以考虑使用 path = QPainterPath()
方式代替。
20. 鼠标单击、双击问题解决
在一个函数中,如果给全局变量赋值后,在本次执行过程中,定时器的槽函数对这个全局变量的修改不会被该函数获取到;
void slotTimeout(){
flag = false;
}
void func1(){
cout<<flag; // 第二次进入函数时可以获取到全局变量的更该
flag = true; //对全局变量flag赋值
timer->start(10); //开启定时器,槽函数会对flag修改
cout<<flag; //但本次执行时 flag的值还是true;
}
鼠标的
单击事件: void mousePressEvent(QMouseEvent *e);
双击事件: void mouseDoubleClickEvent(QMouseEvent *event);
在同时出现时会发现冲突,因为双击必然首先发生了单击,导致两个事件都会触发,与设计意图不符。
使用QTimer定时函数进行区分,在设定时间内发生了两次点击则执行双击事件,发生了一次点击则执行单击事件;
// [.h文件]
#ifndef CWINBUTTON_H
#define CWINBUTTON_H
#include <QPushButton>
#include <QTimer>
class CWinButton : public QPushButton
{
Q_OBJECT
public:
explicit CWinButton(QWidget *pParent=nullptr);
private slots:
void slotTimerTimeOut();
void clicked();
private:
int m_nClickTimes;
QTimer m_cTimer;
};
#endif // CWINBUTTON_H
// [.cpp文件]
#include "cwinbutton.h"
#include <QDebug>
CWinButton::CWinButton(QWidget *pParent):QPushButton(pParent)
{
m_nClickTimes = 0;
connect(&m_cTimer,SIGNAL(timeout()),this,SLOT(slotTimerTimeOut()));
connect(this,SIGNAL(clicked(bool)),this,SLOT(clicked()));
}
void CWinButton::slotTimerTimeOut()
{
qDebug()<<"CWinButton::slotTimerTimeOut"<<endl;
m_cTimer.stop();
if(1==m_nClickTimes){
qDebug()<<"click event"<<endl;
//TODO Click respond.
}else if(2==m_nClickTimes){
qDebug()<<"double click event"<<endl;
//TODO Double click respond.
}
m_nClickTimes=0;
}
void CWinButton::clicked()
{
qDebug()<<"CWinButton::clicked"<<endl;
m_nClickTimes++;
m_cTimer.start();
}
参考自 该博主文章 ;
21. SIGSEGV错误
错误提示如图:
使用debug定位时,有时能定位到具体的错误位置;有时只能定位到错误点所在的函数;
SIGSEGV 是一个常见的运行时错误信号;
表示程序试图访问一个无效的内存地址
,通常是访问了未分配的内存、访问已释放的内存或访问越界的数组元素。如访问空指针、数组越界、非法内存操作等。
避免措施:
- 数组定义时,留意数组边界并留下冗余地址;
int status[MAX_SIZE+5][MAX_SIZE+5];
- 结构体/类定义时,通过构造体进行初始化赋值,避免访问空地址。
struct MapData{
int x; // 行、列
int y;
double up[3]; // up的x,y,cost
double down[3];
double left[3];
double right[3];
QByteArray name;
//结构体的构造函数,用于初始化赋值
MapData(){
x= -1;
y = -1;
std::fill(up,up+3,-1);
std::fill(down,down+3,-1);
std::fill(left,left+3,-1);
std::fill(right,right+3,-1);
name="";
}
};
涉及内存操作时,留意是否访问无效内存;
M_Data mapdata[MAX_SIZE+5][MAX_SIZE+5];
xxx
//在内存地址中,复制结构体数组mapdata给temp。 当mapdata中存在未赋值的结构体对象时,报错。
memcpy(temp,mapdata,sizeof(mapdata));
22.由于结构体中使用了QByteArray数据,导致程序崩溃
原因未知
23. ui界面自动生成connect函数的机制
ui界面编译后会生成ui_xxx.h文件,在文件中执行 connectSlotsByName()函数,这个函数将控件与槽函数隐式连接起来
不同的控件类有其固定的信号(函数),通过转到槽的方式将这些信号与槽函数(通过命名的方式)隐式连接。
如:
[signal] void QAbstractItemView::pressed
(const QModelIndex &index)
与
void on_listView_pressed
(const QModelIndex &index);
24. toolbutton显示问题
设置以下才能显示字体