一个PyQt界面程序的优雅之路

有这样一个需求,把图中界面上每个控件显示的内容保存到字典中。

每个控件类都有一个获取展示内容的方法,所以,最直观的实现方案就是逐个控件取。

例如,策略名称(StrategyKey)属于QLineEdit类,用text方法获取展示内容,self.StrategyKey.text();账户(InvestorID)属于QComboBox类,用currentText方法获取展示内容,self.InvestorID.currentText()……

def save(self):    result = {}        # 策略名称    result['StrategyKey'] = self.StrategyKey.text()    # 账户    result['InvestorID'] = self.InvestorID.currentText()        # 买卖    direction = self.Direction.currentText()    if direction == '买':        result['Direction'] = '0'    elif direction == '卖':        result['Direction'] = '1'        # 优先平今    reusult['CloseTodayFirst'] = self.CloseTodayFirst.isChecked()        # 开平    offset_flag = self.OffsetFlag.currentText()    if offset_flag == "开":        result['OffsetFlag'] = '0'    elif offset_flag == "平":        result['OffsetFlag'] = '1'    elif offset_flag == "平今":        result['OffsetFlag'] = '3'    elif offset_flag == "平昨":        result['OffsetFlag'] = '4'        # 报价基准    benchmark_flag = self.BenchmarkFlag.currentText()    if benchmark_flag == "对手价":        result['BenchmarkFlag'] = '0'    elif benchmark_flag == "排队价":      result['BenchmarkFlag'] = '1'            # 交易所    result['ExchangeID'] = self.ExchangeID.currentText()    # 合约代码    result['InstrumentID'] = self.InstrumentID.currentText()    # 目标数量    result['TargetVolume'] = self.TargetVolume.value()    # 单次最大量    result['MaxOrderVolumeLimit'] = self.MaxOrderVolumeLimit.value()    # 开始时间    result['StartTime'] = self.StartTime.time().asString()    # 执行间隔    result['ExecuteGap'] = self.ExecuteGap.value()        return result

虽然这样实现是最简单的,但是当控件多且业务场景复杂时,会产生大量重复代码,也更容易出错。所以,不管从开发的角度还是维护的角度,这样写都不是最优的。

接下来,我们进行优化。

首先,买卖、开平、报单基准价这三个控件展示的是文本,而程序需要的是枚举值,它们之间存在一一对应关系。我们将展示值和枚举值对应关系存放在字典中,使用字典的查找功能就可以替代if……else……

# 买卖展示值 - 枚举值字典direction_text_flag_dict = {    '买':'0',    '卖':'1'}# 开平展示值 - 枚举值字典offsetflag_text_flag_dict = {    '开':'0',    '平':'1',    '平今':'3',    '平昨':'4'}# 报价基准展示值 - 枚举值字典benchmarkflag_text_flag_dict = {    '对手价':'0',    '排队价':'1'}# 买卖枚举值result['Direction'] = benchmarkflag_text_flag_dict.get(self.Direction.currentText(), '')# 开平枚举值result['OffsetFlag'] = benchmarkflag_text_flag_dict.get(self.OffsetFlag.currentText(), '')# 报价基准枚举值result['BenchmarkFlag'] = benchmarkflag_text_flag_dict.get(self.BenchmarkFlag.currentText(), '')

当对应关系发生变化时,也只需要修改字典中的对应关系。

当需要反向转换时,根据枚举值设置展示值,也可以轻松实现。

# 买卖枚举值 - 展示值字典direction_flag_text_dict = dict(zip(direction_text_flag_dict.values(), direction_text_flag_dict.keys()))# 开平枚举值 - 展示值字典offsetflag_flag_text_dict = dict(zip(offsetflag_text_flag_dict.values(), offsetflag_text_flag_dict.keys()))# 报价基准枚举值 - 展示值字典benchmarkflag_flag_text_dict = dict(zip(benchmarkflag_text_flag_dict.values(), benchmarkflag_text_flag_dict.keys()))# 买卖展示值direction_display = direction_flag_text_dict.get(item_dict['Direction'], '')# 开平展示值offsetflag_display = offsetflag_flag_text_dict.get(item_dict['OffsetFlag'], '')# 报价基准展示值benchmarkflag_display = benchmarkflag_flag_text_dict.get(item_dict['BenchmarkFlag'], '')

进一步,利用python语言的反射机制,我们就可以根据名称查找到关联控件实例,例如,getattr(self, 'StrategyKey')就是self.StrategyKey。这样我们就可以通过遍历控件名列表获得相关展示值,并存到字典中。

def from_display(widget, text_list, currenttext_list, value_list, time_list):    result = {}        # QLineEdit类控件展示值    for item in text_list:        result[item] = getattr(widget, item).text() if getattr(widget, item) else ''        # QComboBox类控件展示值    for item in currenttext_list:        result[item] = getattr(widget, item).currentText() if getattr(widget, item) else ''             # QComboBox类控件展示值    for item in value_list:        result[item] = getattr(widget, item).value() if getattr(widget, item) else 0            # QTimeEdit类控件展示值    for item in time_list:      result[item] = getattr(widget, item).time().asString() if getattr(widget, item) else ''            return resultdef save(self):    text_list = [        'StrategyKey',    ]    current_list = [        'InvestorID',        'ExchangeID',        'InstrumentID'    ]    value_list = [        'TargetVolume',        'MaxOrderVolumeLimit',        'ExecuteGap',    ]    time_list = [        'StartTime',    ]        reust = from_display(self, text_list, current_list, value_list, time_list)    result['Direction'] = direction_text_flag_dict.get(self.Direction.currentText(),'')    result['OffsetFlag'] = offsetflag_text_flag_dict.get(self.OffsetFlag.currentText(),'')    result['BenchmarkFlag'] = benchmarkflag_text_flag_dict.get(self.BenchmarkFlag.currentText(),'')

因为不同类控件获取展示值的方法不同,QLineEdit使用text方法,QComboBox使用currentText方法,QSpinBox使用value方法,所以理论上有几个控件,上述代码中的from_display函数就需要几个参数,还是不够简洁。

是否可以给不同的控件类增加一个相同的获取展示值的方法呢?当然可以。

QtWidgets.QLineEdit.getDisplay = lambda self: self.text()QtWidgets.QTimeEdit.getDisplay = lambda self: self.time().toString()QtWidgets.QCheckBox.getDisplay = lambda self: self.isChecked()QtWidgets.QSpinBox.getDisplay = lambda self: self.value()QtWidgets.QComboBox.getDisplay = lambda self: self.currentText()

通过以上定义,我们就给用到的几个控件类打了个补丁,增加一个getDisplay方法,用来获取展示值。

之前写的from_display函数就不需要区分具体的控件类了。

def from_display(widget, item_list):    result = {}        for item in item_list:        reuslt[item] = getattr(self, item).getDisplay()            return resultdef save(self):    item_list = [        'StrategyKey',        'InvestorID',        'ExchangeID',        'InstrumentID',        'TargetVolume',        'MaxOrderVolumeLimit',        'ExecuteGap',        'StartTime',        'CloseTodayFirst',    ]        reuslt = from_display(self, item_list)    result['Direction'] = benchmarkflag_text_flag_dict.get(self.Direction.currentText(), '')    result['OffsetFlag'] = benchmarkflag_text_flag_dict.get(self.OffsetFlag.currentText(), '')    result['BenchmarkFlag'] = benchmarkflag_text_flag_dict.get(self.BenchmarkFlag.currentText(), '')

优化之后,随着控件数量的增加,代码量不会显著增加。

通过上述过程总结下来的经验,将字典中的数值展示到控件上的需求就可以这样来实现了:

QtWidgets.QLineEdit.setDisplay = lambda self, value: self.setText(str(value))QtWidgets.QTimeEdit.setDisplay = lambda self, value: self.setTime(QtCore.QTime.fromString(value))QtWidgets.QCheckBox.setDisplay = lambda self, value: self.setChecked(value)QtWidgets.QSpinBox.setDisplay = lambda self, value: self.setValue(value)QtWidgets.QComboBox.setDisplay = lambda self, value: self.setCurrentText(str(value))def display(self, item_dict):    item_dict['Direction'] = direction_flag_text_dict.get(item_dict['Direction'], '')    item_dict['OffsetFlag'] = offsetflag_flag_text_dict.get(item_dict['OffsetFlag'], '')    item_dict['BenchmarkFlag'] = benchmarkflag_flag_text_dict.get(item_dict['BenchmarkFlag'], '')        for key, value in item_dict.items():        widget = getattr(self, key, None)        if widget and getattr(widget, 'setDisplay', None):            widget.setDisplay(value)
展开阅读全文

页面更新:2024-03-02

标签:开平   基准   控件   字典   优雅   界面   名称   买卖   代码   关系   程序   方法   内容

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号

Top