Python+Qt Quick:一种便捷的桌面软件开发模式

引言

Python大家都耳熟能详,Qt Quick是自Qt 4.7发布的一种方式有别于传统的界面开发技术,从名字就能看出它追求便捷的目标。Qt Quick为Qt引入了一门叫QML(Qt Meta/Modeling Language)的脚本语言,它是ECMAScript标准的实现,意即,有着和JavaScript一样的语法(学过JS的朋友上手非常容易)。这意味着我们可以和开发网页一样开发程序界面,想想是不是还有点小激动呢。

开发平台:Windows 7/10

分享一下涉及到的资源文件:http://pan.baidu.com/s/1cpftDk

开发环境搭建

■ Python

Python官网下载最新版(当前为3.6.1)安装包,因为最终做出来的程序最好同时能在32位和64位机器上运行,所以选择x86版本的,安装在自己喜欢的路径,比如:C:\Python\Python36-32,并加环境变量(C:\Python\Python36-32C:\Python\Python36-32\Scripts)。

■ PyQt

PyQt是Qt的Python binding,最新版本是5.8.2,可惜它在后续程序打包发布的时候存在bug(会按开发环境的绝对路径寻找PyQt控件的资源图片,结果必然是找不到),因此我找到了PyQt 5.7.1,下载wheel文件PyQt5-5.7.1-5.7.1-cp34.cp35.cp36.cp37-none-win32.whl(我保存到了D盘根目录下),安装:

pip3 install D:\PyQt5-5.7.1-5.7.1-cp34.cp35.cp36.cp37-none-win32.whl

■ Qt Creator

这是Qt提供的集成开发环境,我们用Qt Quick其实不需要靠它拖控件,直接手敲所有代码就行,但我仍建议你安装,用它编辑QML代码,有高亮、纠错、标识符匹配提选等功能,同时包含有Qt文档,可以快速查阅各个类的使用方法。

官网下载不但需要注册账号,还需要填一份承诺式的问卷,读者可以直接使用我分享的安装包

安装时勾选「msvc2015」组件即可,因为它包含了Qt文档。
QML文件在Qt Creator中编辑的效果

程序开发

推荐《Qt Quick核心编程》,结合Qt文档,可以解决95%以上的问题,我在这里只谈及一些比较重要的或很难搜到的点(示例代码取自之前开发的次第程序)。

《Qt Quick核心编程》

■ Python与QML的结合

这种开发模式不再是通过不断调用库函数来生成、设置界面元素,界面乃至操作层面的响应逻辑全部以ECMAScript的脚本形式存在,99%的代码的都在QML文件,由Python把它驱动起来:

# cidi.py
from PyQt5.QtCore import QUrl
from PyQt5.QtGui import QGuiApplication
from PyQt5.QtQml import QQmlApplicationEngine

if __name__ == '__main__':
    app = QGuiApplication([])
    engine = QQmlApplicationEngine()
    engine.load(QUrl('./res/cidi.qml')) #QML文件的相对路径
    app.exec_()

最简单的QML文件示例:

// ./res/cidi.qml
import QtQuick 2.7
import QtQuick.Window 2.0

Window {
    title: qsTr("次第 3.0.0")
    visible: true
}

运行(我把代码文件放在D:\cidi\\目录下):

python d:\cidi\cidi.py

当然我个人喜欢写个批处理放在旁边,每次直接双击就行:

@echo off
python cidi.py
pause

众所周知,Qt的事件处理机制靠信号和槽实现,PyQt中有多种使用方式,我觉得将Python类注册到Qt的做法最清晰、便捷。例如定义一个判断文件路径是否为文件夹的方法(槽),使用注解@pyqtSlot描述参数和返回值的类型:

# cidi.py
from PyQt5.QtCore import QUrl, QObject, pyqtSlot, QFileInfo
from PyQt5.QtGui import QGuiApplication
from PyQt5.QtQml import QQmlApplicationEngine

class Dealer(QObject):
    @pyqtSlot(str, result=bool)
    def isDir(self, url):
        fileInfo = QFileInfo(url)
        return fileInfo.isDir()

if __name__ == '__main__':
    app = QGuiApplication([])
    qmlRegisterType(Dealer, "cidi.qt.Dealer", 1, 0, "Dealer") #将Dealer注册到Qt
    engine = QQmlApplicationEngine()
    engine.load(QUrl('./res/cidi.qml'))
    app.exec_()
// ./res/cidi.qml
import QtQuick 2.7
import QtQuick.Window 2.0
import cidi.qt.Dealer 1.0 //像模块一样导入

Window {
    title: qsTr("次第 3.0.0")
    visible: true

    //像一般控件一样定义后使用
    Dealer {
        id: dealer
    }

    //可以在任何地方直接调dealer.isDir(pathStr)使用
}

■ 设置程序icon

即程序窗口左上角的小图标。在QGuiApplication实例化语句后添加:

QGuiApplication.setWindowIcon(QIcon("./res/cidi.ico"))

icon制作推荐Axialis IconWorkshop,试过诸多工具,唯有Axialis能生成256×256的超大图标(此处不需要这么大,但程序发布时需要),但它的试用版只能用一个月,暂时没找到破解版。

发布

需要发布的是Python程序,Qt作为其库被它调用即可。Python的打包工具大抵有py2exePyInstallercx_Freeze三种,其中py2exe只支持到Python 2.7,PyInstaller支持到3.5但操作起来比较复杂(反正我试了一下没搞定),cx_Freeze支持到3.6且操作便捷,缺点是会把许多没用到的库也打包进来,需要手动筛减,但可能前两者也存在同样的问题。

安装和使用cx_Freeze

PyPI下载cx_Freeze-5.0.1-cp36-cp36m-win32.whl,安装:

pip3 install D:\cx_Freeze-5.0.1-cp36-cp36m-win32.whl

注意莫把whl文件放在中文路径下,不知为何,pip3似乎不支持。

与其他Python工具不同的是,cx_Freeze装完后,Scripts文件夹下居然没有相应的可执行文件:

只有三个没有后缀的文件

我一脸懵逼,根本不知道怎么用,试了几次才琢磨出来。先切换到Scripts目录:

cd C:\Python\Python36-32\Scripts

使用python cxfreeze -h命令查看cx_Freeze文档:

有些选项如目标路径、图标设置一目了然,有些选项不明所以。官网和一些技术博客喜欢介绍编辑一个setup.py文件的使用方法,但我觉得一般使用不需要这么复杂,一句简单的命令足矣:

python cxfreeze --target-dir="d:/cidi/dist" --icon="d:/cidi/res/cidi.ico" --base-name=win32gui D:\cidi\cidi.py
  • --base-name选项指定生成目录。
  • --icon选项用于嵌入图标文件,即最终所得exe文件的图标。
  • --base-name=win32gui选项隐藏Python的控制台黑框,调试时可去掉。

这条命令下去,只见命令行刷刷地滚动,D:\cidi\\目录下分分钟多了个200M左右(吓死人)的dist文件夹,里头内容狗血式的丰富:

一堆Python和Qt库,Qt占了大半体积,需要人工甄别哪些是没用的(这一过程并不复杂)。

我的次第程序最终删减到30余M,这一数量级还是可以接受的。

注意事项

  • 也许是PyQt库的bug,生成的文件无法在中文路径下运行,但我们可以通过动态设置PyQt查找模块的路径(原路径可能存在字符编码的问题)来解决这一问题:
engine.setImportPathList([sys.path[0] + "/PyQt5/Qt/qml"]) #engine为QQmlApplicationEngine实例
  • Python 3.6基于VS 2015,部分缺少其库的电脑需要安装「Visual C++ Redistributable for Visual Studio 2015」补丁才能运行我们发布的程序。

  • Python从3.5开始不再支持XP,我们的程序要求系统至少是Vista。同时,所用的PyQt版本可能对显卡提出要求,太老旧的电脑hold不住。一句话,新的技术需要新的环境。

  • 生成的主程序(即可执行程序)在修改文件名后无法正常运行,这个问题有待后续解决。

比如我把它命名成「次第.exe」


2017年4月25日、26日 苏州

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容