• 【秒懂音视频开发】06_Qt开发基础


    .pro文件的配置

    跨平台配置

    之前我们分别在WindowsMac环境的Qt项目中集成了FFmpeg。

    可以发现在.pro文件的配置中,FFmpeg库在Mac、Windows上的位置是有所差异的。这样就会导致.pro文件无法跨平台使用。

    # windows
    INCLUDEPATH += F:/Dev/ffmpeg-4.3.2/include
    
    # mac
    INCLUDEPATH += /usr/local/Cellar/ffmpeg/4.3.2/include
    

    为了实现跨平台配置,可以在配置前面加上平台标识的前缀,表示这个配置只会在对应的平台生效。

    # windows
    win32:INCLUDEPATH += F:/Dev/ffmpeg-4.3.2/include
    win32:LIBS += -LF:/Dev/ffmpeg-4.3.2/lib 
                  -lavcodec 
                  -lavdevice 
                  -lavfilter 
                  -lavformat 
                  -lavutil 
                  -lpostproc 
                  -lswscale 
                  -lswresample
    
    # mac
    macx:INCLUDEPATH += /usr/local/Cellar/ffmpeg/4.3.2/include
    macx:LIBS += -L/usr/local/Cellar/ffmpeg/4.3.2/lib 
                -lavcodec 
                -lavdevice 
                -lavfilter 
                -lavformat 
                -lavutil 
                -lpostproc 
                -lswscale 
                -lswresample 
                -lavresample
    
    # linux
    # linux:INCLUDEPATH += ...
    # linux:LIBS += ...
    

    以后针对每个平台的配置可能会比较多,可以使用大括号来简化。

    # windows
    win32 {
        INCLUDEPATH += F:/Dev/ffmpeg-4.3.2/include
        LIBS += -LF:/Dev/ffmpeg-4.3.2/lib 
                -lavcodec 
                -lavdevice 
                -lavfilter 
                -lavformat 
                -lavutil 
                -lpostproc 
                -lswscale 
                -lswresample
    }
    
    # mac
    macx {
        INCLUDEPATH += /usr/local/Cellar/ffmpeg/4.3.2/include
        LIBS += -L/usr/local/Cellar/ffmpeg/4.3.2/lib 
                -lavcodec 
                -lavdevice 
                -lavfilter 
                -lavformat 
                -lavutil 
                -lpostproc 
                -lswscale 
                -lswresample 
                -lavresample
    }
    

    自定义变量

    可以将公共的信息抽取成变量,然后使用$${}去访问。

    # mac
    macx {
        FFMPEG_HOME = /usr/local/Cellar/ffmpeg/4.3.2
        INCLUDEPATH += $${FFMPEG_HOME}/include
        LIBS += -L$${FFMPEG_HOME}/lib 
                -lavcodec 
                -lavdevice 
                -lavfilter 
                -lavformat 
                -lavutil 
                -lpostproc 
                -lswscale 
                -lswresample 
                -lavresample
    }
    

    读取系统环境变量

    也可以通过$$()读取系统的环境变量。比如,我的Windows中有个叫做JAVA_HOME的环境变量。

    环境变量

    # 使用message打印环境变量JAVA_HOME的值
    message($$(JAVA_HOME))
    

    最后可以在概要信息处看到JAVA_HOME的打印结果。

    概要信息

    控件的基本使用

    为了更好地学习Qt控件的使用,建议创建项目时先不要生成ui文件。

    不生成ui文件

    打开mainwindow.cpp,在MainWindow的构造函数中编写界面的初始化代码。

    窗口设置

    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent) {
        // 设置窗口标题
        setWindowTitle("主窗口");
    
        // 设置窗口大小
        // 窗口可以通过拖拽边缘进行自由伸缩
    //    resize(400, 400);
        
        // 设置窗口的固定大小
        // 窗口不能通过拖拽边缘进行自由伸缩
        setFixedSize(400, 400);
    
        // 设置窗口的位置
        // 以父控件的左上角为坐标原点
        // 没有父控件,就以屏幕的左上角作为坐标原点
        move(100, 100);
    }
    

    Qt坐标系如下图所示。
    Qt坐标系

    添加子控件

    #include <QPushButton>
    
    // 创建按钮
    QPushButton *btn = new QPushButton;
    // 设置按钮的文字
    btn->setText("登录");
    // 设置父控件为当前窗口
    btn->setParent(this);
    // 设置按钮的位置和大小
    btn->move(50, 50);
    btn->resize(100, 50);
    
    // 创建第2个按钮
    new QPushButton("注册", this);
    

    new出来的Qt控件是不需要程序员手动delete的,Qt内部会自动管理内存:当父控件销毁时,会顺带销毁子控件。

    信号与槽

    基本使用

    • 信号(Signal):比如点击按钮就会发出一个点击信号
    • 槽(Slot):一般也叫槽函数,是用来处理信号的函数
    • 官方文档参考:Signals & Slots

    信号与槽

    上图中的效果是:

    • Object1发出信号signal1,交给Object2的槽slot1、slot2去处理
      • Object1是信号的发送者,Object2是信号的接收者
    • Object1发出信号signal2,交给Object4的槽slot1去处理
      • Object1是信号的发送者,Object4是信号的接收者
    • Object3发出信号signal1,交给Object4的槽slot3去处理
      • Object3是信号的发送者,Object4是信号的接收者
    • 1个信号可以由多个槽进行处理,1个槽可以处理多个信号

    通过connect函数可以将信号的发送者信号信号的接收者连接在一起。

    connect(信号的发送者, 信号, 信号的接收者, 槽);
    
    // 比如点击按钮,关闭当前窗口
    // btn发出clicked信号,就会调用this的close函数
    connect(btn, &QPushButton::clicked, this, &MainWindow::close);
    
    // 可以通过disconnect断开连接
    disconnect(btn, &QPushButton::clicked, this, &MainWindow::close);
    

    自定义信号与槽

    信号的发送者和接收者都必须继承自QObject,Qt中的控件最终都是继承自QObject,比如QMainWindow、QPushButton等。

    信号的发送者

    • sender.h
      • Q_OBJECT用以支持自定义信号和槽
      • 自定义的信号需要写在signals:下面
      • 自定义的信号只需要声明,不需要实现
    #ifndef SENDER_H
    #define SENDER_H
    
    #include <QObject>
    
    class Sender : public QObject {
        Q_OBJECT
    public:
        explicit Sender(QObject *parent = nullptr);
    
        // 自定义信号
    signals:
        void exit();
    };
    
    #endif // SENDER_H
    
    • sender.cpp
    #include "sender.h"
    
    Sender::Sender(QObject *parent) : QObject(parent) {
    
    }
    

    信号的接收者

    • receiver.h
      • 自定义的槽建议写在public slots:下面
    #ifndef RECEIVER_H
    #define RECEIVER_H
    
    #include <QObject>
    
    class Receiver : public QObject {
        Q_OBJECT
    public:
        explicit Receiver(QObject *parent = nullptr);
    
        // 自定义槽
    public slots:
        void handleExit();
    };
    
    #endif // RECEIVER_H
    
    • receiver.cpp
    #include "receiver.h"
    #include <QDebug>
    
    Receiver::Receiver(QObject *parent) : QObject(parent) {
    
    }
    
    // 实现槽函数,编写处理信号的代码
    void Receiver::handleExit() {
        qDebug() << "Receiver::handleExit()";
    }
    

    连接

    • mainwindow.h
    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    
    class MainWindow : public QMainWindow {
        Q_OBJECT
    public:
        MainWindow(QWidget *parent = nullptr);
        ~MainWindow();
    };
    #endif // MAINWINDOW_H
    
    • mainwindow.cpp
    #include "mainwindow.h"
    #include "sender.h"
    #include "receiver.h"
    
    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent) {
        // 创建对象
        Sender *sender = new Sender;
        Receiver *receiver = new Receiver;
    
        // 连接
        connect(sender,
                &Sender::exit,
                receiver,
                &Receiver::handleExit);
    
        // 发出信号
        // 最终会调用Receiver::handleExit函数
        emit sender->exit();
            
        // 销毁对象
        delete sender;
        delete receiver;
    }
    
    MainWindow::~MainWindow() {
    
    }
    

    参数和返回值

    信号与槽都可以有参数和返回值:

    • 发信号时的参数会传递给槽
    • 槽的返回值会返回到发信号的位置
    // 自定义信号
    signals:
        int exit(int a, int b);
    
    // 自定义槽
    public slots:
        int handleExit(int a, int b);
    
    int Receiver::handleExit(int a, int b) {
        // Receiver::handleExit() 10 20
        qDebug() << "Receiver::handleExit()" << a << b;
        return a + b;
    }
    
    // 发出信号
    int a = emit sender->exit(10, 20);
    // 30
    qDebug() << a;
    

    需要注意的是:信号的参数个数必须大于等于槽的参数个数。比如下面的写法是错误的:

    // 自定义信号
    signals:
        void exit(int a);
    
    // 自定义槽
    public slots:
        void handleExit(int a, int b);
    

    连接2个信号

    比如下图,连接了Object 1的Signal 1A和Object 2的Signal 2A

    • 当Object 1发出Signal 1A时,会触发Slot X、Slot Y
    • 当Object 2发出Signal 2A时,只会触发Slot Y,而不会触发Slot X

    连接2个信号

    可以利用connect函数连接2个信号

    • 当sender发出exit信号时,sender2会发出exit2信号
    • 当sender2发出exit2信号时,sender并不会发出exit信号
    connect(sender,
            &Sender::exit,
            sender2,
            &Sender2::exit2);
    

    Lambda

    也可以直接使用Lambda处理信号。

    connect(sender, &Sender::exit, []() {
        qDebug() << "lambda handle exit";
    });
    

    ui文件

    如果你的控件是通过ui文件生成的,连接槽函数的步骤会更加简单。

    首先建议给按钮们起个有意义的变量名,比如分别叫做:loginButtonregisterButton

    起名

    对着登录按钮右键,选择转为槽

    转为槽

    选择clicked信号,然后OK

    clicked

    此时,Qt Creator已经帮你自动生成了槽函数的声明和实现,当我们点击登录按钮时,就会调用这个函数。

    class MainWindow : public QMainWindow {
        Q_OBJECT
    private slots:
        // 槽函数的声明
        void on_loginButton_clicked();
    };
    
    // 槽函数的实现
    void MainWindow::on_loginButton_clicked() {
        qDebug() << "on_loginButton_clicked";
    }	
    

    其实,认真观察函数名可以发现一个规律,函数名的命名规则是:on_控件的变量名_事件名

    于是,我们可以尝试编写以下代码。

    class MainWindow : public QMainWindow {
        Q_OBJECT
    private slots:
        // 槽函数的声明
        void on_registerButton_clicked();
    };
    
    // 槽函数的实现
    void MainWindow::on_registerButton_clicked() {
        qDebug() << "on_registerButton_clicked";
    }	
    

    然后,你点击一下注册按钮,会发现成功调用了MainWindow::on_registerButton_clicked函数。

    于是得知:ui文件中的控件会自动跟符合命名规则的槽函数建立连接

    最后,再提示一个知识点:ui文件中的控件可以在代码中通过ui->变量名访问。

    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent), ui(new Ui::MainWindow) {
        ui->setupUi(this);
    
        // 通过ui->访问ui文件中的2个按钮
        ui->loginButton->setFixedSize(100, 30);
        ui->registerButton->setFixedSize(100, 30);
    }
    
  • 相关阅读:
    聊聊Senior .net 面试,作为面试官你称职吗
    使用Microsoft BizTalk Adapter for mySAP Business Suite需要注意的一些限制点
    eos账号管理
    如何安装以太坊钱包Parity
    Infoq主办 Baidu Web 开发者大会记录
    http请求的详细过程转载
    php 下载保存文件保存到本地
    php section
    用javascript拼接html代码标签
    php使用sql数据库 取得字段问题
  • 原文地址:https://www.cnblogs.com/mjios/p/14506905.html
Copyright © 2020-2023  润新知