QT应用开发笔记

一、参考学习的网站
1、基础教程网站: http://c.biancheng.net/view/1792.html
3、打包完整软件的流程: https://blog.csdn.net/iw1210/article/details/51253458
//
二、Hello Word练习
1、Qt项目管理文件xxx.pro
      项目管理文件用于记录项目的一些设置,以及项目包含文件的组织结构管理。 下表是一个练习的文件源码
 
#-------------------------------------------------
#
# Project created by QtCreator 2020-09-16T14:49:33
#
#-------------------------------------------------
 
QT += core gui  // “Qt += core gui”表示项目中加入 core gui 模块。core gui 是 Qt 用于 GUI 设计的类库模块,如果创建的是控制台(Console)应用程序,就不需要添加 core gui。//
 
greaterThan( QT_MAJOR_VERSION, 4): QT += widgets  // 这是个条件执行语句,表示当 Qt 主版本大于 4 时,才加入 widgets 模块。//
 
TARGET = Test20200916_v0  // 表示生成的目标可执行文件的名称,即编译后生成的可执行文件是 Test20200916_v0.exe//
TEMPLATE = app    //表示项目使用的模板是 app,是一般的应用程序。//
 
 
SOURCES += main.cpp\
mainwindow.cpp
 
HEADERS += mainwindow.h
 
FORMS += mainwindow.ui
 
Qt 类库以模块的形式组织各种功能的类,根据项目涉及的功能需求,在项目中添加适当的类库模块支持。例如,如果项目中使用到了涉及数据库操作的类就需要用到 sql 模块,在 pro 文件中需要增加如下一行:QT+= sql。
2、Qt工程项目中的界面文件xxx.ui
3、Qt项目中的main主函数及其作用
     main() 函数是应用程序的入口。它的主要功能是创建应用程序,创建窗口,显示窗口,并运行应用程序,开始应用程序的消息循环和事件处理。
 
#include "mainwindow.h"
#include <QApplication>
 
int main ( int argc , char * argv [])
{
QApplication a ( argc , argv );   //定义并创建应用程序//
MainWindow w //定义并创建窗口类对象//
w . show ();    //显示窗口//
 
return a . exec ();   //应用程序阻塞运行//
}
 
QApplicationQt 的标准应用程序类,第 1 行代码定义了一个 QApplication 类的实例 a,就是应用程序对象。
//
三、Qt的简单开发流程
1、Qt界面布局管理与程序如何访问界面组件
     关于UI中的布局插件(layouts、spacers)以及设置组件之间的伙伴Tab关系(Edit Buddies),可以参考博文来学习,关键在于实践。
自动配置一个信号槽触发,关联UI组件:
 
第一种方法(辅助添加)
切换到ui组件,鼠标右键点击目标组件,在弹出的功能菜单栏里选择“转到槽”;这时会弹出一个对话框,用于选择需要触发槽函数的信号;确定之后,在xxx.h和xxx.c文件中可以看到自动添加的槽函数框架;可以在框架里实现自己要执行的功能。 这里自动生成的槽函数的名字是固定规则的。
第二种方法(手动关联)
关键的函数接口:connect。首先,在xxx.h文件定义的ui类中的 private slots :下面申明一个自定义槽函数,格式void xxxx_function(里面可以随意);在对应xxx.c中实现这个槽函数;再在ui类的构造函数里,使用connect来链接ui->组件与对应的槽函数。
第三种方法(组件与组件间的关联可用)
切换到ui设计界面,在底下有一栏功能可以配置组件间的功能。 配置好后,会在内部自动生成connect代码,在ui_xxx.c里。
这是一个练习的例子:
2、Qt的信号与槽的机制
        这个核心的原理可以被运来到任何平台上,是一个创新性的思想!!!
在Qt中,实现信号与槽关联的核心函数原型: QObject::connect(sender, SIGNAL(signal()), receiver, SLOT(slot()));这是一个Qt基类中实现的静态函数。 一个信号可以连接多个不同的槽函数,当信号发生时,槽函数按照connect的调用顺序分别被执行; 多个不同的信号也可以连接同一个槽函数,严格来说,信号与槽函数的参数类型的个数需要一致。
注意:Qt中若需要使用到信号与槽功能,需要在类申明中申明宏 Q_OBJECT
3、Qt全局变量、函数与宏定义
    在QtGlobal中定义了丰富的全局变量和函数功能,可以直接调用。是非常实用的。QtMath则定义了丰富的数学函数功能。
QtGlobal中的全局变量定义:
Qt 数据类型
等效定义
字节数
qint8
signed char
1
qint16
signed short
2
qint32
signed int
4
qint64
long long int
8
qlonglong
long long int
8
quint8
unsigned char
1
quint16
unsigned short
2
quint32
unsigned int
4
quint64
unsigned long long int
8
qulonglong
unsigned long long int
8
uchar
unsigned char
1
ushort
unsigned short
2
uint
unsigned int
4
ulong
unsigned long
8
qreal
double
8
qfloat16(5.9.0以上版本)
 
2
QtGlobal中的全局函数定义:
函数
功能
T qAbs(const T &value)
返回变量 value 的绝对值
const T &qBound(const T &min, const T&value, const T &max)
返回 value 限定在 min 至 max 范围之内的値
bool qFuzzyComparc(doublc p1, double p2)
若 p1 和 p2 近似相等,返回 true
bool qFuzzyIsNulI(double d)
如果参数 d 约等于 0,返回 true
double qInf(()
返回无穷大的数
bool qIsFinite(double d) 
若 d 是一个有限的数,返回 true
bool qIsInf(double d) 
若 d 是一个无限大的数,返回 true
bool qIsNaN(double d)
若 d 不是一个数,返回 true
constT&qMax(const T&value1, const T&value2)
返回 value1 和 value2 中较大的值
const T &qMin(const T&value1, const T&value2)
返回 value1 和 value2 中较小的值
qint64 qRound64(double value) 
将 value 近似为最接近的 qint64 整数
int qRound(double value)
将 value 近似为最接近的 int 整数
int qrand()
标准 C++ 中 rand() 函数的线程安全型版本,返回 0 至 RAND_MAX 之间的伪随机数
void qsrand(uint seed)
标准 C++ 中 srand() 函数的线程安全型版本,使用种子 seed 对伪随机数字序列初始化
QtGlobal内的全局宏定义:
 
QT_VERSION
这个宏展开为数值形式 0xMMNNPP (MM = major, NN = minor, PP = patch) 表示 Qt 编译器版本
QT_VERSION_CHECK
这个宏展开为 Qt 版本号的一个整数表示
QT_VERSION_STR
这个宏展开为 Qt 版本号的字符串,如“5.9.0”。
Q_BYTE_ORDER、Q_BIG_ENDIAN 和 Q_LITTLE_ENDIAN
Q_BYTE_ORDER 表示系统内存中数据的字节序,Q_BIG_ENDIAN 表示大端字节序,Q_LITTLE_ ENDIAN 表示小端字节序。
Q_DECL_IMPORT 和Q_DECL_EXPORT
在使用或设计共享库时,用于导入或导出库的内容,后续章节有其使用实例。
Q_DECL_OVERRIDE
在类定义中,用于重载一个虚函数。 例如在某个类中重载虚函数 paintEvem(), void paintEvent(QPaintEvent*) Q_DECL_OVERRIDE;
Q_DECL_FINAL
这个宏将一个虚函数定义为最终级别,不能再被重载,或定义一个类不能再被继承
Q_UNUSED(name)
这个宏用于在函数中定义不在函数体里使用的参数
foreach(variable, container)
foreach 用于容器类的遍历。 例子:
foreach (const QString &codecName, recorder->supportedAudioCodecs())
ui->comboCodec->addItem(codecName);
forever
forever用于构造一个无限循环
qDebug(const char * message,…)
在debugger窗体显示信息, 如果编译器设置了 Qt_NO_DEBUG_OUTPUT,则不作任何输出
4、
//
四、QT里的多态(虚功能函数的重实现)
QT里的所谓多态,其实就是QT预实现了许多虚函数,我们只需要实现对应的内容就可以,至于何时被调用,QT已经自动关联好了。
QWeiget里的虚函数:( 利用这些虚函数,可以让QT关联电脑的鼠标、键盘等一些列事件与输入
 
Protected Functions
 
virtual void actionEvent(QActionEvent *event)
virtual void changeEvent(QEvent *event)
virtual void closeEvent(QCloseEvent *event)
virtual void contextMenuEvent(QContextMenuEvent *event)
 
virtual void dragEnterEvent(QDragEnterEvent *event)
virtual void dragLeaveEvent(QDragLeaveEvent *event)
virtual void dragMoveEvent(QDragMoveEvent *event)
virtual void dropEvent(QDropEvent *event)
virtual void enterEvent(QEvent *event)
virtual void focusInEvent(QFocusEvent *event)
virtual bool focusNextPrevChild(bool next)
virtual void focusOutEvent(QFocusEvent *event)
virtual void hideEvent(QHideEvent *event)
virtual void inputMethodEvent(QInputMethodEvent *event)
virtual void keyPressEvent(QKeyEvent *event)
virtual void keyReleaseEvent(QKeyEvent *event)
virtual void leaveEvent(QEvent *event)
virtual void mouseDoubleClickEvent(QMouseEvent *event)
virtual void mouseMoveEvent(QMouseEvent *event)
virtual void mousePressEvent(QMouseEvent *event)
virtual void mouseReleaseEvent(QMouseEvent *event)
virtual void moveEvent(QMoveEvent *event)
virtual bool nativeEvent(const QByteArray &eventType, void *message, long *result)
virtual void paintEvent(QPaintEvent *event)
virtual void resizeEvent(QResizeEvent *event)
virtual void showEvent(QShowEvent *event)
virtual void tabletEvent(QTabletEvent *event)
virtual void wheelEvent(QWheelEvent *event)
五、QT里实现多线程与线程的管理
曹函数检查触发信号对象: https://blog.csdn.net/jklinux/article/details/71910206
1、在QT里实现多线程的方法:
利用QT的QThread封装一个自定义的线程类,在里面实现虚函数void run();
 
    class MyThread : public QThread {
    public:
        void run() {
            //做线程要作的事情
            //此函数执行结束,线程也就退出工作了。所以这个函数通常都是个循环。
        }
    };
//
    MyThread * t = new MyThread;
    t->start(); //注意不是直接调用run函数,run函数是在线程启动后自动调用的。
            //调用start函数时,也可以指定线程的优先级别
一个例子
 
mywin.cpp
#include "mywin.h"
#include <QDebug>
MyThread::MyThread(int id)
{
    this->id = id;
}
void MyThread::run()
{
    int n;
    QString str("id=%1 : val=%2");
    while (1)
    {
        sleep(3);
        n = qrand()%100; //取100内的随机数
        emit valGot(str.arg(id).arg(n));
    }
}
///
MyWin::MyWin(QWidget *parent) : QWidget(parent)
{
    btn = new QPushButton("new thread", this);
    connect(btn, SIGNAL(clicked(bool)), this, SLOT(slot_btn()));
    resize(320, 240);
}
MyWin::~MyWin()
{
    delete btn;
    //窗口对象退出时,把所有的子线程对象结束工作并回收资源。
    for (int i = 0; i < list.size(); i++ )
    {
        list.at(i)->terminate(); //终止线程对象的工作
        list.at(i)->wait(); //回收线程对象的资源
    }
}
void MyWin::slot_btn()
{
    static int id = 0; //用于分配线程的ID
    MyThread *t;
    t = new MyThread(id++);
    //连接线程对象的信号, 当线程对象的信号发出时,触发槽slot_thread
    connect(t, SIGNAL(valGot(QString)), this, SLOT(slot_thread(QString)));
    list.append(t); //把创建出来的线程对象的地址存入链表
    t->start(QThread::LowPriority); //启动线程,并指定此线程的优先级别比一般的线程要低
}
void MyWin::slot_thread(QString str)
{
    qDebug() << str; //输出线程对象发出的参数
}
 
//
六、QT的网络编程
1、TCP服务器与客户端的实现
创建一个服务器:
 
    //1.  创建一个QTcpServer对象
        QTcpServer *server = new QTcpServer;
 
    //2. 调用对象的listen函数成员进行绑定地址与端口号, 并监听端口
        server->listen(QHostAddress::Any, 9999); // 绑定端口号9999, 成功返回true, 失败返回false
 
    // 3.  连接对象的newConnection信号到一个槽函数,用于处理客户端的连接。
            connect(server, SIGNAL(newConnection()), this, SLOT(new_client()));  //当有客户端连接时,对象会发出newConnection信号,客户端的连接处理就在触发的槽函数new_client里处理了。
 
    // 4. 在处理客户端连接的槽函数new_client里处理连接. 每个客户端连接上来后,在服务器端就会有一个QTcpSocket对象对一个客户端通信使用,如多个客户端连接上来,则会有多个QTcpSocket对象.
    QTcpSocket *client;
 
    client = server->nextPendingConnection(); //处理客户端连接, 调用此处理函数后,会得到一个QTcpSocket对象的地址,此对象专用于这个连接上来的客户端通信使用。
 
    // QTcpSocket对象在服务器端用于与客户端通信使用,当客户端发数据到服务器端时,它会发出信号readyRead, 通知接收客户端的数据. 当客户端断开连接时,会发出disconnected信号,通知客户端已断线.发送数据则调用对象的write函数即可.
 
    //连接信号,做相应的处理
    connect(client, SIGNAL(readyRead()), this, SLOT(tcp_read()));  // tcp_read槽函数用于接收客户端的数据, 在槽函数里调用QTcpSocket对象的read函数即可.
 
   connect(client, SIGNAL(disconnected()), this, SLOT(lost_client()));  // lost_client槽函数用于处理客户端断开连接
创建一个客户端:
 
    // 1. 创建QTcpSocket对象
       QTcpSocket *tcp = new QtcpSocket;
 
    // 2. 连接服务器端的IP地址与端口号, 连接成功会发出connected信号。也可以直接调用waitForConnected等待连接的结果。
    tcp->connectToHost("192.168.250.250", 9999);
 
    // 3. 调用对象的read/write函数即可与服务器端进行收发数据了。当服务器端有发数据过来时,会发出readyRead信号,在连接此信号的槽函数里接收数据即可.
 
2、UDP通信的实现
//
七、QT实现电脑上文件的操作
1、打开选择文件对话框选择文件:
 
# include < QFileDialog>  
 
QString QFileDialog:: getOpenFileName( QWidget * parent = nullptr, const QString & caption = QString(), const QString & dir = QString(), const QString & filter = QString(), QString * selectedFilter = nullptr, QFileDialog::Options options = Options() )  //选择打开的文件,这里只是打开,不指定任何具体读写操作//
eg:
OpenFile_Name = QFileDialog:: getOpenFileName( this, QString( "选择本地文件"), QString( "./"), "Text File(*.cnc)");
QSring QFileDialog :: getSaveFileName( QWidget * parent = nullptr, const QString & caption = QString(), const QString & dir = QString(), const QString & filter = QString(), QString * selectedFilter = nullptr, QFileDialog::Options options = Options() )  //选择要保存的文件的对象//
eg:
OpenFile_Name = QFileDialog:: getSaveFileName( this, QString( "保存的目标文件"), QString( "./"), "Text File(*.cnc)");
2、打开文件后,对文件的具体读写操作
 
# include < QFile>
 
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QFileDialog>
#include <QFileDevice>
#include <QFile>
#include <QMessageBox>
#include <QtEvents>
#include <QTextStream>
int flag_isOpen = 0;
int flag_isNew = 0;
QString Last_FileName;
QString Last_FileContent;
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}
MainWindow::~MainWindow()
{
    delete ui;
}
void MainWindow::on_open_file_triggered()
{
    QString fileName;
    fileName = QFileDialog::getOpenFileName(this,"Open File","","Text File(*.txt)");
    if(fileName == "")
    {
        return ;
    }
    else
    {
        QFile file(fileName);
        if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
        {
            QMessageBox::warning(this,"error","open file error!");
            return;
        }
        else
        {
            if(!file.isReadable())
                QMessageBox::warning(this,"error","this file is not readable!");
            else
            {
                QTextStream textStream(&file);
                while(!textStream.atEnd())
                {
                    ui->textEdit->setPlainText(textStream.readAll());
                }
                ui->textEdit->show();
                file.close();
                flag_isOpen = 1;
                Last_FileName = fileName;
            }
        }
    }
}
void MainWindow::on_new_file_triggered()
{
    ui->textEdit->clear();
    ui->textEdit->setHidden(false);
    flag_isNew = 1;
    flag_isOpen = 1;
}
void MainWindow::on_save_as_file_triggered()
{
    QFileDialog fileDialog;
    QString fileName = fileDialog.getSaveFileName(this,"Open File","","Text File(*.txt)");
    if(fileName == "")
    {
        return;
    }
    QFile file(fileName);
    if(!file.open(QIODevice::WriteOnly | QIODevice::Text))
    {
        QMessageBox::warning(this,"error","open file failure!");
        return;
    }
    else
    {
        QTextStream textStream(&file);
        QString str = ui->textEdit->toPlainText();
        textStream<<str;
        QMessageBox::warning(this,"tip","Save File Success!");
        Last_FileContent = str;
        Last_FileName = fileName;
        flag_isNew = 0;
        file.close();
    }
}
void MainWindow::on_save_file_triggered()
{
    if(flag_isNew)
    {
        if(ui->textEdit->toPlainText()=="")
        {
            QMessageBox::warning(this,"error","content can not be none!",QMessageBox::Ok);
        }
        else
        {
            QFileDialog fileDialog;
            QString str = fileDialog.getSaveFileName(this,"Open File","","Text File(*.txt)");
            if(str == "")
            {
                return;
            }
            QFile filename(str);
            if(!filename.open(QIODevice::WriteOnly | QIODevice::Text))
            {
                QMessageBox::warning(this,"error","Open File Error!");
                return;
            }
            else
            {
                QTextStream textStream(&filename);
                QString str = ui->textEdit->toPlainText();
                textStream << str;
                Last_FileContent =str;
            }
            QMessageBox::information(this,"Ssve File","Save File Success",QMessageBox::Ok);
            filename.close();
            flag_isNew = 0;
            Last_FileName = str;
        }
    }
    else
    {
        if(flag_isOpen)
        {
            QFile file(Last_FileName);
            if(!file.open(QIODevice::WriteOnly | QIODevice::Text))
            {
                QMessageBox::warning(this,"error","Open File Faile");
                return;
            }
            else
            {
                QTextStream textString(&file);
                QString str = ui->textEdit->toPlainText();
                textString << str;
                Last_FileContent = str;
                file.close();
            }
        }
        else
        {
            QMessageBox::warning(this,"Warning","Please new or open a file");
            return;
        }
    }
}
void MainWindow::on_closeEvent(QCloseEvent *event)
{
    if(ui->textEdit->toPlainText() == Last_FileContent)
        event->accept();
    else
    {
        if(QMessageBox::warning(this,"Warning","the file have not save,ensure exit?",QMessageBox::Yes|QMessageBox::No) == QMessageBox::Yes)
        {
            event->accept();
        }
        else
            event->ignore();
    }
}
3、QString与char之间的转换:( QString是QT自带的字符串封装模式,与char有区别
 
QString  --> char:
Qstring  str;
char*  ch;
QByteArray ba = str.toLatin1();    
ch=ba.data();
 
char --> QString:(直接转换)
方法1:char* ch = "acuity";
              QString str(ch);
方法2:
             char *ch = "xxxx";
             QString  stt.append(ch);
 
///
八、QT的QMessageBox消息弹窗的几个常用函数
1、 warning()  弹出警示弹窗,一般用于强提醒
2、 critical()  警告弹窗,一般用于报错
3、 information()  消息提示弹窗,用于显示及时消息信息
4、 about() 一般性弹窗,可以用于显示积极但不重要的信息。
这四个函数的参数接口均一致。
//
九、 QT中对超大文本文件的读写操作
1、对超大文件的读取
 
头文件:
# include < QFile>
# include < QFileDialog>
# include < QFileDevice>
代码步骤:
1、 Bin_file_write_Path = QFileDialog:: getOpenFileName( this, "选择xxx.app和xxx.crc", "./", "TextFile(*.app *.crc)");  //指定目标文件//
2、 QFile PLC_Bin_fb( Bin_file_write_Path);
PLC_Bin_fb. open( QIODevice:: ReadOnly);  //以只读形式打开目标文件//
3、char *read_data =  PLC_Bin_fb. map( 0, PLC_Bin_fb. size());  //将文件中的内容整篇映射到程序的应用空间中//
4、读取read_data内的数据后, PLC_Bin_fb.close(); //关闭文件并取消映射//
2、将超数据量写入文件
头文件:
#include <QFile>
#include <QFileDialog>
#include <QFileDevice>
代码步骤:
1、Dowload_PLC_Bin_Path = QFileDialog::getSaveFileName(this,"下载app文件","./","TextFile(*.app)");  //选择要写入的文件//
2、QFile Arr_File_fd(Dowload_PLC_Bin_Path);
Arr_File_fd.open(QIODevice::WriteOnly);  //以只写入的方式将文件打开//
3、Arr_File_fd.write((char*)APP_Data,readed_size);  //直接调用write函数将数据写入即可//
4、Arr_File_fd.close();  //关闭文件//
//
散记:
1、自动打包工程完整的执行包,用于发布软件
第一步:生成工程文件的 Release包;定位到xxx.exe文件目录下;
第二步:单独将xxx.exe拷贝到一个目录里,打开cmd调试窗口;
第三步:在cmd窗口中,cd到存放单独的xxx.exe文件的位置;
第四步:执行指令 D:\QT5.12.9\5.12.9\mingw73_32\bin\ windeployqt.exe  xxx.exe 使用工具 windeployqt自动为xxx.exe配置依赖库。
2、利用QT自带的cmd环境对应编译器打包
1、使用QT自带编译器的Release模式,生成完整的运行包;定位到该目录下,找到对应的xxx.exe文件。
2、将xxx.exe文件拷贝出来到自定义目录下(建议为纯英文路径)
3、打开电脑的“开始”菜单,找到QT的目录,在下面找到 对应编译器的CMD环境,将其打开
4、在打开的cmd环境中,输入执行: windeployqt xxx.exe即可。
3、打包发布软件遇到运行缺库报警或无法找到(0xc00007b)错误的解决方案
 
分析:
1、可能是使用的cmd和编译器不匹配,请仔细检查!!
2、电脑运行环境中,PATH目录下没用关联到对应的打包工具环境
 
解决问题2方法:
1、先将之前编译生成的目录及exe删除;
2、鼠标右击“电脑”-->属性--->“高级系统设置” --> 高级选项卡下的环境变量
3、找到“PATH”后,点击“编辑”,在里面添加QT所有的编译器工具路径
4、D:\QT5.12.9\5.12.9\这个目录下面除了“Src”其他的都是对应编译器的工具,对应目录下的bin里面
5、举个例子:D:\QT5.12.9\5.12.9\mingw73_32\bin 这个目录路径添加到PATH里
6、重新开始编译打包流程。
4、如何给自己的软件加logo
图片在线转换工具: http://www.ico51.cn/
 
方法1:
1、 使用qmake来生成makefile文件,只需要在.pro中添加: RC_ICONS = logo.ico
2、将对应的logo.ico放在pro文件同个目录下;
3、重新编译生成exe即可。
注意:若要更换ico,需要先make clear 再更换ico,再重新编译!!
 
方法2:
1.在项目代码文件夹中,新建一个logo.txt文件,在文件里写上以下内容: IDI_ICON1 ICON DISCARDABLE "logo.ico"
2、 然后重命名为logo.rc文件;
3、 在.pro文件里添加:RC_FILE = logo.rc
 
//
 
 
 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值