Python GUI初学者计划1——PySide2和PyQt5库的安装

Python GUI初学者计划2——手写代码的方式实现PySide2界面设计(详细讲解内部联系)

基于上期的内容: Python GUI初学者计划2——手写代码的方式实现PySide2界面设计(详细讲解内部联系) ,我们大致说了下直接用代码创建UI界面,以及详述了信号signal和槽slot之间的联系。

手动写代码虽然可以让我们清楚的知道每一控件的具体设置,但是有时候对于具体控件的创建方式我们记不清或者把握不准创建的方式,需要一步步的调节,浪费时间而且效率不高,那么有没有一种方法,我们直接通过拖拽的形式讲我们需要的界面直接建立好,在代码中一键导入就可以编辑程序呢?

Python GUI初学者计划1——PySide2和PyQt5库的安装 这一期的内容中我们讲了如何在Python环境下安装PySide2和PyQt5等,作为Python程序执行的第三方库,通常相关的安装程序都会在Python安装目录下的第三方库的包里,也就是:Python目录下的site-packages文件夹内。

我的安装目录如下: 那么这个文件夹内就有我们安装的PySide2和PyQt5等库: 点击PySide2,有一个designer的.exe可执行文件,双击它便可得到一个创建GUI的工具。 打开界面后,如果是汉化版的话,左上角是Qt 设计师的标志。 在 Python GUI初学者计划2——手写代码的方式实现PySide2界面设计(详细讲解内部联系) ,我们说到,很多的控件类都是继承自QWidge,包括QMainWindow,QPlainTextEdit,QMessageBox等等。

一、GUI的设计

1 打开UI设计界面

我们选择创建一个Widget的界面框,然后点击【创建】: 得到这么一个界面:

2、 创建自己需要的UI内容

如果我们需要创建一个按键对象,按键对应的是Push Button控件,那我们只需要点击Buttons,然后找到Psuh Button,将鼠标移到Push Button上面,左键按住,然后拖曳到UI界面框内所需位置即可。 创建完之后,右边会出现UI界面的信息,当你点击控件时,右边的【对象】和【属性】会高光显示。我们需要对对象下面的名字进行修改。

2.1 为什么要修改对象名?

因为每个控件都有自己所要实现的功能,当用户事件(点击,输入等)发生后,控件对应的函数会发生作用,那么控件需要连接到函数进行功能的响应,如果控件太多的话,容易混乱控件与控件之间的关系。

如下图所示,两个PushButton按钮,文件名的区别不明显,且其要完成的功能也不够直观,故而需要对对象名进行修改 如我们需要两个按钮,分别完成点击之后出现一句开玩笑的弹窗,和进行文本框内容的复制等2个功能,修改如图所示: 那左边两个提示名字都是PushButton,如何区分呢,双击按钮,进行名字修改即可: 如此算是修改完成。

2.2 如果我需要创建多个一样的控件,怎么办?

如果我们在创建UI的时候,需要创建多个控件,比如Button按钮,每次都要从左边的Widget Box中拖曳,比较麻烦,有没有方便快捷的方法呢?

有。我们鼠标左键点击需要复制的按钮,摁住Ctrl键,然后进行拖拽即可。(有多个复制的则Ctrl之后分别点击,然后再行拖拽),如下图: 然后步骤如2.1进行对象名的修改。

对象名的修改是为了:在代码中能更快让它(控件)与功能函数(def ...)进行链接(connect)。比如:Butto_jok按钮,当被点击的时候,出现弹窗,就用Button_jok..clicked.connect(实现的函数)

3、 设计好GUI,添加属性

创建好一个大概的GUI界面,如下图所示,修改文本框的对象名为:text_input(叫什么名无所谓,主要是为了方便好找,以及一眼就知道它是实现什么功能的)。

3.1 如果我们需要在文本框没输入东西的时候有默认提示信息怎么弄?

有时候GUI界面在打开的时候,我们需要提示用户按照指令进行操作,比如,在左边的文本框中带有默认信息 “请在此输入文本信息”。

默认提示信息的功能是文本框text_input所属的类APlainTextEdit的功能。 在这里插入图片描述 找到placeholderText,双击右边的【值(Value)】: 输入提示信息后: 题外 :其实这个地方,在右边输入字体,左边的文本框会跟着出现一样信息的功能也是signal和slot的响应关系。

3.2 UI界面左上方Form 和 untitled* 是什么,怎么修改?

Form就是你创建的这个整个UI界面的一个Titile,比如你要完成的是斗地主功能的设计,你可以命名【 愉快斗地主】,你要完成的是图像的简单处理,你也可以命名为 【图像处理器】。

那么untitled* 是什么呢?就是你这一整个UI 的命名,是在程序中导入.ui文件的时候,导入的文件名。同理你也可以命名为:my_ui.ui,UI.ui等。

---- untitled * 的修改在保存这个UI文件的时候可以重命名。

---- Form 的修改可以点击【对象查看器】的【对象】,在【属性编辑器】的【QWidget】中修改,。 【QWidget】下有一个windowTitle,修改其【值】即可。 修改之后:

二、Signal 与Slot的联系

4、UI文件介绍

这是刚才保存的UI文件: 我们用编辑文本打开它(我用EditPlus,其他的也可以),效果如下: 可以看到文本内容是.XML 格式来储存的UI信息,这样的好处是当我们下次打开的时候,系统就会根据这个文件打开我们创建的UI界面。

5 、动态加载UI界面

有两种方式导入.ui文件

#导入UI方式1
self.ui = QUiLoader().load('UIUI.ui')
#导入UI方式2
qfile_UIUI = QFile("UIUI.ui")
qfile_UIUI.open(QFile.ReadOnly)
qfile_UIUI.close()
self.ui = QUiLoader().load(qfile_UIUI)

5.1 直接导入UI文件(2种方式)【第一种】

from PySide2.QtWidgets import QApplication,QMessageBox
from PySide2.QtUiTools import QUiLoader
class UIUI:
	def __init__(self):
		self.ui = QUiLoader().load('UIUI.ui')
		self.ui.Button_jok.clicked.connect(self.yahoo)
		self.ui.Button_copy.clicked.connect(self.copy_text)
	def yahoo(self): #与手动创建代码不同,这里需要在()加入self
		print('i was be knocked')
		QMessageBox.about(self.ui, '反馈结果', '哎呦,宝贝你来啦')
		#(self.ui, '反馈结果', '哎呦,宝贝你来啦')这里的self.ui不是窗口初始化的new_window,也不是self
	def copy_text(self):
		info = self.ui.text_input.toPlainText()#与手动创建代码不同,这里需要在()加入self
		QMessageBox.about(self.ui, '复制的新窗口', f'{info}')
app = QApplication([])
uiui = UIUI()
uiui.ui.show()
app.exec_()

5.2 直接导入UI文件(2种方式)【第二种】

from PySide2.QtWidgets import QApplication,QMessageBox
from PySide2.QtUiTools import QUiLoader
from  PySide2.QtCore import QFile
class UIUI:
	def __init__(self):
	#先导入.ui文件,存在qfile_UIUI。然后关闭
		qfile_UIUI = QFile("UIUI.ui")
		qfile_UIUI.open(QFile.ReadOnly)
		qfile_UIUI.close()
		# 导入加载的UI类(返回的就是UI界面对应的QWidget窗体对象)
		self.ui = QUiLoader().load(qfile_UIUI)  # 界面对象
		self.ui.Button_jok.clicked.connect(self.yahoo)
		self.ui.Button_copy.clicked.connect(self.copy_text)
	def yahoo(self): #与手动创建代码不同,这里需要在()加入self
		print('i was be knocked')
		QMessageBox.about(self.ui, '反馈结果', '小宝贝,你来了')
		#(self.ui, '反馈结果', '哎呦,宝贝你来啦')这里的self.ui不是窗口初始化的new_window,也不是self
	def copy_text(self):
		info = self.ui.text_input.toPlainText()#与手动创建代码不同,这里需要在()加入self
		QMessageBox.about(self.ui, '复制的新窗口', f'{info}')
app = QApplication([])
uiui = UIUI()
uiui.ui.show()
app.exec_()

开玩笑按钮: 复制按钮:

如果代码没错,自己修改过之后一直出现这样的问题,解决不了:

AttributeError: 'UIUI' object has no attribute 'ui'

---------------建议重新建个新 .py 文件编写(反正我是如此解决的)---------------------

除了动态加载的方式(2种导入方式),我们能否将设计的.ui文件转化为.py文件,文件中有界面的所有详细参数,(就像我们自己手写代码定义的一样,区别是用.ui转化而来)。

答案是可以的!!!

接下来让我们进入正题: 先找到你的.ui存储的位置,我的是 Win+R,输入cmd进入终端: 进入到文件保存的盘,并输入转换指令:

> e (我的文件在E盘)
> cd  ...\...\...\(cd 到某个文件夹)
> pyside2-uic UIUI.ui > JM_ui.py
下列的代码为将.ui文件转换为对应的.py文件的指令:

pyside2-uic UIUI.ui > JM_ui.py
察看导出的.py 文件
打开为下列代码:

# -*- coding: utf-8 -*-
################################################################################
## Form generated from reading UI file 'UIUI.ui'
## Created by: Qt User Interface Compiler version 5.15.2
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtWidgets import *
class Ui_Form(object):   
	#有些转换出来是:class Ui_MainWindow(object):
    def setupUi(self, Form):
        if not Form.objectName():
            Form.setObjectName(u"Form")
        Form.resize(532, 380)
        self.Button_jok = QPushButton(Form)
        self.Button_jok.setObjectName(u"Button_jok")
        self.Button_jok.setGeometry(QRect(380, 90, 81, 41))
        self.text_input = QPlainTextEdit(Form)
        self.text_input.setObjectName(u"text_input")
        self.text_input.setGeometry(QRect(30, 20, 301, 341))
        self.Button_copy = QPushButton(Form)
        self.Button_copy.setObjectName(u"Button_copy")
        self.Button_copy.setGeometry(QRect(380, 180, 81, 41))
        self.retranslateUi(Form)
        QMetaObject.connectSlotsByName(Form)
    # setupUi
    def retranslateUi(self, Form):
        Form.setWindowTitle(QCoreApplication.translate("Form", u"\u8fd9\u4e0d\u662f\u4e00\u4e2a\u6b63\u7ecf\u7684GUI", None))
        self.Button_jok.setText(QCoreApplication.translate("Form", u"\u70b9\u6211\u5f00\u73a9\u7b11", None))
        self.text_input.setPlaceholderText(QCoreApplication.translate("Form", u"\u8bf7\u5728\u6b64\u8f93\u5165\u6587\u672c\u4fe1\u606f", None))
        self.Button_copy.setText(QCoreApplication.translate("Form", u"\u70b9\u6211\u590d\u5236", None))
    # retranslateUi

通过代码观察我们可以看到,在类class中为class Ui_Form(object):,但是有些朋友转换出来可能是class Ui_MainWindow(object):。

这到底是是为什么呢?

让我们使用步骤1打开Designer,观察.ui文件的控件信息。 右边的类是Qwidget,对象名就是Form。 因为我们创建的时候选择的就是Widget: 如果选择的是Main Window创建UI文件: 将.ui转换为.py文件: 这个细节需要注意,有些同学在导入的时候容易发生错误,也是因为这个地方的原因,并不是所有的都是 class Ui_MainWindow(object):

对.ui文件转换为.py文件后,就可以把这个.py文件当做是自己手写的创建UI的代码(比自己慢慢调尺寸,位置方便很多),保持这个文件别动,重新!重新!重新!(说三遍)创建一个新的.py文件用来写执行功能。

.ui转.py文件保存为:JM_ui.py 新建实现的文件为:UIUI.py

实现效果为: 实现代码为:

from PySide2.QtWidgets import QApplication,QMessageBox,QMainWindow
from JM_ui import *   #需要从JM_ui.py导入内容
import sys
class UIUI(QMainWindow,Ui_Form):
	def __init__(self, parent=None):
		super(UIUI, self).__init__(parent)
		#子类继承了父类的所有属性和方法,父类属性自然会用父类方法来进行初始化
		self.ui = Ui_Form()
		#转换的.py文件是class Ui_Form(object):
		self.ui.setupUi(self)#初始化界面
		self.ui.Button_jok.clicked.connect(self.yahoo)
		self.ui.Button_copy.clicked.connect(self.copy_text)
	def yahoo(self): #与手动创建代码不同,这里需要在()加入self
		print('i was be knocked')
		QMessageBox.about(self.ui, '反馈结果', '小宝贝,你来了')
		#(self.ui, '反馈结果', '哎呦,宝贝你来啦')这里的self.ui不是窗口初始化的new_window,也不是self
	def copy_text(self):
		info = self.ui.text_input.toPlainText()#与手动创建代码不同,这里需要在()加入self
		QMessageBox.about(self.ui, '复制的新窗口', f'{info}')
if __name__ == "__main__":
	app = QApplication(sys.argv)
	uiui = UIUI()
	uiui.show()
	sys.exit(app.exec_())

疑问:这么多方法,到底哪一个最好,或者说哪一个方法最不容易出错呢?

答:我觉得用Designer设计出UI文件之后,动态加载UI文件,然后处理。这样的方法是最不容易出错的,况且载入UI的方法也比较多。

写在最后: 你要相信大多数人与人之间的差距并不大,但是0.99的N次方和1.1的N次方差距是随着N多增多而越来越大的;坚定的目标和持久的努力一定会成功!

你偷过的每一个懒,都会成为你日后最深的遗憾。

我是通信不二,一个积极努力,乐观向上的程序猿!!!

分类:
代码人生
标签: