主界面的Tick显示在订阅数过多的情况下,刷新压力过大,严重会造成界面卡死。为了解决这个问题,做了分页刷新的功能。
把原来的tick显示改为tab显示,显示时只刷新当中选中的tab页。
talk is cheap, show code:
1、在vnpy->trader->ui->widget增加TabTickMonitor类,作为每个tab页的实际内容承载,其实主要就去掉了原TickMonitor的EventTick事件响应
class TabTickMonitor(BaseMonitor):
"""
Monitor for tick data.
"""
data_key = "vt_symbol"
sorting = True
headers = {
"symbol": {"display": "代码", "cell": BaseCell, "update": False},
"exchange": {"display": "交易所", "cell": EnumCell, "update": False},
"name": {"display": "名称", "cell": BaseCell, "update": True},
"last_price": {"display": "最新价", "cell": BaseCell, "update": True},
"volume": {"display": "成交量", "cell": BaseCell, "update": True},
"open_price": {"display": "开盘价", "cell": BaseCell, "update": True},
"high_price": {"display": "最高价", "cell": BaseCell, "update": True},
"low_price": {"display": "最低价", "cell": BaseCell, "update": True},
"bid_price_1": {"display": "买1价", "cell": BidCell, "update": True},
"bid_volume_1": {"display": "买1量", "cell": BidCell, "update": True},
"ask_price_1": {"display": "卖1价", "cell": AskCell, "update": True},
"ask_volume_1": {"display": "卖1量", "cell": AskCell, "update": True},
"datetime": {"display": "时间", "cell": TimeCell, "update": True},
"gateway_name": {"display": "接口", "cell": BaseCell, "update": False},
}
def __init__(self, main_engine: MainEngine, event_engine:EventEngine, tab_name:str):
super().__init__(main_engine, event_engine)
self.tab_name = tab_name
self.bind_tick_signal()
def bind_tick_signal(self):
self.signal.connect(self.process_event)
self.event_engine.register(self.event_type, self.signal.emit)
def update_tick_event(self, event):
self.signal.emit(event)
2、增加PortionTickMonitor作为Tab页控件,承载所有表格,同时作为tick事件的入口,选择当前的Tab页进行刷新。达到TAB_SYMBOL_COUNT指定的合约数量后自动添加新的tab页
class PortionTickMonitor(QtWidgets.QTabWidget):
"""
"""
signal: QtCore.pyqtSignal = QtCore.pyqtSignal(Event)
TAB_SYMBOL_COUNT = 20
def __init__(self, main_engine: MainEngine, event_engine: EventEngine):
super().__init__()
self.main_engine = main_engine
self.event_engine = event_engine
self.tab_widget_list: List[TabTickMonitor] = []
self.tab_widget_dict: Dict[str, TabTickMonitor] = {}
self.symbol_tab_map: Dict[str, TabTickMonitor] = {}
self.tab_symbol_count: Dict[TabTickMonitor, int] = defaultdict(int)
self.current_widget = None
self.register_event()
def register_event(self):
self.signal.connect(self.process_tick_event)
self.event_engine.register(EVENT_TICK, self.signal.emit)
self.currentChanged.connect(self.on_tab_changed)
def process_tick_event(self, event):
tick_data = event.data
tab_widget: TabTickMonitor = self.symbol_tab_map.get(tick_data.vt_symbol, None)
if not tab_widget:
new_tab = self.get_last_tab()
self.symbol_tab_map[tick_data.vt_symbol] = new_tab
self.tab_symbol_count[new_tab] += 1
new_tab.update_tick_event(event)
elif tab_widget == self.current_widget:
tab_widget.update_tick_event(event)
def get_last_tab(self):
if self.tab_widget_list:
last_widget = self.tab_widget_list[-1]
if self.tab_symbol_count[last_widget] < self.TAB_SYMBOL_COUNT:
return last_widget
else:
return self.get_new_tab()
else:
return self.get_new_tab()
def get_new_tab(self):
new_tab_name = f"{len(self.tab_widget_list)}"
new_tab = TabTickMonitor(self.main_engine, self.event_engine, new_tab_name)
self.tab_widget_list.append(new_tab)
self.addTab(new_tab, new_tab_name)
self.tab_widget_dict[new_tab_name] = new_tab
if len(self.tab_widget_list) == 1:
self.current_widget = new_tab
return new_tab
def on_tab_changed(self, i):
self.current_widget = self.tab_widget_list[i]
3、把vnpy->trader->ui->main_window下面初始化docker时的TickMonitor改为PortionTickMonitor即可
def init_dock(self) -> None:
""""""
tick_widget, tick_dock = self.create_dock(
PortionTickMonitor, "行情", QtCore.Qt.RightDockWidgetArea
)
4、其他的额外的import请自行添加
后记:这个只是实现了按顺序和数量分页,如果实现按品种或板块的分页,可以在这个框架的基础上自行修改