搞了多年的工控,年过半百突然想要学习编程,单打独斗在黑暗中摸索,每获得一分收获都要付出几倍的艰辛。学习python一年有余,陆续做过了几个小工程,初步建立了适合自己的应用框架。阶段总结,备忘。同时虚心接受高手指点。
Pyside的基本框架,主要特点:
1、尽量使用Qt Designer组态界面,这符合工控人的使用习惯,从wincc、组态王等过来的,很容易接受。
2、功能代码和界面媒体前后端分离。
3、结构简单清晰,容易嫁接复制。
4、尽量使用较少的编程知识,避免陷入学习深渊。
实施过程:
1、按个人习惯创建文件夹目录,本次demo的结构为:
这里的UIS是按照软件包创建的,软件包文件夹和普通文件夹的区别在于软件包文件夹的根目录下有__init__.py文件,即使__init__.py是空的。
2、在Qt Designer里创建两个窗口画面,并存盘。命名为demo.ui和demo_2.ui.保存在UIS文件夹内。
3、使用pyuic工具将demo.ui和demo_2.ui转换为.py文件,得到了两个文件demo_rc.py和demo_2_rc.py。
4、修改UIS文件夹内__init__.py文件,内容如下:
from .demo_rc import *
from .demo_2_rc import *
这个的含义是:我们已经把UIS创建为一个软件包,当在主脚本里通过from UIS import *时,__init__.py中列出的内容会被导入
5、创建主脚本main.py文件,调用。
main.py代码:
# encoding: utf-8
import os
import sys
from functools import partial
from PySide6.QtCore import Signal, QTimer
# 获取当前脚本的目录
current_dir = os.path.dirname(os.path.abspath(__file__))
# 将 UIS 文件夹的路径添加到 sys.path 中
uis_dir = os.path.join(current_dir, 'UIS')
sys.path.append(uis_dir)
from UIS import *
# 主画面类
class MainWindow(QMainWindow, demo_rc.Ui_MainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
self.run() # 初始化
# 主画面的初始化
def run(self):
self.move(200, 200)
self.show() # 显示画面
self.btn_station = self.btn_group.children() # 按钮站
self.label_1.setText('0')
self.label_2.setText('0')
self.label_second.setText('0')
self.btn_all.setProperty('activated', True)
self.btn_all.setStyleSheet(self.btn_all.styleSheet())
self.signal_slot() # 信号和槽
# 画面层面的信号和槽
def signal_slot(self):
# 按钮站的槽函数
def buttons_clicked(button): # 回调
def one_btn_clicked(): # 闭包
# 设置各个按钮的显示外观
def set_styleSheet():
for b in self.btn_station:
if b != button:
b.setProperty('activated', False)
else:
b.setProperty('activated', True)
b.setStyleSheet(b.styleSheet()) # 刷新显示
set_styleSheet()
# 每个按钮的功能函数
if button is self.btn_1:
self.frame_1.show()
self.frame_2.hide()
elif button is self.btn_2:
self.frame_2.show()
self.frame_1.hide()
elif button is self.btn_none:
self.frame_1.hide()
self.frame_2.hide()
elif button is self.btn_all:
self.frame_1.show()
self.frame_2.show()
return one_btn_clicked
# 按钮站的信号连接
for btn in self.btn_station:
btn.clicked.connect(partial(buttons_clicked(btn)))
# 滑块改变数值的槽函数
def slider_1_valueChanged(value):
ui.value_slider1.emit(value) # 当滑块改变数值,项目级别的信号ui.Signal1发射
# 滑块值改变的信号连接
self.slider_1.valueChanged.connect(slider_1_valueChanged)
# label_1的文字内容的槽函数
def label_1_setText(x):
self.label_1.setText(str(x))
# label_1的文字内容信号连接
ui.value_slider1.connect(label_1_setText)
# label_2的文字内容的槽函数
def label_2_setText(x):
self.label_2.setText(str(x))
# label_2的文字内容信号连接
ui.value_slider1.connect(label_2_setText)
# label_second的文字内容的槽函数
def label_second_setText():
self.label_second.setText(Jobs.Job_todo_2())
# label_second的文字内容信号连接
ui.secondSignal.connect(label_second_setText)
# frame1的overFlow特性设定槽函数
def frame1_set_overFlow(x):
this = self.frame_1
if x > 200:
this.setProperty('overFlow', True)
else:
this.setProperty('overFlow', False)
this.setStyleSheet(this.styleSheet())
# frame1的overFlow特性设定信号连接
ui.value_slider1.connect(frame1_set_overFlow)
# 退出系统的槽函数
def quit_system():
Jobs.before_quit()
self.btn_exit.clicked.connect(quit_system)
# Window2的画面类
class Window2(QMainWindow, demo_2_rc.Ui_MainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
self.run()
# 初始化
def run(self):
self.move(500, 500)
self.show() # 显示画面
self.label_1.setText('0')
self.signal_slot()
# 画面层面的信号和槽
def signal_slot(self):
def label_1_setText(x):
self.label_1.setText(Jobs.Job_todo_1(x))
ui.value_slider1.connect(label_1_setText)
# 一些作业函数和功能函数
class Jobs:
@staticmethod
def Job_todo_1(var):
return str(var * 2)
@staticmethod
def Job_todo_2():
ui.seconds += 1
if ui.seconds == 60:
ui.seconds = 0
return str(ui.seconds)
# 退出系统前的保存、清理、释放等操作
@staticmethod
def before_quit():
if ui.windows:
for w in ui.windows:
w.close()
# 项目的定义
class UI(QObject): # 将项目定义为QObject,用来管理项目级别的信号和变量
value_slider1 = Signal(int) # 这是一个项目级别的信号,对应于主窗口的滑块_slider1的值
secondSignal = Signal() # 这是一个项目级别的信号,每秒发出一个信号
def __init__(self):
super().__init__()
self.timer = QTimer() # 一个项目级别的定时器
self.seconds = 0 # 读秒数
self.run() # 初始化
# 项目的初始化
def run(self):
self.timer.start(1000)
# 项目层面的信号和槽
def signal_slot():
# 秒信号的发射槽函数
def secondSignal_emit():
self.secondSignal.emit()
# 秒信号的连接
self.timer.timeout.connect(secondSignal_emit)
# 退出系统之前的操作
app.aboutToQuit.connect(Jobs.before_quit)
signal_slot()
# #############################主程序##################################
if __name__ == '__main__':
app = QApplication(sys.argv)
# 项目的实例化
ui = UI()
ui.windows = [] # 所有用到的窗口
# 初始化画面
mainWindow = MainWindow() # 主画面实例化
ui.windows.append(mainWindow)
window2 = Window2() # window2画面实例化
ui.windows.append(window2)
sys.exit(app.exec())
另一个小demo
import sys
from functools import partial
from PySide6.QtCore import Signal, QObject
from PySide6.QtWidgets import QApplication, QMainWindow, QPushButton, QGroupBox
class MainWindow(QMainWindow):
function_signal = Signal(object)
def __init__(self):
super().__init__()
self.setFixedSize(300, 400)
# 按钮群
self.btn_group = QGroupBox(self)
self.btn_group.setGeometry(50, 50, 200, 300)
# 创建按钮
self.button1 = QPushButton('功能1', self.btn_group)
self.button1.setCheckable(True)
self.button1.setGeometry(50, 50, 100, 50)
self.button2 = QPushButton('功能2', self.btn_group)
self.button2.setCheckable(True)
self.button2.setGeometry(50, 120, 100, 50)
self.button3 = QPushButton('功能3', self.btn_group)
self.button3.setCheckable(True)
self.button3.setGeometry(50, 190, 100, 50)
# 槽和信号
self.slot_signal()
# 槽和信号
def slot_signal(self):
# 按钮站的定义
self.btnStation = self.btn_group.children()
# 按钮站的槽函数
def slot_btn(btn):
def set_check():
for b in self.btnStation:
if b != btn:
b.setChecked(False)
else:
b.setChecked(True)
if btn == self.button1:
self.function_signal.emit('功能1')
print('btn1 is clicked')
elif btn == self.button2:
self.function_signal.emit('功能2')
print('btn2 is clicked')
elif btn == self.button3:
self.function_signal.emit('功能3')
print('btn3 is clicked')
return set_check
for b in self.btnStation:
b.clicked.connect(partial(slot_btn(b))) # 连接信号到槽函数
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())