我正在编写一个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() ,或使用 RedrawWindow() 强制立即重绘:

CPicture myPicture;

myPicture.Invalidate();

要么
myPicture.RedrawWindow();



为了传递数据,可以在CPicture类(或程序中的其他位置)中声明包含该数据的结构,然后可以从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()中(您还应该将原始笔刷选择回设备上下文中,以避免资源泄漏):
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
  • 对于该图的
  • ,您具有从PicControl派生的CStatic,并且该控件位于对话框上。
  • 从主线程
  • 开始,一个工作线程开始读取数据。



  • 我将在此处尝试简短描述其中一种可能性,因为这实际上应该是一个单独的问题。

    首先,PicControl的对象必须是CLongbowDlg的成员,我认为是这种情况(我们称它为m_PicControl)-因此,在CLongbowDlg类中:
    PicControl m_PicControl;
    

    对于数据(我将使用上面的myData作为示例数据):在主线程(对话框)中,创建myData类型的变量:m_data(对于较大的数据,您可以在堆上分配空间,或者使用CArray或一些其他容器):
    myData m_data;
    

    PicControl中,创建一个myData*类型的成员变量,然后在PicControl构造函数中将其设置为NULL。
    myData *m_pData;
    

    OnInitDialog()(主对话框)中,为m_picControl提供指向数据的指针(或者最好在PicControl中创建一个函数来做到这一点):
    m_picControl.m_pData = &m_data;
    

    启动工作线程时,还应为其提供指向m_data的指针和/或指向对话框本身的指针(this)。

    确保使用关键部分保护数据。

    当数据输入时,工作线程可以通过提供的指针对其进行写入。

    PicControl::OnPaint()中,可以通过m_pData访问相同的数据。

    要启动重绘,有几种方法:
  • 使用PicControl内部或主对话框中的计时器,并在每次计时器触发时调用Invalidate()
  • 以控制从工作线程中重绘(例如,当到达一定数量的新数据时),可以使用PostMessage()将消息发布到主对话框(使用启动线程时提供的指针-this指针) )。

    要接收消息,您必须在主对话框中创建一个消息处理程序,然后在其中调用Invalidate()上的m_picControl(您也可以将消息直接发布到PicControl,但我更喜欢通过主窗口来执行)。
  • 10-08 09:14