简体   繁体   English

在C ++ MFC应用程序中绘制图形

[英]Drawing a Graph in C++ MFC App

I am writing a C++ MFC application to control a machine in a manufacturing setting. 我正在编写一个C ++ MFC应用程序来控制制造环境中的机器。 This app also needs to analyze a lot of information in a very short cycle time. 此应用程序还需要在非常短的周期内分析大量信息。

For testing purposes and long term maintenance, I need to be able to graph data coming from a sensor on the console. 出于测试目的和长期维护,我需要能够在控制台上绘制来自传感器的数据。 I may have totally overlooked an option (feel free to propose other options) but my research has taken me to using a picture control. 我可能完全忽略了一个选项(随意提出其他选项),但我的研究让我使用了图片控件。

I am successfully drawing in this control by use of OnPaint() . 我通过使用OnPaint()成功地绘制了这个控件。 My issue is that I need to redraw a new image every few seconds and I cannot call OnPaint() repetitively or pass data to it. 我的问题是我需要每隔几秒重绘一个新图像,我不能重复调用OnPaint()或将数据传递给它。

How can I create a new function that can be used to draw on the picture control repetitively? 如何创建一个可用于重复绘制图片控件的新功能? Also, this is my first foray into an MFC app so please explain on an appropriate level. 此外,这是我第一次涉足MFC应用程序,所以请在适当的级别进行解释。 Thanks! 谢谢!

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);
}

I guess the question is how and where to access this 我想问题是如何以及在何处访问它

//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);
}

You can call Invalidate() on your control when new data arrives, or use RedrawWindow() to force an immediate redraw: 您可以在新数据到达时在控件上调用Invalidate() ,或使用RedrawWindow()强制立即重绘:

CPicture myPicture;

myPicture.Invalidate();

or 要么

myPicture.RedrawWindow();

I cannot call OnPaint() repetitively or pass data to it. 我不能重复调用OnPaint()或将数据传递给它。

To pass data, a structure containg the data can be declared inside your CPicture class (or some place else in your program), and that data can then be accessed from within OnPaint() : 要传递数据,可以在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();
};

In OnPaint() (you should also select the original brush back into the device context to avoid resource leaks): 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);
}

Update (working with threads): 更新 (使用线程):

Assuming the following (from the comments): 假设以下(来自评论):

  • for the main thread you have a dialog CLongbowDlg . 对于主线程,你有一个对话框CLongbowDlg

  • for the graph, you have a PicControl derived from CStatic , and that control is placed on the dialog. 对于图形,您有一个从CStatic派生的PicControl ,该控件放在对话框中。

  • from the main thread, a worker thread is started to read the data. 从主线程开始,工作线程开始读取数据。

PicControl and CLongbowDlg are defined in the same header, but are independent of each other. PicControl和CLongbowDlg在同一标头中定义,但彼此独立。 I need to be able to call Invalidate() or RedrawWindow() from inside CLongbowDlg's functions because they represent the primary thread. 我需要能够从CLongbowDlg函数内部调用Invalidate()或RedrawWindow(),因为它们代表主线程。

I'll try to give a short description of one of the possibilities here, because this should actually be a seperate question. 我将尝试简要介绍一下这里的一种可能性,因为这实际上应该是一个单独的问题。

Firstly, an object of PicControl has to be a member of CLongbowDlg , which I assume is the case (let's call it m_PicControl ) - So, in class CLongbowDlg : 首先的一个目的PicControl必须是成员CLongbowDlg ,我以为是这样(我们称之为m_PicControl ) -那么,在课堂上CLongbowDlg

PicControl m_PicControl;

For the data (I'll be using the above myData as example data): in your main thread (the Dialog), create a variable of type myData : m_data (for larger data you could allocate space on the heap, or use CArray or some other container): 对于数据(我将使用上面的myData作为示例数据):在主线程(Dialog)中,创建一个myData类型的变量: m_data (对于较大的数据,您可以在堆上分配空间,或者使用CArray或其他一些容器):

myData m_data;

In PicControl create a member variable of type myData* and set it to NULL in the PicControl constructor. PicControl创建myData*类型的成员变量,并在PicControl构造函数中将其设置为NULL。

myData *m_pData;

In OnInitDialog() (main dialog), provide m_picControl with a pointer to the data (or better create a function to do that in PicControl): OnInitDialog() (主对话框)中,为m_picControl提供一个指向数据的指针(或者更好地创建一个在PicControl中执行此操作的函数):

m_picControl.m_pData = &m_data;

When starting the worker thread, also provide it a pointer to m_data and/or a pointer to the dialog itself ( this ). 启动工作线程时,还要为它提供指向m_data的指针和/或指向对话框本身的指针( this )。

Make sure to protect the data with a critical section. 确保使用关键部分保护数据。

When data comes in, the worker thread can write to it via the provided pointer. 当数据进入时,工作线程可以通过提供的指针写入它。

In PicControl::OnPaint() , the same data can be accessed through m_pData . PicControl::OnPaint() ,可以通过m_pData访问相同的数据。

To initiate a redraw, there are several ways: 要启动重绘,有以下几种方法:

  • use a timer inside PicControl or in the main dialog, and call Invalidate() every time the timer fires. PicControl或主对话框中使用计时器,并在每次计时器触发时调用Invalidate()

  • to control the redrawing from the worker thread (when a certain amount of new data has arrived for example) a message can be posted, using PostMessage() , to the main dialog (using the pointer that was provided when starting the thread - the this pointer). 控制从工作线程重绘(例如,当有一定数量的新数据到达时)可以使用PostMessage()将消息发布到主对话框(使用启动线程时提供的指针 - this指针)。

    To receive the message you'll have to create a message handler in the main dialog, and from there call Invalidate() on m_picControl (you could also post a message directly to PicControl, but I prefer to do it via the main window). 要接收消息,您必须在主对话框中创建消息处理程序,并从那里调用m_picControl上的Invalidate() (您也可以直接向PicControl发送消息,但我更喜欢通过主窗口执行此操作)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM