标签 Qt 下的文章

pyqt 介绍

qt 介绍

Qt 是一个著名的 C++ 库——并不只是一个 GUI 库。使用 Qt,在一定程序上你获得的是一个“一站式”的服务:不再需要研究 STL,不再需要 C++ 的string,因为Qt有它自己的 QString 等等。Qt 本身包含的模块也日益丰富, 一直有新模块和第三方模块加入进来。

QT中的信号与槽(Signal & Slot)机制是 Qt 编程的基础,也是 Qt 的一大创新,使得在 Qt 中处理界面各个组件的交互操作时变得更加直观和简单。

Qt的优点在于:

  • 跨平台实现
  • 广泛的库
  • 友好的API,友好的库实现代码
  • 提供偏向生产力的 Qt widgets 和 偏向交互的 Qt Quick,以及使用 html 的 Qt webengine

基于 Qt 开发的软件: KDE, WPS、YY语音、Skype、豆瓣电台、虾米音乐、淘宝助理、千牛、暴雪的战网客户端、VirtualBox、Opera、咪咕音乐、Google地图、Adobe Photoshop Album 等

嵌入式 Linux 上很多带界面软件也是基于 Qt 来编写的。

pyqt 介绍

PyQt实现了一个Python模块集。它有超过300类,将近6000个函数和方法。它是一个多平台的工具包,可以运行在所有主要操作系统上,包括UNIX,Windows和Mac。

为可用的类有很多,他们被分成几个模块。

  • QtCore模块包含核心的非GUI功能。该模块用于时间、文件和目录、各种数据类型、流、网址、MIME类型、线程或进程。
  • QtGui模块包含图形组件和相关的类,例如按钮、窗体、状态栏、工具栏、滚动条、位图、颜色、字体等。
  • QtNetwork模块包含了网络编程的类,这些类允许编写TCP/IP和UDP的客户端和服务器,他们使网络编程更简单,更轻便。
  • QtXml包含使用XML文件的类,这个模块提供了SAX和DOM API的实现。
  • QtSvg模块提供显示的SVG文件的类。可缩放矢量图形(SVG)是一种用于描述二维图形和图形应用程序的XML语言。
  • QtOpenGL模块使用OpenGL库渲染3D和2D图形,该模块能够无缝集成Qt的GUI库和OpenGL库。
  • QtSql模块提供用于数据库的类。

基于 qt 的 python 界面: pyqt, pyside 基于 qt 的界面:Tkinter, WxPython

- 阅读剩余部分 -

1. 发送信号

在发送的头文件中标明需要发送的信号

    Q_OBJECT    //必须使用宏Q_OBJECT
signals:                    //使用signals声明信号函数,访问级别为protected
    void testSignal(int v);     //信号只能声明不能定义

在源文件中,函数内部可以通过 emit 来发送这个信号

emit testSignal(i);     //通过emit关键字发射信号

2. 接收信号的槽

在接收头文件中标明槽函数

    Q_OBJECT
protected slots:
    void mySlot(int v)
    {
        qDebug() << "Value: " << v;
    }

3. 绑定信号和槽

在类似于 mainwindow 这样的上层文件中,需要拿到包含信号的实例和包含槽的实例,然后把信号和对应的槽通过 connect 绑定在一起。

    TestSignal t;
    RxClass r;

    //信号函数与槽函数需要一致,并且不出现参数名
    QObject::connect(&t, SIGNAL(testSignal(int)), &r, SLOT(mySlot(int)));

参考: https://blog.csdn.net/small_prince_/article/details/96106202

1. 使用命令 qmlscene 可以直接执行 qml 文件。

2. qml 中 quick 对应的版本

Qt QtQml QtQml.Models QtQuick QtQuick.Controls QtQuick.Layouts QtQuick.Dialogs QtQuick.Particles 4.7.1 1.0
4.7.4 1.1
5.0 2.0 2.0 2.0 5.1 2.1 2.1 2.1 1.0 1.0 1.0 2.0 5.2 2.2 2.1 2.2 1.1 1.1 1.1 2.0 5.3 2.2 2.1 2.3 1.2 1.1 1.2 2.0 5.4 2.2 2.1 2.4 1.3 1.1 1.2 2.0 5.5 2.2 2.2 2.5 1.4 1.2 1.2 2.0 5.6 2.2 2.2 2.5 1.5 1.3 1.2 2.0 5.7 2.2 2.2 2.7 2.0 1.3 1.2 2.0 5.8 2.2 2.2 2.7 2.1 1.3 1.2 2.0 5.9 2.2 2.2 2.7 2.2 1.3 1.2 2.0 5.10 2.2 2.2 2.7 2.3 1.3 1.3 2.0 5.11 2.11 2.11 2.11 2.4 1.11 1.3 2.11 5.12 2.12 2.12 2.12 2.5 1.12 1.3 2.12 5.13 2.13 2.13 2.13 2.13 1.13 1.3 2.13 … … … … … … … …

参考: https://beyondyuanshu.github.io/2019/11/19/qt-qml-quick-andsoon.html

3. 自定义标题栏和实现鼠标拖动

参考: https://blog.csdn.net/laughing_cui/article/details/74025206

1. 安装见

https://www.cnblogs.com/ramlife/p/14096103.html
http://www.ramlife.org/2020/12/07/272.html

2. 安装好后,import 一下,看看有没有问题。

python3

import PyQt5

exit()

3. 用 qtdesigner 做一个只有 label 的 ui,然后在 ui文件的 同目录下新建一个 py 文件。

#!/usr/bin/python3

import sys
from PyQt5.uic import loadUi
from PyQt5.QtWidgets import QMainWindow, QApplication

class MainWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        loadUi("test.ui", self)

app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())

这样就可以直接使用这个 ui 文件了。 这里面使用的 api 是 loadUi,而不是 loadUiType,所以不需要 setupUi 和 super。 所有 ui 界面里面的东西可以直接用 self 来调用了。比如 self.pushButton.clicked.connect(ShowString)

参考: https://blog.csdn.net/josephzhang1012/article/details/86696107

4. pyqt5 qml 简单例子

main.qml

import QtQuick.Window 2.2
import QtQuick 2.3

Window {
visible:true
width:600
height:400
color:"yellow"
title: "PyQt5 QML Window"
}

main.py

from PyQt5.QtQml import QQmlApplicationEngine
from PyQt5.QtWidgets import QApplication
from PyQt5.QtGui import QIcon
import sys

def runQML():
    app =QApplication(sys.argv)
    engine = QQmlApplicationEngine()
    app.setWindowIcon(QIcon("icon.png"))
    engine.load('main.qml')

    if not engine.rootObjects():
        return -1

    return app.exec_()

if __name__ == "__main__":
    sys.exit(runQML())

执行 main.py,就可以出现窗口了。

参考: https://codeloop.org/how-to-create-window-in-pyqt5-qtquick/

5. 信号与槽

from PyQt5.QtCore import QObject , pyqtSignal

class CustSignal(QObject):

    #声明无参数的信号
    signal1 = pyqtSignal()

    #声明带一个int类型参数的信号
    signal2 = pyqtSignal(int)

    #声明带int和str类型参数的信号
    signal3 = pyqtSignal(int,str)

    #声明带一个列表类型参数的信号
    signal4 = pyqtSignal(list)

    #声明带一个字典类型参数的信号
    signal5 = pyqtSignal(dict)

    #声明一个多重载版本的信号,包括带int和str类型参数的信号和带str类型参数的信号
    signal6 = pyqtSignal([int,str], [str])

    def __init__(self,parent=None):
        super(CustSignal,self).__init__(parent)

        #将信号连接到指定槽函数
        self.signal1.connect(self.signalCall1)
        self.signal2.connect(self.signalCall2)
        self.signal3.connect(self.signalCall3)
        self.signal4.connect(self.signalCall4)
        self.signal5.connect(self.signalCall5)
        self.signal6[int,str].connect(self.signalCall6)
        self.signal6[str].connect(self.signalCall6OverLoad)

        #发射信号
        self.signal1.emit()
        self.signal2.emit(1)
        self.signal3.emit(1,"text")
        self.signal4.emit([1,2,3,4])
        self.signal5.emit({"name":"wangwu","age":"25"})
        self.signal6[int,str].emit(1,"text")
        self.signal6[str].emit("text")

    def signalCall1(self):
        print("signal1 emit")

    def signalCall2(self,val):
        print("signal2 emit,value:",val)

    def signalCall3(self,val,text):
        print("signal3 emit,value:",val,text)

    def signalCall4(self,val):
        print("signal4 emit,value:",val)

    def signalCall5(self,val):
        print("signal5 emit,value:",val)

    def signalCall6(self,val,text):
        print("signal6 emit,value:",val,text)

    def signalCall6OverLoad(self,val):
        print("signal6 overload emit,value:",val)

if __name__ == '__main__':  
    custSignal = CustSignal()

参考: https://www.cnblogs.com/XJT2018/p/10222981.html https://blog.csdn.net/qq_38463737/article/details/107806432

6. button 设置样式表

    self.mBtnRecord.setStyleSheet("QPushButton{border-image: url(./assets/ico-常规背景.svg)} \
        QPushButton:hover{border-image: url(./assets/ico-选中后背景.svg)} \
        QPushButton:checked{border-image: url(./assets/ico-保持背景.svg)} \
        QPushButton:pressed{border-image: url(./assets/ico-点击背景.svg)} \
        QPushButton:disabled{border-image: url(./assets/ico-不可用背景.svg)}")

参考: https://blog.csdn.net/jays_/article/details/83785898 https://blog.csdn.net/weixin_47142322/article/details/105976861 https://www.cnblogs.com/xj626852095/p/3648119.html https://www.cnblogs.com/aheng123/p/5630761.html

7. button 设置持续按下

        self.mBtnRecord.setCheckable(True)
        self.mBtnRecord.setChecked(False)

检查按钮按下的情况

        if self.mBtnRecord.isChecked() is False:
            ...
        else:
            ...

参考: https://blog.csdn.net/qiangzi4646/article/details/80135120 https://www.cnblogs.com/lomper/p/4249575.html

8. button 按下换图标:

self.mBtnSpeed.setIcon(QIcon('./assets/ico-' + "变速" + '.svg'))

类似于这样来设置新图标就可以了。

9. timer

参考: https://www.cnblogs.com/liming19680104/p/10663968.html https://www.jianshu.com/p/74ea98e77114

参考书目: 《QmlBook》In Chinese https://cwc1987.gitbooks.io/qmlbook-in-chinese/content/ QmlBook http://qmlbook.github.io/index.html PyQt5 基本教學 (1) 安裝 PyQt5,印出 Hello World! https://clay-atlas.com/blog/2019/08/26/python-chinese-pyqt5-tutorial-install/

X86 直接安装

sudo apt install python3-pyqt5

或者

python3 -m pip install --upgrade pip
pip3 install pyqt5==5.14.2 --user

pyqt5 最好和 qt5 版本对应。 参考: https://stackoverflow.com/questions/59711301/install-pyqt5-5-14-1-on-linux

ARM 源码安装

安装包见附件

安装必要的开发版本软件

sudo dnf install python3-devel
sudo dnf install qt5-devel

安装 sip

tar zxvf sip-4.19.8.tar.gz
cd sip-4.19.8
python3 configure.py
make
sudo make install

安装 pyQt5

tar zxvf PyQt5_gpl-5.10.1.tar.gz
cd PyQt5_gpl-5.10.1
python3 configure.py --qmake /usr/bin/qmake-qt5
make
sudo make install

为了方便后续安装,可以把编译好的文件进行打包,然后写一个脚本用来安装。

#!/usr/bin/bash

SIP=sip-4.19.8
PYQT=PyQt5_gpl-5.10.1

rm -rf ~/${SIP}
rm -rf ~/${PYQT}

tar xvfz ./${SIP}_build.tar.gz -C ~/
tar xvfz ./${PYQT}_build.tar.gz -C ~/

cd ~/${SIP}
sudo make install

cd ~/${PYQT}
sudo make install

rm -rf ~/${SIP}
rm -rf ~/${PYQT}

echo "install done."

附件

附件中压缩包内是编译好的 rk3399 的二进制,解压出来的是 编译好的 rk3228 的二进制。 附件pyqt5_install.tar.gz

尝试在 3399 上面安装 pyside2 ,结果碰到很多问题。

  1. 需要 qt5.12
  2. 需要 clang

全部需求如下:

General Requirements¶

    Python: 3.5+ and 2.7

    Qt: 5.12+ is recommended

    libclang: The libclang library, recommended: version 10 for PySide2 5.15. Prebuilt versions of it can be downloaded here.

    CMake: 3.1+ is needed.

尝试使用 qt5.10 编译 pyside2

结果发现 pyside2 里面没有 5.10 的分支,而且还要先编译 shiboken ,然后在编译 pyside2。放弃。 https://github.com/pyside/pyside2-setup https://wiki.qt.io/Qt_for_Python/GettingStarted

qt5.12

参考下面这个网页来编译 https://blog.csdn.net/qqwangfan/article/details/84964856

clang 二进制版本

https://releases.llvm.org/download.html#10.0.1 从上面下载 aarch64 版本,结果运行起来找不到 tinfo 的库文件。 放弃。 有说法是可以吧 ncurse 的库链接过去,不过没有尝试。

clang 源码版本

http://clang.llvm.org/get_started.html 按照上面的步骤来,但是要注意默认的是 debug 模式,编译出来空间不够,需要设置为 release 模式,编译出来就只有 1.7 G 左右了。当时从 github 上面指定下载 10.x 的最后一次提交。 具体配置可以参考: https://llvm.org/docs/CMake.html 参考: https://blog.csdn.net/petersmart123/article/details/78418765

1. 获取容器的最大最小值,注意返回的不是数值,需要 *。

```c++ min_data = min_element(myarr.begin(),myarr.end()); auto mydata = minmax_element(myarr.begin(),myarr.end()); cout<<"min: " << mydata.first << " max: " << *mydata.second << "\n";

QVector::iterator max = std::max_element(std::begin(data) std::end(data));


参考: https://en.cppreference.com/w/cpp/algorithm/minmax
https://blog.csdn.net/weixin_43971252/article/details/88831917
https://www.icxbk.com/ask/detail?tid=38382
https://blog.csdn.net/Littlehero_121/article/details/100565527

# 2. 需要字符串中的字串:
```c++
QString QString::mid(int position, int n = -1) const

std::basic_string::substr(size_type __pos, size_type __n) const
basic_string substr(size_type pos = 0, size_type count = npos);

参考:https://blog.csdn.net/u014252478/article/details/80034026

3. 信号与槽

https://blog.csdn.net/humanking7/article/details/86071134 https://www.cnblogs.com/raina/p/11312097.html

4. 当需要容器即可以随机存取,也可以在头部添加删除数据的时候,可以选用 deque。

参考: https://blog.csdn.net/weixin_42462202/article/details/87537503 https://blog.csdn.net/gogokongyin/article/details/51178378

5. mainwindow 里面 增加 graphicview,可以把 graphicview 当作一个 widget 来添加。

```c++ m_view1 = new View("left front"); ui->gridLayout->addWidget(m_view1, 0, 0);


# 6. 两个 QString 比较不区分大小写

qDebug() << str1.compare(str2, Qt::CaseInsensitive);


参考: https://blog.csdn.net/Colin_RZL/article/details/106642982

# 7. QTextBrowser的一些设置
https://blog.csdn.net/u010779194/article/details/9075309

# 8. timer 暂停就用 stop(),恢复就用 start()
参考: https://oomake.com/question/5276301  
https://bbs.csdn.net/topics/310074466  

# 9. 菜单项快捷键使用 `&`, 比如说: `File(&F)`
参考: https://blog.csdn.net/weixin_44591035/article/details/102674002  

# 10. about 提示框 `QMessageBox::about(this, tr("About消息框"), tr("这是一个About消息框测试!"));`
参考: https://blog.csdn.net/qq_36908789/article/details/106439905  

# 11. 菜单项 connect 槽函数,信号是 `&QAction::triggered`
参考: https://blog.csdn.net/dianzishi123/article/details/85854321  

class Process : public QObject
{
    Q_OBJECT
public:
    Process()
    {
        connect(&m_process, SIGNAL(readyReadStandardOutput()), this, SLOT(onReadData()));
        m_process.setReadChannel(QProcess::StandardOutput);
        m_process.start("cmd /c ping /t www.qt.io");
    }

private slots:
    void onReadData()
    {
        qDebug() << m_process.readAllStandardOutput(); 
    }

private:
    QProcess m_process;
};

参考: https://zhuanlan.zhihu.com/p/86206831

今天使用 qt 的写入文件,发现中文乱码,经过一番查找,解决问题。 ```c++ QTextStream txt(&file); txt.setCodec(QTextCodec::codecForName("utf-8")); txt << QString::fromStdString(json.toFormattedString()) << endl;