Qt 常用语法
Qt Creator 工程
初始化
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 命令如下所示:
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)运行命令很简单
cmake --build {build_dirctory} --target all
上面的是使用 QtCreator 图形化界面来进行完成的。实际上只是点击部署,运行按钮会出现这些东西。
我还尝试了一下仅使用命令行来运行 Qt 工程,也可以成功,命令如下
$ 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 来进行赋值
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 编码的方法。
std::string str = Msg.toStdString(); //Msg QString型变量
const char* p = str.c_str(); //char型中文大多数占用3个字节,少数4个字节
展示图像
展示图像代码如下所示,这里考虑的是从 cv::Mat frame 来转换到 Qt 显示图像的。这里有个重要的细节是 scene 必须不能是一个局部变量,否则图像将无法显示,应该用全局变量,或者成员变量。这是我自己测试出来的,没看 Qt 文档到底是怎么回事。
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 ,仅仅举个例子。
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 后,使用这个工具转换成代码,直接调用即可。
pyuic5 -o form_ui.py form.ui
rcc/pyrcc5/pyside6-rcc
与上面的同理,用来将 qrc 资源文件转换成对应的文件。
pyside6-rcc background.qrc
程序依赖问题
Qt5LinguistTools
在 Ubuntu20.04 上有时库若安装不完全,会报这个库相关的 cmake 文件不存在的错误。只需要安装相应的包就行。在 Ubuntu 官网查询这个关键字能查到需要安装如下包:
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 可以将动态链接库全部单独列出来
# 在可执行文件所在目录下操作
ldd Program > dependancy.txt
dll=$(cat dependancy.txt | awk "print $")
cp $dll ./lib
添加动态链接库路径
export LD_LIBRARY_PATH=$LD_LIABRARY_PATH:${PWD}/lib
添加动态库路径会出现段错误,因为会出现库的冲突,主要在于 LD_LIBRARY_PATH 的库与默认库冲突,即打包时也打包了系统库,运行时,两个库出现冲突(可能是系统不同导致,可能就是不允许出现两次)。
libc6 兼容(操作系统兼容)
21.10 支持到libc6(2.34)版本,而20.04只支持到2.31版本。
使用DEBUG调试
export QT_DEBUG_PLUGINS=1
对于转移后出现的问题的程序,这样可以详细的罗列程序执行到哪一步出错。一般都是 XCB 出错。