在上一篇文章中,小编教大家用PySimpleGUI这个库编写了一个登录窗口,小编刚开始的时候觉得比较满意。
可到了后来,当小编用pysimplegui-exemaker这个库把这个程序打包成exe可执行文件时,这大小非常惊人:
然后,当小编双击几十秒之后,界面才出来。
在PySimpleGUI的官方文档上,我看到了这句话:
翻译成中文后,大意是这样的:
创建与直接使用tkinter、Qt、WxPython和Remi创建的窗口外观和操作相同的窗口。
这时,我就想:真相只有一个!那就是:过度追求简单,忽略了运行效率。
于是,我就不打算用这个库了,用Qt吧!听说它很专业。
但是,专业=复杂,这句话“岂虚言哉!”(意思是说这句话不是假的,是真的),因此,我学了一段时间,才自己做出来了一个小窗口。
而今天,小编就教大家把这个窗口给做出来。
在之前的cmd中输入pip install PyQt5 -i https://pypi.douban.com/simple/,以安装PyQt5这个库。
有一个工具,它可以让你在可视化的界面拖拖拽拽,再调一下参数即可完成大部分的界面设计(不包括功能部分),他就是Qt Designer。(中文名:Qt设计师)
要想得到它,只需要在之前的cmd在输入pip install PyQt5Designer -i https://pypi.douban.com/simple/就可以了。
你可能很惊讶,接下来的步骤不是敲代码,而是先把界面给画出来。那怎么画呢?就用安装好的Qt Designer来画。它安装到了哪里呢?在Python安装目录下的\Scripts\designer.exe这个程序,就是安装好的Qt Designer。例如,我的Python解释器是安装在D:\Python311这个目录下的,designer.exe这个程序在我的电脑的全路径就是D:\Python311\Scripts\designer.exe。
双击之后,是不是看到了这样的一个半汉化界面?
接下来应该怎么做呢?
一般情况下,我们都是选择Main Window。
(注意:实际上所有的Qt控件类名的前面都有一个Q的,例如:Main Window实际上叫QMainWindow。)
接着,因为窗口上面的菜单栏对于现在的我们来说还不需要,就移除掉。
然后把整个窗口拽宽一点,再拽一下高度(宽度和高度没有什么要求,基本上可以说是随便,下面的也是)。我的窗口的尺寸是1219x438。
第一步,我们的窗口得要有两个控件来告诉用户哪里是填密码的,哪里是填用户名的。这个控件不仅仅不是之前的T,也不是什么文本框,而是标签控件——Label控件。
将Widget Box中的Display Widgets展开,再将Label控件拽到界面上,然后双击一下,把这里面的文本改为“用户名”。
接着,再拽一个Label控件,把这里面的文本改为“密码”。
第二步,我们要把单行文本输入框给画出来了。那么,在Qt Designer中,哪一个控件是单行文本输入框呢?答案是Line Edit控件是。我们把Input Widgets展开,然后拽两个Line Edit到窗口上。
(注意:尽管现在我们的窗口很丑,控件摆得一点也不整齐,但无所谓,到了后面,我们可以用一样东西让这些控件立马变整齐。)
第三步,我们要把两个按钮给拽出来了。那么,在Qt Designer中,哪个控件是按钮呢?
不得不说,PyQt5的控件就是丰富,连按钮都有好几种,它们各自都有不同的用途。而现在需要用到的是Push Button控件。所以,我们就把Buttons展开,然后拽两个Push Button控件到窗口上。并双击一下,改一下这里面的文字。
设置样式的第一步:我们先按住Ctrl键,然后把Push Button控件和Label控件都左键点击一下以选中,接着将属性编辑器从右边拽出来,再接着将QWidget中的font展开,将粗体的选项给勾上。这样,这些字体都变粗了一点,就好看很多了。
第二步,我们先把对象查看器从左边拽出来,然后右键单击对象名为statusbar的控件,把它移除掉,因为它也没必要。
第三步,先选中窗口的一个控件,然后在对象查看器中的对象那一栏中把它的名字改成一个你认为的好记的名字(名字只要是英文名都无所谓)。像这样:
第四步,在对象查看器中右键单击最上层的QMainWindow,在下拉的菜单中点击改变样式表然后就会弹出个窗口。这时,你或许会问:在这窗口里面敲代码吗?对,但这敲的是QSS代码。
然后,如果你会美术,那接下来就是展现真正的技术的时候了。因为只要你擅长于用于网页设计的CSS,那你就能很快地精通QSS!而原因是:它们很相似,像双胞胎一样,只是性别不同,一个用于网页中的UI(user interface)设计,一个用于软件中的UI设计。
下面小编总结了一下它们的不同点。(因为它们的确很相似,所以我也就总结了五点)
QSS和CSS的一些不同点 |
||
不同的地方 |
QSS |
CSS |
是否可以单独放在一个文件后缀名为.css的文本文件里,然后在正式的文件里通过链接的方式调用。 |
不可以直接这样做,但可以先将QSS的内容赋个变量,放在一个文件后缀名为.py的模块文件里,然后再用import等方法调用。 |
可以这样做,到时候在.html文件指定文件的地址即可。 |
选择器的#是选择什么 |
#是选择当前窗体对象名称为……的控件,如:#ok就是选择当前窗体对象名称为ok的控件。 |
#是选择当前HTML 文档中id属性值为……的元素,如:#zw就是选择当前HTML 文档中id属性值为zw的元素。 |
用途 |
软件的UI设计。 |
网页的UI设计。 |
选择器中没有.、#等符号的含义 |
选择所有类名为……的控件(包括它的子类)。 |
选择标签名为……的元素(包括嵌在这里面的所有元素)。 |
选择器的开头有.的含义 |
.后面跟的是类名,选择类名为……的控件,但不包括它的子类。 |
除去开头的.,选择HTML文档中class的值为……的元素,并对嵌在这里面的所有元素生效。 |
回到前面的那个写样式代码窗口,小编在那个窗口里写了这些代码:
* {
font-size:40px;
font-family:'宋体';
}
QPushButton{
border-radius:25%;
padding:20%;
margin:25%;
}
#ok {
color:#f3fce1;
background-color:#0538f7;
}
/*hover的意思是当鼠标移动到某个控件时,这个控件的样式就会有这些改变*/
#ok:hover {
background-color:#0538c7;
color:#ffffff;
}
#no {
background-color:#fffafd;
}
效果:
前面小编提到了有一种东西,可以让我们的控件立马变得整齐,那这是什么东西呢?那就是布局!
那怎么进行布局。
第一步,我们还是按住Ctrl键,左键依次单击左边的Qlabel控件和右边的单行文本输入框,然后点击工具栏的在窗体布局中布局,这样,在那点击鼠标的一瞬间,那四个控件顿时就成了一个整体
对!这就是我认为的Qt布局的基本思想:化零为整!
第二步,以化零为整的思想,继续对那两个按钮进行布局。而我这里用的是水平布局,那选中后直接点击工具栏的水平布局即可。
第三步,在对象查看器中,点击垂直布局,我们就已经给整个窗口进行布局了。这样,到时候,我们调整一下窗口的宽度和高度,窗口里面的控件也会自适应了。
现在我们的窗口虽然已经可以说是画好了,但是,还有一些问题,例如:用户在输入密码的的那个单行文本输入框里输入内容,那些内容会不会被隐藏?
我们先解决这个问题。
选中那个单行文本输入框,按Ctrl+I,属性编辑器出现以后,展开QLineEdit那一栏,将echoMode的值设为Password。
接着,按Ctrl+R预览一下,果然,输入的内容会被隐藏。
现在还有一个简单的问题:用户点击取消按钮后,窗口会被关闭吗?
现在就来解决它。
首先,在工具栏中切换到编辑信号的模式。
然后选中取消按钮并按住鼠标左键往外拽,在弹出的窗口中左边那一栏选择clicked(),右边那一栏选择close()(要先勾选左下角的显示从QWidget继承的信号和槽),接着,点击OK。
预览一下看看。
果然,点击取消按钮后窗口就会关闭。
虽然这个界面是被我们画出来了,但是,最后我们还是要让它变成.py文件。怎么变呢?
我们可以用cd 命令进入到当前.ui所在的目录,然后执行以下格式的命令即可:
pyuic5 .ui文件名>.py文件名
比如说,我把那个文件命名为作品_登录窗口.ui,就执行pyuic5 作品_登录窗口.ui>作品_登录窗口.py。
然后,在D:\编程\Qt这个目录下就出现了一个.py文件:
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file '作品_登录窗口.ui'
#
# Created by: PyQt5 UI code generator 5.15.8
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Window(object):
def setupUi(self, Window):
Window.setObjectName("Window")
Window.resize(1219, 292)
Window.setStyleSheet("* {\n"
" font-size:40px;\n"
" font-family:\'宋体\';\n"
"}\n"
"\n"
"QPushButton{\n"
" border-radius:25%;\n"
" padding:20%;\n"
" margin:25%;\n"
"}\n"
"\n"
"#ok {\n"
" color:#f3fce1;\n"
" background-color:#0538f7;\n"
"}\n"
"\n"
"/*hover的意思是当鼠标移动到某个控件时,这个控件的样式就会有这些改变*/\n"
"#ok:hover {\n"
" background-color:#0538c7;\n"
" color:#ffffff;\n"
"}\n"
"\n"
"#no {\n"
" background-color:#fffafd;\n"
"}")
self.centralwidget = QtWidgets.QWidget(Window)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName("verticalLayout")
self.formLayout = QtWidgets.QFormLayout()
self.formLayout.setObjectName("formLayout")
self.user = QtWidgets.QLabel(self.centralwidget)
font = QtGui.QFont()
font.setFamily("宋体")
font.setPointSize(-1)
font.setBold(True)
font.setItalic(False)
font.setWeight(75)
self.user.setFont(font)
self.user.setObjectName("user")
self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.user)
self.input_user = QtWidgets.QLineEdit(self.centralwidget)
self.input_user.setObjectName("input_user")
self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.input_user)
self.password = QtWidgets.QLabel(self.centralwidget)
font = QtGui.QFont()
font.setFamily("宋体")
font.setPointSize(-1)
font.setBold(True)
font.setItalic(False)
font.setWeight(75)
self.password.setFont(font)
self.password.setStyleSheet("")
self.password.setObjectName("password")
self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.password)
self.input_password = QtWidgets.QLineEdit(self.centralwidget)
self.input_password.setEchoMode(QtWidgets.QLineEdit.Password)
self.input_password.setObjectName("input_password")
self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.input_password)
self.verticalLayout.addLayout(self.formLayout)
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.ok = QtWidgets.QPushButton(self.centralwidget)
font = QtGui.QFont()
font.setFamily("宋体")
font.setPointSize(-1)
font.setBold(True)
font.setItalic(False)
font.setWeight(75)
self.ok.setFont(font)
self.ok.setObjectName("ok")
self.horizontalLayout.addWidget(self.ok)
self.no = QtWidgets.QPushButton(self.centralwidget)
font = QtGui.QFont()
font.setFamily("宋体")
font.setPointSize(-1)
font.setBold(True)
font.setItalic(False)
font.setWeight(75)
self.no.setFont(font)
self.no.setObjectName("no")
self.horizontalLayout.addWidget(self.no)
self.verticalLayout.addLayout(self.horizontalLayout)
Window.setCentralWidget(self.centralwidget)
self.retranslateUi(Window)
self.no.clicked.connect(Window.close) # type: ignore
QtCore.QMetaObject.connectSlotsByName(Window)
def retranslateUi(self, Window):
_translate = QtCore.QCoreApplication.translate
Window.setWindowTitle(_translate("Window", "MainWindow"))
self.user.setText(_translate("Window", "用户名"))
self.password.setText(_translate("Window", "密码"))
self.ok.setText(_translate("Window", "确认"))
self.no.setText(_translate("Window", "取消"))
如果你认为每次都要去cmd敲命令太麻烦了,就在一个.py文件里敲这几行代码,只要告诉程序你的.ui文件的名字即可(不用带后缀名)。
# 这个文件和.ui文件要在同一工作目录才行
from os import system, getcwd
system(str(getcwd)[:1])
system(f"cd {getcwd}")
file_ui = input("请输入UI文件的文件名")
print(file_ui)
system(f"pyuic5 {file_ui}.ui>{file_ui}.py")
这就行了吗?
还不行,这些都只是定义好了窗口的内容而已,还没有把窗口给展示出来。
在后面加上这几行代码:
if __name__ == "__main__":
app = QtWidgets.QApplication([])
mainWindow = QtWidgets.QMainWindow()
ui = Ui_Window()
ui.setupUi(mainWindow)
mainWindow.show()
app.exec_()
完成了吗?
没有,先定义一个函数和一些属性来处理点击确认所发生的事件:
# 这些属性我是封装到Ui_Window那个类里面的
User1 = {'用户名': 'fggf', '密码': '123'}
User2 = {'用户名': 'ghh23456', '密码': '456'}
User_List = [User1, User2]
# 这个函数我也是封装到Ui_Window那个类里面的
def ok_event(self):
user_ = self.input_user.text()
password_ = self.input_password.text()
for i in Ui_Window.User_List:
if user_ == i["用户名"] and password_ == i["密码"]:
right = True
else:
error = True
try:
if right is True:
QtWidgets.QMessageBox.about(self.centralwidget, "输入正确", "输入正确")
exit(0)
except NameError:
QtWidgets.QMessageBox.warning(self.centralwidget, "输入错误", "输入错误")
self.input_password.clear()
self.input_user.clear()
接着,把if……的那几行代码改一下,实现功能
if __name__ == "__main__":
app = QtWidgets.QApplication([])
mainWindow = QtWidgets.QMainWindow()
ui = Ui_Window()
ui.setupUi(mainWindow)
# 加上了两行代码
# 如果用户点击了确认按钮,就交给ui.ok_event这个函数来处理
ui.ok.clicked.connect(ui.ok_event)
# 如果用户在输入密码的那个单行文本输入框中按下了enter键,就交给ui.ok_event这个函数来处理
ui.input_password.returnPressed.connect(ui.ok_event)
mainWindow.show()
app.exec_()
这样,一个用PyQt5编写的登录窗口就完成了。
这是小编的第二篇文章,如有不足之处请指出,谢谢!