因为以前学过QT,再加上之前的代码是用python的,所以就选择了用pyqt来做界面。
QT做界面一个重要优点就跨*台,当然这里我们主要还是觉得它因为比较简单(相较于win32和MFC来说可以说是我这种小菜鸟的福音了)。可惜的是目前pyqt还没有类似于C++的QT Creator,不能方便的直接在界面设计里添加槽函数。当是可以通过qt designer来绘制界面也省下不少功夫。尽管做过QT,但是边学边做的过程中我和我的小伙伴还是遇到不少困难……
如何美化界面
窗口设计好后不能有效切换窗口
如何进行题目求解,怎么设计答案选项才更接**常的考试
窗口不能返回到之前的界面
其中,窗口部分由我设计的,以下我在写窗口过程中遇到问题和解决方法:
窗体设计
qtdesigner通过组建拖拽做界面很简单,网上教程也很多,但是样式设计的进阶教程却是很难找到。想要做一个类似QQ登录界面并不简单。设计登录界面如下:
主要的困难在于需要去掉窗口的标题栏,没有标题栏就不能关闭和最小化,也不能进行窗口的拖拽,所以需要重写最小化和关闭按键,以及实现拖拽,代码入下:
self.close.clicked.connect(QCoreApplication.instance().quit)
self.bmin.clicked.connect(self.showMinimized)
关闭按键和最小化按键响应事件设置
# 重写三个方法使窗口支持拖动,上面参数window就是拖动对象
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.m_drag = True
self.m_DragPosition = event.globalPos() - self.pos()
event.accept()
self.setCursor(QCursor(Qt.OpenHandCursor))
def mouseMoveEvent(self, QMouseEvent):
if Qt.LeftButton and self.m_drag:
self.move(QMouseEvent.globalPos() - self.m_DragPosition)
QMouseEvent.accept()
def mouseReleaseEvent(self, QMouseEvent):
self.m_drag = False
self.setCursor(QCursor(Qt.ArrowCursor))
想要让界面更加美化一点需要用到QSS(样式表),很遗憾关于样式表教程并不多,QSS类似网页设计CSS(就是来源于吧==)
以关闭按钮举例:实现按钮,鼠标选中和鼠标按下三种不同情况的贴图
图片素材:
对应三种按键情况
"QPushButton{background-image:url(./qrc/btn_close_mormal.png);width:39px;height:18px;padding-top:0px;border:0px;}"
"QPushButton:hover{background-image:url(./qrc/btn_close_highligt.png)}"
"QPushButton:pressed{background-image:url(./qrc/btn_close_down.png)}"
分别定义三种情形的QSS样式表,在代码中用setStyleSheet("qss")函数进行设置。
滑块与微调框
设计用户选择题目数量的部分,我选择了滑块组件,可以很方便的限制题目范围在10-30以内,但是滑块并不能显示数字,于是我加了spinBox(微调框)来选择题目数和显示数字
如何把滑块与微调框的值绑定起来,百度后知道是需要分别写两个组建的valueChanged的槽函数,也没找到源码实例,就只有自己写了。
self.nub_horizontalSlider.valueChanged.connect(self.spin_change) #类中加入事件
self.nub_spinBox.valueChanged.connect(self.slider_change)
'''
--------------------------------------------------------------------------
'''
def spin_change(self): #绑定滑块与控件,使其中一个改变另一个也改变
self.nub_spinBox.setValue(self.nub_horizontalSlider.value())
def slider_change(self):
self.nub_horizontalSlider.setValue(self.nub_spinBox.value())
倒计时
在做题过程中,需要加入考试倒计时,当倒计时结束停止答题。倒计时我通过数码管组建来做,但是由于时间匆忙,并没有达到我想要的样子。
倒计时要用到QTimer模块,通过一个定时器获得时钟频率,就和硬件实训的定时器差不多。
from PyQt5.QtCore import QTimer
#窗口类中加入定时器
self.timer = QTimer(self)
self.timer.timeout.connect(self.timer_oprate)
self.timer.start(1000)
#槽函数,计数-1,当为0时关闭窗口
def timer_oprate(self):
self.time_lcdNumber.display(self.time_lcdNumber.intValue()-1)
if self.time_lcdNumber.intValue() == 0:
self.myWin5 = ui_score.MyWindow5()
self.myWin5.show()
self.hide()
打开网页链接
我的小伙伴还写了一个html的诚信考试协议,嘻嘻,不签协议怎么能让你考试呢是吧:)
打开本地html文件我是通过os模块执行start命令行命令来实现,但是有个问题是打开的时候会出现黑窗口闪烁,这个bug还没有解决。
程序打包
终于完成项目后怎么能不和小伙伴们分享呢(特别是让家里的弟弟妹妹感受一下被算术统治的恐怖hhh)。
python打包的方法有几种,常用的是Py2exe和PyInstaller,因为前者用于老版本的python,可能打包过程中会出现各种问题,我选择了或者。安装方式很简单,直接pip install PyInstaller。
pyinstaller语法也简单执行命令: pyinstaller main.py
main.py是我程序入口,当然我的工程里不能只有一个py文件,所以你会发现这样打包后的exe并不能用QAQ
加上-w参数,会递归打包引用的其他py: pyinstaller -w main.py
(我试过加上-F,打包成一个文件,但是最后的exe并不能运行,我也不知道为啥)
然后会看到新增加了两个目录build和dist,dist下面的文件夹里的exe就是可以发布的可执行文件。当然,得把你的资源文件复制到文件夹下面。EXE文件会自动加上一个图标,如果想改自己的图标输入pyinstaller时命令添加一个 -i picture.ioc(路径),太懒(困)我就没弄…
点击main.exe就可以运行了,其实这个课执行文件比我想象中的要小,才1608K,当然包括其他动态库就不止这点了,QT的一个不好的地方就是设计的程序会比一般其他开发环境的大上一些。
当然,觉得这么多文件不美观,ctrl+shift拖动文件在桌面建个快捷方式吧。
总结:
给我们第一感觉就是这次结对编程做得太赶了,很多地方想去优化都来不及,比如一些提示的地方我用们了弹窗,但是现在好像用弹窗的地方已经很少了,影响用户体验,很多程序都是在窗口上显示提示信息,可以通过label来实现。
不显示错误原因,就这么傲娇的结束运行了??(Fxxx)还是最后一天凌晨在室友电脑上用另一个IDE才知道哪里错了(喜极而泣)。
通过这次实验我和我的搭档虽然有临时抱佛脚的嫌疑,但是确实学到很多,是一笔宝贵的经验,有一种再让我们做一个桌面程序可以分分钟搞定的感觉hhh。最后感谢一下我们室友的帮助(谁让他先做完呢=)