纯手工打造UART版资料清洗工具之 PySide2 GUI 大补帖 - Part B

从七月开始从零开始研究PySide2 GUI相关设计及程序如何撰写,已经有一段时间了,笔者深深有感,PySide 系列的水很深。

Let's GO ~~

  1. 如何把获取以下项目的文字

    • 下拉式选单
      self.ui.[opt].currentText()

    • LineEdit
      self.ui.[opt].text()

    • spinbox
      self.ui.[opt].text()

    [笔记]

    • 括号内是变数名称
  2. 下拉式选单的进阶应用, 选择选单中的任何项目,均得到不同的回应

以常见的UART (Serial Port)的连线设定为例

作法:

  1. 建立Parifc字典表
  2. 依照对应到的选项查表
  3. 回应查到的数值内容
Pari = {'None': "serial.PARITY_NONE", 'Even': "serial.PARITY_EVEN", 'Odd': "serial.PARITY_ODD",
             'Mark': "serial.PARITY_MARK", 'Space': "serial.PARITY_SPACE"}
fc = {"None": [False, False, False], "XON/ XOFF": [True, False, False], "RTS/CTS": [False, True, False],
                  "XON/ XOFF & RTS/CTS": [True, True, False],
                  "DTR/DSR": [False, False, True], "XON/ XOFF & DTR/DSR": [True, False, True]}
    def getdValue(self, whichDict, target):
        if debug:
            print(target, whichDict)
        for key, value in eval(whichDict).items():
            if key == target:
                return value

fxopt = ["'COM{0}'".format(self.ui.le_eqComID.text()),
        int(self.ui.spb_eqBaudRate.text()), int(self.ui.le_eqDatabit.text()),
        self.fn.getdictValue("pari", self.ui.cb_eqParity.currentText()),
        int(self.ui.le_eqStopbit.text()),
        float(self.ui.le_eqTimeout.text()) / 1000,
        self.getdValue("fc",
        self.ui.cb_eqFlowControl.currentText()),
        ]
  1. 新增文字到不同Textbox元件的另类用法,使用eval

作法:

  1. 笔者在function中传入textbox的变数名称,利用eval的特性移除双引号,再将之导入到变数中
  2. 指标移到最後面,简单的说就是新一行的开头
  3. 插入文字
 def out(self, edit, message):
        """(edit, msg) Write any message to any textbox.
            edit: any Textbox label , e.g txtbox_logs
            msg: any message
        """
        export = eval("self.ui.{0}".format(edit))
        export.moveCursor(QtGui.QTextCursor.End)
        export.insertPlainText("{0} {1}\r\n".format(self.fn.currDate(), message))
  1. 如何将UI及功能分开,防止UI被冻结

简单的说就是要使用thread 去切开使用

作法:

  1. 将要呈现在UI上的动作放在一个thread中
  2. 使用class 去做传入UI前的资料处理
  3. 使用slot及emit的方式将资料传出去 (类似Queue的原理)
from PySide2.QtWidgets import QApplication, QMainWindow, QMessageBox, QWidget, QCheckBox
from PySide2 import QtGui, QtCore
from PySide2.QtCore import QThread, Signal, QObject, QEvent, Qt
class MainWindow(QMainWindow):

    def __init__(self):
        super(MainWindow, self).__init__()
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        .....
        .....
    def runTasks(self):	
        self.Transmitter = from()
        self.thread1 = QThread()
        self.thread1.started.connect(self.Into.work)
        self.Transmitter.from.connect(self.from)
        self.Transmitter.finished.connect(self.Loop_finished)
        self.Transmitter.finished.connect(self.thread1.quit)
        self.Transmitter.finished.connect(self.Transmitter.deleteLater)
        self.thread1.finished.connect(self.thread1.deleteLater)
        self.Transmitter.moveToThread(self.thread1)
        self.thread1.start()        

    def from(self, values):
            self.ui.txtbox_tx.clear()
            self.ui.txtbox_tx.moveCursor(QtGui.QTextCursor.End)
            self.ui.txtbox_tx.insertPlainText(values + "\r\n")
            
    def Loop_finished(self):
        print("Into Loop: Offline")
        print("From Loop: Offline")
class from(QObject):
    finished = Signal()
    from = Signal(str)

    @QtCore.Slot()
    def __init__(self):
        super(Receiver, self).__init__()
        self.working = True
        self.checkTime = 0

    def work(self):
        answer = answer + 100
		while True:
			self.from.emit(autoAnswer)
			time.sleep(0.2)
			if answer > 2000:
			    break        
        self.finished.emit()
  1. 如何在UI中抓取Enter event

使用event handler 侦测键盘事件,但笔者想要做的是当某个区域被触发後键盘事件才会开始侦测。

会这麽设计的原因是,不想要UI一执行的时候就占用大量资源,反而是需要用的时候再启用相关功能就好了

未来在维护上也会相对简单许多

作法:

  1. 使用按钮触发一个事件後让Groupbox 启用
  2. 开始在输入视窗内侦测键盘按键,如果有出现Enter Key 就直接将输入的内容传入上方的文字视窗中
  3. 清除输入框的文字
  4. 点选Exit , 关闭Groupbox,停止侦测键盘事件

效果:

class MainWindow(QMainWindow):

    def __init__(self):
        ...
        ...
        self.ui.btn_conExit.clicked.connect(lambda: self.exitSingleMode())
        self.ui.btnSingle.clicked.connect(lambda: self.singleMode())

    def singleMode(self):
        self.ui.grpObj_SingleMode.setEnabled(True)
        self.ui.cmdline.installEventFilter(self)
        self.ui.btn_single.setEnabled(False)
        
    def exitSingleMode(self):
        self.ui.btn_single.setEnabled(True)
        self.ui.grpObj_SingleMode.setEnabled(False)
        self.ui.cmdline.removeEventFilter(self)

结论:
基本上笔者整理的资料,是以简单的template为主,很多详细说明是刻意没写出来的,因为笔者需要的很多未来可以使用到的范例。让未来的自己可以直接复制贴上再改点变数就可以直接套用的。或者是可以把这些范本直接写入code snippet中当作未来的参考


<<:  学习Python纪录Day11 - 开启文字档案与写入资料

>>:  Flutter基础介绍与实作-Day12 Nice to Meet you Widgets-范例实作

使用 MockK 做测试

接下来的测试将会需要用到 mocking 的 library ,在 Android 大家比较常用的是...

如何在 Angular 获取 URL 资讯

在实作里,很多时後我们会将一些必要资讯记录在网址上,直接在网址里就能得到我们要的讯息 不用再透过组件...

26.unity打字机(StartCoroutine)

实现打字机功能:字出现之间会有时差,让一个字接一个字出现。 回圈{ //画面texe += 清单[第...

Ruby on Rails Controller 是干嘛的

Controller 中⽂可翻译成「控制器」,顾名思义,就是⽤来控制流程⽤的。它可能需 要跟 Mod...

Vue出一个行事历 Calendar

前言: 此单元较为复杂,若元件观念较不熟悉的同学,请斟酌观看 这里会运用到props、emit、ES...