基本概念

Model/View

  • 主要类

    • Model

      • 抽象基类 QAbstractItemModel
      • 实现类

        • QFileSystemModel
        • QStringListModel

          • string list 字符串列表
    • View

      • 抽象基类 QAbstractItemView
      • 实现类

        • QTableView

          • 即表格,类似 Excel
        • QListView
        • QHeaderView

          • table 和 tree 都有表头
    • Delegate

      • 抽象基类 QAbstractItemDelegate
      • 实现类

        • QStyledItemDelegate

          • 简单工具可以继承它,而不是 QAbstractItemDelegate

分工

  • 标准 MVC 框架

    • Model : 负责数据
    • View : 负责展示
    • Controller : 负责交互,用户的操作
  • Qt Model/View

  • Model

    • 负责数据访问
  • View

    • 整体布局 Layout
    • 在需要处理和编辑时,与 Delegate 合作 Editing
    • 展示 Present
    • 跳转 Navigation
    • 选择 Selection
    • 交互

      • 拖拽 Drag and Drop
      • 右键菜单 Context Menu
    • 编辑工具

访问

  • QModelIndex

    • 通过 (row, column, parent_index) 获取
    • 父 Item –> parent_index
  • Role 角色

    • Qt::ItemDataRole (枚举类型)
    • 作用:同一个 item 可以存储不同类型数据

      • 类似 一个 python dict {key: vlaue, …}
      • 为不同用途,提供不同数据
    • 获取

      • model->data(index, role_type)

使用简介

窗口部件

QDialog

QColorDialog –> class + head file

method

1
2
3
QColor getColor(Qt::red ->默认颜色, this,
                title ->标题,
                QColorDialog::ShowAlphaChanel)

–> constructor QDialog(Qt::red, this)

–> method setOption(QColorDialog::ShowAlphaChannel) exec() —>以模态方式运行 currentColor() —> 返回 QColor

QFileDialog

  • methods

    • QFileDialog::getOpenFileName(this, Title, "d:" 默认路径, ("图片文件(*png *jpg);; (文本文件(*txt))"))

Qt Creator 软件操作

帮助

  • 定位到帮助模式: Ctrl + 6
  • 添加书签:Ctrl + M
  • 索引搜索:Alt + L 进入搜索框

    • 进入索引模式:Alt + i (似乎不正确)

Qt 工具

Qt Assistant

  • 用于帮助文档

Qt Designer

Qt Linguist

快速查找文件

  • 快捷键: Ctrl + K
  • 查找方式:可以使用通配符*

    • 如:he*ui –> helloworld.ui

代码自动补全

  • 强制补全:Ctrl + <SPACE>

发布软件

  • 文件复制

    1. 创建软件的文件夹

      • 新建一个文件夹,重命名为“我的第一个 Qt 程序”,
    2. 复制应用程序

      • 然后将 release 文件夹中的 helloworld.exe 复制过来,
    3. 复制动态链接库文件,即: .dll 文件

      • 再去 Qt 安装目录的 bin 目录中将

        libgcc_s_dw2-1.dll、 libstdc++-6.dll、 libwinpthread-1.dll、 Qt5Core.dll、Qt5Gui.dll 和 Qt5Widgets.dll 这 6 个文件复制过来 ,。

  • 复制模块插件所需要的 dll 动态库文件

    • 另外,还需要将 C:\Qt\Qt5.6.1\5.6mingw49_32\plugins 目录中的 platforms 文件夹复制过来 (不要修改该文件夹名称),里面只需要保留 qwindows.dll 文件即可
  • 发布软件需要的的文件列表

    – libgcc_s_dw2-1.dll
    – libstdc++-6.dll
    – libwinpthread-1.dll

    helloworld –|– Qt5Core.dll

    – Qt5Gui.dll
    – Qt5Widgets.dll
    – plateforms – qwindows.dll
    – helloworld.exe
  • 软件编写中用到特别的模块,要适当添加文件

    • 图片

      • 若程序中使用了 png 以外格式的图片, 在发布程序时就要将 Qt 安装目录下的 plugins 目录 中的 imageformats 文件夹复制到发布程序文件夹中, 其中只要保留自己用到的文件格式的 dll 文件即可。
      • 例如:用到了 gif 文件,那么只需要保留 qgif.dll。
    • 数据库

      • 而如果程序中使用了其他的模块,比如数据库, 那么就要将 plugins 目录中的 sqldrivers 文件夹复制过来, 里面保留自己用到的数据库驱动。

设置应用程序图标

  1. 图标图片命名

    • myico.ico
    • 复制到 source file 源文件目录
  2. 在 helloworld.pro 文件中添加

    • RC_ICONS = myico.ico
  3. 重新编译运行程序

创建 Qt 程序

纯代码编写 Qt 程序

使用 Qt Creator

  1. 选择模板时

    • 选 empty qmake project
  2. 修改 project 文件

    • 在 helloworld.pro 添加下述代码
    • greaterThan(QT_MAJOR_VERSION, 4): QT += widigets
  3. 添加 main.cpp 的源代码
  4. 编译运行

使用命令行 terminal

  1. 添加 main.cpp 等源代码
  2. 使用开始菜单中的 MinGW(Qt 5.6 for Desktop (MinGW 4.9.2 32 bit))

    • cd HelloWorld 程序文件夹
    • 这个 MinGW for Desktop 的目录

      • 默认路径在 C:\Qt\Qt5.6.1\5.6mingw49_32
      • 在 bin 下有 qtenv2.bat
  3. 生成 project 文件.pro

    • qmake -project
  4. 修改 project 文件

    • 在 helloworld.pro 添加下述代码
    • greaterThan(QT_MAJOR_VERSION, 4): QT += widigets
  5. 直接使用 qmake 命令生成 Makefile

    • qmake
  6. 使用 mingw32-make 命令编译

    • mingw32-make
  7. 运行程序

    1
    2
    3
    4
    5
    6
    7
    
    $qmake –project
    $vim *.pro
    这时在helloworld.pro文件中添加QT += widgets ,然后依次执行如下命令:
    $qmake
    $mingw32-make
    $cd release
    $./helloworld.exe

使用.ui 文件

在 Qt Creator 中使用.ui 文件

  1. 添加.ui 文件

    • hellodialog.ui
    • add file 添加文件
    • 选择模板

      • Dialog without buttons
  2. 在 Qt Designer 中编辑,保存
  3. build,生成对应的头文件

    • build 生成:Ctrl + Shift + B
    • ui_helloworld.h
  4. 在 main.cpp 中添加内容

    • 操纵 hellodialog.ui
    • Ui::HelloDialog ui;
    • ui.setupUi(&window);

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      
      #include "ui_hellodialog.h"  // <---*** this was added
      int main(int argc, char *argv[])
      {
          QApplication a(argc, argv);
          QDialog w;
          Ui::HelloDialog ui;        // <---*** this was added
          ui.setupUi(&w);            // <---*** this was added
          w.show();
          return a.exec();
      }
  5. 编译运行

注: build 即生成,包括编译连接两步。

在命令行 terminal 中使用.ui 文件

  1. 复制.ui 文件与 main.cpp 等源代码

    • hellodialog.ui
    • .ui 需要在 Qt Creator 中先创建
  2. 编译.ui 文件

    • uic hellodialog.ui -o ui_hellodialog.h
  3. 创建项目其余部分

    • 如上面从 terminal 创建 Qt 一样

      1
      2
      3
      4
      5
      6
      7
      
      $qmake –project
      $vim *.pro
      这时在helloworld_2.pro文件中添加QT += widgets ,然后依次执行如下命令:
      $qmake
      $mingw32-make
      $cd release
      $./helloworld.exe

自定义 C++类

  1. 创建空项目

    • Empty qmake project
    • .pro 文件添加:greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
  2. 创建自定义 C++类

    • 添加文件
    • 选择 C++类,

      • 基类选择自定义<Custom>
      • 再选择或填写 QDialog
    • 类名:HelloDialog
  3. 添加 main.cpp 源代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    #include <QApplication>
    #include "hellodialog.h"
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        HelloDialog w;
        w.show();
        return a.exec();
    }
  4. 添加.ui 文件 helloworld.ui
  5. 更改 C++类,HelloDialog

    • 不在使用 main.cpp 操纵.ui 文件
    • 在 HelloDialog 类中操纵.ui 文件
    • 如何操纵:

      • eg:

        1
        2
        
        Ui::Hellodialog *ui;
        ui->setupUi();
      • 在新 C++类中包含一个 Ui::HelloDialog 对象
    • C++类源码:

      • 头文件

        • eg: hellodialog.h

           1
           2
           3
           4
           5
           6
           7
           8
           9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          
          #ifndef HELLODIALOG_H
          #define HELLODIALOG_H
          
          #include<QDialog>
          
          namespace Ui
          {
              class HelloDialog;
          }
          
          class HelloDialog: public QDialog
          {
              Q_Object
          
              public:
                  explicit HelloDialog(QWidget* parent=0);
                  ~HelloDialog();
              private:
                  Ui::HelloDialog *ui;
          }
          #endif
      • 新 C++类,实现文件 cpp

        • hellodialog.cpp

           1
           2
           3
           4
           5
           6
           7
           8
           9
          10
          11
          12
          13
          14
          15
          16
          17
          
          #include "hellodialog.h"
          #include "ui_hellodialog.h"
          HelloDialog::HelloDialog(QWidget *parent) :
              QDialog(parent)
          {
              ui = new Ui::HelloDialog;
              ui->setupUi(this);
          }
          /*
           ,* 或者这样
           HelloDialog::HelloDialog(QWidget *parent) :
           QDialog(parent),
           ui(new Ui::HelloDialog)
           {
           ui->setupUi(this);
           }
          ,*/
  6. 编译运行

使用 Qt designer,Qt 设计师界面类

  1. 创建空项目

    • Empty qmake project
    • .pro 文件添加:greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
  2. 添加文件

    • 模板选择

      • Qt 设计师界面类,Qt designer form class
      • Dialog without buttons
    • 这样会同时添加一个 head file 头文件和一个 form 即.ui 文件
    • 相当于上面的自定义一个 C++类,再添加一个.ui 文件
  3. 修改 main.cpp

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    #include <QApplication>
    #include "hellodialog.h"
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        HelloDialog w;
        w.show();
        return a.exec();
    }

关于.ui 文件与头文件

文件列表

  1. hellodialog.ui
  2. ui_hellodialog.h

    • class Ui_HelloDialog

      • 没有继承其他类
    • namespace Ui{ class HelloDialog: public Ui_HelloDialog; }

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      
      QT_BEGIN_NAMESPACE // begin
      
      class Ui_HelloDialog
      {
      }; //有分号
      
      namespace Ui
      {
          class HelloDialog: public Ui_HelloDialog; //继承.ui文件中的自动生成类
      }  //没分号
      
      QT_END_NAMESPACE //end  **-->注意这一对宏
      
  3. hellodialog.h

    • class HelloDialog: public QDialog{};
    • namespace Ui{class HelloDialog;}
    • 不包含#include"ui_hellodialog.h"
  4. hellodialog.cpp

    • #include"ui_hellodialog.h"
    • #include"hellodialog.h"

注意:

  • 对应的 form 文件.ui,类文件

    • 使用相同的名字 hellodialog
  • 对应的类

    • 使用相同的名字 HelloDialog, Ui_HelloDialog
  • 类 HelloDialog 包含一个通类型的指针

    • Ui::HelloDialog* ui = new Ui::HelloDialog
    • 初始化方法

      • 放到构造函数的函数体中

        1
        2
        3
        4
        5
        6
        
        HelloDialog::HelloDialog(QWidget *parent) :
            QDialog(parent),
        {
            ui= new Ui::HelloDialog;
            ui->setupUi();
        };
      • 或者放到构造函数的初始化列表中

        1
        2
        3
        4
        5
        6
        
        HelloDialog::HelloDialog(QWidget *parent) :
            QDialog(parent),
            ui(new Ui::HelloDialog)
        {
            ui->setupUi();
        };

字符串

实现多语言

  • 使用 string = QObject::tr("your string text")

Qt 类的定义

  • 在类定义的第一行添加 Q_Object

    • Q_Object
    • 扩展 c++类的功能
    • 必须在最开始添加

      1
      2
      3
      4
      5
      6
      7
      8
      9
      
      class HelloDialog: public QDialog
      {
      
          Q_Object // 最开始添加,没有分号
      
          public:
              int i;
              // ...
      }

show()显示函数,调用 message loop

  • 有几个 show()就有几个窗口 window

QWidget

  • 最基础的 Qt 用户界面类的基类
  • 被称为基础窗口部件类,基础 widget
  • 父类:

    • QObject
    • QPaintDevice

窗口部件 Widget,简称部件

  • 大窗口的组成元素,
  • 如:按钮,标签 Label,对话框等等

窗口状态 WindowStates

  • flags, 目的:

    • 用来标记窗口状态

      • 最小化:Qt::WindowMinimized
      • 最大化:Qt::WindowMaximized
      • 全屏:Qt::WindowFullScreen
      • 激活状态,键盘作用的地方: Qt::WindowActive
      • 正常状态:Qt::WindowNoState
  • 设置方法:

    • widget->setWindowState(Qt::WindowStates state)

Qt 枚举型

  • 特征:

    • 如:Qt::WindowNoState,Qt::WindowStates 类型

      • 以 Qt 开头
      • 每个单词首字母都大写
    • 如:Qt::GlobalColor 类型,Qt::white

      • 枚举元素,也可能全小写字母
    • 如:Qt::AA_DontShowIconsInMenus,Qt::ApplicationAtribute 类型

      • 加类型前缀大写字母
    • 如:Qt::Key_Tab,Qt::Key 类型

      • 加类型名当前缀

窗口

  1. 定义:

    • 没有父部件的部件
  2. 独特性质:

    • 没有 parent 父部件
  3. 一般性质:

    • 有边框

      • 无边框方法:

        • Qt::WindowFlags f=…
    • 有标题栏
  4. 名词:

    • 顶级部件 top-level widget: 即窗口
    • 子部件 child-level widget
  5. 构造函数

    • QWidget(QWidget* parent=nullprt, Qt::WindowFlags f=…)

      1
      
      QWidget *widget = new QWidget(0, Qt::Dialog | Qt::FramelessWindowHint);
  6. Qt::WindowFlags

    • 枚举类型 enum
    • 成员:

      • Qt::FramelessWindowHint 无边框
      • Qt::SplashScreen
      • Qt::WindowStaysOnTopHint 停留在其他窗口上面
  7. 几何布局

    • 两个特殊的点(位置)

      • pos(): 窗口的最左上角

        • 坐标:

          • pos().x()
          • pos().y()
      • geometry(): 窗口主内容部分的最左上角,返回 QRect

        • 坐标:

          • geometry.x()
          • geometry.y()
        • 另一层意思:内容部分尺寸

          • 宽:geometry.width()同 width()
          • 高: geometry.height()同 height()
    • 主窗口部分

      • frameGeometry()返回 QRect
      • 宽:frameGeometry().width()
      • 高:frameGeometry().height()
    • 主内容部分

      • 宽:geometry.width()同 width()
      • 高: geometry.height()同 height()
  8. 移动:

    • move():作用的是主窗口的 pos(),x,y
  9. 几个位置函数

    • rect()不包含 frame
    • size()不包含 frame
    • 包含框架:x()、y()、frameGeometry()、pos()和 move()等函数;
    • 不包含框架:geometry()、width()、height()、rect()和 size()等函数。

QDialog

模态

  1. 模态对话框

    • 模态 Modal
    • 特点:

      • 不关闭该窗口,不能操作其他窗口
    • 实现方法

      • 调用对应的 app.exec()

        1
        2
        
        QDialog dialog(this);
        dialog.exec();
      • show()之前调用 setModal()

        1
        2
        3
        
        QDialog *dialog = new QDialog(this);
        dialog->setModal(true);
        dialog->show();
      • 使用 setWindowModality()

        • 方法来源:

          • 继承自 QWidget
        • 输入参数

          • Qt::NonModal(不阻塞任何窗口,就是非模态)
          • Qt::WindowModal(阻塞它的父窗口和所有祖先窗口以及它们的子窗口)
          • Qt::ApplicationModal(阻塞整个应用程序的所有窗口)
        • setModal()函数默认设置的是 Qt::ApplicationModal
    • 信号处理

      • 信号发出者

        • QDialog::accept(), QDialog::reject()
      • 信号传递者

        • QDialog::exec()

          • 返回类型

            • QDialog::QDialogCode 枚举型

              • 成员:

                • QDialog::Accepted
                • QDialog::Rejected
      • 运作方式

        • QDialog::accept() <—> 发出 QDialog::Accepted

          • Hides the modal dialog and sets the result code to Accepted

            • 隐藏模态 Qdialog,返回信号 QDialog::Accepted
          • 在模态的 dialog 中的槽中调用 accept(),
          • dialog->exec()返回 QDialog::Accepted
        • QDialog::reject() <—> 发出 QDialog::Rejected

          • 在模态的 dialog 中的槽中调用 reject()
          • dialog->exec()返回 QDialog::Rejected
  2. 非模态对话框

    • 特点:

      • 开着它,也能操作别的窗口
    • 实现方法

      • 使用 show()函数来显示

        1
        2
        
        QDialog *dialog = new QDialog(this);
        dialog->show();

标准对话框

  1. 颜色对话框 QColorDialog

    • 使用方式

      • 静态方法
      • 直接创建实例
    • 接口

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      
      getColor(default_color, parent, window_title, dialog_options)
      //  QColor color = QColorDialog::getColor(Qt::red, this, tr("颜色对话框"),
      //                                          QColorDialog::ShowAlphaChannel);
      
      QColorDialog dialog(Qt::red, this);                // 创建对象
      dialog.setOption(QColorDialog::ShowAlphaChannel); // 显示alpha选项
      dialog.exec();                                    // 以模态方式运行对话框
      QColor color = dialog.currentColor();             // 获取当前颜色
      
      qDebug() << "color: " << color;
  2. 文件对话框 QFileDialog

    • 接口

      1
      2
      3
      4
      5
      6
      7
      8
      9
      
      QString str= QFileDialog::getOpenFileName(parent,titleStr,str_directory,tr("Image (*.png *.jpg)"));
      //    QString fileName = QFileDialog::getOpenFileName(this, tr("文件对话框"),
      //                             "D:", tr("图片文件(*png *jpg);;文本文件(*txt)"));
      
      //    qDebug() << "fileName:" << fileName;
      
      QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("文件对话框"),
                                                            "D:", tr("图片文件(*png *jpg)"));
      qDebug()<< "fileNames:" << fileNames;
  3. 字体对话框 QFontDialog

    1
    2
    3
    4
    5
    6
    7
    8
    
    QFont font=QFontDialog::getFont(bool* ok, parent);
    // ok用于标记是否按下了“OK”按钮
    bool ok;
    QFont font = QFontDialog::getFont(&ok, this);
    // 如果按下“OK”按钮,那么让“字体对话框”按钮使用新字体
    // 如果按下“Cancel”按钮,那么输出信息
    if (ok) ui->pushButton_3->setFont(font);
     else qDebug() << tr("没有选择字体!");
  4. 输入对话框 QInputDialog

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
    bool ok; // 当用户在QInputDialog对话框中按下OK键时,把bool ok设成ok=true,否则是,false
    // 获取字符串
    QString string = QInputDialog::getText(this, tr("输入字符串对话框"),
                                           tr("请输入用户名:"), QLineEdit::Normal,tr("admin"), &ok);
    if(ok) qDebug() << "string:" << string;
    // 获取整数
    int value1 = QInputDialog::getInt(this, tr("输入整数对话框"),
                                      tr("请输入-1000到1000之间的数值"), 100, -1000, 1000, 10, &ok);
    if(ok) qDebug() << "value1:" << value1;
    // 获取浮点数
    double value2 = QInputDialog::getDouble(this, tr("输入浮点数对话框"),
                                            tr("请输入-1000到1000之间的数值"), 0.00, -1000, 1000, 2, &ok);
    if(ok) qDebug() << "value2:" << value2;
    QStringList items;
    items << tr("条目1") << tr("条目2");
    // 获取条目
    QString item = QInputDialog::getItem(this, tr("输入条目对话框"),
                                         tr("请选择或输入一个条目"), items, 0, true, &ok);
    if(ok) qDebug() << "item:" << item;
  5. 消息对话框 QMessageBox

    • 接口,很多

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      
      int ret=QMessageBox::question(parent,title,label_str="你了解这个问题吗",buttons=MessageBox::Ok,default_button=MessageBox::Ok);
      information(parent,title,label_str,buttons,default_button);
      warning(parent,title,label_str,buttons=MessageBox::Abort,default_button);
      critical(parent,title,label_str,buttons=MessageBox::YesAll,default_button);
      about(parent,title,label_str);
      
      // 问题对话框
      int ret1 = QMessageBox::question(this, tr("问题对话框"),
                                       tr("你了解Qt吗?"), QMessageBox::Yes, QMessageBox::No);
      if(ret1 == QMessageBox::Yes) qDebug() << tr("问题!");
      // 提示对话框
      int ret2 = QMessageBox::information(this, tr("提示对话框"),
                                          tr("这是Qt书籍!"), QMessageBox::Ok);
      if(ret2 == QMessageBox::Ok) qDebug() << tr("提示!");
      // 警告对话框
      int ret3 = QMessageBox::warning(this, tr("警告对话框"),
                                      tr("不能提前结束!"), QMessageBox::Abort);
      if(ret3 == QMessageBox::Abort) qDebug() << tr("警告!");
      // 错误对话框
      int ret4 = QMessageBox::critical(this, tr("严重错误对话框"),
                                       tr("发现一个严重错误!现在要关闭所有文件!"), QMessageBox::YesAll);
      if(ret4 == QMessageBox::YesAll) qDebug() << tr("错误");
      // 关于对话框
      QMessageBox::about(this, tr("关于对话框"),
                         tr("yafeilinux致力于Qt及Qt Creator的普及工作!"));
    • 返回类型,枚举型,QMessageBox::StandardButton 类型

      • QMessageBox::Ok
      • QMessageBox::Cancel
      • QMessageBox::Close 等等
    • 关于 buttons 参数,default_buttons 参数

      • buttons:

        • 设置对话框会显示哪些按钮
      • default_buttons:

        • 设置默认会选择的按钮,必须是 buttons 中设定好的
  6. 进度对话框 QProgressDialog

    • 构造

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      
      QProgressDialog::QProgressDialog(const QString &labelText,
                                       const QString &cancelButtonText,
                                       int minimum, int maximum,
                                       QWidget *parent = nullptr, Qt::WindowFlags f = ...);
      QProgressDialog dialog(tr("文件复制进度"), tr("取消"), 0, 50000, this);
      dialog.setWindowTitle(tr("进度对话框"));     // 设置窗口标题
      dialog.setWindowModality(Qt::WindowModal);  // 将对话框设置为模态
      dialog.show();
      for(int i=0; i<50000; i++) {                // 演示复制进度
        dialog.setValue(i);                     // 设置进度条的当前值
        QCoreApplication::processEvents();      // 避免界面冻结
        if(dialog.wasCanceled()) break;         // 按下取消按钮则中断
       }
      dialog.setValue(50000);    // 这样才能显示100%,因为for循环中少加了一个数
      qDebug() << tr("复制结束!");
    • 例子:

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      
      QProgressDialog progress("Copying files...", "Abort Copy", 0, numFiles, this);
      progress.setWindowModality(Qt::WindowModal);
      progress.show();
      
      for (int i = 0; i < numFiles; i++) {
        progress.setValue(i); //进度当前值
      
        if (progress.wasCanceled())
          break;
        //... copy one file
       }
      progress.setValue(numFiles);//由for循环少加了1,这样才能显示100%
      
    • 重要函数与方法:

      • dialog->setValue(value)
      • dialog->wasCanceled()
      • QtCoreApplication::processEvents()

        • 防止冻结界面
  7. 错误信息对话框 QErrerMessage

    1
    2
    3
    
    QErrorDialog errordlg= new QErrorDialog();
    errordlg->setWindowTitle(tr("错误信息对话框"));
    errordlg->showMessage(tr("这里是出错信息!"));
  8. 向导对话框 QWizard

    • 重要部分

      • 方法:wizard->addPage(QWizardPage* page)
      • 类型:QWizardPage
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    
      QWizardPage * MyWidget::createPage1()  // 向导页面1
      {
        QWizardPage *page = new QWizardPage;
        page->setTitle(tr("介绍"));
        return page;
      }
      QWizardPage * MyWidget::createPage2()  // 向导页面2
      {
        QWizardPage *page = new QWizardPage;
        page->setTitle(tr("用户选择信息"));
        return page;
      }
      QWizardPage * MyWidget::createPage3()  // 向导页面3
      {
        QWizardPage *page = new QWizardPage;
        page->setTitle(tr("结束"));
        return page;
      }
    
      // 向导对话框
      void MyWidget::on_pushButton_8_clicked()
      {
        QWizard wizard(this);
        wizard.setWindowTitle(tr("向导对话框"));
        wizard.addPage(createPage1());     // 添加向导页面
        wizard.addPage(createPage2());
        wizard.addPage(createPage3());
        wizard.exec();
      }
  9. 注:以上这些对话框类,最好直接查询 Help Mode,static method,property

对话框的共性

  1. 共同方法:

    • setWindowTitle()
    • setOption(), setOptions()

      • 每种对话框,都定义了一些枚举型,以设置几个特定选项
      • 如:QColorDialog::QColorDialogOption 类型,QColorDialog::AlphaChanel
  2. 模态
  3. 对于需要显示文本信息的对话框

    • setText()

      • QMessageBox 输出文本
    • setLabel
    • setLabelText

      • QInputDialog
      • QProgressDialog

图片类

QMovie

  • 作用:

    • 存放.gif 文件

      1
      2
      3
      
      QMovie *movie = new QMovie("F:/donghua.gif");
      ui->label->setMovie(movie);     // 在标签中添加动画
      movie->start();

QPixmap

  • 作用:

    • 存放.png 文件

      1
      
      ui->label->setPixmap(QPixmap("F:/logo.png"));

QLineEdit

  • 自动补全功能

    • 实现方式:使用 QCompleter 类

      1
      2
      3
      4
      5
      6
      7
      
      QStringList wordList;
      wordList << "Qt" << "Qt Creator" << tr("你好");
      // 新建自动完成器
      QCompleter *completer = new QCompleter(wordList, this);
      // 设置大小写不敏感
      completer->setCaseSensitivity(Qt::CaseInsensitive);
      ui->lineEdit4->setCompleter(completer);

数值设定

  • QAbstractSpinBox:抽象基类

    • 目的:提供一个数值设定框和一个行编辑器来显示数值

QDateTimeEdit(日期时间设定)

QSpinBox(整数设定)

QDoubleSpinBox(浮点数的设定)

QDateTimeEdit

1
2
3
4
5
// 设置时间为现在的系统时间
ui->dateTimeEdit->setDateTime(QDateTime::currentDateTime());
// 设置时间的显示格式
ui->dateTimeEdit->setDisplayFormat(
                                 tr("yyyy年MM月dd日ddd HH时mm分ss秒"));

滑块部件

  • QAbstractSlider 类

    • 目的:

      • 提供了一个区间内的整数值,它有一个滑块,可以定位到一个整数区间的任意值。

QScrollBar

滚动条 QScrollBar 更多的是用在 QScrollArea 类中来实现滚动区域;

QSlider

而 QSlider 是我们最常见的音量控制或多媒体播放进度等滑块;

QDial

是一个刻度表盘。

信号与槽

教程:

  • PyQt6 Signals and Slots - CodersLegacy
  • 本质:

    • 信号与槽都是函数
  • QObject::connect 两种连接方法

    • 函数指针法
    • SIGNAL 和 SLOT 宏 修饰法

      • 有默认参数时

        • singal 参数数量必须 >= slot 参数数量
  • 特性

    • 信号 signal

      • 必须和 slot 函数接口一致
    • 槽 slot

      • 函数接口 可以有 比 slot 更多的默认参数
    • 定义

      • 都是 public 方法
      • 定义位置

        • 只能在头文件中(原因:sigal 由 moc 生成, 即 Meta Object Compiler)
      • 返回值

        • void, 即没有返回值
      • 参数类型

        • 最好是常用类型

          • 方便 signal 和 slot 的重用性
    • 调用位置

      • signal

        • 推荐:定义类内部或子类
    • slot 调用顺序

      • 按 connect 注册顺序
    • 性能

      • 与 callback 回调函数 比较

        • 更灵活,但是更慢(有 overhead)
    • 发送 signal

      • 使用 emit 语句

        1
        2
        3
        4
        5
        6
        7
        
        void Counter::setValue(int value)
        {
          if (value != m_value) {
            m_value = value;
            emit valueChanged(value);   // 这是信号 signal
          }
        }
    • 激活

      • 由 emit 语句触发
      • emit 语句 存放在某个函数中

        • 这样 调用某个函数(或赋值语句等等),就会在后台 发出 emit signal
    • 本质

      • 执行一个函数,触发执行,一个或多个注册关联(connect)的 其他函数
      • 回调函数,执行完成后,再接着执行的函数(参数表一致)
    • sender, reciever 用途

      • singal 和 slot 各自的执行环境,上下文
      • 说明执行线程 context thread
    • 获取 sender 对象

      • QObject::sender()

        • 注意

          • 只有在作用 slot 使用的函数 被 signal 激发时才有效,否则返回 nullptr

信号

  • 注意

    • 只需要声明即可
    • 定义

      • moc 模块自动生成

  • 定义

    1
    2
    
    public slots:
    void showChildDialog();
    • 要加上 slots

      • Qt5 中不加也可,但推荐加上
    • public 表示在类外部也可使用它

连接信号与槽

使用 connect()函数

  • 位置

    • 在 QObject 中定义
  • 函数接口

    1
    2
    3
    4
    5
    
    QObject::connect(const QObject *sender,
                     const char *signal,
                     const QObject *receiver,
                     const char *method,
                     Qt::ConnectionType type = Qt::AutoConnection)
    • connect(ui->showChildButton, &QPushButton::clicked, this, &MyWidget::showChildDialog);
    • QPushButton::clicked()信号在 QPushButton 类中定义
  • 四个参数:

    • 发送者对象 sender
    • 发送的信号 signal
    • 接收者对象 receiver
    • 要执行的槽 method
用法
  • 直接使用

    • 直接写函数名

      1
      
      connect(sender, &QObject::destroyed, this, &MyObject::objectDestroyed);
  • 使用宏修饰函数

    • 使用 SIGNALSLOT

      • 使用环境

        • 有默认参数
        • signal 比 slot 有相同或更多的参数 (args_signal >= args_slot)
      • 例子

        1
        2
        3
        
        connect(sender, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed(Qbject*)));
        connect(sender, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed()));
        connect(sender, SIGNAL(destroyed()), this, SLOT(objectDestroyed()));
  • 注意

    • slot 和 signal 参数数量 compiler 不会检测
自定义类型 作 signal 和 slot 参数
  • 需要注册 Qt,以前 Qt 能在运行时 contruct, destruct, copy
  • 参考:qRegisterMetaType的使用_wadfji 的博客-CSDN博客_qregistermetatype
  • 官方教程

    • QMetaType
    • qRegisterMetaType<MyType>(const char* "MyType")

      • 要求

        • type 必须满足 rule of three (constructor, copy constructor, destructor)
        • 指针:指向的内容满足 rule of three
        • typedef 类型
    • qRegisterMetaType<MyType>()

      • 无参数
      • 要求

        • 用于被宏函数 Q_DECLARE_METATYPE() 修饰过的类型

使用 Qt Creator 的设计模式 Design mode

  • 进入编辑信号和槽模式的方法

    • 使用按钮

      • 设计模式顶上工具栏中的按钮
    • 使用快捷键

      • 快捷键:F4
  • 关联方法:

    • 鼠标拖拽

自动关联

  • 特点:

    • 不用手动设置 connect 关联
    • Qt 自动处理
    • 因此,源代码里找不到 connect 函数
  • 原理:

    • 自动生成与 sender,signal 对应名称的槽函数
    • 自动生成对应的 connect 函数语句
  • 方法:

    • 在设计模式中,右键发出信号的 widget,sender
    • 选择“转到槽”(Go to slot…)

      1
      2
      3
      4
      
      void MyDialog::on_pushButton_clicked()
      {
        accept();
      }
    • 命名方式:

      • 如:on_pushButton_clicked()
      • 名字组成

        • on
        • sender 信号发出者
        • signal 信号

信号发送者

  • QObject::sender()

    • 在 slot 函数中,获取当前 thread 内部的信号 signal 发送者
    • 注意: 不可是其它线程中的信号发送者

事件 Event

参考:

产生:

  • 一个事件发生,Qt 就会生成一个 QEvent 事件对象
  • 这个事件由接收者的 QObject::event(QEvent*) 方法处理

机制:

  • QObject::event(QEvent *e)

    • 不直接处理事件,把事件的处理分发给其它函数

QTimerEvent 定时发生的事件

参考:

特点:

  • 每隔一个 interval 时间段就会发生

触发:

  • QObject::startTimer(int interval) 启动

处理:

  • QObject::timerEvent(QTimerEvent*) 接收处理

QTimer 类, 计时器

参考:

方法:

  • start()

    • 启动
  • stop()

    • 暂停

更改对象名

  • widget->setObjectName(QStringLiteral("newname"))

QDebug

  • 两种用法

    • 类似 printf

      • qDebug("x: %d", x)
    • 类似 cout

      • qDebug()<<x<<str<<endl;
      • 这种用法要加头文件#include<QDebug>
  • 输出位置

    • Qt Creator 的应用程序输出

布局 Layout

  • 主要函数

  • QLayout

    • 基类:

      • QObject
      • QLayoutItem
  • 称呼:

    • 布局管理器
  • 具体布局类型

    1. QStackedLayout
    2. QGridLayout
    3. QFormLayout
    4. QBoxLayout

      • 子类型
    5. QHBoxLayout

      • QVBoxLayout
  • 选定布局管理器

    • QWidget::setLayout()

QHBoxLayout

1
2
3
4
5
6
7
QHBoxLayout *layout = new QHBoxLayout;      // 新建水平布局管理器
layout->addWidget(ui->fontComboBox);        // 向布局管理器中添加部件
layout->addWidget(ui->textEdit);
layout->setSpacing(50);                     // 设置部件间的间隔
layout->setContentsMargins(0, 0, 50, 100); // 设置布局管理器到边界的距离,
                                           // 四个参数顺序是左,上,右,下
setLayout(layout);

QGridLayout

1
2
3
4
5
6
7
8
QGridLayout *layout = new QGridLayout;
// 添加部件,从第0行0列开始,占据1行2列
layout->addWidget(ui->fontComboBox, 0, 0, 1, 2);
// 添加部件,从第0行2列开始,占据1行1列
layout->addWidget(ui->pushButton, 0, 2, 1, 1);
// 添加部件,从第1行0列开始,占据1行3列
layout->addWidget(ui->textEdit, 1, 0, 1, 3);
setLayout(layout);

设置部件大小

  • 名词:

    • hint:原意暗示,此处意为建议的 recommended
  • 两个大小属性(QWidget)

    • 属性

      • sizeHint
      • minimumSizeHint
    • 获取方法:对应的函数形式

      • sizeHint()
      • minimumSizeHint()
    • 设置方法: set 形式

      • setSizeHint()
      • setMinimumSizeHint()

名词

  • splash screen

    • 启动画面,版权页,溅射屏幕

进入 Qt 帮助模式教程

  • 搜索 Qt overview,进入总教程
  • 搜索 User Interfaces,进入 UI 教程

ui 文件

编译 uic

  • 作用

    • 把 ui 文件转换城头文件
  • 命令调用

    1
    
    uic -o ui_hellodialog.h hellodialog.ui

头文件

自动生成的头文件 ui_hellodialog.h

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
QT_BEGIN_NAMESPACE  //QT namespace


// 在全局中声明自动生成的UI类
class Ui_HelloDialog {

public:
  QDialog * dialog;
  // ... UI Form 中添加与定义的widgets 部件

  void setupUI(QDialog* dialog);  // 这里的类型由创建时选择的主类决定
  // 初始化UI formu

  void retranslateUi(QDialog* dialog);
  // translate 翻译widgets 中的文字,国际化操作
};


// 把自动生成的UI类,放入namespace Ui 中
namespace Ui {
class Dialog: public Ui_Dialog {};} // namespace Ui

QT_END_NAMESPACE

使用自动生成的头文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//*** mydialog.h

// * 声明自动生成的UI 类
QT_BEGIN_NAMESPACE
namespace Ui{
  class HelloDialog;
  // 这里只是声明,因此,不必写出继承等等信息
}
QT_END_NAMESPACE


// * 声明自己的类
//   用来包装UI form 自动生成的类, has a 类型

class HelloDialog {

  // 特殊宏: 定义QT 类
  QT_OBJECT

  public:
  // 构造 与 析构
  HelloDialog(QWidget* parent=nullptr): QDialog(parent),  // 基类的构造
                                        ui(new Ui::HelloDialog) // 自动类实例的创建
    {
      ui->setupUi(this) ; // 把Ui 自动类实例绑定到this上
    }

  ~HelloDialog(){
    delete ui;
  }
private:
  // * 存储UI form 自动生成类的实例
  Ui::HelloDialog* ui;
};

相关的三个类

  1. UI form 自动生成类 Ui_HelloDialog

    • 定义与声明在 QT 命名空间对之间
  2. 放入到 namespace Ui 中的 Ui::HelloDialog

    • 继承自 Ui_HelloDialog
    • 为了名称好看,使用命名空间进行包装
    • 可以外部使用了通过头文件 ui_hellodialog.h
    • 定义与声明在 QT 命名空间对之间

      • QT_BEGIN_NAMESPACE
      • QT_END_NAMESPACE
  3. 全局类 HelloDialog

    • 通过 has a 关系,内部绑定了 Ui::HelloDialog 类
    • 裸露在外,全局类型,不在命名空间中
    • 通过 QT_OBJECT 宏定义

解说

  • 添加一个 ui 文件

    • hellodialog.h
  • 自动生成其余三个文件

    • ui_hellodialog.h 和 hellodialog.h 与 helloworld.cpp
  • hellodialog.h

    • 不使用#include"ui_hellodialog.h"
    • 因为使用的只是 Ui::HelloDialog 的声明
  • hellodialog.cpp

    • 必须使用#include"ui_hellodialog.h"
    • 因为这里是使用了 Ui::HelloDialog 的实现内容

Qt Quick

QML Item

transform 变形功能

scale 放缩
  • 沿一个点放缩
  • 沿一个轴防缩
rotate 旋转
  • 沿一个点旋转 Origin
  • 沿一个轴旋转 Axis
translate 平移

pimpl 手法

  • 参考:QT namespace UI_hebbely 的博客-CSDN博客
  • 解释

    • point to implementation, 指向实现的指针
  • 作用

    • 消除传统偶合 编程

      • eg:

         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        
        MyType c = MyType();
        MyType *c = new MyType();
        
        
        // c.hpp 文件
        #include<x.hpp>
        class C
        {
        public:
                void f1();
        private:
                X x; //与X的强耦合
        };
        • 每一次编译,x.hpp 更改, c.hpp 都会重新编译
  • 机理

    • eg:

      1
      2
      3
      4
      5
      6
      7
      8
      
      //c.hpp
      class X; //用前导声明取代include
      class C
      {
              ...
              private:
              X* pImpl; //声明一个X*的时候,class X不用完全定义
      };
    • class C 的 访问者只能访问到 C 的 接口,

      • 访问不到 X 的 接口,起到了隔绝作用
  • 总结

    • 三个类 X, C, S
    • C 的实现依赖 X
    • 但是做到 C 的 接口不依赖 X
    • 这样 X 的 更改 不会影响 S
  • 本质

    • 在 一处 声明变量(类)
    • 在 另一处 定义这个变量(类)

图表

表格

QtCore

QString

  • 方法:

    • 运算符

      • +,+=
    • 索引

      • at(index)
    • 查询

      • indexOf(str, from)

        • //返回找到 str 的 index, from 是开始寻找的位置, 返回-1 表示没找到
      • lastIndexOf(str, from)

        • //str 最后出现的位置
    • 各处插入

      • str.insert(index,str2)

        • str="zg";str.insert(1,"yl");//str==zylg
      • pend

        • str.append(str2)
        • str.prepend(str2)
      • push

        • str.push_back(str)
        • str.push_front(str)
    • 删除

      • remove(str, Qt::CaseInsensitive)//删除所有出现的 str
      • remove(index, len)//从 index 开始的 len 个
    • 清空

      • clear()
    • 格式化字符串

      • QString("%1 is %2").arg(value).arg(value)
      • str.sprintf("%s, %s", str2,str3)
    • 替换

      • str.replace(index,len,str2)
      • str.replace(QRexExp& rx, str2)
      • str.replace(QRegularExpression& re, str2)
    • 修剪
    • 作用于 str 本身

      • str.trimed()
      • str.simplified()//去掉空白,单个空白代替
      • str.truncate(len)//只留前面 len 个
      • str.chop(n)//去掉右边的 n 个
    • 返回新 QString,substring

      • str.left(n)//返回左边 n 个
      • str.right(n)
      • str.mid(index,len)//从 index 开始的 len 个
      • str.mid(index)//从 index 开始的剩余部分
      • str.chopped(len)//左边 len 个
    • 判断

      • str.startsWith("zy",Qt::CaseInsensitive);
      • str.endsWith("zy",Qt::CaseInsensitive);
      • str.contains("zy",Qt::CaseInsensitive);//return bool
      • str.isNull() –> QChar.isNull()
      • str.isEmpty()
    • 转换

      • str.toInt()

        • str="125"; long hex=str.toInt(&ok,16);//ok=true,hex=293
      • str.fill(char,n)//转换成 n 个 char

        • str.fill("A",2) //str="AA"
      • 数字变成 QString

        • str.setNum(int)//把 int 变成 QString,存入 str
        • QString::number(value) //返回字符串,静态方法

          • QString::number(int,int base=10)

            • QString s = QString::number(a, 16);// s == "3f"
          • QString::number(double)
    • 比较

      • str.compare(str_other, Qt::CaseInsensitive)

        • Qt::Sensitive
        • Qt::Sensitive
    • 切割 section

      • str.section(char_seperator, start_index, end_index)

        1
        2
        3
        4
        5
        6
        7
        
        QString csv = "forename,middlename,surname,phone";
        QString path = "/usr/local/bin/myapp"; // First field is empty
        QString::SectionFlag flag = QString::SectionSkipEmpty;
        
        str = csv.section(',', 2, 2);   // str == "surname"
        str = path.section('/', 3, 4);  // str == "bin/myapp"
        str = path.section('/', 3, 3, flag); // str == "myapp"
        
    • 迭代器 QString::iterator 类型

      • begin()
      • end()//指向 index=size(),即最后一个元素的后面,越界一个元素
      • rbegin()//逆序第一个
      • rend()
      • cbegin()//对应常量指针类型,不可改变*cbegin(),

        • 返回类型 QString::const_iterator
      • cend()
      • constBegin()
      • constEnd()
      • crbegin()
      • crend()
    • 计数

      • count(char)
      • count(str)
      • count(QRegExp &rx)
      • count(QRegularExpression &re)
    • 标准 C 字符串

      • QChar* data()
    • 大小写

      • toUpper()
      • toLower()

QChar

方法

  • 判断

    • isLetter()
    • isNumber()不只是 10 个阿拉伯数字
    • isDigit()只是阿拉伯数字
    • isLower()
    • isUpper()
    • isTtileCase()
    • isNull()
    • isPunct()
    • isSpace()
    • isPrint()
    • Unicode

      • isSurrogate()用于判断是否输入 Surrogate Range 范围内,Unicode 概念
      • isHighSurrogate()
      • isLowerSurrogate()
    • isSymbol() 不懂
  • 其他

    • digitValue()对应的数值 int
    • category()所属类型
    • direction()特殊语言,如阿拉伯语,书写方向

QDir 和 QFile

  • QDir 用来路径操纵
  • QFile 用来 IO 读写

QStringList

  • 例子

    1
    2
    
    QStringList wordList;
    wordList << "Qt" << "Qt Creator" << tr("你好");

QRect

  • 尺寸函数:

    • x()
    • y()
    • width()
    • height()
  • 哪些是返回 QRect 类型的

    • geometry()
    • frameGeometry()

QSize

  • 尺寸函数:只有宽和高

    • width()
    • height()
  • 返回 QSize 类型的函数

    • size()

容器

QGroupBox 组合框

  • 布局参考:QGroupBox使用总结_fanyun 的博客-CSDN博客_qgroupbox
  • 带绘制出外边框和 Title 的分组容器
  • 属性

    • name
    • title
    • font
    • checkable: bool

      • 提供一个 选择框
    • checked: bool

      • checked is True, 子部件才能被 enabled (accessible)
      • False, 子部件不能被访问
  • 可以容纳多个 widget

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    
    # pyqt5
    groupBox = QGroupBox("Exclusive Radio Buttons")
    
    radio1 = QRadioButton("&Radio button 1")
    radio2 = QRadioButton("R&adio button 2")
    radio3 = QRadioButton("Ra&dio button 3")
    
    radio1.setChecked(True)
    
    
    vbox = QVBoxLayout()
    vbox.addWidget(radio1)
    vbox.addWidget(radio2)
    vbox.addWidget(radio3)
    vbox.addStretch(1)

QScrollArea 滚动区

  • 作用

    • 给 子 Widget 添加滚动条

      • 当 容纳不下 内部子 Widget 时,显示滚动条
  • 属性

    • name
    • font
  • 函数

    • addWidget()
    • setBackgroundRole()
  • 示例

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    
    from xinet import QtWidgets, QtCore, QtGui
    from xinet.run_qt import run
    
    
    class ImageView(QtWidgets.QScrollArea):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            # 载入图片
            imageLabel = QtWidgets.QLabel(self)
            image = QtGui.QPixmap("test.jpg")
            imageLabel.setPixmap(image)
            # 设定滚动条组件
            self.setBackgroundRole(QtGui.QPalette.Dark)
            self.setWidget(imageLabel)
            # 初始化设定
            self.init_Ui()
    
        def init_Ui(self):
            # 修改窗口默认尺寸
            self.resize(500, 500)
    
    
    if __name__ == '__main__':
        run(ImageView)

QToolBox

  • 作用

    • 可隐藏式 多部件 分组
  • 属性

    • name
    • font
    • currentIndex

      • 当前活动页
    • 活动标签

      • itemLabel
      • itemName
      • itemBackgroundModel
  • 方法

    • addItem(QWidget, …)
    • count() const
    • currentIndex() const
    • currentItem() const
    • indexOf(QWidget)
    • insertItem(index, widget, …)
    • item(index)
    • setCurrentIndex
    • setCurrentItem
    • setItemLabel
  • 效果示例:Qt学习10——工具盒类QToolBox_shawn06-CSDN博客_qtoolbox
  • 解说:

    • 可包含多个子部件
    • 显示方式

      • 每一个子部件 –> 一个 按钮

        • 按钮展示

          • 按钮可以有:文字 + Icon
        • 主体内容暂时

          • 点击按钮实现
          • 隐藏 + 展示 两种状态

QTabWidget

  • 作用

    • 通过 tab 标签选择展示组合中的一个标签 Wiget
  • 属性

    • name
    • currentPage
    • margin
    • tabShape

      • 标签 shape
    • 活动标签

      • pageName
      • pageTitle
  • 函数

    • addTab(widget, …)
    • setMovable(bool)
    • setTabEnabled(index, bool)
    • QWidget* currentPage()
    • int currentPageIndex()

QStackedWidget

QFrame

  • 功能

    • 基础分组部件
  • 属性

    • name
    • framesShape

      • 边框形状
      • QFrame::Shape 枚举类型,形状

        • QFrame::NoFrame
        • QFrame::Box
        • Panel 平板 对阴影起衬托作用
        • WinPanel windows 风格 panel
        • HLine 水平线,用于分割,不框住任何东西
        • VLine 垂直线
        • StyledPanel 使用 QStyle::drawPannel
    • framesShadow

      • 边框阴影特性
      • QFrame::Shadow 阴影类型,枚举

        • QFrame::Plain 和周围一样高
        • QFrame::Raised 凸起
        • QFrame::Sunken 凹陷
        • QFrame::MShadow 内部的,对于阴影的掩码

QWidget

  • 功能

    • 基础类
    • 本身不可见
    • 可以包含子部件,删除 QWidget 时,子部件一起删除
  • 属性

    • name
    • font
    • cursor 光标样式
  • 方法

    • childAt(x, y, bool includeThis=False)

      • (x, y) 处的子部件
      • 重载

        • childAt(Point &p, bool includeThis=False)
    • drawText(x, y, const QString& str)

QMdiArea

  • 参考:QMdiArea Class | Qt Widgets 5.15.5
  • 实现效果参考:Qt之容器控件(QMdiArea)_Shijia Yin-CSDN博客_qmdiarea
  • MDI: multiple document interface 多文档界面,多文件参与的窗口

    • 对比 QMainWindow(SDI, single document interface) 单文件参与窗口
  • 功能

    • 多文档处理
    • 内部多子窗口
  • 属性

    • name
    • font
    • viewMode 视图模式

      • TabbedView 或 SubWindowView
    • documentMode

      • 保存的标签栏在选项卡视图模式是否设置为文件的模式,默认为 false
    • viewMode == TabbedView 时

      • tabShape
      • tabPosition
  • 方法

    • addSubWindow(QWidget*, …)
    • removeSubWindow(QWidget*)
    • setBackground(QBrush(Q::green))
    • activeSubWindow() const
    • QMdiSubWindow* currentSubWindow()
    • setActiveSubWindow(QMdiSubWindow*)
    • 切换窗口

      • activateNextSubWindow()
      • activatePreviousSubWindow()
      • setActiveWindow(QWidget*)
    • 排布窗口

      • cascadeSubWindows()
      • tileSubWoindows
    • 关闭

      • closeActiveSubWindow()
      • closeAllSubWindows()
  • 信号

    • subWindowActivated(QMdiSubWindow *window)

QDockWidget

  • 使用参考:QDockWidget详解_chenlong12580 的专栏-CSDN博客_qdockwidget
  • 效果:QDockWidget嵌套布局详解
  • 功能

    • 停靠窗体
  • 属性

    • name
    • font
    • floating

      • 是否可以 float
    • feature

      • 参考:QDockWidget 停靠特征解说 | Qt Widgets 5.15.5
      • QDockWidget::DockWidgetFeatures 枚举类型,停靠特征

        • QDockWidget::DockWidgetClosable
        • QDockWidget::DockWidgetMovable
        • QDockWidget::DockWidgetFloatable
        • QDockWidget::DockWidgetVerticalTitleBar
        • QDockWidget::AllDockWidgetFeatures
        • QDockWidget::NoDockWidgetFeatures
    • allowedArea

      • 可停靠区域
      • 枚举类型 Qt::DockWidgetArea

        • Qt::LeftDockWidgetArea 左
        • Qt::RightDockWidgetArea 右
        • Qt::TopDockWidgetArea 上
        • Qt::BottomDockWidgetAreas 下
        • Qt::AllDockWidgetArea (默认值)所有四个区域
        • Qt::NoDockWidgetArea 不可停靠
    • windowTitle

      • 停靠窗体 title
    • dockWidgetArea (Qt 官方没有)

      • 停靠的区域
    • docked (Qt 官方没有)

      • 停靠状态
  • 函数

    • setWidget(QWidget*) 设置内部子部件
    • setFeatures(features)
    • setFloating(bool)
    • setTitleBarWidget(QWidget*)

      • 自定义标题栏 Widget
      • 设置 nullptr, 恢复默认样式

按钮类部件

QAbstractButton

  • 作用:

    • Button 类的抽象基类,提供按钮的通用功能

按钮类型

标准按钮 QPushButton

  • 设置文本

    • 添加快捷键

      • 在对应字母前添加&符号
      • 调用方法:Alt + 给定字母

        1
        2
        3
        4
        5
        6
        7
        
        ui->pushBtn1->setText(tr("&nihao"));     // 这样便指定了Alt+N为加速键
        ui->pushBtn2->setText(tr("帮助(&H)"));
        ui->pushBtn2->setIcon(QIcon("../image/help.png"));
        ui->pushBtn3->setText(tr("z&oom"));
        QMenu *menu = new QMenu(this);
        menu->addAction(QIcon("../image/zoom-in.png"), tr("放大"));
        ui->pushBtn3->setMenu(menu);

复选框 QCheckBox

  • 功能

    • 提供对号框

单选框按钮 QRadioButton

  • 功能

    • 多选一列表
  • 特点

    • 在一个容器或布局内,自动互斥

      • 互斥:点击一个 radio, 另一个就会取消选中

工具按钮 QToolButton。

  • 功能

    • 用在 ToolBar 中的按钮
    • 可以添加 action, 可以显示图片 icon

QCommandLinkButton

  • 功能

    • 多选一功能按钮

QDialogButtonBox

  • 参考:

  • 功能

    • QDiaglog 用来快速添加多个按钮
  • 属性

    • centerButtons: bool

      • 是否居中
    • orientation: Qt::Orientation

      • 方向,水平还是竖直
    • standardButtons: QStandardButton

      • 按钮有哪些
  • 函数

    • 添加单个 button

      • addButton(…)

        • 重载多,添加单个 button
    • 设置多个 button

      • setStandarButtons(QStandardButton buttons)
    • 判断

      • QStandardButton standardButton(QAbstractButton* button) const

        • 判断 给定 button 的 QStandardButton 枚举类型
      • QDialogButtonBox::ButtonRole buttonRole(QAbstractButton *button) const

        • 判断 QDialogButtonBox::QButtonRole 枚举类型
    • 方位给定 按钮

      • box->button(button_type)
  • button 类型

    • QDialogButtonBox::QStandardButton 枚举类型
    • 内部实际存储: QAbstractButton* 指针类型
  • 信号

    • clicked(QAbstractButton* button)
  • 点击后,判断是哪个按钮被按下

    1. 通过信号 clicked(QAbstractButton*)
    2. 判断传过来的是什么 button 类型即可

    3. 快捷判断

      • 信号

        • accepted()
        • helpRequested()
        • rejected()
  • 练习实现, PySide6

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    
    from PySide6.QtCore import Qt, Slot
    from PySide6.QtWidgets import (
        QApplication, QDialogButtonBox, QDialog, QAbstractButton, QLabel, QVBoxLayout
    )
    
    class Window(QDialog):
        def __init__(self):
            super().__init__()
    
            self.initUI()
    
        def initUI(self):
            self.box = QDialogButtonBox(self)
            self.box.setStandardButtons(QDialogButtonBox.StandardButton.Abort | QDialogButtonBox.Apply | QDialogButtonBox.Help)
    
            self.box.setOrientation(Qt.Orientation.Vertical)
    
            self.label = QLabel("init text", self)
    
            self.vlayout = QVBoxLayout(self)
            self.vlayout.addWidget(self.label)
            self.vlayout.addStretch(1)
            self.vlayout.addWidget(self.box)
    
            self.setLayout(self.vlayout)
    
            self.box.clicked.connect(self.onClickedButton)
    
        def onClickedButton(self, button: QAbstractButton):
            msg = '%s been clicked'
            if self.box.standardButton(button) == QDialogButtonBox.Help:
                self.label.setText(msg % "help")
            elif self.box.buttonRole(button) == QDialogButtonBox.ApplyRole:
                self.label.setText(msg % "apply role")
            elif self.box.standardButton(button) == QDialogButtonBox.Abort:
                self.label.setText(msg % "abort")
            else:
                self.label.setText(msg % "Nothing")
    
    
    def main():
        app = QApplication()
        w = Window()
        w.show()
        app.exec()

视图

QAbstractItemView

  • 要点功能

    • 选择
    • 滚动
    • 拖拽
    • 显示和编辑

      • setItemDelegate()
    • model 操作
  • 继承

    • 继承子类只要实现特定功能相关相关功能方法即可
  • 属性

    • 滚动

      • autoScroll: bool
      • autoScrollMargin: int
    • 拖动

      • dragEnabled: bool
      • dragDropMode
    • 编辑

  • 方法

    • index

      • rootIndex()
      • currentIndex()

QListView

  • 功能

    • 展示 文字列表 或 Icon 列表
  • 子类

    • QListWidget

      • QListView 需要自己创建设置 Model
      • QListWidget 内建 Model,用户 addItem()即可

显示图片

  • QLabel.setPixelmap()
  • 例子

    1
    2
    3
    
    imageLabel = QtWidgets.QLabel(self)
    image = QtGui.QPixmap("test.jpg")
    imageLabel.setPixmap(image)

PySide6

signals 和 slots 相关问题

  • 连接:

    • QtCore.SINGAL
    • QtCore.SLOT
    • QtCore.QObject.connect
  • 定义

    • 装饰器声明重载函数接口
    • QtCore.Signal
    • QtCore.Slot

连接 connect

  • 使用 connect

    1. 通过信号调用

      1
      
      self.clicked.connect(other, other.slot_function)
    2. 通过 QObject.connect

      1
      2
      3
      
      from PySide6 import QtWidgets, QtCore
      
      QtCore.connect(boxA, boxA.clicked, window, window.onMywindowClicked)
    3. 使用 SIGNAL, SLOT 宏

      1
      2
      3
      4
      
      from PySide6.QtCore import SIGNAL, SLOT
      
      QObject.connect(scrollBar, SIGNAL(valueChanged(int)),
                      label, SLOT(setNum(int)))

定义 singals 和 slots, 重载问题

  • 定义 信号 与 槽

    • 使用 QtCore.Signal 类 和 QtCore.Slot 类

      1
      2
      3
      4
      5
      
      class Foo(QObject):
      
          @Slot(float, result=int)
          def getFloatReturnInt(self, f):
              return int(f)
    • Signal 类

      • 方法

        • connect
        • disconnect
        • emit(*args)

          • args – 信号的相关参数
          • eg: heySignal.emit("hello there")
      • 构造 – 创建 信号

        1
        2
        3
        
        class Communicate(QObject):
            # create a new signal on the fly and name it 'speak'
            speak = Signal(str)
        • 直接创建,无需定义

信号

特点

  1. 形式

    • 过去时单次

      • clicked
      • pressed
      • released
      • valueChanged
  2. 意义

    • 不执行特殊动作,通过 slot 执行动作
    • 只是表示一个事件的发生
  3. 函数接口

    • 无返回值

PyQt6

signals 和 slots

定义 signals

  • 通过 pyqtSignal 类实现
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
from PyQt6.QtCore import QObject, pyqtSignal

class Foo(QObject):

    # This defines a signal called 'closed' that takes no arguments.
    closed = pyqtSignal()

    # This defines a signal called 'rangeChanged' that takes two
    # integer arguments.
    range_changed = pyqtSignal(int, int, name='rangeChanged')

    # This defines a signal called 'valueChanged' that has two overloads,
    # one that takes an integer argument and one that takes a QString
    # argument.  Note that because we use a string to specify the type of
    # the QString argument then this code will run under Python v2 and v3.
    valueChanged = pyqtSignal([int], ['QString'])
注意
  • signal 对象只能是类属性

    • 也就是说,在 __init__ 中创建的 signal 无效
    • 正确例子

      1
      2
      3
      4
      5
      6
      7
      
      from Qt.QtCore import pyqtSignal
      from Qt.QtWidgets import QWidget
      
      class MyApp(QWidget):
          closeSignal = pyqtSignal(str)
          def __init__(self):
              self.closeSignal.connect(self.close)
    • 错误例子

      1
      2
      3
      4
      5
      6
      7
      
      from Qt.QtCore import pyqtSignal
      from Qt.QtWidgets import QWidget
      
      class MyApp(QWidget):
          def __init__(self):
              self.closeSignal = pyqtSignal(str) # 这样无效
              self.closeSignal.connect(self.close)

注意

QLayout 中的 addChildWidget() Vs addWidget() 不同

  • addChildWidget

    • 在 addWidget 内部被调用
    • 如果直接使用 addChildWidget 会造成添加的 widget 不被显示

拖拽 dnd – Drag and Drop

参考:

QDrag::hotSpot

  • hotSpot()

    • 拖拽时,背景图片 pixel_map 左上角相对光标的偏离位置

qt designer

pyqt6

注意:

  • 需要额外安装

    • pip install pyqt6-tools
  • 调用方式

    1
    2
    3
    4
    5
    
    # qt designer
    pyqt6-tools designer
    
    # qt uic 
    pyuic6

FAQ

python + qt 如何隐藏 cmd prompt

  1. python 代码

    • 解决方法:使用 pythonw.exe
    • eg: 使用 pythonw.exe main.py
  2. pyinstaller + qt 代码