代码重构(OOP)-小栗子(PyQt5)
主要是为了练习下 面向对象, 不断提醒自己代码一定要写成 营销风格, 和优雅.
最近在B站上看一下关于 Python GUI 编程的内容. 恰好呢, 前不久的一个 将本地 Ecxcel 数据 发布到 Tableau Server 中, 当核心接口搞定后, 工程化领导让弄 web, 我们果断拒绝了, 不太熟前端也暂时不想学, 就用 Python 自带的 Tk 模块来写一版, 涉及安全就不能共享出来, 总体蛮简单的. 后来, 倒是引发我对 gui 的一点小兴趣. 就没事看看 PyQt5 的内容, 没事学学, 目的就是为了熟练 Pyhton 而已.
在 tk 中, 给控件绑定自定义函数, 通过 command 来实现, 还有 bind 等事件绑定. 跟 js 也是一样的. PyQt5 中, 被称为 信号与槽. 从开发的角度来看, 差不多的内容. 然后 我发现, 代码重构 是一个特别有趣, 特别有挑战的事情, 重构就意味着要 封装性更好, 代码质量高. 我是有这方面的洁癖, so, 总是喜欢不断优化, 追求完美.
这里取了一个B站视频的 小片段而已, 怎么把 乱七八糟的代码 进行 面向对象.
需求
简化了哈, 就是要自己实现一个顶层窗口, 包含3个控件, 最大化, 最小化, 退出. (蛮简单的哈) 效果图如下
然后就照着写, 代码并不难, 就是控件的计算可能需要绕一点而已.
from PyQt5.Qt import *
import sys
# 1. 创建应用程序的对象
app = QApplication(sys.argv) # 接收命令行参数(整个项目都能用)
# 2. 控件的操作
# 2.1 创建控件
# 去掉边框, 标题栏
# win = QWidget(flags=Qt.FramelessWindowHint)
win = QWidget()
# 去掉标题栏 + 设置透明度
win.setWindowFlags(Qt.FramelessWindowHint)
win.setWindowOpacity(0.8)
# 2.2 设置控件
win.setWindowTitle("顶层窗口操作-案例")
win.resize(500, 300)
top_margin = 10
btn_w = 80
btn_h = 30
# 添加3个子控件, 窗口的右上角
close_btn = QPushButton(win)
close_btn.setText("关闭")
close_btn.resize(btn_w, btn_h)
# move_x: 窗口的宽度 - 控件的宽度
# close_btn_x = win.width()- close_btn.width()
close_btn_x = win.width() - btn_w
close_btn_y = top_margin
close_btn.move(close_btn_x, close_btn_y)
# 最大化按钮
max_btn = QPushButton(win)
max_btn.setText("最大化")
max_btn.resize(btn_w, btn_h)
max_btn_x = close_btn_x - btn_w
max_btn.move(max_btn_x, top_margin)
mini_btn = QPushButton(win)
mini_btn.setText("最小化")
mini_btn.resize(btn_w, btn_h)
mini_btn_x = max_btn_x - btn_w
mini_btn.move(mini_btn_x, top_margin)
# 监听: 信号与槽, 点击实现 最大化, 最小化, 关闭
close_btn.pressed.connect(win.close)
def max_normal():
if win.isMaximized():
win.showNormal() # 变回普通
max_btn.setText("最大化")
else:
win.showMaximized()
max_btn.setText("恢复")
max_btn.pressed.connect(max_normal)
mini_btn.pressed.connect(win.showMinimized)
# 2.3 展示控件
win.show()
# 3. 让主程序进入死循环 (tk 里面的 mainloop)
if __name__ == '__main__':
sys.exit(app.exec())
其实写到这里, 就会发现, 随着控件的增多, 代码逻辑其实就会混乱. 代码跟函数 放混在一起, 这是绝不能这样做的. 不然后面就维护起来非常困难了. 因此才需要重构.
代码重构
其实就是将这个 业务过程的代码, 封装为面向对象, 阅读体验更好和维护更加容易.
重构 - 封装继承 QWidget
最为直接 和 最为最要的一点就是, 封装类的结构设计. 这里首先就是要对 设计全局的 QWidget 对象进行封装, 我们全程需要用到它, 而且又有新的功能扩充或者交互, 因此, 我们首先设计的类, 必须要 继承 , 然后新功能则 重写.
OOP
掌握 继承, 就是拥有父类的所有功能, 当然, 理解 self 的本质 和 super() 也是很关键的. self 还好, 就是一个形参, 表示类对象自身嘛(属性和方法) ;
理解 super( ) 从功能上, 修复了 类搜索的 "钻石调用问题", 采用了其 mro 顺序搜索. (本质是 广度优先哦) 不清楚可以 看看之前的记录:
多继承 MRO: https://www.cnblogs.com/chenjieyouge/p/12246113.html
from PyQt5.Qt import *
import sys
class Window(QWidget):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setWindowTitle("顶层窗口操作")
self.resize(500, 300)
# 去掉标题栏 + 设置透明度
self.setWindowFlags(Qt.FramelessWindowHint)
self.setWindowOpacity(0.8)
# 1. 创建应用程序的对象
app = QApplication(sys.argv) # 接收命令行参数(整个项目都能用)
# win = QWidget()
win = Window()
# 先省略了后面的代码.
这种继承再重写, 追加的思维, 真的蛮用得很普遍的. 很优雅. 但我的数据工作呢. 其实更多是过程, 脚本..只能在博客上来练习面向对象...
重构 __ init __ 与 ui 连接
- 将控件都封装在 setup_ui () 中, 并 将其置与 __ init __()
- 将 win 全部替换为 self
class Window(QWidget):
def __init__(self, *args, **kwargs):
# 为了直接表示, 省略了这里的代码.
# 控件相关
self.setup_ui()
def setup_ui(self):
# 公共数据 (全局变量)
top_margin = 10
btn_w = 80
btn_h = 30
# 控件布局
# 添加3个子控件, 窗口的右上角
close_btn = QPushButton(self)
close_btn.setText("关闭")
close_btn.resize(btn_w, btn_h)
close_btn_x = self.width() - btn_w
close_btn_y = top_margin
close_btn.move(close_btn_x, close_btn_y)
# 最大化按钮
max_btn = QPushButton(self)
max_btn.setText("最大化")
max_btn.resize(btn_w, btn_h)
max_btn_x = close_btn_x - btn_w
max_btn.move(max_btn_x, top_margin)
mini_btn = QPushButton(self)
mini_btn.setText("最小化")
mini_btn.resize(btn_w, btn_h)
mini_btn_x = max_btn_x - btn_w
mini_btn.move(mini_btn_x, top_margin)
# 监听: 信号与槽, 点击实现 最大化, 最小化, 关闭
close_btn.pressed.connect(self.close)
def max_normal():
if self.isMaximized():
self.showNormal() # 变回普通
max_btn.setText("最大化")
else:
self.showMaximized()
max_btn.setText("恢复")
max_btn.pressed.connect(max_normal)
mini_btn.pressed.connect(self.showMinimized)
重构 - 全局变量
- 将用到的全局变量, 给 self 绑定, 作为类的一部分
- 修复
from PyQt5.Qt import *
import sys
class Window(QWidget):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setWindowTitle("顶层窗口操作")
self.resize(500, 300)
# 去掉标题栏 + 设置透明度
self.setWindowFlags(Qt.FramelessWindowHint)
self.setWindowOpacity(0.8)
# 公共数据 (全局变量)
self.top_margin = 10
self.btn_w = 80
self.btn_h = 30
# 控件相关, 一定要放在最后哦
self.setup_ui()
def setup_ui(self):
# 控件布局
# 添加3个子控件, 窗口的右上角
close_btn = QPushButton(self)
self.close_btn = close_btn # 临时局部变量
close_btn.setText("关闭")
close_btn.resize(self.btn_w, self.btn_h)
# 最大化按钮
max_btn = QPushButton(self)
self.max_btn = max_btn
max_btn.setText("最大化")
max_btn.resize(self.btn_w, self.btn_h)
mini_btn = QPushButton(self)
self.mini_btn = mini_btn
mini_btn.setText("最小化")
mini_btn.resize(self.btn_w, self.btn_h)
# 监听: 信号与槽, 点击实现 最大化, 最小化, 关闭
close_btn.pressed.connect(self.close)
def max_normal():
if self.isMaximized():
self.showNormal() # 变回普通
max_btn.setText("最大化")
else:
self.showMaximized()
max_btn.setText("恢复")
max_btn.pressed.connect(max_normal)
mini_btn.pressed.connect(self.showMinimized)
def resizeEvent(self, QResizeEvent):
close_btn_x = self.width() - self.btn_w
close_btn_y = self.top_margin
self.close_btn.move(close_btn_x, close_btn_y)
max_btn_x = close_btn_x - self.btn_w
self.max_btn.move(max_btn_x, self.top_margin)
mini_btn_x = max_btn_x - self.btn_w
self.mini_btn.move(mini_btn_x, self.top_margin)
app = QApplication(sys.argv)
win = Window()
win.show()
if __name__ == '__main__':
sys.exit(app.exec())
完成重构
达到非常容易阅读, 和易维护的工程代码.
小结
- 通过这类 GUI 程序来练习代码重构, 类的封装, 继承 (重写, 追加) 等操作
- 加深的 self 和 super() 从本质上去理解, 非常关键对于面向对象
- 锻炼下代码风格, 在功能实现的基础上, 如何增加可读性, 和鲁棒性, 易维护等. 我觉得更为重要.
咱说呢, 我感觉, GUI 用 纯Pyhthon 来写, 感觉还可以哦, 虽然现在 web 是主流, 但我感觉, gui 反而让我更加有成就感一点. 后面也适当记录一波学习的过程. 虽然都是搬砖, 但理解是不同的.
代码重构(OOP)-小栗子(PyQt5)的更多相关文章
- 让代码重构渐行渐远系列(3)——string.Equals取代直接比较与非比较
重构背景及原因 最近由于项目组的人员在不断扩充,导致项目中代码风格各异,大有百花齐放甚至怒放之势.考虑到团队的生存与发展,经过众人多次舌战之后,最终决定项目组根据业务分成几个小分队,以加强团队管理与提 ...
- C++代码重构——从C global到C++ template
在学数据结构的时候,我常有这样目标--写出能够最大程度复用的代码(算法正确,封装优秀).我常想--如何能在短时间内达成"算法正确,封装优秀"这样的目标.经过一段时间的摸索,我的结论 ...
- CSS代码重构与优化之路
作者:@狼狼的蓝胖子 网址:http://www.cnblogs.com/lrzw32/p/5100745.html 写CSS的同学们往往会体会到,随着项目规模的增加,项目中的CSS代码也会越来越多, ...
- CSS代码重构
CSS代码重构的目的 我们写CSS代码时,不仅仅只是完成页面设计的效果,还应该让CSS代码易于管理,维护.我们对CSS代码重构主要有两个目的:1.提高代码性能2.提高代码的可维护性 提高代码性能 提高 ...
- Javaweb统计在线人数的小栗子
最近在学习Javaweb相关的内容(不黑不吹之前对web开发零基础),下面通过一个统计在线人数的小栗子讲讲Servlet监听器吧 开发环境 eclipse tomcat 7 先说说这个小栗子的构思: ...
- .NET - 代码重构技巧
通过面向对象三大特性:封装.继承.多态的学习,可以说我们已经掌握了面向对象的核心.接下来的学习就是如何让我们的代码更优雅.更高效.更易读.更易维护.当然了,这也是从一个普通程序员到一个高级程序员的必由 ...
- 代码重构 & 代码中的坏味道
1.重构 1.1 为什么要重构 1.1.1 改进程序设计 程序员为了快速完成任务,在没有完全理解整体架构之前就开始写代码, 导致程序逐渐失去自己的结构.重构则帮助重新组织代码,重新清晰的体现 程序结构 ...
- 代码重构方向原则指导(转载 cnblogs)
英文原文:Hill Climbing (Wonkish) 重构是一种对软件进行修改的行为,但它并不改变软件的功能特征,而是通过让软件程序更清晰,更简洁和更条理来改进软件的质量.代码重构之于软件,相 ...
- SpringBoot+Shiro入门小栗子
写一个不花里胡哨的纯粹的Springboot+Shiro的入门小栗子 效果如图: 首页:有登录注册 先注册一个,然后登陆 登录,成功自动跳转到home页 home页:通过认证之后才可以进 代码部分: ...
- 一个小栗子聊聊JAVA泛型基础
背景 周五本该是愉快的,可是今天花了一个早上查问题,为什么要花一个早上?我把原因总结为两点: 日志信息严重丢失,茫茫代码毫无头绪. 对泛型的认识不够,导致代码出现了BUG. 第一个原因可以通过以后编码 ...
随机推荐
- nginx失效 nginx不起作用
nginx失效的原因 今天大晚上的,服务器更新了,重启了,然后我重新开一下后端,nginx. 奇了个怪,一直给我报404,而且不是nginx给我报的啊,就是普通的404,完全404了. 我看nginx ...
- Typecho博客服务器搬家换空间方法教程
Typecho 博客搬家方法步骤: 1.备份Typecho博客数据库,进入到phpmyadmin选择自己博客的数据表进行导出备份 2.使用FTP(或者登陆空间控制面板)把所有的Typecho文件下载到 ...
- Datagrip 破解
题记部分 方法一 [参考链接]:DataGrip 2023.2最新安装使用教程(附激活码,亲测好用)_糖果果爱分享的技术博客_51CTO博客 [软件版本]:datagrip-2023.3.4.win ...
- thinkphp或laravel连接sql server 2014数据库
问题描述:平时使用最多为mysql数据库,目前有项目数据库为sql server 2014,列出连接全过程 首先下载安装SQLserver的odbc开放数据库链连接,下载地址:https://lear ...
- PHP中&&与and、||与or的区别
https://blog.csdn.net/asty9000/article/details/80652064 在PHP中,&&与and都表示逻辑与,||与or都表示逻辑或,并且它们都 ...
- 【编程思想】C# delegate 委托的本质:方法对象的应用
一.前言 翻回之前写的博客,前期写的结构确实差很多, 这次细看了<委托那些事(一).(二)>,忍不住重新写一下,之前把简单的事情复杂化了. 为什么现在思维不一样了,有一点我认为是见识的计算 ...
- 绝了!k3s (k8s) 安装 ollama 运行 deepseek 全流程揭秘,yaml全公开
k3s (k8s) 环境搭建与 ollama 相关 yaml 文件部署 在容器编排的世界中,k3s (k8s) 无疑是备受瞩目的存在.此次聚焦在 k3s (k8s) 环境下安装 ollama,并实现运 ...
- MySQL查询建表规范
因为之前一直再查找一些比较好的数据库规范,以方便在开发时连接 MySQL 进行查询/建表的时候,能根据规范来执行,达到提高 查询速度 / 执行 SQL 的性能 和提升 MySQL 的整体性能, 这里主 ...
- 零经验选手,Compose 一天开发一款小游戏!
猛男翻卡牌 猛男启动 继上一个 Compose 练习项目 SimpleTodo 之后,又尝试用 Compose 来做了一个翻牌记忆游戏[猛男翻卡牌].这次是零经验写游戏项目,连原型都没有做设计,问了 ...
- gin Http请求Body和Header的获取 request post form Query header
gin Http请求Body和Header的获取 request post form Query header 请求参数 POST /post?id=1234&page=1 HTTP/1.1 ...