在 C++ MFC 应用程序中绘制图形
Drawing a Graph in C++ MFC App
我正在编写 C++ MFC 应用程序来控制制造环境中的机器。这个应用程序还需要在很短的周期时间内分析大量信息。
出于测试目的和长期维护目的,我需要能够绘制来自控制台上传感器的数据。我可能完全忽略了一个选项(请随意提出其他选项),但我的研究使我使用图片控件。
我使用 OnPaint()
成功绘制了这个控件。我的问题是我需要每隔几秒重新绘制一张新图像,我不能重复调用 OnPaint()
或向它传递数据。
如何创建一个可用于在图片控件上重复绘制的新函数?此外,这是我第一次涉足 MFC 应用程序,因此请在适当的级别上进行解释。谢谢!
class CPicture : public CStatic
{
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnPaint();
};
BEGIN_MESSAGE_MAP(CPicture, CStatic)
ON_WM_PAINT()
END_MESSAGE_MAP()
void CPicture::OnPaint()
{
CPaintDC dc(this); // device context for painting
dc.SelectStockObject(BLACK_BRUSH);
dc.Rectangle(5, 50, 1000, 51);
}
我想问题是如何以及在哪里访问这个
//Picture
class CPicture : public CStatic
{
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnPaint();
vector<Coordinates> GraphData;
};
void CPicture::OnPaint()
{
// device context for painting
CPaintDC dc(this);
// save current brush
CBrush *pOldBrush = (CBrush*)dc.SelectStockObject(BLACK_BRUSH);
int NumPoints = GraphData.size() - 1;
for (int N = 0; N <= NumPoints; N++) {
dc.Rectangle(GraphData[N].x, GraphData[N].y, GraphData[N].x, GraphData[N].y);
}
// select original brush into device contect
dc.SelectObject(pOldBrush);
}
您可以调用 Invalidate()
on your control when new data arrives, or use RedrawWindow()
强制立即重绘:
CPicture myPicture;
myPicture.Invalidate();
或
myPicture.RedrawWindow();
I cannot call OnPaint() repetitively or pass data to it.
要传递数据,可以在 CPicture
class(或程序中的其他地方)中声明包含数据的结构,然后可以从 OnPaint()
:
struct myData {
int value1;
int value2; // or an array, or some other data structure
}
class CPicture : public CStatic
{
DECLARE_MESSAGE_MAP()
public:
myData m_data;
afx_msg void OnPaint();
};
在OnPaint()
中(你也应该select把原来的刷回设备环境,避免资源泄露):
void CPicture::OnPaint()
{
CPaintDC dc(this); // device context for painting
// save current brush
CBrush *pOldBrush = (CBrush*)dc.SelectStockObject(BLACK_BRUSH);
// check pOldBrush - could be NULL
// dc.Rectangle(5, 50, 1000, 51);
// access m_data here, for example
dc.Rectangle(m_data.value1, m_data.value2, 1000, 51);
// select original brush into device contect
dc.SelectObject(pOldBrush);
}
更新(使用线程):
假设如下(来自评论):
对于主线程,您有一个对话框 CLongbowDlg
。
对于图形,您有一个从 CStatic
派生的 PicControl
,并且该控件位于对话框上。
从主线程开始,一个工作线程开始读取数据。
PicControl and CLongbowDlg are defined in the same header, but are
independent of each other. I need to be able to call Invalidate() or
RedrawWindow() from inside CLongbowDlg's functions because they
represent the primary thread.
我将尝试在这里对其中一种可能性进行简短描述,因为这实际上应该是一个单独的问题。
首先,PicControl
的对象必须是 CLongbowDlg
的成员,我假设是这种情况(我们称它为 m_PicControl
)- 所以,在 class CLongbowDlg
:
PicControl m_PicControl;
对于数据(我将使用上面的 myData
作为示例数据):在您的主线程(对话框)中,创建一个类型为 myData
的变量:m_data
(对于更大的数据,您可以在堆上分配 space,或使用 CArray
或其他容器):
myData m_data;
在PicControl
中创建一个myData*
类型的成员变量,并在PicControl构造函数中将其设置为NULL。
myData *m_pData;
在 OnInitDialog()
(主对话框)中,为 m_picControl
提供指向数据的指针(或者最好在 PicControl 中创建一个函数来执行此操作):
m_picControl.m_pData = &m_data;
启动辅助线程时,还为其提供指向 m_data
的指针 and/or 指向对话框本身的指针 (this
)。
确保使用临界区保护数据。
当数据进来时,工作线程可以通过提供的指针写入它。
在PicControl::OnPaint()
中,可以通过m_pData
访问相同的数据。
要启动重绘,有几种方法:
在 PicControl
或主对话框中使用计时器,并在每次计时器触发时调用 Invalidate()
。
控制工作线程的重绘(例如,当一定数量的新数据到达时)可以使用PostMessage()
编辑消息post,以主对话框(使用启动线程时提供的指针 - this
指针)。
要接收消息,您必须在主对话框中创建消息处理程序,然后从那里在 m_picControl
上调用 Invalidate()
(您也可以直接 post 消息到 PicControl,但我更喜欢通过主 window).
我正在编写 C++ MFC 应用程序来控制制造环境中的机器。这个应用程序还需要在很短的周期时间内分析大量信息。
出于测试目的和长期维护目的,我需要能够绘制来自控制台上传感器的数据。我可能完全忽略了一个选项(请随意提出其他选项),但我的研究使我使用图片控件。
我使用 OnPaint()
成功绘制了这个控件。我的问题是我需要每隔几秒重新绘制一张新图像,我不能重复调用 OnPaint()
或向它传递数据。
如何创建一个可用于在图片控件上重复绘制的新函数?此外,这是我第一次涉足 MFC 应用程序,因此请在适当的级别上进行解释。谢谢!
class CPicture : public CStatic
{
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnPaint();
};
BEGIN_MESSAGE_MAP(CPicture, CStatic)
ON_WM_PAINT()
END_MESSAGE_MAP()
void CPicture::OnPaint()
{
CPaintDC dc(this); // device context for painting
dc.SelectStockObject(BLACK_BRUSH);
dc.Rectangle(5, 50, 1000, 51);
}
我想问题是如何以及在哪里访问这个
//Picture
class CPicture : public CStatic
{
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnPaint();
vector<Coordinates> GraphData;
};
void CPicture::OnPaint()
{
// device context for painting
CPaintDC dc(this);
// save current brush
CBrush *pOldBrush = (CBrush*)dc.SelectStockObject(BLACK_BRUSH);
int NumPoints = GraphData.size() - 1;
for (int N = 0; N <= NumPoints; N++) {
dc.Rectangle(GraphData[N].x, GraphData[N].y, GraphData[N].x, GraphData[N].y);
}
// select original brush into device contect
dc.SelectObject(pOldBrush);
}
您可以调用 Invalidate()
on your control when new data arrives, or use RedrawWindow()
强制立即重绘:
CPicture myPicture;
myPicture.Invalidate();
或
myPicture.RedrawWindow();
I cannot call OnPaint() repetitively or pass data to it.
要传递数据,可以在 CPicture
class(或程序中的其他地方)中声明包含数据的结构,然后可以从 OnPaint()
:
struct myData {
int value1;
int value2; // or an array, or some other data structure
}
class CPicture : public CStatic
{
DECLARE_MESSAGE_MAP()
public:
myData m_data;
afx_msg void OnPaint();
};
在OnPaint()
中(你也应该select把原来的刷回设备环境,避免资源泄露):
void CPicture::OnPaint()
{
CPaintDC dc(this); // device context for painting
// save current brush
CBrush *pOldBrush = (CBrush*)dc.SelectStockObject(BLACK_BRUSH);
// check pOldBrush - could be NULL
// dc.Rectangle(5, 50, 1000, 51);
// access m_data here, for example
dc.Rectangle(m_data.value1, m_data.value2, 1000, 51);
// select original brush into device contect
dc.SelectObject(pOldBrush);
}
更新(使用线程):
假设如下(来自评论):
对于主线程,您有一个对话框
CLongbowDlg
。对于图形,您有一个从
CStatic
派生的PicControl
,并且该控件位于对话框上。从主线程开始,一个工作线程开始读取数据。
PicControl and CLongbowDlg are defined in the same header, but are independent of each other. I need to be able to call Invalidate() or RedrawWindow() from inside CLongbowDlg's functions because they represent the primary thread.
我将尝试在这里对其中一种可能性进行简短描述,因为这实际上应该是一个单独的问题。
首先,PicControl
的对象必须是 CLongbowDlg
的成员,我假设是这种情况(我们称它为 m_PicControl
)- 所以,在 class CLongbowDlg
:
PicControl m_PicControl;
对于数据(我将使用上面的 myData
作为示例数据):在您的主线程(对话框)中,创建一个类型为 myData
的变量:m_data
(对于更大的数据,您可以在堆上分配 space,或使用 CArray
或其他容器):
myData m_data;
在PicControl
中创建一个myData*
类型的成员变量,并在PicControl构造函数中将其设置为NULL。
myData *m_pData;
在 OnInitDialog()
(主对话框)中,为 m_picControl
提供指向数据的指针(或者最好在 PicControl 中创建一个函数来执行此操作):
m_picControl.m_pData = &m_data;
启动辅助线程时,还为其提供指向 m_data
的指针 and/or 指向对话框本身的指针 (this
)。
确保使用临界区保护数据。
当数据进来时,工作线程可以通过提供的指针写入它。
在PicControl::OnPaint()
中,可以通过m_pData
访问相同的数据。
要启动重绘,有几种方法:
在
PicControl
或主对话框中使用计时器,并在每次计时器触发时调用Invalidate()
。控制工作线程的重绘(例如,当一定数量的新数据到达时)可以使用
PostMessage()
编辑消息post,以主对话框(使用启动线程时提供的指针 -this
指针)。要接收消息,您必须在主对话框中创建消息处理程序,然后从那里在
m_picControl
上调用Invalidate()
(您也可以直接 post 消息到 PicControl,但我更喜欢通过主 window).