pezayo's Blog

蓦然回首,那人却在灯火阑珊处

0%

Qt 常用语法

Qt Creator 工程#

初始化#

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
namespace Ui { class MainWindow; }
class MainWindow : public QMainWindow
{
Q_OBJECT

public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();

void TrtInfer(const std::string& model_dir, const std::string& video_file);

QGraphicsScene scene;
// QPixmap pixmap;
// QImage image;

private slots:
void on_ok_btn_clicked();

void on_quit_btn_clicked();

void on_show_btn_clicked();

public slots:
void show_result();

private:
Ui::MainWindow *ui;
};

初始化大致如上所示。其中 Q_OBJECT 乃是宏定义,记录了一些默认的元数据(成员变量,成员函数)

编译运行#

先前使用的是 qmake,qmake 我懒得看到底怎么弄了,干脆直接用 QtCreator 来实现就行了。

2023 年了,使用 cmake 进行编译。QtCreator 中的默认的 cmake generator 命令如下所示:

1
2
3
4
5
6
cmake -DQT_QMAKE_EXECUTABLE:STRING=%{Qt:qmakeExecutable} \
-DCMAKE_PREFIX_PATH:STRING=%{Qt:QT_INSTALL_PREFIX} \
-DCMAKE_C_COMPILER:STRING=%{Compiler:Executable:C} \
-DCMAKE_CXX_COMPILER:STRING=%{Compiler:Executable:Cxx} \
-G"CodeBlocks - Ninja" \
-S {source_director} -B {build_directory}

部署(build)运行命令很简单

1
cmake --build {build_dirctory} --target all

上面的是使用 QtCreator 图形化界面来进行完成的。实际上只是点击部署,运行按钮会出现这些东西。

我还尝试了一下仅使用命令行来运行 Qt 工程,也可以成功,命令如下

1
2
3
4
5
6
7
8
9
$ mkdir build && cd build

# 创建 build tree
$ cmake .. -D{必要的自定义宏}

# 生成 target
$ cmake --build . --target all
或者尝试使用 make
$ make

其中上面的宏,我并没有像 QtCreator 中一样有那么多,其实完全都可以不用宏(假如这个 Qt 程序不联合其他的工程)便可以跑起来。

Qt 语法#

字符串#

Qt 中字符串有 QString 和 QTextStream 类型。当然,也有 QChar 的类型。

其中就有涉及到给字符串写入的操作。在 Qt 的文档中,原本有 asprintf() 可以调用,相当于 sprintf() ,但是 Qt 特别说明了不建议采用这个

Warning: We do not recommend using QString::asprintf() in new Qt code. Instead, consider using QTextStream or arg(), both of which support Unicode strings seamlessly and are type-safe. Here is an example that uses QTextStream:

如上所述,可以使用 arg()QTextStream 来进行赋值

1
2
3
4
5
6
7
8
9
10
11
12
QString tempport;

//QTextStream 赋值
QTextStream aa(&tempport) ;
aa.setCodec("UTF-8");
aa << tr("using QTextStream\n服务器端口: ") << port;

//arg()赋值
tempport = QString("服务器地址: %1\n服务器端口: %2\n").arg(IP).arg(port);

//直接赋值
tempport = "服务器地址: "+ IP + "\n" + "服务器端口: " + QString::number(port) + "\n";

QString 和 char* 转换网上有许多种说法。和一旦出现中文 char* 转换为 QString 许多方法都会出现乱码的情况,我在 Qt 官方论坛中看到一个方法,不用导入 GBK 编码的方法。

1
2
std::string str = Msg.toStdString();	//Msg QString型变量
const char* p = str.c_str(); //char型中文大多数占用3个字节,少数4个字节

展示图像#

展示图像代码如下所示,这里考虑的是从 cv::Mat frame 来转换到 Qt 显示图像的。这里有个重要的细节是 scene 必须不能是一个局部变量,否则图像将无法显示,应该用全局变量,或者成员变量。这是我自己测试出来的,没看 Qt 文档到底是怎么回事。

1
2
3
4
5
void MainWindow::show_image(){
scene.addPixmap(QPixmap::fromImage(QImage(frame.data, frame.cols, frame.rows, frame.step,QImage::Format_RGB888)));
ui->graphicsView->setScene(&scene);
ui->text_plain->setText("Just show an image");
}

类成员变量#

有类成员变量的话建议使用指针,这样可以自己在构造函数或者在其他函数中来创建这个成员变量,从而清晰的调用这个类成员变量本身的构造函数。例如 QThread ,仅仅举个例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class MyThread; // 前向声明
class MainWindow : public QMainWindow {
MainWindow(){}
~MainWindow(){}
MyThread * t;

void MyCreateThread(){ t = new MyThread(); t->start(); }
}

class MyThread : public QThread {
MyThread() {
...
}
~Mythread(){}
}

调试#

某些情况下 Qt 不允许两个调试器同时在调试,所以我在同时调试客户端和服务端时出现异常报错

Unexpected run control state RunControlState::Running when worker DebuggerRunTool started

在 Qt 论坛找到的说法是

It could be that you had indeed two debugger sessions running. I just noticed that the views including the ‘active’ frame marker in the stack view are not changed properly right now.

改为一个运行,一个调试之后,这个报错消失。

Qt 工具#

uic/pyuic5/pyside6-uic#

可以用来将 ui 文件进行转换,转换成 cpp 文件,Python 文件。使用 Qt Designer 设计 ui 后,使用这个工具转换成代码,直接调用即可。

1
pyuic5 -o form_ui.py form.ui 

rcc/pyrcc5/pyside6-rcc#

与上面的同理,用来将 qrc 资源文件转换成对应的文件。

1
pyside6-rcc background.qrc

程序依赖问题#

Qt5LinguistTools#

在 Ubuntu20.04 上有时库若安装不完全,会报这个库相关的 cmake 文件不存在的错误。只需要安装相应的包就行。在 Ubuntu 官网查询这个关键字能查到需要安装如下包:

1
sudo apt install qttools5-dev

安装完之后能够看到相应的目录 /usr/lib/x86_64-linux-gnu/cmake/Qt5LinguistTools

Qt6 安装问题#

Qt6 没有发布安装文件,只给了源代码,可以进行编译然后安装。在 Qt 官网查询得到 Ubuntu 需要 gcc11 套装才能进行编译。与 Ubuntu20.04 无缘,遂没安装。

但奇怪的是由 python 管理的 PySide6 却可以进行使用。

fcitx5 输入法问题#

使用 PySide6 和 PyQt5 时在输入框中不能使用搜狗输入法。搜狗输入法本身基于 fcitx5。需要下载安装相应的 qt-fcitx5 的包(一系列,不具体叫这个名字)

在网上得知可以在 Github 上找到相应的 fcitx5-qt 的仓库,克隆下来进行编译即可得到相应的 libfcitxplatforminputcontextplugin.so 的动态链接库,将这个动态链接库复制到 Python 环境相应的位置即可。

程序打包移植#

添加所有动态链接库#

使用ldd可以将所有的隐式动态链接库罗列出来,然后再使用 awk 可以将动态链接库全部单独列出来

1
2
3
4
# 在可执行文件所在目录下操作
ldd Program > dependancy.txt
dll=$(cat dependancy.txt | awk "print $")
cp $dll ./lib

添加动态链接库路径#

1
export LD_LIBRARY_PATH=$LD_LIABRARY_PATH:${PWD}/lib

添加动态库路径会出现段错误,因为会出现库的冲突,主要在于 LD_LIBRARY_PATH 的库与默认库冲突,即打包时也打包了系统库,运行时,两个库出现冲突(可能是系统不同导致,可能就是不允许出现两次)。

libc6 兼容(操作系统兼容)#

21.10 支持到libc6(2.34)版本,而20.04只支持到2.31版本。

使用DEBUG调试#

1
export QT_DEBUG_PLUGINS=1

对于转移后出现的问题的程序,这样可以详细的罗列程序执行到哪一步出错。一般都是 XCB 出错。

-------------本文结束感谢您的阅读-------------

欢迎关注我的其它发布渠道