策略为王源代码扩展系列-主菜单-历史行情分时图增加行情回放工具条及实现回放功能

Published

G:\stock\TskingVS2019\src\Client\StkUI\View\HistoryRealTimeView.cpp

思路:

step 1.在主程序Main.cpp启动时创建行情回放工具条(实际为1个窗口程序)

step 2:在src\Client\StkUI\View\HistoryRealTimeView.cpp中添加对实现对播放工具条每个按钮点击事件的函数。

step 3:设计1个定时器对数据每隔3秒刷新,按钮事件控制定时器的刷新间隔

先备份数据,清空原数据。利用定时器中填入原始数据后,调用Invalidate()。视图就会更新。

 

第一部分 新增加一个工具条资源IDR_REPLAY ToolBar

第二部分 在主程序中创建\启用行情回放工具条(实际为1个窗口)

首先,要在主程序中把工具条创建出来

step 1:在MainFrm.cpp中添加对CPlayBackView.h类的引用

/*****custom extend 播放工具条**********/
	CToolBar	m_wndPlaybackBar;
	/************end********************/

step 2:创建行情播放工具条窗口

G:\stock\TskingVS2019\src\Client\StkUI\MainFrm.cpp

 

/*****custom extend 播放工具条**********/
BOOL CMainFrame::CreatePlaybackBar()
{
	if (!m_wndPlaybackBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
		| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC, CRect(0, 0, 0, 0), IDW_PERIODBAR)
		|| !m_wndPlaybackBar.LoadToolBar(IDR_REPLAY))
	{
		TRACE0("Failed to create periodbar\n");
		return FALSE;      // fail to create
	}
#if 0
	CString	strBarTitle;
	strBarTitle.LoadString(IDS_TITLE_PERIODBAR);
	m_wndPeriodBar.SetWindowText(strBarTitle);
#endif	
	return TRUE;
}

至此,在程序启动时,行情回放工具条已经准备好了。

第三部分 在历史行情分时图视图程序中添加对按钮事件的处理

首先定义消息

G:\stock\TskingVS2019\src\Client\StkUI\View\HistoryRealTimeView.h

/*************custom extend 工具条 by freema*******/
	afx_msg void OnPlaybackBegin();
	afx_msg void OnPlaybackEnd();
	afx_msg void OnPlaybackForward();

	afx_msg void OnPlaybackPause();
	afx_msg void OnPlaybackFastfw();
	afx_msg void OnPlaybackFastrev();
	afx_msg void OnPlaybackStop();
	/*************************************************/

然后,将按钮和消息一一对应

G:\stock\TskingVS2019\src\Client\StkUI\View\HistoryRealTimeView.cpp

/*************custom extend 行情回放播放工具条 by freema*******/
ON_COMMAND(ID_PLAYBACK_BEGIN, OnPlaybackBegin)
ON_COMMAND(ID_PLAYBACK_END, OnPlaybackEnd)
ON_COMMAND(ID_PLAYBACK_FORWARD, OnPlaybackForward)

ON_COMMAND(ID_PLAYBACK_PAUSE, OnPlaybackPause)
ON_COMMAND(ID_PLAYBACK_FASTFW, OnPlaybackFastfw)
ON_COMMAND(ID_PLAYBACK_FASTREV, OnPlaybackFastrev)
ON_COMMAND(ID_PLAYBACK_STOP, OnPlaybackStop)
/*****************************************/

 

最后,在HistoryRealTimeView.cpp中药实现各按钮的点击事件处理。

G:\stock\TskingVS2019\src\Client\StkUI\View\HistoryRealTimeView.cpp

/*************custom extend 工具条 by freema*******/


void CHistoryRealTimeView::OnPlaybackBegin()
{
	
}

void CHistoryRealTimeView::OnPlaybackEnd()
{

}

void CHistoryRealTimeView::OnPlaybackForward()
{

	
	m_realtime[0].m_nCurrentStartPos2 = 0;
	


}



void CHistoryRealTimeView::OnPlaybackPause()
{
	KillTimer(RTV_TIMER_REFRESHHISTORYREPLY);
}

void CHistoryRealTimeView::OnPlaybackFastfw()
{
	KillTimer(RTV_TIMER_REFRESHHISTORYREPLY);
	m_timer = m_timer - 500;
	if (m_timer <= 0)
		m_timer = 10;
	SetTimer(RTV_TIMER_REFRESHHISTORYREPLY, m_timer, NULL);
}



void CHistoryRealTimeView::OnPlaybackFastrev()
{
	KillTimer(RTV_TIMER_REFRESHHISTORYREPLY);
	m_timer = m_timer + 500;
	SetTimer(RTV_TIMER_REFRESHHISTORYREPLY, m_timer, NULL);
}

void CHistoryRealTimeView::OnPlaybackStop()
{

}
/*****/

 

第四部分 为回放视图添加功能

1.在主程中序添加支持键盘精灵

 src/Client/StkUI/MainFrm.cpp
@@ -1248,7 +1248,7 @@ BOOL CMainFrame::PreTranslateMessage(MSG* pMsg)
					|| pView->IsKindOf(RUNTIME_CLASS(CSListView))
					|| pView->IsKindOf(RUNTIME_CLASS(CBaseView))
					|| pView->IsKindOf(RUNTIME_CLASS(CSelectorView))
					|| pView->IsKindOf(RUNTIME_CLASS(CPlayBackView))))
					|| pView->IsKindOf(RUNTIME_CLASS(CPlayBackView)))) //add 添加对行情回放视图对键盘精灵的支持 by freeman
			{
				CRect	rect;
				GetClientRect(&rect);
@@ -1266,7 +1266,7 @@ BOOL CMainFrame::PreTranslateMessage(MSG* pMsg)
					|| pView->IsKindOf(RUNTIME_CLASS(CRealTimeView))
					|| pView->IsKindOf(RUNTIME_CLASS(CMultiSortView))
					|| pView->IsKindOf(RUNTIME_CLASS(CSListView))
					|| pView->IsKindOf(RUNTIME_CLASS(CPlayBackView))))
					|| pView->IsKindOf(RUNTIME_CLASS(CPlayBackView)))) //add 添加对行情回放视图对键盘精灵的支持 by freeman
				pView->SetFocus();
		}
	}

2.修改窗口里的标题提示文字

G:\stock\TskingVS2019\src\Client\StkUI\resource.h

ID值定义

/* *** extend 提示字符串 by freeman ****/
//行情回放
#define IDS_TITLE_REPLAYREALTIMEVIEW   46000
#define IDS_REPLAYEALTIME_TITLE        46001
//历史行情
#define IDS_TITLE_HISTORYREALTIMEVIEW   46010
#define IDS_HISTORYREALTIME_TITLE       46011

/**************************************/

 

提示字符串

/************custonm extend 字符串定义 by freeman***********************************/

STRINGTABLE
BEGIN
    IDS_TITLE_HISTORYREALTIMEVIEW  "历史行情"
	IDS_HISTORYREALTIME_TITLE "历史行情"

END

STRINGTABLE
BEGIN
    IDS_TITLE_REPLAYREALTIMEVIEW  "行情回放"
    IDS_REPLAYEALTIME_TITLE "行情回放"

END
/**********************************************************************************/

修改窗口标题提示

G:\stock\TskingVS2019\src\Client\StkUI\View\RePlayRealTimeView.cpp

LRESULT CRePlayRealTimeView::OnGetViewTitle(WPARAM wParam, LPARAM lParam)
{
	CString	strTitle;
	strTitle.LoadString(IDS_TITLE_REPLAYREALTIMEVIEW); //修改窗口标题

	lstrcpyn((LPTSTR)lParam, (LPCTSTR)strTitle, wParam);
	if ((int)wParam > strTitle.GetLength())
		wParam = strTitle.GetLength();
	return wParam;
}

修改行情回放分时图标题

G:\stock\TskingVS2019\src\Client\StkUI\View\RePlayRealTime.cpp

//实时行情画分时线:画价格和成交量 by freeman 2019/06/08
void CRePlayRealTime::DrawPriceVolume( CDC * pDC )
{
	DECLARE_COLOR_DEFINATION

	// Draw Time Axis String
	DrawDateAxis( pDC );

	// Draw Title
	CString	strTitle;
	pDC->SetTextColor( clrTitle );
	pDC->SetBkColor( clrBK );
	strTitle.LoadString(IDS_REPLAYEALTIME_TITLE); //修改行情回放分时图标题
	if( CRePlayRealTime::modePriceLine != m_nDrawMode )
		strTitle	= m_CurStock.GetStockCode();

第五部分 实现思路

G:\stock\TskingVS2019\src\Client\StkUI\View\HistoryRealTimeView.cpp

生成1个定时器

int CHistoryRealTimeView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	
	//行情回放定时器add by freeman
	m_timer = 1000;
	SetTimer(RTV_TIMER_REFRESHHISTORYREPLY, m_timer, NULL);

	return 0;
}

定定时器事件处理函数,

void CHistoryRealTimeView::OnTimer(UINT nIDEvent) 
{
	//行情回放
	if (RTV_TIMER_REFRESHHISTORYREPLY == nIDEvent && m_realtime[0].m_nCurrentStartPos2 >=0)
	{
		m_realtime[0].OnTimer();
	}


	//大单交易
	if(RTV_TIMER_REFRESHBIGTRADE == nIDEvent)
	{
		int	nDrawMode	=	m_realtime[0].GetDrawMode();
		int	nReportWhat	=	m_realtime[0].GetReportWhat();

		if(CHistoryRealTime::modeBigTradeDetail == nDrawMode)
			Invalidate();
		else if(CHistoryRealTime::modePriceLine == nDrawMode
			&& CHistoryRealTime::reportBigTrade == nReportWhat)
			m_realtime[0].DrawReportRegion(NULL);
	}

	//定时向行情服务器发起请求
	if(RTV_TIMER_REFRESH == nIDEvent)
	{
		SendRequestQuote(FALSE);
	}

	CView::OnTimer(nIDEvent);
}

1.定时器刷新

在定时器中修改数据后,调用Invalidate()后会发送消息,会调用ondraw()函数绘图。

G:\stock\TskingVS2019\src\Client\StkUI\View\HistoryRealTime.cpp

/***********custom extend by freeman*************************/

//用定时器填入股票信息
BOOL CHistoryRealTime::OnTimer()
{
	CStockInfo	info;
	info = m_CurStock.GetStockInfo();

	BOOL	bInv = FALSE;

	//未选择播放时,直接返回,不执行行情播放
	if (m_nCurrentStartPos2 == -1)
		return TRUE;

	if (m_nCurrentStartPos2 < 0)
		m_nCurrentStartPos2 = 0;


	//播放开始,先备份m_CurStock到m_CurStockBackup,然后将m_CurStock清0,分时线从头开始
	if (m_nCurrentStartPos2 == 0)
	{
		//计算买卖挂单变化
		CReport& aReport = m_CurStock.GetReport();
		aReport.CalBuySellVolumeChanged();

		//把数据作为备份存下来
		m_CurStockBackup = m_CurStock;




		m_CurStock.GetReport().RemoveAll();
		m_CurStock.GetMinute().RemoveAll();
		m_CurStock.GetOutline().RemoveAll();
	}

	//插入分钟线
	if (m_nCurrentStartPos2 < m_CurStockBackup.GetReport().GetSize())
	{
		//将m_CurStock2的成交明细填入 m_CurStock的stockInfo,用于右则显示
		//UpdateStockInfoByREPORT(m_CurStock.GetStockInfo(), &m_CurStock2.GetReport()[m_nCurrentStartPos2]);

		if (-1 != m_CurStock.GetReport().InsertReportSort(m_CurStockBackup.GetReport()[m_nCurrentStartPos2]))
		{
			//转换为分钟线插入
			MINUTE	minute;
			if (convert_REPORT_to_MINUTE(&(m_CurStockBackup.GetReport()[m_nCurrentStartPos2]), &minute))
				m_CurStock.GetMinute().InsertMinuteSort(minute);
			m_nCurrentStartPos = -1;


		}



		REPORT pReport = m_CurStockBackup.GetReport()[m_nCurrentStartPos2];






		info.m_fHigh = m_nCurrentStartPos2;

		// 成交买卖价量信息
		if (pReport.m_fLast > 1e-4)	info.m_fLast = pReport.m_fLast;
		info.m_fOpen = pReport.m_fOpen;
		info.m_fHigh = pReport.m_fHigh;
		info.m_fLow = pReport.m_fLow;
		info.m_fClose = pReport.m_fNew;
		info.m_fVolume = pReport.m_fVolume;
		info.m_fAmount = pReport.m_fAmount;

		info.m_fBuyPrice[0] = pReport.m_fBuyPrice[0];
		info.m_fBuyPrice[1] = pReport.m_fBuyPrice[1];
		info.m_fBuyPrice[2] = pReport.m_fBuyPrice[2];
		info.m_fBuyPrice[3] = pReport.m_fBuyPrice[3];
		info.m_fBuyPrice[4] = pReport.m_fBuyPrice[4];
		info.m_fBuyVolume[0] = pReport.m_fBuyVolume[0];
		info.m_fBuyVolume[1] = pReport.m_fBuyVolume[1];
		info.m_fBuyVolume[2] = pReport.m_fBuyVolume[2];
		info.m_fBuyVolume[3] = pReport.m_fBuyVolume[3];
		info.m_fBuyVolume[4] = pReport.m_fBuyVolume[4];
		info.m_fSellPrice[0] = pReport.m_fSellPrice[0];
		info.m_fSellPrice[1] = pReport.m_fSellPrice[1];
		info.m_fSellPrice[2] = pReport.m_fSellPrice[2];
		info.m_fSellPrice[3] = pReport.m_fSellPrice[3];
		info.m_fSellPrice[4] = pReport.m_fSellPrice[4];
		info.m_fSellVolume[0] = pReport.m_fSellVolume[0];
		info.m_fSellVolume[1] = pReport.m_fSellVolume[1];
		info.m_fSellVolume[2] = pReport.m_fSellVolume[2];
		info.m_fSellVolume[3] = pReport.m_fSellVolume[3];
		info.m_fSellVolume[4] = pReport.m_fSellVolume[4];

		//挂单变化信息复制到 stockinfo变量

		memcpy(info.m_fSellVolumeChanged, pReport.m_fSellVolumeChanged, sizeof(info.m_fSellVolumeChanged));
		memcpy(info.m_fBuyVolumeChanged, pReport.m_fBuyVolumeChanged, sizeof(info.m_fBuyVolumeChanged));

		m_CurStock.SetStockInfo(&info);//当前股票
		m_nCurrentStartPos2++;
	}

	bInv = TRUE;
	m_nCurrentStartPos = -1;


	//Invalidate的调用会触发对view中OnDraw函数的调用
	if (bInv && m_pParent && ::IsWindow(m_pParent->GetSafeHwnd()))
		m_pParent->Invalidate();

	return TRUE;
}

/************************************/