PyQt项目从入手到放弃

前言

首先说明一下,这个项目并不是一个比较正式的项目,只是博主在业余时间接下来的一个私活,项目虽然是个坑,但是依然让我学习到了Python的很多知识,钱没有赚到,知识学到也算是一种进步吧。

这篇文章就来说说这个项目我是如何从入手到放弃的,顺便聊聊给传统工厂车间做软件的体验,这酸爽....只有亲身体验才知道啊。

背景

关于这个项目的前期需求分析阶段就不多说了,总的功能概括一下就是软件控制传送带运行与停止,控制扫码枪扫码,软件记录扫描结果与预设值进行比对,然后做对应的报警处理。

拿到需求之后准备进入开发阶段,博主首选的开发语言是WPF,但是博主之前并没有WPF的开发经验,放弃。然后考虑的是java,博主用java写过界面,那个痛苦的过程就不说了,画界面岂是一般人能干的事儿?再说java天生就不适合做这种桌面客户端,放弃java。接着想到了易语言,毕竟博主7年前还用易语言写过外挂,但是现在让博主用易语言开发个桌面客户端,似乎有点太不正规了,总觉得怪怪的,放弃易语言。然后想到了微软的老牌编程语言VB,开发起来简单,但是博主并没有写过VB的软件,so...放弃。怎么办?好焦虑啊!!想来想去忽然想到,Python不也可以写界面?正好博主还是比较擅长写Python的,只是对于Python的GUI编程并没有经验,想想应该不会太难(事实证明博主太天真),就决定使用Python开发这个桌面程序,而且还可以跨平台使用。

开发

Python的GUI方案比较多,博主就选择了pyqt,Qt作为一款非常火爆的GUI编程方案,在C++上用的多,后来被移植到Python,想必也会跟C++下面使用一样方便吧。博主经过短暂的学习就准备开工了,甲方问我多少时间能够开发完,我给时间为2周交付测试版本,报价为5000块,想到既然是帮同学开发,价格随意就好,为了保险起见我提出了先付定金签合同,然后再开发,然而Z的领导说先让我出测试版,想想既然项目不大也就算了,先开发就先开发吧。

其实2周时间对我来说绝对是足够的,开发这样一个软件无非就是串口通信,数据库的读写,excel的解析,导入导出等等这些功能,博主之前写Arduino的时候对串口通信也有比较深入的学习,所以写起来难度并不是很大。这里给出我写的测试版本界面(运行在Linux系统下面)

2017-10-18 14-31-50屏幕截图.png - 大小: 109.13 KB - 尺寸:  x  - 点击打开新窗口浏览全图

这里对使用的一些模块以及实现的方法做个简单的介绍,还有一些坑的解决方法。

首先,需要构建窗体,实际上构建窗体是非常简单的,我这里需要构建两个窗体,一个主窗体,一个是点击设置按钮的时候弹出来的一个模态框,当然模态框也是一个窗体,将其模式设置为模态就可以了,使用

setModal(True)
如果你想设置一个半透明的窗体也是非常的简单,使用下面这个方法
setWindowOpacity(0.5)
需要注意的是PyQt里面如果想要窗体启动的时候正好位于屏幕正中央,没有什么好方法,就是要自己计算宽高偏移坐标。

在PyQt里面布局并不是很难,有个很好用的组件叫做弹簧组件,这个组件可以帮助你实现居左居右的布局,非常好用,具体实现方法可以搜索PyQt的 addStretch() 方法。

通用的一些样式设置都对应到不同的组件,我之前有文章做了记录,这里贴出来我自己使用的一些组件

from PyQt5.QtWidgets import QApplication, QMessageBox, QWidget, QGroupBox, QButtonGroup, QTextBrowser, QHBoxLayout, QComboBox
from PyQt5.QtWidgets import QVBoxLayout, QTableWidget, QDialog, QTableWidgetItem, QAbstractItemView, QHeaderView, QRadioButton, QSpinBox, QFileDialog
from PyQt5.QtWidgets import QDesktopWidget, QLineEdit, QInputDialog, QGridLayout, QLabel, QPushButton, QFrame
from PyQt5.QtGui import QIcon, QCursor, QColor
from PyQt5.QtCore import Qt, QSize, QTimer

串口通信使用的是 serial 模块,这个模块相当的好用,想要获取串口设备的列表要导入 serial.tools.list_ports 这个工具,然后使用下面这段代码获取

def get_coms():
    port_list = list(serial.tools.list_ports.comports())
    port_name_list = []
    if len(port_list) < 1:
        print("The Serial port can't find!")
    else:
        for port in port_list:
            port_name_list.append(list(port)[0])
    return port_name_list
是不是非常的简单,如果想要向某个串口发送数据怎么办呢,非常简单,首先实例化一个串口对象,然后打开串口,接着把需要发送的字符串转换成字节码,发送出去就好了,代码如下
try:
    self.ser_scanner = serial.Serial(self.serial_name_scanner, 15200, timeout=0)
    run_bytes = []
    for i in "56".split():
            run_bytes.append(binascii.a2b_hex(i))
    ser.writelines(run_bytes)
except Exception as e:
    print(e)
记住这里一定要使用Try except 来捕获异常,因为在实际使用中经常会遇到各种神奇的异常操作,比如串口接触不良,外部设备突然被拔出等等情况,如果没有异常捕获程序直接就死了,要么闪退,这是非常不好的体验。

PyQt里面设置样式有个神奇的方法,就是写样式可以像写css一样简单,甚至语法都是一样的,如果你使用的Qtcreator,那么ui跟业务逻辑可以完全分开,博主这个项目并没有使用Qtcreator,而是直接使用idea进行开发,所以很多东西都是混合在一起的,小项目可以这么做,大项目还是分开比较好。

使用PyQt创建的项目,UI界面在不同的系统平台上打开显示的效果很有可能不一样,所以,有时候需要根据当前的操作系统类型动态的改变样式,我这里使用的是 platform 模块判断操作系统类型

        if platform == "linux" or platform == "linux2":
            # linux
            self.setGeometry(350, 350, 450, 390)
        elif platform == "darwin":
            # OS X
            self.setGeometry(350, 350, 450, 330)
        elif platform == "win32":
            # Windows...
            self.setGeometry(350, 350, 450, 330)

Python里面对于excel的导入导出也非常简单,我这里使用的模块是pyexcel_xls,导入对应的方法进行导入导出操作

from pyexcel_xls import get_data
from pyexcel_xls import save_data
我这里贴出导入excel并解析数据然后存储到sqlite的代码,具体含义就不解释了,毕竟需要结合上下文逻辑才能看得懂
    def excel_import(self):
        importFileName, importFileType = QFileDialog.getOpenFileName(self, 'Openfile', './', 'xls Files (*.xls)')
        if len(importFileName) < 1:
            print('no file found')
        else:
            xls_data = get_data(importFileName)
            xls_list = []
            for sheet_n in xls_data.keys():
                this_xls_item = xls_data[sheet_n]
                if len(this_xls_item) > 0:
                    xls_list.append(this_xls_item)
            if len(xls_list) < 1:
                print('xls is empty')
            else:
                print('xls is usable')
                for item in xls_list:

                    item_id = item[0][0]
                    item_website = item[0][1]
                    item_status = item[0][2]
                    item_createtime = item[0][3]
                    insert_item_sql = """INSERT INTO records(`barcode`,`status`,`createtime`) VALUES(?,?,?)"""
                    try:
                        my_sqlite_db = Database()
                        my_sqlite_db.insert(insert_item_sql, [item_website, item_status, item_createtime])
                        print('save item ok')
                        self.query_data_from_db()
                    except Exception as e:
                        print(e)


关于程序的一些关键点就写这么多,如果有朋友需要参考完整代码的可以联系我邮箱。

后续

程序写的差不多完成的时候拿去工厂进行测试,由于当时带的笔记本是Linux操作系统,现场网络环境非常差,工厂里面可供使用的电脑配置也很一般,我只能在我的笔记本上演示,演示过程比较顺利,而且Linux下面是不需要安装任何设备驱动的,这一点非常好。

本以为演示完之后就可以顺利的签合同进行收尾的开发,图样图森破!!!

Z的领导说软件不止这个工厂使用,总公司那边也需要使用,而且总公司那边的人看不懂中文(PS:这个厂是中日港三方合资总公司在深圳),而且菲律宾那边的工厂也需要用,所以软件需要使用全英文的界面,这就是前面我的截图全是英文的原因...

你以为这样就结束了?这还没完,软件在授权给其他公司使用的时候需要授权费,Z的厂需要收取对应的费用才能给其他厂使用,所以也需要注册机制!!

EXO ME?当初可没这个需求啊,不是说自己工厂用的吗?咋突然改成要卖给其他厂了?

我在现场提出了注册机制需要联网,不然很容易被破解,然而,Z的领导说工厂流水线上的电脑根本就没有网络,系统有的还是xp系统....我的天呐,我当初还设计了数据库集中统一管理的方案,这特么告诉我没网络........Z的领导提出了一个神奇的方案,就是搞一个假的注册码,反正写死在软件里面,一个注册码授权20台机器....这是哪门子授权啊,反正我是一脸蒙比。

还有扫描结果每天要自动生成文件自动导出到电脑的D盘等等附加的需求....

结束了演示,回到家各种纠结,然后想办法导出了exe可执行文件,结果各种幺蛾子,要么缺文件,要么不能在64位上执行,更可气的是,这玩意根本不支持xp系统啊,,,,so???

做到这我已经没有继续做下去的欲望了,不支持xp等于白搭,还是微软自己家的C#靠谱啊,算了,放弃这个项目了,

跟甲方解释了一番,表示环境各种配,没有网络太复杂了,程序兼容性不好解决等等问题,balabala一大堆,瞬间轻松了....

最后

虽然我加班熬夜了好多个通宵,最终没有完成这个项目,但是好歹也是做成了Linux下面能用的软件,如果下次让我去帮工厂做软件,我一定让他们把那些破机器全部换成树莓派,又省钱又好做软件,还不占地方。

最近听说Z自己使用java在开发这个软件,衷心的希望他能坚持做完这个神奇的软件...

如果您觉得文章有帮助到您,请到 https://www.92ez.com/index.php?action=show&id=23403 进行打赏/捐赠,谢谢!
如果您觉得文章有帮助到您,请 使劲戳这里 进行打赏/捐赠,谢谢!
本文链接:https://www.92ez.com/?action=show&id=23455
提示:技术文章有一定的时效性,请先确认是否适用你当前的系统环境。

关键词: pyqt

上一篇: PyQt5 几个关键模块的用途【备忘】
下一篇: Kali Linux 安装 OneinStack

访客评论
#1
回复 路由器A 2017-10-23, 10:40 AM
建议不要写商业化的东西在博客,避免纠纷
发表评论

评论内容 (必填):