我接触的绘制有两种:gdi+和qt绘图。可以灵活的绘制任何想要的东西。

先上效果图吧。

如下:基于gdi+的股指和股票的绘制。上面是沪深成分股实时生成的股票指数走势,下面是IF主力走势和开平仓位置。

如下,基于qt绘图的期货数据显示,模仿的博易大师。

现在贴上代码:

1、gdi+

#pragma once

#include <comdef.h>
#include <GdiPlus.h>
#include <Windows.h>
#include <map>
#include <list>
#include <vector>
#include <thread>
#include "my_protocol_struct.h"
using namespace Gdiplus;
using namespace std; #pragma comment(lib, "gdiplus.lib") // 其他指标信息容器
int iColorArr[]; struct OtherInfo
{
char pName[MAX_PATH];
Color color;
int penStyle;
double dBound;
bool bShow;
list<double>* listInfo; // 其他辅助信息 OtherInfo()
{
penStyle = ;
dBound = 1.5f;
pName[] = ;
color = iColorArr[];
bShow = true;
listInfo = NULL;
}
}; // 选中后需要显示的其他信息
struct OtherShowInfo
{
char pName[MAX_PATH];
double dValue;
Color color;
}; class DrawModule
{
public:
DrawModule();
~DrawModule(); private:
RECT m_rc;
unsigned int m_nOffset; //Gdi初始化变量
GdiplusStartupInput m_Gdistart;
ULONG_PTR m_GdiplusToken; //透明度
BYTE m_Transparency;
// 画布
Bitmap *bitmap_background;
Bitmap *bitmap_kline_index;
Bitmap *bitmap_user_show_info; //双缓存绘图
Gdiplus::Graphics *drawObj; // 当前屏幕上的最大最小值
double m_dMax;
double m_dMin; int nIntervalTime;
int RIGHT_SPACE;
bool bOtherGreen; int m_minCycle;
int m_maxCycle;
SIndexData m_pankou; int m_nSelectKlineDate;
int m_nSelectKlineTime; HANDLE m_hEvent;
bool m_bThread;
shared_ptr<thread> m_thdDraw; public:
// 显示十字光标
int m_nShowCursel;
bool m_bSetOther; private:
list<Skline>* m_pListKline;
list<Skline>* m_pCompareListKline;
vector<OtherInfo> m_vecOtherInfo;
vector<STradeData>* m_vecTradeData;
//vector<OpenDot> m_vecOpenDot; private:
// 绘制背景色等
bool PreDrawInfo(); // 绘制坐标线
void DrawBackGround(); // 绘制数字
void DrawNumber(); // 绘制K线
void DrawKLine(bool bDrawAll = true); // 局部重绘
void DoDrawAll(); // 数据转点
Point DataToPoint(double dValue,int nCount,double dCurMin,double dUnit); void DrawOther(bool bDrawAll = true); bool IsSameCycle(int nTime, int nKlineTime); void ThreadDraw(); public:
// 初始化传入控件句柄
void IniDrawModule(HWND hWnd); //是否半透明
void SetTransparency(BYTE b); // 塞入想要绘制的信息
// K线 其他信息 NULL结尾
void SetInfoToDraw(list<Skline>* pList); //
void SetCompareKline(list<Skline>* pList); // 清空指标容器
void ClearOther(); // 塞入指标
void SetOtherInfo(OtherInfo& pInfo); // 盘口数据
void SetPankou(SIndexData& data); // 设置开平仓点
void SetTradeDot(vector<STradeData>* p); // 设置其他的绿柱颜色
void SetOtherGreenColor(); // 设置纵向周期 秒数
void SetCrossCycle(int min_cycle, int max_cycle); // 放大缩小重置间距
void DefaultResetInterval(bool bAdd); // 左移和右移重置偏移量
void DefaultResetOffset(bool bLeft); // 需要显示的信息
bool InfoToShow(unsigned int nX, unsigned int nY); // 获取点击的k线
Skline* GetSelectKline(unsigned int nX); // 左移和右移重置偏移量
void PercentResetOffset(unsigned int nPercent); // 执行绘制
void DoDraw(); //开始线程
void Start(); // 结束绘制
void Stop(); };
// GDIPLUS4KLINE.cpp : 定义 DLL 应用程序的导出函数。
// #include "stdafx.h"
#include "GDIPLUS4KLINE.h"
#include <Windows.h> #define TOP_INFO_SPACE 30 int iColorArr[] = {Color::Yellow,Color::Brown,Color::DarkGoldenrod,Color::Magenta,Color::Blue,Color::Purple,Color::White,
Color::DarkOrange,Color::DarkRed,Color::DarkMagenta,Color::DarkGray,Color::DarkBlue,Color::Gray,
Color::LightPink,Color::LightSalmon,Color::LightYellow,Color::LightGray,Color::LightSkyBlue,Color::LightSeaGreen};
int iInterval[] = {,,,,,,,,,,,};
int iSpace[] = {,,,,,,,, , , , }; static int to_second(int time)
{
int nHour = time / ;
int nMini = time / - nHour * ;
int nSec = time - nHour * - nMini * ;
return nHour * * + nMini * + nSec;
} DrawModule::DrawModule()
{
nIntervalTime = ;
m_nOffset = ;
m_pListKline = NULL; m_dMax = DBL_MIN;
m_dMin = DBL_MAX; bitmap_background = NULL;
bitmap_kline_index = NULL;
bitmap_user_show_info = NULL; drawObj = NULL; m_nShowCursel = ;
bOtherGreen = false;
m_Transparency = ;
RIGHT_SPACE = ; m_minCycle = ;
m_maxCycle = ;
m_nSelectKlineDate = ;
m_nSelectKlineTime = ;
GdiplusStartup(&m_GdiplusToken,& m_Gdistart,NULL);
m_vecTradeData = nullptr;
m_pCompareListKline = nullptr;
m_pankou = { };
m_bThread = true;
m_bSetOther = false;
m_thdDraw = nullptr;
m_hEvent = ::CreateEvent(nullptr, false, false, nullptr);
} DrawModule::~DrawModule()
{
GdiplusShutdown(m_GdiplusToken);
} void DrawModule::IniDrawModule(HWND hWnd)
{
if (!drawObj)
{
drawObj = new Graphics(hWnd);
}
else
{
delete drawObj;
drawObj = new Graphics(hWnd);
} if (bitmap_user_show_info!=NULL) { delete bitmap_user_show_info; }
bitmap_user_show_info = new Bitmap(m_rc.right-m_rc.left,m_rc.bottom-m_rc.top); GetClientRect(hWnd,&m_rc);
DrawBackGround();
if (RIGHT_SPACE != )
RIGHT_SPACE = ;
} void DrawModule::SetTransparency(BYTE b)
{
m_Transparency = b;
DrawBackGround();
} void DrawModule::DrawBackGround()
{
if (bitmap_background!=NULL) { delete bitmap_background; }
bitmap_background = new Bitmap(m_rc.right-m_rc.left, m_rc.bottom-m_rc.top);
Graphics graphics_temp(bitmap_background); if (m_Transparency != )
{
SolidBrush blackBrush_clear(Color(, , ));
graphics_temp.FillRectangle(&blackBrush_clear, , , m_rc.right - m_rc.left, m_rc.bottom - m_rc.top);
}
SolidBrush blackBrush(Color(m_Transparency, , , ));
graphics_temp.FillRectangle(&blackBrush,,,m_rc.right-m_rc.left,m_rc.bottom-m_rc.top); /*if (m_Transparency != 255)
return;*/ // 2、坐标线
Pen redPen_Solid(Color(,,),0.3f); // 实线画笔
redPen_Solid.SetDashStyle(DashStyleSolid); Pen redPen_Dash(Color(,,),0.3f); // 虚线画笔
redPen_Dash.SetDashStyle(DashStyleDash); graphics_temp.DrawLine(&redPen_Solid,
m_rc.right-m_rc.left-RIGHT_SPACE, ,
m_rc.right-m_rc.left-RIGHT_SPACE, m_rc.bottom-m_rc.top-TOP_INFO_SPACE);//右数据轴 | // 3、虚线
for (unsigned int i=;i<=;i++)
{
graphics_temp.DrawLine(&redPen_Dash,
, (m_rc.bottom-m_rc.top-TOP_INFO_SPACE)/*i+TOP_INFO_SPACE,
m_rc.right-m_rc.left-RIGHT_SPACE, (m_rc.bottom-m_rc.top-TOP_INFO_SPACE)/*i+TOP_INFO_SPACE);
}
} void DrawModule::SetInfoToDraw(list<Skline>* pList)
{
m_pListKline = pList;
} void DrawModule::SetCompareKline(list<Skline>* pList)
{
m_pCompareListKline = pList;
} void DrawModule::ClearOther()
{
m_vecOtherInfo.clear();
} void DrawModule::SetOtherInfo(OtherInfo& pInfo)
{
m_vecOtherInfo.push_back(pInfo);
} void DrawModule::SetPankou(SIndexData& data)
{
m_pankou = data;
} void DrawModule::SetTradeDot(vector<STradeData>* p)
{
m_vecTradeData = p;
} void DrawModule::SetOtherGreenColor()
{
bOtherGreen = true;
} void DrawModule::SetCrossCycle(int min_cycle, int max_cycle)
{
m_minCycle = min_cycle;
m_maxCycle = max_cycle;
} void DrawModule::DefaultResetInterval(bool bAdd)
{
if (nIntervalTime> && nIntervalTime<)
{
if (bAdd) ++nIntervalTime;
else --nIntervalTime;
}else if (nIntervalTime== && bAdd)
{
++nIntervalTime;
}else if (nIntervalTime== && !bAdd)
{
--nIntervalTime;
}
else
return; DoDraw();
} void DrawModule::DefaultResetOffset(bool bLeft)
{
if (m_pListKline==NULL)
{
return;
}
unsigned int oldOffset = m_nOffset;
int nShowCount = (m_rc.right-m_rc.left-RIGHT_SPACE)/(iInterval[nIntervalTime]+*iSpace[nIntervalTime]);
int nListCount = m_pListKline->size(); if (nListCount <= nShowCount)
{
m_nOffset = ;
}
else
{
if (bLeft)
{
int nCanOffset = nListCount - m_nOffset - nShowCount;
if (nCanOffset > )
{
m_nOffset++;
}
}
else if(m_nOffset >)
{
m_nOffset--;
}
}
if (m_nOffset!=oldOffset)
{
DoDraw();
}
} void DrawModule::PercentResetOffset(unsigned int nPercent)
{
if (nPercent> || m_pListKline==NULL)
{
return;
}
int nShowCount = (m_rc.right-m_rc.left-RIGHT_SPACE)/(iInterval[nIntervalTime]+*iSpace[nIntervalTime]);
int nListCount = m_pListKline->size();
int oldOffset = m_nOffset;
int nOffset = (-nPercent)*nListCount/; if ((nOffset+nShowCount)>nListCount)
{
m_nOffset = nListCount - nShowCount;
}
else
{
m_nOffset = nOffset;
}
if (m_nOffset!=nOffset)
{
DoDraw();
}
} bool DrawModule::PreDrawInfo()
{
if (m_pListKline == NULL)
{
return false;
} int nKlineCount = m_pListKline->size(); list<Skline>::reverse_iterator rIter = m_pListKline->rbegin();
if (rIter != m_pListKline->rend() && m_nOffset)
{// 指针偏移
int nCount = ;
while (nCount<m_nOffset)
{
rIter++;
nCount++;
}
} double dMax = -1.79769313486231570E+308,dMin = DBL_MAX;
int nMaxShow = (m_rc.right-m_rc.left-RIGHT_SPACE)/(iInterval[nIntervalTime]+*iSpace[nIntervalTime]);
while (rIter != m_pListKline->rend() && nMaxShow)
{// 取频幕上最大最小值
if (dMax<rIter->dHigh)
{
dMax = rIter->dHigh;
}
if (dMin>rIter->dLow)
{
dMin = rIter->dLow;
}
rIter++;
nMaxShow--;
} for (unsigned int i = ; i < m_vecOtherInfo.size(); i++)
{
if (m_vecOtherInfo[i].bShow)
{
list<double>::reverse_iterator rOtherIter = m_vecOtherInfo[i].listInfo->rbegin();
if (rOtherIter != m_vecOtherInfo[i].listInfo->rend() && m_nOffset)
{// 指标偏移
int nCount = ;
while (nCount < m_nOffset && rOtherIter != m_vecOtherInfo[i].listInfo->rend())
{
rOtherIter++;
nCount++;
}
} nMaxShow = (m_rc.right - m_rc.left - RIGHT_SPACE) / (iInterval[nIntervalTime] + * iSpace[nIntervalTime]);
while (rOtherIter != m_vecOtherInfo[i].listInfo->rend() && nMaxShow)
{
if (dMax < *rOtherIter)
{
dMax = *rOtherIter;
}
if (dMin > *rOtherIter)
{
dMin = *rOtherIter;
}
rOtherIter++;
nMaxShow--;
}
}
}
m_dMax = dMax;
m_dMin = dMin;
return true;
} void DrawModule::DrawNumber()
{
double dUnit = (m_dMax - m_dMin)/(m_rc.bottom-m_rc.top-TOP_INFO_SPACE)/0.9; // 数据轴单位
double dCurMin = m_dMin - 0.05*(m_rc.bottom-m_rc.top-TOP_INFO_SPACE)*dUnit; // 数据轴最小值 //if (m_Transparency != 255)
// return; FontFamily fontFamily(L"楷体");
Gdiplus::Font font(&fontFamily, , FontStyleRegular, UnitPixel);
StringFormat stringformat;
stringformat.SetAlignment(StringAlignmentNear);
stringformat.SetLineAlignment(StringAlignmentCenter); if (bitmap_kline_index!=NULL) { delete bitmap_kline_index; }
bitmap_kline_index = new Bitmap(m_rc.right-m_rc.left, m_rc.bottom-m_rc.top);
Graphics graphics_kline_index(bitmap_kline_index);
graphics_kline_index.SetTextRenderingHint(TextRenderingHintAntiAlias); char szValue[];
wchar_t wcstring[];
SolidBrush red_brush(Color(,,));
for (unsigned int i=;i<=;i++)
{
int nHorien = (m_rc.bottom-m_rc.top-TOP_INFO_SPACE)/*(-i)+TOP_INFO_SPACE; _snprintf_s(szValue,,"%.2f",dCurMin+dUnit*(m_rc.bottom-m_rc.top-TOP_INFO_SPACE)/*i);
MultiByteToWideChar(CP_ACP,,szValue,,wcstring,);
graphics_kline_index.DrawString(wcstring,wcslen(wcstring),&font,
RectF(m_rc.right-m_rc.left-RIGHT_SPACE+,nHorien-,RIGHT_SPACE-,),&stringformat,&red_brush);
} if (m_pankou.ask_volume != && m_pankou.bid_volume != ) {
SolidBrush white_brush(Color(, , ));
Point pt_new = DataToPoint(m_pankou.index_tick, , dCurMin, dUnit);
SolidBrush RedBrush(Color(, , ));
graphics_kline_index.FillRectangle(&RedBrush, m_rc.right - m_rc.left - RIGHT_SPACE, pt_new.Y - , , ); _snprintf_s(szValue, , "%.2f", m_pankou.ask_price);
MultiByteToWideChar(CP_ACP, , szValue, , wcstring, );
graphics_kline_index.DrawString(wcstring, wcslen(wcstring), &font,
RectF(m_rc.right - m_rc.left - RIGHT_SPACE, pt_new.Y - , strlen(szValue) * + , TOP_INFO_SPACE / ), &stringformat, &white_brush); _snprintf_s(szValue, , "%.2f", m_pankou.bid_price);
MultiByteToWideChar(CP_ACP, , szValue, , wcstring, );
graphics_kline_index.DrawString(wcstring, wcslen(wcstring), &font,
RectF(m_rc.right - m_rc.left - RIGHT_SPACE, pt_new.Y , strlen(szValue) * + , TOP_INFO_SPACE / ), &stringformat, &white_brush);
}
} bool DrawModule::InfoToShow(unsigned int nX, unsigned int nY)
{
if (nX>=(m_rc.right-m_rc.left-RIGHT_SPACE) || m_pListKline==NULL)
{
return false;
} int nScreenOffset = (m_rc.right-m_rc.left - nX - RIGHT_SPACE)/(iInterval[nIntervalTime]+*iSpace[nIntervalTime]); // 屏幕偏移
int nScreenCount = nScreenOffset;
nScreenOffset += m_nOffset; // 容器偏移
list<Skline>::reverse_iterator rIter = m_pListKline->rbegin();
while(rIter != m_pListKline->rend() && nScreenOffset>)
{
nScreenOffset--;
rIter++;
} if (rIter == m_pListKline->rend())
{
return false;
} if (nY<TOP_INFO_SPACE)
{
return false;
} vector<OtherShowInfo> vecOther;
vector<OtherInfo>::iterator iterOther = m_vecOtherInfo.begin();
while (iterOther != m_vecOtherInfo.end())
{
nScreenOffset = (m_rc.right - m_rc.left - nX - RIGHT_SPACE) / (iInterval[nIntervalTime] + * iSpace[nIntervalTime]) + m_nOffset;
list<double>::reverse_iterator subrIterOther = iterOther->listInfo->rbegin();
while (subrIterOther != iterOther->listInfo->rend() && nScreenOffset)
{
nScreenOffset--;
subrIterOther++;
}
if (subrIterOther != iterOther->listInfo->rend())
{
OtherShowInfo osi;
strcpy_s(osi.pName, iterOther->pName);
osi.dValue = *subrIterOther;
osi.color = iterOther->color;
vecOther.push_back(osi);
}
iterOther++;
} Skline& m_lastKline = *rIter;
if (bitmap_user_show_info!=NULL) { delete bitmap_user_show_info; }
bitmap_user_show_info = new Bitmap(m_rc.right-m_rc.left,m_rc.bottom-m_rc.top); Graphics graphics_user_show_info(bitmap_user_show_info);
graphics_user_show_info.DrawImage(bitmap_background,,,bitmap_background->GetWidth(),bitmap_background->GetHeight());
graphics_user_show_info.DrawImage(bitmap_kline_index,,,bitmap_kline_index->GetWidth(),bitmap_kline_index->GetHeight()); int y = ; FontFamily fontFamily(L"楷体");
Gdiplus::Font font(&fontFamily, , FontStyleRegular, UnitPixel);
StringFormat stringformat;
stringformat.SetAlignment(StringAlignmentNear);
stringformat.SetLineAlignment(StringAlignmentCenter);
graphics_user_show_info.SetTextRenderingHint(TextRenderingHintAntiAlias); char szValue[];
wchar_t wcstring[];
_snprintf_s(szValue,,"%d,%d,开:%.2f,高:%.2f,低:%.2f,收:%.2f,成交量:%d,持仓量:%d;",
m_lastKline.nDate,m_lastKline.nTime,
m_lastKline.dOpen,m_lastKline.dHigh,m_lastKline.dLow,m_lastKline.dClose,
m_lastKline.nVolume,m_lastKline.dInterest); MultiByteToWideChar(CP_ACP,,szValue,,wcstring,);
SolidBrush white_brush(Color(,,));
graphics_user_show_info.DrawString(wcstring,wcslen(wcstring),&font,
RectF(,y,strlen(szValue)*,TOP_INFO_SPACE/-),&stringformat,&white_brush); y = TOP_INFO_SPACE / + ;
int x = ;
for (int i = ; i < vecOther.size(); i++)
{
SolidBrush the_brush(vecOther[i].color);
_snprintf_s(szValue, , "%s:%.2f;", vecOther[i].pName, vecOther[i].dValue);
MultiByteToWideChar(CP_ACP, , szValue, , wcstring, );
graphics_user_show_info.DrawString(wcstring, wcslen(wcstring), &font,
RectF(x, y, strlen(szValue) * , TOP_INFO_SPACE / - ), &stringformat, &the_brush);
x += strlen(szValue) * ;
} if (m_nShowCursel > )
{
Pen WhitePen(Color(,,),1.0f);
// 横、纵、数字
if (m_nShowCursel > )
{
double dUnit = (m_dMax - m_dMin) / (m_rc.bottom - m_rc.top - TOP_INFO_SPACE) / 0.9;
double dCurMin = m_dMin - 0.05*(m_rc.bottom - m_rc.top - TOP_INFO_SPACE)*dUnit; // 数据轴最小值
Point ptLeft; ptLeft.X = ; ptLeft.Y = nY;
Point ptRight; ptRight.X = m_rc.right - m_rc.left - RIGHT_SPACE; ptRight.Y = nY;
graphics_user_show_info.DrawLine(&WhitePen, ptLeft, ptRight); SolidBrush RedBrush(Color(, , ));
graphics_user_show_info.FillRectangle(&RedBrush, m_rc.right - m_rc.left - RIGHT_SPACE, nY - , , ); _snprintf_s(szValue, , "%.2f", (m_rc.bottom - m_rc.top - nY)*dUnit + dCurMin);
MultiByteToWideChar(CP_ACP, , szValue, , wcstring, );
graphics_user_show_info.DrawString(wcstring, wcslen(wcstring), &font,
RectF(m_rc.right - m_rc.left - RIGHT_SPACE, nY - , strlen(szValue) * + , TOP_INFO_SPACE / ), &stringformat, &white_brush);
} int nKlineX = m_rc.right-m_rc.left-RIGHT_SPACE - nScreenCount*(iInterval[nIntervalTime]+iSpace[nIntervalTime]*) - iInterval[nIntervalTime]/ - iSpace[nIntervalTime];
Point ptTop; ptTop.X = nKlineX;ptTop.Y = TOP_INFO_SPACE;
Point ptBottom; ptBottom.X = nKlineX; ptBottom.Y = m_rc.bottom-m_rc.top;
graphics_user_show_info.DrawLine(&WhitePen, ptTop, ptBottom);
} drawObj->DrawImage(bitmap_user_show_info,,,bitmap_user_show_info->GetWidth(),bitmap_user_show_info->GetHeight());
return true;
} Skline* DrawModule::GetSelectKline(unsigned int nX)
{
if (nX >= (m_rc.right - m_rc.left - RIGHT_SPACE) || m_pListKline == NULL)
{
return nullptr;
} int nScreenOffset = (m_rc.right - m_rc.left - nX - RIGHT_SPACE) / (iInterval[nIntervalTime] + * iSpace[nIntervalTime]); // 屏幕偏移
int nScreenCount = nScreenOffset;
nScreenOffset += m_nOffset; // 容器偏移
list<Skline>::reverse_iterator rIter = m_pListKline->rbegin();
while (rIter != m_pListKline->rend() && nScreenOffset > )
{
nScreenOffset--;
rIter++;
} if (rIter == m_pListKline->rend())
{
return nullptr;
} vector<OtherShowInfo> vecOther;
vector<OtherInfo>::iterator iterOther = m_vecOtherInfo.begin();
while (iterOther != m_vecOtherInfo.end())
{
nScreenOffset = (m_rc.right - m_rc.left - nX - RIGHT_SPACE) / (iInterval[nIntervalTime] + * iSpace[nIntervalTime]) + m_nOffset;
list<double>::reverse_iterator subrIterOther = iterOther->listInfo->rbegin();
while (subrIterOther != iterOther->listInfo->rend() && nScreenOffset)
{
nScreenOffset--;
subrIterOther++;
}
if (subrIterOther != iterOther->listInfo->rend())
{
OtherShowInfo osi;
strcpy_s(osi.pName, iterOther->pName);
osi.dValue = *subrIterOther;
osi.color = iterOther->color;
vecOther.push_back(osi);
}
iterOther++;
} Skline& m_lastKline = *rIter;
m_nSelectKlineDate = m_lastKline.nDate;
m_nSelectKlineTime = m_lastKline.nTime;
return &m_lastKline;
} void DrawModule::DrawKLine(bool bDrawAll)
{
if (m_pListKline==NULL) return; list<Skline>::reverse_iterator rIter = m_pListKline->rbegin();
int nCountOffset = ;
if (rIter != m_pListKline->rend() && m_nOffset)
{// K线偏移
while (nCountOffset<m_nOffset)
{
rIter++;
nCountOffset++;
}
} list<Skline>::reverse_iterator rIterCompare;
if (m_pCompareListKline)
{
rIterCompare = m_pCompareListKline->rbegin();
advance(rIterCompare, nCountOffset);
}
double dUnit = (m_dMax - m_dMin)/(m_rc.bottom-m_rc.top-TOP_INFO_SPACE)/0.9; // 数据轴单位
double dCurMin = m_dMin - 0.05*(m_rc.bottom-m_rc.top-TOP_INFO_SPACE)*dUnit; // 数据轴最小值 // 画笔
Pen RedPen(Color(,,),1.5f);
Pen LightRedPen(Color(, , ), 0.5f);
LightRedPen.SetDashStyle(DashStyleDash);
Pen GreenPen(Color(,,),1.5f);
Pen OtherGreenPen(Color(, , ), 1.5f);
Pen WhitePen(Color(,,),1.5f);
Pen yellowPen(Color(, , ), 1.5f);
SolidBrush GreenPenTrade(Color(, , ));
SolidBrush RedPenTrade(Color(, , )); // 画刷
SolidBrush GreenBrush(Color(,,));
SolidBrush RedBrush(Color(, , ));
SolidBrush OtherGreenBrush(Color(, , ));
SolidBrush yellowBrush(Color(, , )); Graphics graphics_kline_index(bitmap_kline_index);
int nMaxCount = (m_rc.right-m_rc.left-RIGHT_SPACE)/(iInterval[nIntervalTime]+*iSpace[nIntervalTime]);
int nCount = ;// 画图上第多少个
double dMaxScreen=DBL_MIN,dMinScreen=DBL_MAX;
Point ptMax,ptMin;
if (iInterval[nIntervalTime]<)
{// 间距小于4只画线
while (rIter != m_pListKline->rend() && nMaxCount)
{
double dMulti = rIter->dClose - rIter->dOpen;
Point ptHigh = DataToPoint(rIter->dHigh,nCount,dCurMin,dUnit);
Point ptLow = DataToPoint(rIter->dLow,nCount,dCurMin,dUnit);
if (m_maxCycle != && m_minCycle != ) {
int hX = ptLow.X + iInterval[nIntervalTime] / + iSpace[nIntervalTime]; // 纵向网格
int sec = to_second(rIter->nTime);
if (sec % m_maxCycle == ) {
graphics_kline_index.DrawLine(&RedPen, hX, TOP_INFO_SPACE, hX, m_rc.bottom - m_rc.top);
}
else if (sec % m_minCycle == ) {
graphics_kline_index.DrawLine(&LightRedPen, hX, TOP_INFO_SPACE, hX, m_rc.bottom - m_rc.top);
}
} if (dMulti< -0.01)
{// 绿线
graphics_kline_index.DrawLine(bOtherGreen ? &OtherGreenPen : &GreenPen,ptLow,ptHigh);
}
else
{// 红线
graphics_kline_index.DrawLine(&RedPen,ptLow,ptHigh);
} if (rIter->dHigh > dMaxScreen)
{
dMaxScreen = rIter->dHigh;
ptMax = ptHigh;
} if (dMinScreen > rIter->dLow)
{
dMinScreen = rIter->dLow;
ptMin = ptLow;
}
nCount++;
rIter++;
if (m_pCompareListKline && rIterCompare!= m_pCompareListKline->rend()) rIterCompare++;
nMaxCount--;
}
}
else
{
while (rIter != m_pListKline->rend() && nMaxCount)
{
double dMulti = rIter->dClose - rIter->dOpen;
Point ptOpen = DataToPoint(rIter->dOpen,nCount,dCurMin,dUnit);
Point ptHigh = DataToPoint(rIter->dHigh,nCount,dCurMin,dUnit);
Point ptLow = DataToPoint(rIter->dLow,nCount,dCurMin,dUnit);
Point ptClose = DataToPoint(rIter->dClose,nCount,dCurMin,dUnit);
if (m_maxCycle != && m_minCycle != ) {
int hX = ptLow.X + iInterval[nIntervalTime] / + iSpace[nIntervalTime]; // 纵向网格
int sec = to_second(rIter->nTime);
if (sec % m_maxCycle == ) {
graphics_kline_index.DrawLine(&RedPen, hX, TOP_INFO_SPACE, hX, m_rc.bottom - m_rc.top);
}
else if (sec % m_minCycle == ) {
graphics_kline_index.DrawLine(&LightRedPen, hX, TOP_INFO_SPACE, hX, m_rc.bottom - m_rc.top);
}
} if (dMulti< -0.01)
{// 绿柱
if (m_pCompareListKline && rIterCompare != m_pCompareListKline->rend() && rIterCompare->dOpen <= rIterCompare->dClose)
{
graphics_kline_index.DrawRectangle((rIter->nDate == m_nSelectKlineDate && rIter->nTime == m_nSelectKlineTime) ? &yellowPen : &GreenPen,
ptOpen.X - iInterval[nIntervalTime] / , ptOpen.Y,
iInterval[nIntervalTime], ptClose.Y - ptOpen.Y);
graphics_kline_index.DrawLine((rIter->nDate == m_nSelectKlineDate && rIter->nTime == m_nSelectKlineTime) ? &yellowPen : &GreenPen, ptHigh, ptOpen);
graphics_kline_index.DrawLine((rIter->nDate == m_nSelectKlineDate && rIter->nTime == m_nSelectKlineTime) ? &yellowPen : &GreenPen, ptLow, ptClose);
}
else
{
graphics_kline_index.FillRectangle((rIter->nDate == m_nSelectKlineDate && rIter->nTime == m_nSelectKlineTime) ? &yellowBrush : &GreenBrush,
ptOpen.X - iInterval[nIntervalTime] / , ptOpen.Y,
iInterval[nIntervalTime], ptClose.Y - ptOpen.Y);
graphics_kline_index.DrawLine((rIter->nDate == m_nSelectKlineDate && rIter->nTime == m_nSelectKlineTime) ? &yellowPen : &GreenPen, ptHigh, ptLow);
}
}
else if (dMulti < 0.01)
{// 白十字
graphics_kline_index.DrawLine((rIter->nDate == m_nSelectKlineDate && rIter->nTime == m_nSelectKlineTime) ? &yellowPen : &WhitePen,ptHigh,ptLow);
graphics_kline_index.DrawLine((rIter->nDate == m_nSelectKlineDate && rIter->nTime == m_nSelectKlineTime) ? &yellowPen : &WhitePen,
ptOpen.X-iInterval[nIntervalTime]/,ptOpen.Y,
ptOpen.X+iInterval[nIntervalTime]/,ptOpen.Y);
}
else
{// 红柱
if (m_pCompareListKline && rIterCompare != m_pCompareListKline->rend() && rIterCompare->dOpen <= rIterCompare->dClose)
{
graphics_kline_index.FillRectangle((rIter->nDate == m_nSelectKlineDate && rIter->nTime == m_nSelectKlineTime) ? &yellowBrush : &RedBrush, ptClose.X - iInterval[nIntervalTime] / , ptClose.Y,
iInterval[nIntervalTime], ptOpen.Y - ptClose.Y);
graphics_kline_index.DrawLine((rIter->nDate == m_nSelectKlineDate && rIter->nTime == m_nSelectKlineTime) ? &yellowPen : &RedPen, ptHigh, ptLow);
}
else
{
graphics_kline_index.DrawRectangle((rIter->nDate == m_nSelectKlineDate && rIter->nTime == m_nSelectKlineTime) ? &yellowPen : &RedPen,
ptClose.X - iInterval[nIntervalTime] / , ptClose.Y,
iInterval[nIntervalTime], ptOpen.Y - ptClose.Y);
graphics_kline_index.DrawLine((rIter->nDate == m_nSelectKlineDate && rIter->nTime == m_nSelectKlineTime) ? &yellowPen : &RedPen, ptHigh, ptClose);
graphics_kline_index.DrawLine((rIter->nDate == m_nSelectKlineDate && rIter->nTime == m_nSelectKlineTime) ? &yellowPen : &RedPen, ptLow, ptOpen);
}
} if (m_vecTradeData) {
for (auto iter_trade = m_vecTradeData->begin(); iter_trade != m_vecTradeData->end(); iter_trade++)
{
if (iter_trade->nDate == rIter->nDate && IsSameCycle(iter_trade->nTime, rIter->nTime))
{////▲▼▼▲↑
Point ptPrice = DataToPoint(iter_trade->dPrice, nCount, dCurMin, dUnit);
SolidBrush KongBrush(Color(, , ));
SolidBrush DuoBrush(Color(, , ));
SolidBrush checkBrush(Color(, , ));
FontFamily fontFamily(L"楷体");
Gdiplus::Font font(&fontFamily, , FontStyleRegular, UnitPixel);
StringFormat stringformat;
stringformat.SetAlignment(StringAlignmentCenter);
stringformat.SetLineAlignment(StringAlignmentCenter);
graphics_kline_index.SetTextRenderingHint(TextRenderingHintAntiAlias); if (iter_trade->chDir == '')
{
char szValue[]; wchar_t wcstring[];
_snprintf_s(szValue, , "▲\n%d|%d", iter_trade->nVolume, iter_trade->nNetPos);
MultiByteToWideChar(CP_ACP, , szValue, , wcstring, );
//graphics_kline_index.FillRectangle(&checkBrush, RectF(ptPrice.X - 28, ptPrice.Y, 56, 28));
graphics_kline_index.DrawString(wcstring, wcslen(wcstring), &font,
RectF(ptPrice.X - , ptPrice.Y, , ), &stringformat, &DuoBrush);
}
else
{
char szValue[]; wchar_t wcstring[];
_snprintf_s(szValue, , "%d|%d\n▼", iter_trade->nVolume, iter_trade->nNetPos);
MultiByteToWideChar(CP_ACP, , szValue, , wcstring, );
//graphics_kline_index.FillRectangle(&checkBrush, RectF(ptPrice.X - 28, ptPrice.Y - 28, 56, 28));
graphics_kline_index.DrawString(wcstring, wcslen(wcstring), &font,
RectF(ptPrice.X - , ptPrice.Y-, , ), &stringformat, &KongBrush);
} //_snprintf_s(szValue, 50, "%d", iter_trade->nNetPos);
//MultiByteToWideChar(CP_ACP, 0, szValue, 50, wcstring, 100);
//graphics_kline_index.DrawString(wcstring, wcslen(wcstring), &font,
// RectF(ptPrice.X + 1, iter_trade->chDir == '1' ? ptPrice.Y - 7 : ptPrice.Y, 14, 28), &stringformat, &WhiteBrush); }
}
} if (rIter->dHigh > dMaxScreen)
{
dMaxScreen = rIter->dHigh;
ptMax = ptHigh;
} if (dMinScreen > rIter->dLow)
{
dMinScreen = rIter->dLow;
ptMin = ptLow;
}
nCount++;
rIter++;
if (m_pCompareListKline && rIterCompare != m_pCompareListKline->rend()) rIterCompare++;
nMaxCount--;
}
}
if (dMinScreen!=DBL_MAX && dMaxScreen!=DBL_MIN)
{
SolidBrush WhiteBrush(Color(,,));
FontFamily fontFamily(L"楷体");
Gdiplus::Font font(&fontFamily, , FontStyleRegular, UnitPixel);
StringFormat stringformat;
stringformat.SetAlignment(StringAlignmentNear);
stringformat.SetLineAlignment(StringAlignmentCenter);
graphics_kline_index.SetTextRenderingHint(TextRenderingHintAntiAlias); char szValue[];wchar_t wcstring[];
_snprintf_s(szValue,,"←%.2f",dMinScreen);
MultiByteToWideChar(CP_ACP,,szValue,,wcstring,);
graphics_kline_index.DrawString(wcstring,wcslen(wcstring),&font,
RectF(ptMin.X,ptMin.Y-,RIGHT_SPACE,),&stringformat,&WhiteBrush); _snprintf_s(szValue,,"←%.2f",dMaxScreen);
MultiByteToWideChar(CP_ACP,,szValue,,wcstring,);
graphics_kline_index.DrawString(wcstring,wcslen(wcstring),&font,
RectF(ptMax.X,ptMax.Y-,RIGHT_SPACE,),&stringformat,&WhiteBrush);
}
} Point DrawModule::DataToPoint(double dValue, int nCount, double dCurMin, double dUnit)
{
Point pt;
pt.X = m_rc.right-m_rc.left-RIGHT_SPACE-(iInterval[nIntervalTime]+iSpace[nIntervalTime]*)*nCount+iSpace[nIntervalTime]+iInterval[nIntervalTime]/;
pt.Y = m_rc.bottom-m_rc.top-(dValue-dCurMin)/dUnit;
return pt;
} void DrawModule::DrawOther(bool bDrawAll)
{
double dUnit = (m_dMax - m_dMin) / (m_rc.bottom - m_rc.top - TOP_INFO_SPACE) / 0.9; // 数据轴单位
double dCurMin = m_dMin - 0.05*(m_rc.bottom - m_rc.top - TOP_INFO_SPACE)*dUnit; // 数据轴最小值 Graphics graphics_kline_index(bitmap_kline_index);
for (unsigned int i = ; i < m_vecOtherInfo.size(); i++)
{
Pen randomPen(m_vecOtherInfo[i].color, m_vecOtherInfo[i].dBound);
randomPen.SetDashStyle(DashStyle(m_vecOtherInfo[i].penStyle));
if (m_vecOtherInfo[i].bShow)
{
list<double>::reverse_iterator rOtherIter = m_vecOtherInfo[i].listInfo->rbegin();
if (rOtherIter != m_vecOtherInfo[i].listInfo->rend() && m_nOffset)
{
int nCount = ;
while (nCount < m_nOffset && rOtherIter != m_vecOtherInfo[i].listInfo->rend())
{
rOtherIter++;
nCount++;
}
} int nMaxCount = (m_rc.right - m_rc.left - RIGHT_SPACE) / (iInterval[nIntervalTime] + * iSpace[nIntervalTime]);
int nCount = ;
Point ptLast;
while (rOtherIter != m_vecOtherInfo[i].listInfo->rend() && nMaxCount)
{
Point ptThis = DataToPoint(*rOtherIter, nCount, dCurMin, dUnit);
if (nCount > )
{
graphics_kline_index.DrawLine(&randomPen, ptLast, ptThis);
}
rOtherIter++;
nCount++;
nMaxCount--;
ptLast = ptThis;
}
}
}
} bool DrawModule::IsSameCycle(int nTime, int nKlineTime)
{
int n1 = nTime / ;
int n2 = nKlineTime / ;
if (n1 % == )
{
n1 += ;
}
else
{
n1 += ;
} if (n1 == n2)
return true;
return false;
} void DrawModule::ThreadDraw()
{
while (m_bThread)
{
if (WaitForSingleObject(m_hEvent, ) == WAIT_TIMEOUT)
continue; if (PreDrawInfo())
{
DoDrawAll();
}
}
} void DrawModule::DoDraw()
{
::SetEvent(m_hEvent);
//if(PreDrawInfo())
//{
// DoDrawAll();
//}
} void DrawModule::Start()
{
if (m_thdDraw) return;
m_thdDraw = make_shared<thread>(&DrawModule::ThreadDraw, this);
} void DrawModule::Stop()
{
m_bThread = false;
if (m_thdDraw && m_thdDraw->joinable())
m_thdDraw->join();
} void DrawModule::DoDrawAll()
{
// 在画布上绘制
DrawNumber();
DrawKLine();
DrawOther(); // 显示到控件上
if (!bitmap_user_show_info) return;
Gdiplus::Graphics graphics_user_show_info(bitmap_user_show_info);
graphics_user_show_info.DrawImage(bitmap_background,,,bitmap_background->GetWidth(),bitmap_background->GetHeight());
graphics_user_show_info.DrawImage(bitmap_kline_index,,,bitmap_kline_index->GetWidth(),bitmap_kline_index->GetHeight());
drawObj->DrawImage(bitmap_user_show_info,,,bitmap_user_show_info->GetWidth(),bitmap_user_show_info->GetHeight());
}

2、qt绘图

#pragma once
#include <QVBoxLayout>
#include <QFrame>
#include <QPixmap>
#include <QLabel>
#include <QList>
#include <QPen>
#include <QBrush>
#include <list>
#include "user_define_struct.h"
#include "TradeStruct.h" //关联外部定义结构体到绘图模块,实现必要的函数
typedef Skline QDrawKline;
typedef SIG_TYPE QDrawSignalType;
typedef STRUCT_RSP_SIGNAL QDrawSignal;
typedef PositionDetail QDrawPosition; class QKlineInfo : public QWidget
{
public:
QKlineInfo(QWidget *parent) : QWidget(parent), m_precision()
{
QVBoxLayout* layout = new QVBoxLayout(this);
layout->setContentsMargins(, , , );
layout->addWidget(new QLabel(u8"<span style='color:white;'>日期</span>"));
m_lb_date = new QLabel(this);
layout->addWidget(m_lb_date);
layout->addWidget(new QLabel(u8"<span style='color:white;'>时间</span>"));
m_lb_time = new QLabel(this);
layout->addWidget(m_lb_time);
layout->addWidget(new QLabel(u8"<span style='color:white;'>开盘</span>"));
m_lb_open = new QLabel(this);
layout->addWidget(m_lb_open);
layout->addWidget(new QLabel(u8"<span style='color:white;'>最高</span>"));
m_lb_high = new QLabel(this);
layout->addWidget(m_lb_high);
layout->addWidget(new QLabel(u8"<span style='color:white;'>最低</span>"));
m_lb_low = new QLabel(this);
layout->addWidget(m_lb_low);
layout->addWidget(new QLabel(u8"<span style='color:white;'>收盘</span>"));
m_lb_close = new QLabel(this);
layout->addWidget(m_lb_close);
layout->addWidget(new QLabel(u8"<span style='color:white;'>成交</span>"));
m_lb_volume = new QLabel(this);
layout->addWidget(m_lb_volume);
layout->addWidget(new QLabel(u8"<span style='color:white;'>持仓</span>"));
m_lb_interest = new QLabel(this);
layout->addWidget(m_lb_interest);
} void SetPrecision(int precision)
{
m_precision = precision;
} void UpdateKline(QDrawKline& k, double& last_close)
{
m_lb_date->setText(QString("<span style='color:white;'>%1</span>").arg(k.Date()));
m_lb_time->setText(QString("<span style='color:white;'>%1</span>").arg(k.Time()));
m_lb_open->setText(QString("<span style='color:%1;'>%2</span>").arg(GetColor(k.Open(), last_close)).arg(QString::number(k.Open(), 'f', m_precision)));
m_lb_high->setText(QString("<span style='color:%1;'>%2</span>").arg(GetColor(k.High(), last_close)).arg(QString::number(k.High(), 'f', m_precision)));
m_lb_low->setText(QString("<span style='color:%1;'>%2</span>").arg(GetColor(k.Low(), last_close)).arg(QString::number(k.Low(), 'f', m_precision)));
m_lb_close->setText(QString("<span style='color:%1;'>%2</span>").arg(GetColor(k.Close(), last_close)).arg(QString::number(k.Close(), 'f', m_precision)));
m_lb_volume->setText(QString("<span style='color:yellow;'>%1</span>").arg(k.Volume()));
m_lb_interest->setText(QString("<span style='color:yellow;'>%1</span>").arg(QString::number(k.Interest(), 'f', )));
} protected:
QString GetColor(const double& this_value,const double& last_value)
{
if (this_value > last_value)
return "#DB3320";
if (this_value < last_value)
return "#00E700";
return "#E7E7E7";
} protected:
QLabel* m_lb_date;
QLabel* m_lb_time;
QLabel* m_lb_open;
QLabel* m_lb_high;
QLabel* m_lb_low;
QLabel* m_lb_close;
QLabel* m_lb_volume;
QLabel* m_lb_interest; int m_precision;
}; class QDrawModule : public QFrame
{
Q_OBJECT using kline_riter = std::list<QDrawKline>::reverse_iterator;
using curve_riter = std::list<double>::reverse_iterator; struct DataCoverage
{
std::list<QDrawKline>* m_pListKline;
std::list<double>* m_pListCurve; kline_riter m_offset_kline_iter;
curve_riter m_offset_curve_iter; QPixmap m_pixCoverage;
QString name;
QColor clr;
DataCoverage()
{
m_pListKline = nullptr;
m_pListCurve = nullptr;
}
bool operator ==(const DataCoverage& other)
{
bool bRet = m_pListKline == other.m_pListKline;
bRet &= m_pListCurve == other.m_pListCurve;
return bRet;
}
void ResetIter()
{
if (m_pListKline) m_offset_kline_iter = m_pListKline->rbegin();
if (m_pListCurve) m_offset_curve_iter = m_pListCurve->rbegin();
}
}; struct UserPosition
{
int user_key;
QDrawPosition* m_position;
UserPosition()
{
user_key = ;
m_position = nullptr;
}
}; #define SHOW_ALL_POSITION INT_MAX
int m_showUserPosition;
QList<UserPosition> m_userPosition;//用户仓位 struct UserSignal
{
int user_key;
std::list<QDrawSignal>* m_signal;
};
QList<UserSignal> m_userSignal; public:
QDrawModule(QWidget *parent);
~QDrawModule();
static int PushOneKey() { return ++user_key_index; } public:
void SetListKline(std::list<QDrawKline>* p);//设置K线容器
void SetCurve(std::list<double>* p, QString name, QColor clr);//设置曲线容器
void RemoveCoverage(void* p);//移除容器对应的图层 void SetInterval(int interval);//间距
void SetSpace(int top, int bottom, int left, int right);//上下空挡
void SetDataCount(int count);//总数
void SetOffset(int offset);//与最后一根的距离
void SetPrecision(int precision);//设置精度,小数点后保留位数,类似期权数据大于0小于1的情况
void SetUserPosition(int user_key, QDrawPosition* p);
void SetShowUserPosition(int user_key); public slots:
void DoDraw(bool draw_all);
void PageUpDown(bool up_down); protected:
void DrawCoordinate();//坐标线
void DrawProcess();//绘图过程
//更新最大最小值
void UpdateMaxMin();
void UpdateMaxMin(kline_riter riter_start, kline_riter riter_end, kline_riter& offset_riter);
void UpdateMaxMin(curve_riter riter_start, curve_riter riter_end, curve_riter& offset_riter);
void DrawKline(DataCoverage& dc);//K线
void DrawCurve(DataCoverage& dc);//曲线
void DrawSignal();//信号位置
void DrawPosition();//仓位线 void ErasePixmap(QPixmap& pix, QRect& rc);//部分擦除
int DataToPointY(const double& value, const double& min_data, const double& unit_data);//数值转为Y坐标
double PointYToData(int& y, const double& min_data, const double& unit_data);
void CenterPointCount();//中心点个数
void UnitData();//Y轴单位
void DrawOneKline(QPixmap& pix, int x, QDrawKline& k, QColor& clr);//画一个K线 protected:
void resizeEvent(QResizeEvent *event);
void focusInEvent(QFocusEvent *event);
void focusOutEvent(QFocusEvent *event);
void leaveEvent(QEvent *event);
void mouseMoveEvent(QMouseEvent *event);//数值提示
void mouseDoubleClickEvent(QMouseEvent *event);//十字线
void keyReleaseEvent(QKeyEvent *event);//上下左右
void paintEvent(QPaintEvent *event); protected:
QList<DataCoverage> m_dataCoverage;//数据&图层
static int user_key_index; private:
bool m_draw_all;//是否全部重绘
//数据结构参数
double m_try_min_data, m_try_max_data;//更新之后的最大最小
double m_min_data, m_max_data;//实际最大最小
int m_min_data_x, m_max_data_x;//实际最大最小对应的位置
double m_unit_data;//一个像素点对应的高度数值
int m_max_center_point;//中心点的最大数
int m_widget_width, m_widget_height;
int m_interval;
bool m_cross;
QRect m_space;
int m_precision;
int m_total_count;
int m_offset;
int m_last_offset; //绘画工具
QPixmap m_pixCoor;
QPixmap m_pixCross;
QPixmap m_pixPosition;
QPen m_pen;
QBrush m_brush;
QColor m_clrRed;
QColor m_clrGreen; QKlineInfo* m_widget_info;
};
#include "QDrawModule.h"
#include <QPainter>
#include <QKeyEvent>
#include <QMouseEvent>
#include <QFocusEvent>
#include "qcoreevent.h" int QDrawModule::user_key_index = ;
QDrawModule::QDrawModule(QWidget *parent)
: QFrame(parent)
{
m_clrGreen = QColor(, , );
m_clrRed = QColor(, , );
m_offset = ;
m_last_offset = m_offset;
m_interval = ;
m_precision = ;
m_cross = false;
m_showUserPosition = SHOW_ALL_POSITION;
m_try_min_data = m_min_data = 1.79769313486231570E+308;
m_try_max_data = m_max_data = -1.79769313486231570E+308;
m_widget_info = new QKlineInfo(this);
m_widget_info->setObjectName("m_widget_info");
m_widget_info->setStyleSheet("#m_widget_info{border:1px solid white}");
if (!m_cross) m_widget_info->hide();
setMouseTracking(true);
setFocusPolicy(Qt::FocusPolicy::ClickFocus);
} QDrawModule::~QDrawModule()
{
} void QDrawModule::SetListKline(std::list<QDrawKline>* p)
{
DataCoverage dc;
dc.m_pListKline = p;
dc.ResetIter();
m_dataCoverage.push_back(dc);
} void QDrawModule::SetCurve(std::list<double>* p, QString name, QColor clr)
{
DataCoverage dc;
dc.m_pListCurve = p;
dc.name = name;
dc.clr = clr;
dc.ResetIter();
m_dataCoverage.push_back(dc);
} void QDrawModule::RemoveCoverage(void * p)
{
for (auto& dc : m_dataCoverage)
{
if (dc.m_pListKline == p || dc.m_pListCurve == p) {
m_dataCoverage.removeOne(dc);
break;
}
}
} void QDrawModule::SetInterval(int interval)
{
m_interval = interval;
} void QDrawModule::SetSpace(int top, int bottom, int left, int right)
{
m_space.setTop(top);
m_space.setBottom(bottom);
m_space.setLeft(left);
m_space.setRight(right);
m_widget_info->setFixedSize(left - , );
} void QDrawModule::SetDataCount(int count)
{
m_total_count = count;
} void QDrawModule::SetOffset(int offset)
{
m_offset = offset;
} void QDrawModule::SetPrecision(int precision)
{
m_precision = precision;
m_widget_info->SetPrecision(precision);
} void QDrawModule::SetUserPosition(int user_key, QDrawPosition* p)
{
UserPosition up;
up.user_key = user_key;
up.m_position = p;
m_userPosition.push_back(up);
} void QDrawModule::SetShowUserPosition(int user_key)
{
m_showUserPosition = user_key;
} void QDrawModule::DoDraw(bool draw_all)
{
m_draw_all = draw_all;
CenterPointCount();
UpdateMaxMin();
if (m_try_max_data != m_max_data || m_try_min_data != m_min_data)
{
m_max_data = m_try_max_data;
m_min_data = m_try_min_data;
m_draw_all = true;
}
UnitData();
DrawProcess();
if (m_cross)
{
m_pixCross = QPixmap(m_widget_width, m_widget_height);
m_pixCross.fill(Qt::transparent);
}
update();
} void QDrawModule::PageUpDown(bool up_down)
{
if (up_down)
{
m_offset -= m_max_center_point;
if (m_offset < )
m_offset = ;
}
else
{
int max_offset = m_max_center_point;
for (auto& dc : m_dataCoverage)
{
if (dc.m_pListKline)
{
int offset_count = ;
auto riter = dc.m_offset_kline_iter;
while (riter != dc.m_pListKline->rend() && offset_count < m_max_center_point)
{
riter++;
offset_count++;
} if (max_offset > offset_count)
max_offset = offset_count;
} if (dc.m_pListCurve)
{
int offset_count = ;
auto riter = dc.m_offset_curve_iter;
while (riter != dc.m_pListCurve->rend() && offset_count < m_max_center_point)
{
riter++;
offset_count++;
}
if (max_offset > offset_count)
max_offset = offset_count;
}
}
m_offset += max_offset;
}
} void QDrawModule::DrawCoordinate()
{
int work_height = m_widget_height - m_space.top() - m_space.bottom();
int line_numb = work_height / ;//需要绘制的坐标线个数
double line_interval = (m_max_data - m_min_data) / (line_numb + );
double fundation = ;
if (line_interval > )
{
int interval = line_interval;
while (interval / > )
{
interval /= ;
fundation *= ;
}
fundation *= interval + ;
}
else if (line_interval > )
{
while (line_interval < )
{
line_interval *= ;
fundation *= ;
}
line_interval = (int)line_interval;
fundation = line_interval / fundation;
}
else
{
return;
} double start_line = ((int)(m_min_data / fundation) + ) * fundation;
m_pixCoor = QPixmap(m_widget_width, m_widget_height);
m_pixCoor.fill(Qt::transparent);
QPainter painter(&m_pixCoor);
m_pen.setColor(QColor(, , ));
m_pen.setWidth();
m_pen.setStyle(Qt::PenStyle::SolidLine);
painter.setPen(m_pen);
painter.drawLine(m_space.left() - , , m_space.left() - , m_widget_height);
m_pen.setStyle(Qt::PenStyle::DotLine);
QPen white_pen = m_pen;
white_pen.setColor(QColor(, , ));
white_pen.setWidth();
white_pen.setStyle(Qt::PenStyle::SolidLine);
do
{
int point_y = DataToPointY(start_line, m_min_data, m_unit_data);
painter.setPen(m_pen);
painter.drawLine(m_space.left(), point_y, m_widget_width - m_space.right(), point_y);
painter.setPen(white_pen);
painter.drawText(, point_y - , m_space.left() - , , Qt::AlignRight | Qt::AlignCenter, QString::number(start_line, 'f', m_precision));
start_line += fundation;
} while (start_line <= m_max_data);
} void QDrawModule::UpdateMaxMin()
{
m_try_min_data = 1.79769313486231570E+308;
m_try_max_data = -1.79769313486231570E+308;
for (auto& dc : m_dataCoverage)
{
if (dc.m_pListKline) {
UpdateMaxMin(dc.m_pListKline->rbegin(), dc.m_pListKline->rend(), dc.m_offset_kline_iter);
}
if (dc.m_pListCurve) {
UpdateMaxMin(dc.m_pListCurve->rbegin(), dc.m_pListCurve->rend(), dc.m_offset_curve_iter);
}
}
} void QDrawModule::DrawProcess()
{
if (m_draw_all)
DrawCoordinate();
for (auto& dc : m_dataCoverage)
{
if (dc.m_pListKline)
DrawKline(dc);
if (dc.m_pListCurve)
DrawCurve(dc);
}
DrawSignal();
DrawPosition();
} #define UPDATE_OFFSET_RITER()\
int bak_offset = m_offset;\
if (bak_offset > m_last_offset)\
{\
while (bak_offset != m_last_offset)\
{\
if (offset_riter != riter_end)\
{\
offset_riter++;\
}\
bak_offset--;\
}\
}\
else if (bak_offset < m_last_offset)\
{\
while (bak_offset != m_last_offset)\
{\
if (offset_riter != riter_start)\
{\
offset_riter--;\
}\
bak_offset++;\
}\
} void QDrawModule::UpdateMaxMin(kline_riter riter_start, kline_riter riter_end, kline_riter& offset_riter)
{
UPDATE_OFFSET_RITER() riter_start = offset_riter;
int start_x = m_max_center_point;
while (riter_start != riter_end && start_x > )
{
if (riter_start->High() > m_try_max_data) {
m_try_max_data = riter_start->High();
m_max_data_x = start_x;
} if (riter_start->Low() < m_try_min_data) {
m_try_min_data = riter_start->Low();
m_min_data_x = start_x;
}
riter_start++;
start_x--;
}
} void QDrawModule::UpdateMaxMin(curve_riter riter_start, curve_riter riter_end, curve_riter& offset_riter)
{
UPDATE_OFFSET_RITER() riter_start = offset_riter;
int start_x = m_max_center_point;
while (riter_start != riter_end && start_x > )
{
if (*riter_start > m_try_max_data)
m_try_max_data = *riter_start; if (*riter_start < m_try_min_data)
m_try_min_data = *riter_start;
start_x--;
riter_start++;
}
} void QDrawModule::DrawKline(DataCoverage& dc)
{
QPixmap& myPix = dc.m_pixCoverage;
kline_riter riter_start = dc.m_offset_kline_iter == dc.m_pListKline->rend() ?
dc.m_pListKline->rbegin() : dc.m_offset_kline_iter;
kline_riter riter_end = dc.m_pListKline->rend(); int start_x = m_max_center_point;
if (m_draw_all)
{
myPix = QPixmap(m_widget_width - m_space.left(), m_widget_height);
myPix.fill(Qt::transparent);
while (riter_start != riter_end && start_x > )
{
DrawOneKline(myPix, start_x, *riter_start, dc.clr);
riter_start++;
start_x--;
}
}
else
{
QRect rc;
rc.setLeft((m_max_center_point - ) * (m_interval + m_interval / ));
rc.setTop();
rc.setHeight(m_widget_height);
rc.setWidth(m_interval);
ErasePixmap(myPix, rc);
DrawOneKline(myPix, start_x, *riter_start, dc.clr);
}
} void QDrawModule::DrawCurve(DataCoverage& dc)
{
QPixmap& myPix = dc.m_pixCoverage;
curve_riter riter_start = dc.m_offset_curve_iter == dc.m_pListCurve->rend() ?
dc.m_pListCurve->rbegin() : dc.m_offset_curve_iter;
curve_riter riter_end = dc.m_pListCurve->rend(); if (m_draw_all) {
myPix = QPixmap(m_widget_width - m_space.left(), m_widget_height);
myPix.fill(Qt::transparent);
}
else
{
QRect rc;
int cent_x2 = (m_max_center_point - ) * (m_interval + m_interval / ) + m_interval / ; rc.setLeft(cent_x2);
rc.setTop();
rc.setHeight(m_widget_height);
rc.setWidth(m_interval);
ErasePixmap(myPix, rc);
} QPainter painter(&myPix);
m_pen.setColor(dc.clr);
m_pen.setWidth();
m_pen.setStyle(Qt::SolidLine);
painter.setPen(m_pen);
int start_x = m_max_center_point;
bool bFirstPoint = true;
QPoint last_point;
if (m_draw_all)
{
while (riter_start != riter_end && start_x > )
{
int cent_x = (start_x - ) * (m_interval + m_interval / ) + m_interval / ;
QPoint this_point(cent_x, DataToPointY(*riter_start, m_min_data, m_unit_data));
if (!bFirstPoint)
{
painter.drawLine(this_point, last_point);
}
last_point = this_point;
bFirstPoint = false;
riter_start++;
start_x--;
}
}
else
{
if (riter_start != riter_end && start_x > )
{
int cent_x = (start_x - ) * (m_interval + m_interval / ) + m_interval / ;
last_point = QPoint(cent_x, DataToPointY(*riter_start, m_min_data, m_unit_data));
riter_start++;
start_x--;
} if (riter_start != riter_end && start_x > )
{
int cent_x = (start_x - ) * (m_interval + m_interval / ) + m_interval / ;
QPoint this_point(cent_x, DataToPointY(*riter_start, m_min_data, m_unit_data));
painter.drawLine(this_point, last_point);
}
}
} void QDrawModule::DrawSignal()
{
} void QDrawModule::DrawPosition()
{
if (m_userPosition.size() == )
return; m_pixPosition = QPixmap(m_widget_width - m_space.left() - m_space.right(), m_widget_height);
m_pixPosition.fill(Qt::transparent);
QPainter painter(&m_pixPosition); auto lambda_func = [&](int user_key, QColor clr, int& count, double& avg_price)
{
m_pen.setColor(clr);
m_pen.setStyle(Qt::PenStyle::DashLine);
painter.setPen(m_pen); int y = DataToPointY(avg_price, m_min_data, m_unit_data);
QString strInfo = QString(u8"[%1]%2手,均价:%3").arg(user_key).
arg(count).arg(QString::number(avg_price, 'f', m_precision + ));
int txt_length = strInfo.size() * ;
if (y < m_space.top())
{
painter.drawText(, m_space.top(), txt_length, , Qt::AlignLeft | Qt::AlignCenter, strInfo);
painter.drawLine(txt_length, m_space.top() + , m_widget_width - m_space.right(), m_space.top() + );
}
else if (y > m_widget_height - m_space.bottom())
{
painter.drawText(, m_widget_height - m_space.bottom() - , txt_length, , Qt::AlignLeft | Qt::AlignCenter, strInfo);
painter.drawLine(txt_length, m_widget_height - m_space.bottom() - , m_widget_width - m_space.right(), m_widget_height - m_space.bottom() - );
}
else
{
painter.drawText(, y - , txt_length, , Qt::AlignLeft | Qt::AlignCenter, strInfo);
painter.drawLine(txt_length, y, m_widget_width - m_space.right(), y);
}
}; for (auto& up : m_userPosition)
{
if (!up.m_position)
continue; if (m_showUserPosition == SHOW_ALL_POSITION || m_showUserPosition == up.user_key)
{
if (up.m_position->GetLongHolding() > )
{
lambda_func(up.user_key, "#FF5C5C", up.m_position->GetLongHolding(), up.m_position->GetLongAvgPrice());
}
else
{
lambda_func(up.user_key, "#00FF00", up.m_position->GetShortHolding(), up.m_position->GetShortAvgPrice());
}
}
}
} void QDrawModule::ErasePixmap(QPixmap& pix, QRect& rc)
{
QPainter painter(&pix);
painter.setCompositionMode(QPainter::CompositionMode_Source);
painter.fillRect(rc, Qt::transparent);
} int QDrawModule::DataToPointY(const double& value, const double& min_data, const double& unit_data)
{
return m_widget_height - m_space.bottom() - (value - min_data) / unit_data;
} double QDrawModule::PointYToData(int& y, const double& min_data, const double& unit_data)
{
return (m_widget_height - m_space.bottom() - y) * unit_data + min_data;
} void QDrawModule::CenterPointCount()
{
int work_width = m_widget_width - m_space.left() - m_space.right();
m_max_center_point = work_width / (m_interval + m_interval / );
} void QDrawModule::UnitData()
{
int work_height = m_widget_height - m_space.top() - m_space.bottom();
m_unit_data = (m_max_data - m_min_data) / work_height;
} void QDrawModule::DrawOneKline(QPixmap & pix, int x, QDrawKline & k, QColor& clr)
{
QPainter painter(&pix);
int clr_idx;
if (k.Open() > k.Close())
{
m_pen.setColor(m_clrGreen);
clr_idx = ;
}
else if (k.Open() < k.Close())
{
m_pen.setColor(m_clrRed);
clr_idx = ;
}
else
{
m_pen.setColor(Qt::white);
clr_idx = ;
}
m_pen.setWidth();
m_pen.setStyle(Qt::PenStyle::SolidLine);
painter.setPen(m_pen);
painter.setBrush(m_brush); int left_x = (x - ) * (m_interval + m_interval / );
int cent_x = left_x + m_interval / ;
int right_x = left_x + m_interval - ;
int top_y = DataToPointY(k.High(), m_min_data, m_unit_data);
int open_y = DataToPointY(k.Open(), m_min_data, m_unit_data);
int close_y = DataToPointY(k.Close(), m_min_data, m_unit_data);
int low_y = DataToPointY(k.Low(), m_min_data, m_unit_data); if (clr_idx == )
{//红色空心
painter.drawRect(QRect(left_x, close_y, m_interval - , open_y - close_y));
painter.drawLine(cent_x, top_y, cent_x, close_y);
painter.drawLine(cent_x, low_y, cent_x, open_y);
}
else if (clr_idx == )
{//绿色实心
painter.fillRect(QRect(left_x, open_y, m_interval, close_y - open_y), m_clrGreen);
painter.drawLine(cent_x, top_y, cent_x, low_y);
}
else
{//白色十字
painter.drawLine(left_x, open_y, right_x, open_y);
painter.drawLine(cent_x, top_y, cent_x, low_y);
} if (x == m_min_data_x)
{//最小值
m_pen.setColor(Qt::white); painter.setPen(m_pen);
if (cent_x > )
painter.drawText(cent_x - , low_y - , , , Qt::AlignRight | Qt::AlignCenter, QString(u8"%1→").arg(QString::number(k.Low(), 'f', m_precision)));
else
painter.drawText(cent_x - , low_y - , , , Qt::AlignLeft | Qt::AlignCenter, QString(u8"←%1").arg(QString::number(k.Low(), 'f', m_precision)));
} if (x == m_max_data_x)
{//最大值
m_pen.setColor(Qt::white); painter.setPen(m_pen);
if (cent_x > )
painter.drawText(cent_x - , top_y - , , , Qt::AlignRight | Qt::AlignCenter, QString(u8"%1→").arg(QString::number(k.High(), 'f', m_precision)));
else
painter.drawText(cent_x - , top_y - , , , Qt::AlignLeft | Qt::AlignCenter, QString(u8"←%1").arg(QString::number(k.High(), 'f', m_precision)));
}
} void QDrawModule::resizeEvent(QResizeEvent * event)
{
m_widget_width = this->width();
m_widget_height = this->height(); DoDraw(true);
m_widget_info->move(, m_space.top());
} void QDrawModule::focusInEvent(QFocusEvent *event)
{
grabKeyboard();
} void QDrawModule::focusOutEvent(QFocusEvent *event)
{
releaseKeyboard();
} void QDrawModule::leaveEvent(QEvent *event)
{
m_pixCross = QPixmap(m_widget_width, m_widget_height);
m_pixCross.fill(Qt::transparent);
update();
} void QDrawModule::mouseMoveEvent(QMouseEvent *event)
{
if (event->pos().x() <= m_space.left() || event->pos().x() >= (m_widget_width - m_space.right()))
{
leaveEvent(nullptr);
return;
} m_pixCross = QPixmap(m_widget_width, m_widget_height);
m_pixCross.fill(Qt::transparent); int y = event->pos().y();
m_pen.setStyle(Qt::PenStyle::SolidLine);
m_pen.setColor(Qt::white);
QPainter painter(&m_pixCross);
painter.setPen(m_pen);
painter.fillRect(, y - , m_space.left() - , , QColor(, , ));
painter.drawText(, y - , m_space.left() - , , Qt::AlignRight | Qt::AlignCenter, QString::number(PointYToData(y, m_min_data, m_unit_data), 'f', m_precision)); if (m_cross)
{
for (auto& dc : m_dataCoverage)
{
painter.drawPixmap(m_space.left(), , dc.m_pixCoverage);
} painter.setCompositionMode(QPainter::CompositionMode_Difference); painter.setPen(m_pen);
painter.drawLine(m_space.left(), y, m_widget_width - m_space.right(), y);
int draw_x = ;
int str_x = m_space.left() + ;
double last_close;
for (auto& dc : m_dataCoverage)
{
if (dc.m_pListKline) {
if (dc.m_offset_kline_iter == dc.m_pListKline->rend())
continue;
auto riter = dc.m_offset_kline_iter;
int x = m_max_center_point;
int main_x = event->pos().x() - m_space.left();
int last_left = m_widget_width - m_space.left();
while (x > && riter != dc.m_pListKline->rend())
{
int left_x = (x - ) * (m_interval + m_interval / );
if (main_x >= left_x && main_x <= last_left)
{
draw_x = left_x + m_interval / ;
QDrawKline k = *riter;
last_close = k.Open();
riter++;
if (riter != dc.m_pListKline->rend())
last_close = riter->dClose; if (m_widget_info->isVisible())
m_widget_info->UpdateKline(k, last_close);
break;
}
riter++;
x--;
last_left = left_x;
}
} if (dc.m_pListCurve) {
if (dc.m_offset_curve_iter == dc.m_pListCurve->rend())
continue;
auto riter = dc.m_offset_curve_iter;
int x = m_max_center_point;
int main_x = event->pos().x() - m_space.left();
int last_left = m_widget_width - m_space.left();
while (x > && riter != dc.m_pListCurve->rend())
{
int left_x = (x - ) * (m_interval + m_interval / );
if (main_x >= left_x && main_x <= last_left)
{
draw_x = left_x + m_interval / ;
m_pen.setColor(dc.clr);
painter.setPen(m_pen);
QString strIndex = dc.name + ":";
strIndex.append(QString::number(*riter, 'f', m_precision));
painter.drawText(str_x, , strIndex.length() * , , Qt::AlignLeft | Qt::AlignCenter, strIndex);
str_x += strIndex.length() * + ;
break;
}
riter++;
x--;
last_left = left_x;
}
}
}
m_pen.setColor(Qt::white);
painter.setPen(m_pen);
if (draw_x != )
painter.drawLine(draw_x + m_space.left(), , draw_x + m_space.left(), m_widget_height);
} update();
} void QDrawModule::mouseDoubleClickEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
{
m_cross = !m_cross;
if (m_cross)
setCursor(Qt::BlankCursor);
else
setCursor(Qt::ArrowCursor);
for (auto& dc : m_dataCoverage)
{
if (dc.m_pListKline)
{
if (!m_cross)
{
m_widget_info->hide();
}
else
{
m_widget_info->show();
}
break;
}
}
mouseMoveEvent(event);
}
} void QDrawModule::keyReleaseEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_Up)
{
if (m_interval < )
{
m_interval += ;
}
else
return;
}
else if (event->key() == Qt::Key_Down)
{
if (m_interval > )
{
m_interval -= ;
}
else
return;
}
else if (event->key() == Qt::Key_Left)
{
QPoint point = mapFromGlobal(QCursor::pos());
if (!m_cross || point.x() <= (m_space.left() + m_interval + m_interval / ))
{
bool enable_offset = true;
for (auto& dc : m_dataCoverage)
{
if (dc.m_pListKline)
{
auto riter = dc.m_offset_kline_iter;
enable_offset &= riter != dc.m_pListKline->rend();
} if (dc.m_pListCurve)
{
auto riter = dc.m_offset_curve_iter;
enable_offset &= riter != dc.m_pListCurve->rend();
}
} if (enable_offset)
m_offset++;
} if (m_cross)
{
if (point.x() > (m_space.left() + m_interval + m_interval / ) && point.x() <= (m_widget_width - m_space.right()))
{
QCursor::setPos(mapToGlobal(QPoint(point.x() - m_interval - m_interval / , point.y())));
}
}
}
else if (event->key() == Qt::Key_Right)
{
QPoint point = mapFromGlobal(QCursor::pos());
if (!m_cross || point.x() > (m_space.left() + (m_max_center_point - ) * (m_interval + m_interval / )))
{
if (m_offset > )
{
m_offset--;
}
} if (m_cross)
{
QPoint point = mapFromGlobal(QCursor::pos());
if (point.x() > m_space.left() && point.x() <= (m_space.left() + (m_max_center_point - ) * (m_interval + m_interval / )))
{
QCursor::setPos(mapToGlobal(QPoint(point.x() + m_interval + m_interval / , point.y())));
}
}
}
else if (event->key() == Qt::Key_PageUp)
{
PageUpDown(true);
}
else if (event->key() == Qt::Key_PageDown)
{
PageUpDown(false);
}
else
{
return;
}
DoDraw(true);
m_last_offset = m_offset;
} void QDrawModule::paintEvent(QPaintEvent * event)
{
QPainter painter(this); painter.drawPixmap(, , m_pixCoor);
for (auto& dc : m_dataCoverage)
{
painter.drawPixmap(m_space.left(), , dc.m_pixCoverage);
} painter.drawPixmap(m_space.left(), , m_pixPosition);
painter.drawPixmap(, , m_pixCross);
}

最新文章

  1. java.lang.IllegalStateException: Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT instead
  2. python图像卷积
  3. popUpWindow 动画无法超出窗体的解决方案
  4. VMware下 Ubuntu 看不到共享文件夹之解决办法
  5. 线程间操作无效: 从不是创建控件“”的线程访问它~~~的解决方法~ 线程间操作无效: 从不是创建控件“Control Name&#39;”的线程访问它问题的解决方案及原理分析
  6. leetcode:Odd Even Linked List
  7. HDU 1518
  8. bzoj1684 [Usaco2005 Oct]Close Encounter
  9. 关于Resharper的使用经验
  10. H面试程序(4):翻转句子中单词的顺序 .
  11. 你必须知道的EntityFramework 6.x和EntityFramework Core变更追踪状态
  12. 第十七节,OpenCV(学习六)图像轮廓检测
  13. 常用的HTML模板(转载)
  14. MyBatis笔记----Mybatis3.4.2与spring4整合:增删查改
  15. 数位dp小结
  16. Scrum 项目7.0——第一个Sprint的演示和回顾
  17. Jetty 的工作原理
  18. elk系列1之入门安装与基本操作【转】
  19. poj32072-sat模板题
  20. P1353_[USACO08JAN]跑步Running 我死了。。。

热门文章

  1. 关于新版vue-cli安装json-server在build文件里没生成出dev-server文件
  2. Mac常用命令行
  3. 每个Web开发者都应该知道的SOLID原则
  4. OpenCV基本绘图函数
  5. Git的精简用法
  6. fiddler使用post方法带参数(base64)请求接口,模拟表单提交,类似工具postman
  7. gulp常用插件之gulp-postcss使用
  8. R语言的内存(小总结)
  9. Agri-Net POJ - 1258 prim
  10. 安装Elasticsearch到Linux(源码)