You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyQt5条件触发样式表动态更新问题:%RETURN字体仅重启GUI才变色

解决PyQt5交易监控GUI中%RETURN组件字体颜色实时更新问题

问题根源

原代码仅通过定时器更新return_text的文本内容,但未在更新时根据收益值的正负动态修改样式表;同时定时器间隔设置为5毫秒过于频繁,会占用不必要的系统资源。此外TextUpdate类的方法中错误地将实例对象self覆盖为文件内容,属于不良编码习惯。

解决方案步骤

  1. 修复TextUpdate类的方法,避免覆盖实例对象self
  2. 创建统一的文本更新函数,在更新return_text时根据收益值判断并修改样式
  3. 调整定时器间隔为合理值(如1秒),减少资源消耗

修改后的完整代码

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QPlainTextEdit, QVBoxLayout, QWidget
from PyQt5.QtCore import QProcess
import subprocess
import sys
import datetime

current_time = datetime.datetime.now()
current_time = current_time.strftime('%Y-%m-%d %H:%M')

class TextUpdate():
    def watch_list(self):
        with open(r"C:\Users\Administrator\Desktop\stat_arb\gui\watchlist.txt", 'r') as f:
            content = f.read()
        return content

    def order_history(self):
        with open(r"C:\Users\Administrator\Desktop\stat_arb\gui\orderhistory.txt", 'r') as f:
            content = f.read()
        return content

    def return_value(self):
        with open(r"C:\Users\Administrator\Desktop\stat_arb\gui\return.txt", 'r') as f:
            content = f.read().strip()
        return content

    def net_value(self):
        with open(r"C:\Users\Administrator\Desktop\stat_arb\gui\netvalue.txt", 'r') as f:
            content = f.read()
        return content

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(915, 413)
        MainWindow.setStyleSheet(
        "background-color: rgb(42, 42 , 42)")

        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.p = None

        self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
        self.gridLayout.setObjectName("gridLayout")

        self.frame = QtWidgets.QFrame(self.centralwidget)
        self.frame.setStyleSheet(
        "background-color: rgb(42, 42 , 42)")
        self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame.setObjectName("frame")

        self.frame_2 = QtWidgets.QFrame(self.frame)
        self.frame_2.setGeometry(QtCore.QRect(20, 30, 411, 221))
        self.frame_2.setStyleSheet(
        "background-color: #202020;\n"
        "border-radius: 12px")
        self.frame_2.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame_2.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame_2.setObjectName("frame_2")

        self.watch_text = QtWidgets.QPlainTextEdit(self.frame_2)
        self.watch_text.setGeometry(QtCore.QRect(10, 40, 391, 121))
        self.watch_text.setMouseTracking(False)
        self.watch_text.setStyleSheet(
        "border:0;\n"
        "font-size: 11px;\n"
        "color: #9e9e9e")
        self.watch_text.setBackgroundVisible(False)
        self.watch_text.setObjectName("watch_text")

        self.watch_label = QtWidgets.QPlainTextEdit(self.frame_2)
        self.watch_label.setGeometry(QtCore.QRect(10, 10, 391, 31))
        self.watch_label.setStyleSheet(
        "border:0;\n"
        "font-size: 10px;\n"
        "font-weight: bold;\n"
        "color: #ffffff")
        self.watch_label.setObjectName("watch_label")

        self.start_button = QtWidgets.QPushButton(self.frame_2)
        self.start_button.setGeometry(QtCore.QRect(100, 180, 221, 28))
        self.start_button.setStyleSheet(
        "background-color: #61ac3e;\n"
        "border-radius: 8px;\n"
        "font-size: 10px;\n"
        "font-weight: bold;\n"
        "color: #ffffff")
        self.start_button.setObjectName("start_button")

        self.frame_3 = QtWidgets.QFrame(self.frame)
        self.frame_3.setGeometry(QtCore.QRect(20, 260, 411, 101))
        self.frame_3.setStyleSheet(
        "background-color: #202020;\n"
        "border-radius: 12px")
        self.frame_3.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame_3.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame_3.setObjectName("frame_3")

        self.output_text = QtWidgets.QPlainTextEdit(self.frame_3)
        self.output_text.setGeometry(QtCore.QRect(10, 40, 391, 51))
        self.output_text.setMouseTracking(False)
        self.output_text.setStyleSheet(
        "border:0;\n"
        "font-size: 11px;\n"
        "color: #9e9e9e;")
        self.output_text.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.output_text.setBackgroundVisible(False)
        self.output_text.setObjectName("output_text")

        self.output_label = QtWidgets.QPlainTextEdit(self.frame_3)
        self.output_label.setGeometry(QtCore.QRect(10, 10, 391, 31))
        self.output_label.setStyleSheet("border:0;\n"
        "font-size: 10px;\n"
        "font-weight: bold;\n"
        "color: #ffffff")
        self.output_label.setObjectName("output_label")

        self.frame_4 = QtWidgets.QFrame(self.frame)
        self.frame_4.setGeometry(QtCore.QRect(450, 140, 411, 221))
        self.frame_4.setStyleSheet(
        "background-color: #202020;\n"
        "border-radius: 12px")
        self.frame_4.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame_4.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame_4.setObjectName("frame_4")

        self.order_text = QtWidgets.QPlainTextEdit(self.frame_4)
        self.order_text.setGeometry(QtCore.QRect(10, 40, 391, 161))
        self.order_text.setMouseTracking(False)
        self.order_text.setStyleSheet(
        "border:0;\n"
        "font-size: 11px;\n"
        "color: #9e9e9e")
        self.order_text.setBackgroundVisible(False)
        self.order_text.setObjectName("order_text")

        self.order_label = QtWidgets.QPlainTextEdit(self.frame_4)
        self.order_label.setGeometry(QtCore.QRect(10, 10, 391, 31))
        self.order_label.setStyleSheet(
        "border:0;\n"
        "font-size: 10px;\n"
        "font-weight: bold;\n"
        "color: #ffffff")
        self.order_label.setObjectName("order_label")

        self.frame_5 = QtWidgets.QFrame(self.frame)
        self.frame_5.setGeometry(QtCore.QRect(450, 30, 411, 101))
        self.frame_5.setStyleSheet(
        "background-color: #202020;\n"
        "border-radius: 12px")
        self.frame_5.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.frame_5.setFrameShadow(QtWidgets.QFrame.Raised)
        self.frame_5.setObjectName("frame_5")

        self.nav_text = QtWidgets.QPlainTextEdit(self.frame_5)
        self.nav_text.setGeometry(QtCore.QRect(10, 40, 181, 41))
        self.nav_text.setMouseTracking(False)
        self.nav_text.setBackgroundVisible(False)
        self.nav_text.setObjectName("nav_text")
        self.nav_text.setStyleSheet(
        "border:0;\n"
        "font-size: 24px;\n"
        "color: #1a62dd")
        self.nav_label = QtWidgets.QPlainTextEdit(self.frame_5)
        self.nav_label.setGeometry(QtCore.QRect(10, 10, 181, 31))
        self.nav_label.setStyleSheet(
        "border:0;\n"
        "font-size: 10px;\n"
        "font-weight: bold;\n"
        "color: #ffffff")
        self.nav_label.setObjectName("nav_label")

        self.return_text = QtWidgets.QPlainTextEdit(self.frame_5)
        self.return_text.setGeometry(QtCore.QRect(210, 40, 181, 41))
        self.return_text.setMouseTracking(False)
        self.return_text.setBackgroundVisible(False)
        self.return_text.setObjectName("return_text")
        # 初始样式
        self.return_text.setStyleSheet(
        "border:0;\n"
        "font-size: 24px;\n"
        "color: #9e9e9e")

        self.return_label = QtWidgets.QPlainTextEdit(self.frame_5)
        self.return_label.setGeometry(QtCore.QRect(210, 10, 181, 31))
        self.return_label.setStyleSheet(
        "border:0;\n"
        "font-size: 10px;\n"
        "font-weight: bold;\n"
        "color: #ffffff")
        self.return_label.setObjectName("return_label")
        self.gridLayout.addWidget(self.frame, 0, 0, 1, 1)
        MainWindow.setCentralWidget(self.centralwidget)

        self.retranslateUi(MainWindow)
        self.timer = QtCore.QTimer()
        # 调整定时器间隔为1秒,避免资源浪费
        self.timer.start(1000)
        # 绑定统一的更新函数
        self.timer.timeout.connect(self.update_all_texts)
        self.start_button.pressed.connect(self.start_process)
        self.output_text.setReadOnly(True)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.watch_label.setPlainText(_translate("MainWindow", "   WATCHLIST"))
        self.start_button.setText(_translate("MainWindow", "START"))
        self.output_label.setPlainText(_translate("MainWindow", "   OUTPUT"))
        self.order_label.setPlainText(_translate("MainWindow", "   ORDER HISTORY"))
        self.nav_label.setPlainText(_translate("MainWindow", "   NET VALUE"))
        self.return_label.setPlainText(_translate("MainWindow", "   %RETURN"))

    def message(self, s):
        self.output_text.appendPlainText(s)

    def start_process(self):
        if self.p is None:
            self.message(f'[STATUS] {current_time} Initializing process...')
            self.p = QProcess()
            self.p.readyReadStandardOutput.connect(self.handle_stdout)
            self.p.readyReadStandardError.connect(self.handle_stderr)
            self.p.stateChanged.connect(self.handle_state)
            self.p.finished.connect(self.process_finished)
            self.p.start(r'C:\Users\Administrator\PycharmProjects\pythonProject\venv\Scripts\python.exe',
                         [r"C:\Users\Administrator\Desktop\stat_arb\31b_aug.py"])

    def handle_stderr(self):
        data = self.p.readAllStandardError()
        stderr = bytes(data).decode("utf8")
        self.message(stderr)

    def handle_stdout(self):
        data = self.p.readAllStandardOutput()
        stdout = bytes(data).decode("utf8")
        self.message(stdout)

    def handle_state(self, state):
        states = {
            QProcess.NotRunning: 'Not running...',
            QProcess.Starting: 'Starting...',
            QProcess.Running: 'Running...',
        }
        state_name = states[state]
        self.message(f'[STATUS] {current_time} {state_name}')

    def process_finished(self):
        self.message("Process finished.")
        self.p = None

    def update_all_texts(self):
        text_updater = TextUpdate()
        # 更新其他文本组件
        self.watch_text.setPlainText(text_updater.watch_list())
        self.order_text.setPlainText(text_updater.order_history())
        self.nav_text.setPlainText(text_updater.net_value())
        
        # 更新%RETURN文本并动态修改样式
        return_str = text_updater.return_value()
        self.return_text.setPlainText(return_str)
        
        # 判断收益值正负,修改字体颜色
        try:
            return_val = float(return_str.replace('%', ''))
            if return_val > 0:
                # 正收益设为绿色
                self.return_text.setStyleSheet(
                    "border:0;\n"
                    "font-size: 24px;\n"
                    "color: #61ac3e"
                )
            elif return_val < 0:
                # 负收益设为红色
                self.return_text.setStyleSheet(
                    "border:0;\n"
                    "font-size: 24px;\n"
                    "color: #ff4444"
                )
            else:
                # 零收益恢复默认灰色
                self.return_text.setStyleSheet(
                    "border:0;\n"
                    "font-size: 24px;\n"
                    "color: #9e9e9e"
                )
        except ValueError:
            # 无法转换为数值时保持默认样式
            self.return_text.setStyleSheet(
                "border:0;\n"
                "font-size: 24px;\n"
                "color: #9e9e9e"
            )

def get_termi_futu():
    subprocess.call("taskkill /F /IM FutuOpenD.exe")
    print('[DISCONNECTED]', current_time, ' Connection status. Trading account is disconnected.')

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    app.exec_()
    get_termi_futu()

关键修改说明

  1. 修复TextUpdate类:将方法中覆盖self的错误改为使用局部变量content,同时改用with语句管理文件,确保文件正确关闭。
  2. 统一更新函数:创建update_all_texts函数,替代多个lambda表达式,集中处理所有文本组件的更新逻辑,便于维护。
  3. 动态样式修改:在更新return_text时,尝试将文本转换为数值,根据正负设置不同的字体颜色(正收益绿色、负收益红色、零收益灰色),无法转换时保持默认样式。
  4. 调整定时器间隔:将原5毫秒的间隔改为1000毫秒(1秒),减少系统资源占用,同时满足实时更新需求。

内容的提问来源于stack exchange,提问作者ms mavie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 17:27:30