PyQt5实战——操作台打印重定向,主界面以及stacklayout使用(四)

news/2024/11/5 15:57:27 标签: qt, python

个人博客:苏三有春的博客
系类往期文章:
PyQt5实战——多脚本集合包,前言与环境配置(一)
PyQt5实战——多脚本集合包,UI以及工程布局(二)
PyQt5实战——多脚本集合包,程序入口QMainWindow(三)

PyQt主窗口框架设计(QWidget)

PrimeWindow.py的主要作用是绘制主窗口,在主窗口中:

  • 最左边是各种功能组件的入口,比如:翻译器,UTF-8转换,图像处理等。
  • 按下左边的按键,则会切换功能区,切换功能并非重新开一个窗口,而是切换中间部分,这里主要是采用stack的原理
  • 最右边是日志打印区,通过重定向的方法,把打印在操作台的内容打印到这个窗口上,这样方便开发人员debug

4.1 import部分

python">import Classes.TranslatorClass as TranslatorClass
import Classes.ConvertorClass as ConvertorClass
import Classes.AudioProcessClass as AudioProcessClass
import Classes.AudiocodecClass as AudiocodecClass
import Classes.AudioPlayerClass as AudioPlayerClass
import Classes.ImgProcessClass as ImgProcessClass
from component.btnStyle import *
from component.editStyle import *

这些引用均来自作者自己的代码,分别保存在Classes目录下和component目录下,从这些目录下import不同的类或方法供PrimeWindow调用。

Classes中的各种类,如TranslatorClass,保存着翻译功能的功能区UI结构:翻译按钮,翻译内容输入框以及翻译结果展示框等,以及各组件的摆放位置。

component中的各种方法,如btnStyle,该文件中有按钮按下的样式,按钮抬起的样式等,只需在点击按钮时调用该方法即可改变按钮样式。

4.2 重定向操作台输出

重定向操作台输出需要调用一些系统方法

python">        current_directory = os.getcwd() # 获取当前工作目录,并将其存储在current_directory中。
        self.original_stdout = sys.stdout # 将当前的标准输出(操作台)保存到self.original_stdout中,这样可以在将来恢复标准输出
        self.output_stream = io.StringIO() # 创建一个StringIO对象,这个对象像一个文件,可以在内存中操作字符串,之后的标准输入输出将写入这个对象
        sys.stdout = self.output_stream # 将标准输出重定向到刚才创建的StringIO对象self.output_stream。这样,所有通过print语句输出的信息都将储存在output_stream中,而不是打印到操作台
        self.timer = QTimer() # 创建一个定时器对象,用于定期触发某些事件
        self.timer.timeout.connect(self.updateOutput) # 将定时器的信号连接到self.updateOutput方法上,当定时器达到超时时间时则会调用该方法
        self.timer.start(1000) # 设置定时器的超时时间为1000ms即1s

以上实现的是:重定向操作台的输出,开启定时器,每1s后,将原本pirnt方法打印到操作台的字符串储存起来,并调用updateOutput方法

以下是代码逐行分析:

  • 获取当前工作目录,并将其存储在current_directory中
  • 将当前的标准输出(操作台)保存到self.original_stdout中,这样可以在将来恢复标准输出
  • 创建一个StringIO对象,这个对象像一个文件,可以在内存中操作字符串,之后的标准输入输出将写入这个对象
  • 将标准输出重定向到刚才创建的StringIO对象self.output_stream。这样,所有通过print语句输出的信息都将储存在output_stream中,而不是打印到操作台
  • 创建一个定时器对象,用于定期触发某些事件
  • 将定时器的信号连接到self.updateOutput方法上,当定时器达到超时时间时则会调用该方法
  • 设置定时器的超时时间为1000ms即1s

updateOutput方法:

python">    def updateOutput(self):
        output = self.output_stream.getvalue() # 从output_stream中获取字符串
        if output: # 如果其中有字符串的话
            cursor = self.consoleedit.textCursor() # 获取日志打印文本编辑控件的当前光标,方便在特定的位置插入文本
            cursor.movePosition(QTextCursor.End) # 将光标移动至结尾,以便现有文本插入新的输出内容
            cursor.insertText(output) # 将内容添加到日志打印文本编辑控件中
            self.consoleedit.setTextCursor(cursor) # 更新光标位置为刚刚移动的光标,这确保了后续的输入或操作将从正确的位置开始
            self.consoleedit.ensureCursorVisible() # 确保光标在文本编辑器中可见,特别是光标在底部时,防止用户无法看到最新的插入内容,尤其是文本框不够大时
            self.output_stream.truncate(0) # 清空output_stream中的内容,将其内容截断为0,使得下一轮输出时不会将之前的内容重复添加

通过这个方法,即可将打印的内容输出到日志打印区中。并每1秒就检查一次是否有新的内容需要输出

  • 因为是利用定时器每1秒检查一次是否有新的输出内容,所以输出并不是实时进行的,如你需要更精确的日志打印,则调小定时器的超时时间,但请注意,定时器的超时时间越短,定时器就会越频繁地调用updateOutput方法,即使什么新内容也没有。如果你需要做一些复杂且精密的操作,则可能需要考虑时间与空间开销的问题。

以下是代码逐行分析:

  • 从output_stream中获取字符串
  • 如果其中有字符串的话
  • 获取日志打印文本编辑控件的当前光标,方便在特定的位置插入文本
  • 将光标移动至结尾,以便现有文本插入新的输出内容
  • 将内容添加到日志打印文本编辑控件中
  • 更新光标位置为刚刚移动的光标,这确保了后续的输入或操作将从正确的位置开始
  • 确保光标在文本编辑器中可见,特别是光标在底部时,防止用户无法看到最新的插入内容,尤其是文本框不够大时
  • 清空output_stream中的内容,将其内容截断为0,使得下一轮输出时不会将之前的内容重复添加

4.3 stackLayout 切换功能

在PyQt中,QStackLayout是用于在同一位置上堆叠多个小组件的布局管理器,允许根据需要在它们之间进行切换,这对实现标签页或动态内容展示非常有用

python">    def create_stack(self):
        
        # create a stack layout
        self.stacklayout = QStackedLayout()
        convertor = ConvertorClass.Wconvertor()
        self.stacklayout.addWidget(convertor)
  • 创建stacklayout
  • 把功能UI实现的对象添加在stacklayout中
python">        # set the convertor buttons
        self.UTF8ConvertorBtn = QPushButton("UTF-8 转换") # 创建按钮对象
        btnReleaseStyleA(self.UTF8ConvertorBtn) # 修改按钮样式,该方法为作者创建,并非第三方库调用
        self.UTF8ConvertorBtn.clicked.connect(self.Cbtn_press_clicked) # 为按钮连接触发事件,该事件会切换stack
        # add the buttons to the layout
        self.btnlayout.addWidget(self.UTF8ConvertorBtn) # 将按钮添加到功能按钮区布局
        updateButtonStyle(self,self.UTF8ConvertorBtn) # 更新按钮样式,该方法为作者创建,并非第三方库调用

UTF8ConvertorBtn按钮连接上了Cbtn_press_clicked方法,表示当该按钮被按下时,则调用Cbtn_press_clicked方法。同时我对按钮的样式做了修改,使用方法btnReleaseStyleA,因为要对按钮做批量相同的修改,因此集成到一个方法中去调用是常见的编程思想。

python">  	def Cbtn_press_clicked(self):
        updateButtonStyle(self,self.UTF8ConvertorBtn) # 更新按钮样式,该方法为作者创建,非第三方库调用
        self.stacklayout.setCurrentIndex(0) # 将当前stack布局设置为第一个抽屉

setCurrentIndex方法的意思是,stacklayout所占据的这一片区域,可以随意切换成被它add了的widget,它就像一个抽屉一样,抽屉的大小固定,但是这个固定的大小所展示的内容是由你抽出第几层决定。就比如参数为0,则抽出的是第1个抽屉,这个抽屉是一个widget,这个widget可以套一个layout,其中放各种各样的组件。同理,参数为1,则表示抽出第2个抽屉,则stacklayout所占据的这一片区域就会切换成第2个抽屉的样子。

4.4 UI初始化

python">    def initUI(self):
        #---------------- create Layout we needed ----------------------------
        self.Mainlayout = QHBoxLayout() # 主窗口
        self.Primarylayout = QVBoxLayout() # 功能区布局
        self.btnlayout = QVBoxLayout() # 功能按钮区布局
        #---------------- create Layout we needed ----------------------------
        
        
        #---------------- there has more btn but unshowing -------------------
        # set the convertor buttons
        self.UTF8ConvertorBtn = QPushButton("UTF-8 转换") # 创建按钮对象
        btnReleaseStyleA(self.UTF8ConvertorBtn) # 修改按钮样式,该方法为作者创建,并非第三方库调用
        self.UTF8ConvertorBtn.clicked.connect(self.Cbtn_press_clicked) # 为按钮连接触发事件,该事件会切换stack
        # add the buttons to the layout
        self.btnlayout.addWidget(self.UTF8ConvertorBtn) # 将按钮添加到功能按钮区布局
        updateButtonStyle(self,self.UTF8ConvertorBtn) # 更新按钮样式,该方法为作者创建,并非第三方库调用
        #---------------- there has more btn but unshowing -------------------
        self.btnlayout.setAlignment(Qt.AlignTop) # 调整按钮区的各组件对齐方式为向上对齐,而非均匀分布
        
        
        #----------------- put the stack in function area --------------------
        widget = QWidget() # 创建一个widget,用于存放stack布局
        widget.setLayout(self.stacklayout) # 将stack布局放到widget中
        self.Primarylayout.addWidget(widget) # 将widget放到功能区布局中,至此stack在功能区中进行切换
        #----------------- put the stack in function area --------------------
        #---------------------- create log area ------------------------------
        self.Consolelayout = QVBoxLayout() # 创建日志区布局
        self.consoleedit = QTextEdit() # 创建日志编辑文本框
        self.consoleedit.setReadOnly(True) # 文本框设置为只读
        TextEditStyle(self.consoleedit) # 修改文本框样式, 该方法为作者创建,并非第三方库调用
        self.consoleedit.verticalScrollBar().setPageStep(100) # 修改滚动条步长
        self.Consolelayout.addWidget(self.consoleedit) # 添加文本框到日志区布局中
        #---------------------- create log area ------------------------------
        
        #------------------ put the layouts in main layout -------------------
        self.Mainlayout.addLayout(self.btnlayout,stretch=1) # 将按钮布局添加到主布局中
        self.Vline = QFrame(self) # 添加细线 将按钮区与功能区分隔开
        self.Vline.setFrameShape(QFrame.VLine) # 优化细线
        self.Vline.setFrameShadow(QFrame.Raised) # 使细线具有凸起的立体感
        self.Vline.setLineWidth(3) # 设置细线外部粗细
        self.Vline.setMidLineWidth(1) # 设置细线内部粗细
        self.Mainlayout.addWidget(self.Vline) # 将细线添加至主布局
        self.Mainlayout.addLayout(self.Primarylayout,stretch=4) # 将功能区添加至主布局中
        self.Mainlayout.addLayout(self.Consolelayout,stretch=2) # 将日志区添加至主布局中
        # add the layout to the window
        self.setLayout(self.Mainlayout) # 将主窗口的布局设置为主布局
        #------------------ put the layouts in main layout -------------------

4.5 结语

到目前为止,我们脚本工具集合包已经具备了初步的大致框架,三大区块已经被划分出来了,接下来的工作将重点放在要开发哪些功能,如何实现这些功能,以及这些功能的UI页面布局。这个系列将会持续更新,动手能力强的小伙伴可以根据路线自己实操一遍,后续我也会将完整代码开源带GitHub上(等系类差不多结束的时候),同时系列文章也会同步更新到我的个人博客中,如果本系列真的帮助到你,请关注本频道,并给我的CSDN 点赞收藏 QAQ,感激不尽!

如有任何疑问,欢迎CSDN私信我或发邮件到707973090@qq.com,在我看到时会第一时间回复!


http://www.niftyadmin.cn/n/5739649.html

相关文章

在区块链技术中,什么是权益证明(PoS)?

权益证明(Proof of Stake, PoS)是一种与工作量证明(Proof of Work, PoW)类似的共识机制,但它通过不同的方式来确保区块链网络的安全性和一致性。PoS的主要目标是解决PoW中存在的高能耗问题,并提高网络的扩展…

【Git】Merge本地和远程不在同一commit

1 前言 当本地仓库与远程仓库不在同一个commit上时,即本地仓库的提交历史与远程仓库的提交历史出现了分歧,但我们需要将本地分支merge到远程的主分支。这个情况是我们在团队协作共同开发一套代码时,经常遇到的问题。本文介绍我常用的操作步骤…

在分布式光伏电站如何进行电能质量的治理?

1.概述 随着全球对可再生能源需求的增加,分布式光伏电站的建设和发展迅速。然而,分布式光伏电站的运行过程中面临着一系列问题,比如导致企业关口计量点功率因数过低、谐波污染等。这些问题不仅影响光伏电站自身的运行效率,还会对…

安利一款开源企业级的报表系统SpringReport

SpringReport是一款企业级的报表系统,支持在线设计报表,并绑定动态数据源,无需写代码即可快速生成想要的报表,可以支持excel报表和word报表两种格式,同时还可以支持excel多人协同编辑,后续考虑实现大屏设计…

气象大模型学习笔记

1 003-2D卷积(nn.Conv2d)和3D卷积(nn.Conv3d)的介绍与对比 2 Python】nn.ConvTranspose1、2、3d()函数详解和示例 3 swin-transformer

vue3中使用vue-diff工具来比较数据差异

1.安装vue-diff npm i vue-diff 2.main.js中全局注册 import VueDiff from "vue-diff"; import "vue-diff/dist/index.css";app.use(VueDiff) 3.使用 <template><div class"contain-page"><el-scrollbar height"100vh&…

【递归】——五道经典链表与递归问题的深度解析

文章目录 面试题08.06.汉诺塔问题合并两个有序链表反转链表两两交换链表中的节点Pow(x,n) 面试题08.06.汉诺塔问题 解题思路&#xff1a; 我们可以使用递归的方法将问题分解为更小的子问题。 对于 n 个盘子&#xff0c;移动过程如下&#xff1a; 移动上 n-1 个盘子&#xff1a…

ES + SkyWalking + Spring Boot:日志分析与服务监控(三)

目录 一、搭建SkyWalking 1.1 版本选择 1.2 下载安装 1.3 配置启动 1.4 SkyWalking UI介绍 二、Springboot项目使用 2.1 Agent下载 2.2 Agent配置skywalking oap地址 2.3 IDEA配置Agent地址 2.4 生成的ES索引介绍 三、在kibana上查看日志 四、问题和解决 3.1 日志…