1
votes

In my small, small and humble c++ Win32 GUI application, I got to the point of being able to draw a grid :

enter image description here

This is in preparation for displaying spectral data, the 36 (floats) measurement points returned from my device. I still have to get the axis labeled... This is my code for drawing the grid so far :

case WM_PAINT:
{
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hWnd, &ps);    

    FillRect(hdc, &ps.rcPaint, HBRUSH (COLOR_WINDOW + 1));  

    bool Retour;
    
    pen = (HPEN)GetStockObject(TRANSPARENT);
    SelectObject(hdc, pen);

    Brosse = CreateSolidBrush(RGB(240, 240, 240));
    SelectObject(hdc, Brosse);

    Retour = LineTo(hdc, 100, 500);*/

    Retour = Rectangle(hdc, 350, 150, 750, 375);

    for (int i = 380; i <= 730; i=i+10) {   // 36 vertical lines
        MoveToEx(hdc, i, 175, NULL);
        LineTo(hdc, i, 350);
    }
    for (int i = 175; i <= 350; i = i + 17) {
        MoveToEx(hdc, 375, i, NULL);
        LineTo(hdc, 730, i);
    }

    DeleteObject(pen);
    DeleteObject(Brosse);

    EndPaint(hWnd, &ps);

As you can see, I located the code to draw the grid inside the WM_PAINT procedure. It made sense to locate the code there to experiment with GDI instructions but also because the grid needs to be visible at launch time as part of the interface.

My question is how should I go "updating" the graph when, after pressing the "Measure Sample" button, I have access to the data? I gather that the code to draw on the grid does not necessarily needs to be located inside the WM_PAINT procedure, does it? According to my limited understanding, as long as I can get a Device Context handle (hDC), I should be good to go? All I need to plot is a "line" uniting the 36 data points from left to right. Not sure I should use simple MOVE_TO and LINE_TO for this purpose? I think there is a way to draw a "smoothed" line that passes through all 36 data points?

One last thing, if I may... I'm going at this in a very elementary way because I'm intimidated by the idea of using a "graphic library" and objects. But I suspect they would make my life a lot easier while offering umpteen options that will take me too long to figure out, I'll bet, and implement?

Thank you so much in advance for your kind help and patience.

2
SelectObject transfers ownership of resources. The resource selected into the device context is owned by the DC, with the object previously selected into the DC is now your responsibility. With that, it's always a mistake to delete an object while it is still selected into a DC. The most common pattern here is: 1 Select object into DC, 2 use the object, 3 select the object back out of (by selecting the previous object into) the DC, 4 clean up your resources. Also make sure to read WM_PAINT message.IInspectable
Quite unrelated to this issue, you might want to see Enabling Visual Styles. It doesn't involve writing any code, but will make your next screenshot look distinctly different. Unarguably better, too.IInspectable

2 Answers

2
votes

You should always do all your drawing in your WM_PAINT handler. That way, the window will redraw correctly when something that was covering it is removed, for example.

When your graph data changes, call InvalidateRect to prompt a redraw.

To determine what to redraw, you will need to pass suitable variables to your WM_PAINT handler. Start with MoveTo and LineTo (or Polyline or PolyPolyline) and get that working first. You can then investigate smoothing algorithms if you think you need them.

0
votes

You should place all of your custom painting code in the WM_PAINT handler of the window, yes. You can call a separate function for painting the graph if you like. Pass it the HDC you get from BeginPaint(...) and your spectral data. However, that function needs to be called from the WM_PAINT handler.

If you handle painting in WM_PAINT then to update the graph when the data changes you would call InvalidateRect(...) on the window. InvalidateRect tells Windows essentially "this window has changed and needs to be repainted". It will drive a call to the paint handler.

One problem you are going to run into is that your graph is going to flicker. It may not be too noticeable. It may not bother you, but the problem is that in each call to the WM_PAINT handler you are erasing the graph in the screen device context; this erasure will be visible. A solution to this problem would be to "double-buffer" the graph: create an offscreen bitmap, paint into that when data changes, and paint the offscreen bitmap to the screen in WM_PAINT. You could also make the graph a separate child window that manages the offscreen bitmap, etc., if you are ever going to need multiple graphs or just to add some modularity to the code.

As for whether you'd have an easier time with a graphics library ... possibly, but more to the point: you would have an easier time using a higher level GUI library than the Win32 API. If you only care about Windows, consider the .Net frameworks WinForms or WPF. Otherwise, consider Qt.