快捷搜索:  汽车  科技

pyqt编程入门教学(一个PyQt界面程序的优雅之路)

pyqt编程入门教学(一个PyQt界面程序的优雅之路)# 买卖枚举值 - 展示值字典 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_d

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

pyqt编程入门教学(一个PyQt界面程序的优雅之路)(1)

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

例如,策略名称(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 result def 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 result def 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)

猜您喜欢: