0%

通过pyqt开发出一款答题的软件

前言

通过pyqt开发出一款答题的软件。

项目背景

在学习了pyqt 的基础知识后,尝试制作一款可以答题的可视化程序。

关键技术

python pyqt

项目流程

基本思路

①构思样式图,完成界面设置,设置简单的槽函数

②解决多界面互动问题

③优化

第一步:构思样式图,完成界面设置,设置简单的槽函数

构思样式图。为上下结构。上部为“问题描述”,下部为“选项”。

如下代码为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
class Ui_MainWindow(Object):import sys
from PyQt5.QtWidgets import QApplication, QWidget, QGroupBox, QVBoxLayout, QHBoxLayout, QRadioButton


class MyWindow(QWidget):

def __init__(self):
super().__init__()
self.init_ui()

def init_ui(self):
# 最外层的垂直布局,包含两部分:爱好和性别
container = QVBoxLayout()

# -----创建第1个组,添加多个组件-----
# hobby 主要是保证他们是一个组。
hobby_box = QGroupBox("爱好")
# v_layout 保证三个爱好是垂直摆放
v_layout = QVBoxLayout()
btn1 = QRadioButton("抽烟")
btn2 = QRadioButton("喝酒")
btn3 = QRadioButton("烫头")
# 添加到v_layout中
v_layout.addWidget(btn1)
v_layout.addWidget(btn2)
v_layout.addWidget(btn3)
# 把v_layout添加到hobby_box中
hobby_box.setLayout(v_layout)

# -----创建第2个组,添加多个组件-----
# 性别组
gender_box = QGroupBox("性别")
# 性别容器
h_layout = QHBoxLayout()
# 性别选项
btn4 = QRadioButton("男")
btn5 = QRadioButton("女")
# 追加到性别容器中
h_layout.addWidget(btn4)
h_layout.addWidget(btn5)
# 添加到 box中
gender_box.setLayout(h_layout)

# 把爱好的内容添加到容器中
container.addWidget(hobby_box)
# 把性别的内容添加到容器中
container.addWidget(gender_box)

# 设置窗口显示的内容是最外层容器
self.setLayout(container)


if __name__ == '__main__':
app = QApplication(sys.argv)

w = MyWindow()
w.show()

app.exec()

设置槽函数

选到某个选项,就弹出对应的窗口,选到错误的甚至可以结束程序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
class RadioDemo(QWidget):
def __init__(self,parent=None):
super(RadioDemo,self).__init__(parent)
#水平布局
layout = QHBoxLayout()
self.btn1=QRadioButton('A:正确答案')
#默认选中btn1
self.btn1.setChecked(True)
#toggled信号与槽函数绑定
self.btn1.toggled.connect(lambda :self.btnstate(self.btn1))
layout.addWidget(self.btn1)

self.btn2 = QRadioButton('B:错误答案')
self.btn2.toggled.connect(lambda: self.btnstate(self.btn2))
layout.addWidget(self.btn2)

self.btn3 = QRadioButton('C:不知道')
self.btn3.toggled.connect(lambda: self.btnstate(self.btn3))
layout.addWidget(self.btn3)

self.setLayout(layout)
self.setWindowTitle('RadioButton demo')

def btnstate(self, btn):
#输出按钮1与按钮2的状态,选中还是没选中
if btn.text()=='A:正确答案':
if btn.isChecked()==True:
msg_box = QMessageBox(QMessageBox.Warning, '正确', '回答正确!')
msg_box.exec_()

if btn.text()=="B:错误答案":
if btn.isChecked() == True:
msg_box = QMessageBox(QMessageBox.Warning, '错误', '回答错误!结束程序!')
msg_box.exec_()
app = QApplication.instance()
app.quit()

if btn.text()=="C:不知道":
if btn.isChecked() == True:
msg_box = QMessageBox(QMessageBox.Warning, '错误', '这都不知道?!再见!')
msg_box.exec_()
app = QApplication.instance()
app.quit()

第二步:解决多界面互动问题

可以采用抽屉结构。在底部添加,“上一题”、“下一题”按钮。但是这种设计不够极简。

我们放弃这种结构。去掉多余的按钮。选了选项后,直接进入下一题,或结束程序。

main.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# -*- coding: utf-8 -*-

#
# Created by: PyQt5 UI code generator 5.13.0
#
# WARNING! All changes made in this file will be lost!

import sys
import tkinter as tk
from PyQt5 import QtCore, QtGui, QtWidgets
from question_1 import question1
from PyQt5.QtWidgets import QApplication, QMainWindow, QDialog
import os
from PyQt5.QtCore import pyqtSignal, QEventLoop
from qt_material import apply_stylesheet
from PyQt5 import Qt

class AdminPage(object):
def __init__(self):
self.app = QtWidgets.QApplication(sys.argv)
widget = QtWidgets.QWidget()
apply_stylesheet(self.app, theme='dark_cyan.xml')
self.Form = None
self.setupUi(widget)
widget.show()
sys.exit(self.app.exec_())
# self.app.exec_()

def setupUi(self, Form):
self.Form = Form
self.Form.setObjectName("Form")
self.Form.resize(455, 525)
self.Form.setWindowFlags(Qt.Qt.CustomizeWindowHint) # 去掉标题栏的代码
#最外层布局
self.allLayout = QtWidgets.QVBoxLayout(self.Form)
#问题容器
self.questionBox = QtWidgets.QGroupBox(self.Form)#相当于container
#容器为垂直布局
self.questionLayout = QtWidgets.QVBoxLayout(self.questionBox)
#选项容器
self.choseBox = QtWidgets.QGroupBox(self.Form) # 相当于container
# 容器为垂直布局
self.anwserLayout = QtWidgets.QVBoxLayout(self.choseBox)
#第一个盒子
self.question = QtWidgets.QLabel("如果您准备就绪,可以点击下方开始按钮,进行答题。", self.questionBox)
self.questionLayout.addWidget(self.question)#添加到垂直布局
#第二个盒子
self.begain = QtWidgets.QPushButton(self.choseBox)#盒子
self.begain.setObjectName("begain") #名字
self.anwserLayout.addWidget(self.begain)#添加到垂直布局
self.allLayout.addWidget(self.questionBox)
self.allLayout.addWidget(self.choseBox)
# 开始答题按钮
self.begain.clicked.connect(lambda: self.question_1())
self.retranslateUi()
QtCore.QMetaObject.connectSlotsByName(self.Form)

def question_1(self):
self.Form.hide()#本界面隐藏
dialog1 = QtWidgets.QDialog()
begain_1 = question1()
begain_1.setupUi(dialog1)
dialog1.show()#展示新的界面
dialog1.exec_()
self.Form.show()

def retranslateUi(self):
_translate = QtCore.QCoreApplication.translate
self.Form.setWindowTitle(_translate("self.Form", "测试器"))
self.begain.setText(_translate("Form", "开始答题"))

if __name__ == '__main__':
obj = AdminPage()

question_1.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# -*- coding: utf-8 -*-

# Created by: PyQt5 UI code generator 5.13.0
#
# WARNING! All changes made in this file will be lost!

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow, QDialog, QRadioButton, QMessageBox
from PyQt5 import Qt


from question_2 import question2

class question1(object):
def __init__(self):
pass

def setupUi(self, question1):
self.Form = question1
self.Form.setObjectName("Form")
self.Form.resize(455, 525)
_translate = QtCore.QCoreApplication.translate
self.Form.setWindowTitle(_translate("self.Form", "好友测试器"))
self.Form.setWindowFlags(Qt.Qt.CustomizeWindowHint) # 去掉标题栏的代码
# 最外层布局
self.allLayout = QtWidgets.QVBoxLayout(self.Form)
# 问题容器
self.questionBox = QtWidgets.QGroupBox(self.Form) # 相当于container
# 容器为垂直布局
self.questionLayout = QtWidgets.QVBoxLayout(self.questionBox)
# 选项容器
self.choseBox = QtWidgets.QGroupBox(self.Form) # 相当于container
# 容器为垂直布局
self.anwserLayout = QtWidgets.QVBoxLayout(self.choseBox)
# 第一个盒子
self.question = QtWidgets.QLabel("问题一:XXXXXXX?", self.questionBox)
self.questionLayout.addWidget(self.question) # 添加到垂直布局
# 第二个盒子
self.buttonA = QRadioButton('A:A', self.choseBox)#盒子
self.buttonB = QRadioButton('B:B', self.choseBox)#盒子
self.buttonC = QRadioButton('C:不知道', self.choseBox)#盒子
self.anwserLayout.addWidget(self.buttonA) # 添加到垂直布局
self.anwserLayout.addWidget(self.buttonB) # 添加到垂直布局
self.anwserLayout.addWidget(self.buttonC) # 添加到垂直布局
self.allLayout.addWidget(self.questionBox)
self.allLayout.addWidget(self.choseBox)
# 默认选中btnA
# self.buttonA.setChecked(True)
self.buttonA.toggled.connect(lambda: self.btnstate(self.buttonA))
self.buttonB.toggled.connect(lambda: self.btnstate(self.buttonB))
self.buttonC.toggled.connect(lambda: self.btnstate(self.buttonC))

def btnstate(self, btn):
if btn.text()=='A:A':
if btn.isChecked()==True:
msg_box = QMessageBox(QMessageBox.Warning, '错误', '回答错误!再见!')
msg_box.exec_()
app = QApplication.instance()
app.quit()

if btn.text()=="B:B": #回答正确进入下一个界面
if btn.isChecked() == True:
self.Form.hide()
dialog1 = QtWidgets.QDialog()
begain = question2()
begain.setupUi(dialog1)
dialog1.show()
dialog1.exec_()
self.Form.show()
if btn.text()=="C:不知道":
if btn.isChecked() == True:
msg_box = QMessageBox(QMessageBox.Warning, '错误', '这你都不知道!即将结束测试!再见!')
msg_box.exec_()
app = QApplication.instance()
app.quit()

第三步:优化

去掉标题栏

1
from PyQt5 import Qt
1
self.Form.setWindowFlags(Qt.Qt.CustomizeWindowHint)  # 去掉标题栏的代码

利用qt_material进行主题设置。

1
from qt_material import apply_stylesheet
1
apply_stylesheet(self.app, theme='dark_cyan.xml')

qt_material自带了很多的主题,可以通过方法 list_themes 来查看。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
'dark_amber.xml', 
'dark_blue.xml',
'dark_cyan.xml',
'dark_lightgreen.xml',
'dark_pink.xml',
'dark_purple.xml',
'dark_red.xml',
'dark_teal.xml',
'dark_yellow.xml',
'light_amber.xml',
'light_blue.xml',
'light_blue_500.xml',
'light_cyan.xml',
'light_cyan_500.xml',
'light_lightgreen.xml',
'light_lightgreen_500.xml',
'light_orange.xml',
'light_pink.xml',
'light_pink_500.xml',
'light_purple.xml',
'light_purple_500.xml',
'light_red.xml',
'light_red_500.xml',
'light_teal.xml',
'light_teal_500.xml',
'light_yellow.xml'

可优化之处

①弹窗全部使用的QMessageBox.Warning。使用其他类型均会出现程序卡死,问题尚待解决

②打包生成的exe太大,程序起步运行太慢。下次应在虚拟环境进行打包

③使用的主题,不太符合预期。应学习如何自己调整各种参数。

④多界面互动的问题,仍可寻求其他方法。

-------------本文结束感谢您的阅读-------------
原创技术分享,您的支持将鼓励我继续创作

欢迎关注我的其它发布渠道