1. 鼠标双击隐藏/显示K线图表全部或部分副图的好处
K线图表通常有主图和多个副图组成,它是我们观察合约 K线和指标的工具。但有时往往因为要显示的指标副图太多,去观察效果受到太大的影响。我们可以通过关闭全部或者是一个富途的方式来让显示变得更为简洁和细致。最方便的方式是使用鼠标来进行操作,而很多市面上的第三方软件也多采用此方法。可是看看维恩派的 K线图表因为没有考虑用户使用时候的这个需求,想实现这个功能还是需要费一番心思的。
那么怎么做呢?初步设想是:
- 当用户用鼠标双击主图时,把所有的附图全部关闭;当用户再次双击主图时,把所有的富途再次显示出来。
- 当用户用鼠标双击其中一个副图时,将其余副图全部隐藏起来,当用户再次双击该副图时,再把之前隐藏的其余副图显示出来。
2. 具体的实现方法:
修改文件vnpy\chart\widget.py
2.1 扩展PlotItem使之可以捕获鼠标双击事件
在引用部分加入下面内容:
from typing import Callable # hxxjava add
PlotItem的扩展类MyPlotItem:
class MyPlotItem(pg.PlotItem):
"""
MyPlotItem:re-implement of PlotItem.
hxxjava add
"""
def __init__(self,name:str,on_mouseDblClicked:Callable=None,*args,**kwargs) -> None:
""" add name attribute and on_mouseDblClicked callback for PlotItem """
super().__init__(*args,**kwargs)
self.name = name
self.on_mouseDblClicked = on_mouseDblClicked
def mouseDoubleClickEvent(self, event: QtGui.QMouseEvent) -> None:
""" re-implement PlotItem's mouseDoubleClickEvent """
super().mouseDoubleClickEvent(event)
if self.on_mouseDblClicked:
self.on_mouseDblClicked(self)
2.2 修改 ChartWidget使之可以具有处理鼠标双击事件
为class ChartWidget添加下面的鼠标双击的下面的回调函数。需要说明的是这里有个约定:容纳主图的PlotItem名称必须为"candle",其他的名称认为是副图,无需纠结是不是太过特别订制了。
def on_mouseDblClicked(self,plot:pg.PlotItem):
"""
所有内含图表被双击的回调函数。 hxxjava add
"""
if plot.name == "candle":
# 选择所有副图
others = [pi for pi in self._plots.values() if pi.name != plot.name]
else:
# 选择其他副图
others = [pi for pi in self._plots.values() if pi.name not in [plot.name,'candle']]
# 求当前幅图的高度变化量
delta_h = 0
for pi in others:
delta_h += pi.height()*(1 if pi.isVisible() else -1)
plot.setFixedHeight(plot.height()+delta_h)
# 隐藏/显示未变双击的图表
for pi in others:
pi.setVisible(not pi.isVisible())
修改class ChartWidget的add_plot()函数,代码如下:
def add_plot(
self,
plot_name: str,
minimum_height: int = 80,
maximum_height: int = None,
hide_x_axis: bool = False
) -> None:
"""
Add plot area.
"""
# Create plot object
# plot: pg.PlotItem = pg.PlotItem(axisItems={'bottom': self._get_new_x_axis()})
plot: pg.PlotItem = MyPlotItem(axisItems={'bottom': self._get_new_x_axis()},name=plot_name,on_mouseDblClicked=self.on_mouseDblClicked)
plot.setMenuEnabled(False)
plot.setClipToView(True)
plot.hideAxis('left')
plot.showAxis('right')
plot.setDownsampling(mode='peak')
plot.setRange(xRange=(0, 1), yRange=(0, 1))
plot.hideButtons()
plot.setMinimumHeight(minimum_height)
if maximum_height:
plot.setMaximumHeight(maximum_height)
if hide_x_axis:
plot.hideAxis("bottom")
if not self._first_plot:
self._first_plot = plot
# Connect view change signal to update y range function
view: pg.ViewBox = plot.getViewBox()
view.sigXRangeChanged.connect(self._update_y_range)
view.setMouseEnabled(x=True, y=True) # hxxjava change,old---view.setMouseEnabled(x=True, y=False)
# Set right axis
right_axis: pg.AxisItem = plot.getAxis('right')
right_axis.setWidth(60)
right_axis.tickFont = NORMAL_FONT
# Connect x-axis link
if self._plots:
first_plot: pg.PlotItem = list(self._plots.values())[0]
plot.setXLink(first_plot)
# Store plot object in dict
self._plots[plot_name] = plot
# Add plot onto the layout
self._layout.nextRow()
self._layout.addItem(plot)
3. 实现的效果
完成了第2部分的代码后,您就可以使用ChartWidget像以往一样创建你的K线图表了。
3.1 一个较为复杂的、完整的K线图表窗口
3.2 双击主图后的K线图表窗口
3.3 双击其中一个副图后的K线图表窗口
双击其中的MACD副图后,K线图表窗口MACD副图会占据其他副图的显示区域,再次双击该MACD副图,K线图表窗口中的其他副图就再次显示出来了。
双击其中的的delta副图后,K线图表窗口delta副图会占据其他副图的显示区域,再次双击该delta副图,K线图表窗口中的其他副图就再次显示出来了。