MFC应用中如何实现两个图表区域的光标与坐标轴同步
实现方案
1. 定义全局自定义消息和通知结构体
先在公共头文件(比如stdafx.h或者单独的公共定义头文件)里加如下代码:
// 自定义消息定义 #define WM_CHART_MOUSEMOVE (WM_USER + 101) #define WM_CHART_AXIS_CHANGED (WM_USER + 102) // 图表通知数据结构体 struct ChartNotifyData { double dataX; // 鼠标对应的数据坐标X double dataY; // 鼠标对应的数据坐标Y double axisXMin; // X轴最小值 double axisXMax; // X轴最大值 double axisYMin; // Y轴最小值 double axisYMax; // Y轴最大值 };
2. 改造CMyChart自定义控件类
MyChart.h 新增内容
class CMyChart : public CWnd // 原有继承关系保持不变即可 { // 原有代码全部保留,新增如下内容 public: // 外部调用接口:设置自定义光标位置(数据坐标) void SetCustomCursorPos(double x, double y); // 外部调用接口:设置坐标轴范围 void SetAxisRange(double xMin, double xMax, double yMin, double yMax); // 内部方法:客户区坐标转数据坐标,需根据你CMyChart的内部实现补全逻辑 void ClientPointToData(CPoint clientPt, double& outX, double& outY); // 内部方法:获取当前坐标轴范围,需根据你CMyChart的内部实现补全逻辑 void GetCurrentAxisRange(double& outXMin, double& outXMax, double& outYMin, double& outYMax); protected: afx_msg void OnMouseMove(UINT nFlags, CPoint point); // 坐标轴修改后调用该方法触发同步通知 void NotifyAxisChange(); DECLARE_MESSAGE_MAP() };
MyChart.cpp 新增内容
BEGIN_MESSAGE_MAP(CMyChart, CWnd) ON_WM_MOUSEMOVE() // 原有其他消息映射全部保留 END_MESSAGE_MAP() void CMyChart::OnMouseMove(UINT nFlags, CPoint point) { // 原有鼠标移动逻辑全部保留,新增如下通知逻辑 double x, y; ClientPointToData(point, x, y); ChartNotifyData notifyData; GetCurrentAxisRange(notifyData.axisXMin, notifyData.axisXMax, notifyData.axisYMin, notifyData.axisYMax); notifyData.dataX = x; notifyData.dataY = y; // 发送消息到父窗口(即CMyDlg) GetParent()->SendMessage(WM_CHART_MOUSEMOVE, GetDlgCtrlID(), (LPARAM)¬ifyData); CWnd::OnMouseMove(nFlags, point); } void CMyChart::NotifyAxisChange() { ChartNotifyData notifyData; GetCurrentAxisRange(notifyData.axisXMin, notifyData.axisXMax, notifyData.axisYMin, notifyData.axisYMax); GetParent()->SendMessage(WM_CHART_AXIS_CHANGED, GetDlgCtrlID(), (LPARAM)¬ifyData); } // 以下两个方法需要根据你CMyChart的内部渲染逻辑补全 void CMyChart::SetCustomCursorPos(double x, double y) { // 实现逻辑:将传入的数据坐标转成当前控件的客户区坐标,在对应位置绘制自定义光标后刷新控件 } void CMyChart::SetAxisRange(double xMin, double xMax, double yMin, double yMax) { // 实现逻辑:修改当前控件的坐标轴参数为传入值,刷新控件 // 注意:此处不要调用NotifyAxisChange(),避免触发循环同步 }
3. 改造CMyDlg对话框类
MyDlg.h 新增内容
class CMyDlg : public CDialog { // 原有代码全部保留,新增如下内容 protected: afx_msg LRESULT OnChartMouseMove(WPARAM wParam, LPARAM lParam); afx_msg LRESULT OnChartAxisChanged(WPARAM wParam, LPARAM lParam); private: BOOL m_bIsSyncing = FALSE; // 同步锁,双重避免循环触发 };
MyDlg.cpp 修改内容
BEGIN_MESSAGE_MAP(CMyDlg, CDialog) ON_MESSAGE(WM_CHART_MOUSEMOVE, &CMyDlg::OnChartMouseMove) ON_MESSAGE(WM_CHART_AXIS_CHANGED, &CMyDlg::OnChartAxisChanged) // 原有其他消息映射全部保留 END_MESSAGE_MAP() LRESULT CMyDlg::OnChartMouseMove(WPARAM wParam, LPARAM lParam) { ChartNotifyData* pData = (ChartNotifyData*)lParam; int senderId = (int)wParam; if (senderId == IDC_CHART_TOP) { m_ChartBottom.SetCustomCursorPos(pData->dataX, pData->dataY); } else if (senderId == IDC_CHART_BOTTOM) { m_ChartTop.SetCustomCursorPos(pData->dataX, pData->dataY); } return 0; } LRESULT CMyDlg::OnChartAxisChanged(WPARAM wParam, LPARAM lParam) { if (m_bIsSyncing) return 0; ChartNotifyData* pData = (ChartNotifyData*)lParam; int senderId = (int)wParam; m_bIsSyncing = TRUE; if (senderId == IDC_CHART_TOP) { m_ChartBottom.SetAxisRange(pData->axisXMin, pData->axisXMax, pData->axisYMin, pData->axisYMax); } else if (senderId == IDC_CHART_BOTTOM) { m_ChartTop.SetAxisRange(pData->axisXMin, pData->axisXMax, pData->axisYMin, pData->axisYMax); } m_bIsSyncing = FALSE; return 0; }
补充说明
你需要在所有修改CMyChart坐标轴的操作(比如缩放、平移、手动修改范围等)执行完成后,调用NotifyAxisChange()方法触发同步通知即可完成双向同步。
内容的提问来源于stack exchange,提问作者id347627
相关产品推荐
相关产品推荐

