user3420063
user3420063

Reputation: 13

In windows 7 or higher: How to display points connected by lines on a monitor, in C++ using GDI+?

I have the following:

Program starts running:

INPUT: from console window, in windows 7 (or higher), the program asks the user for integer numbers, which represent points: y and x for each point (2D-coordinates).

OUTPUT: the program then using these points should display (on the monitor) the points themselves, and lines connecting the points, in a window.

program stops running

All this written in c++, using Codeblocks, and GDI+. My problem is that I can't seem to connect the input from the console to the output with GID+, is it even possbile?

I'm new with c++, and specially with graphics, have no previous programming experience. Looking around on the net, besides the surprisingly low quality, and scarce information about the subject, GDI+ was the solution I concluded. I want the simplest solution possible. Any ideas?

#include <abrazol.h>

using namespace std;

struct koordinata {
 int x;
 int y;
};


int main(){

vector<koordinata> abrazol;

abrazol = koordinataszamol(); //Ignore this, it calculates with 
//the coordinate points, asks the user for the x and y values
//of the points, returns a struct type (koordinata) of vector.


HDC hd;
int a=0;

for (int i=0; i<abrazol.size()-1; i++){

    Drawpoint(hd,abrazol[i]);
    Drawpoint(hd,abrazol[i+1]);
    OnPaint(hd,abrazol[i],abrazol[i+1]);
    a++;

}

    OnPaint(hd,abrazol[a+1],abrazol[0]);

return 0;

}

abrazol.cpp (h)

#include <windows.h>
#include <objidl.h>
#include <gdiplus.h>
#include <stdio.h>
#include <iostream>
#include <koordinataszamol.h>


#pragma comment (lib,"Gdiplus.lib")


using namespace Gdiplus;

VOID OnPaint(HDC hdc, koordinata pont1, koordinata pont2)
{
   Graphics graphics(hdc);
   Pen      pen(Color(255, 0, 0, 255));
   graphics.DrawLine(&pen, pont1.x, pont1.y, pont2.x, pont2.y);


}

VOID Drawpoint(HDC hdc, koordinata pont){

    Graphics graphics(hdc);
    Pen blackPen(Color(255, 0, 0, 0), 3);
    int width = 2;
    int height = 2;
    graphics.DrawRectangle(&blackPen, pont.x-1, pont.y-1, width, height);

}





LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, PSTR, INT iCmdShow)
{
   HWND                hWnd;
   MSG                 msg;
   WNDCLASS            wndClass;
   GdiplusStartupInput gdiplusStartupInput;
   ULONG_PTR           gdiplusToken;

   // Initialize GDI+.
   GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

   wndClass.style          = CS_HREDRAW | CS_VREDRAW;
   wndClass.lpfnWndProc    = WndProc;
   wndClass.cbClsExtra     = 0;
   wndClass.cbWndExtra     = 0;
   wndClass.hInstance      = hInstance;
   wndClass.hIcon          = LoadIcon(NULL, IDI_APPLICATION);
   wndClass.hCursor        = LoadCursor(NULL, IDC_ARROW);
   wndClass.hbrBackground  = (HBRUSH)GetStockObject(WHITE_BRUSH);
   wndClass.lpszMenuName   = NULL;
   wndClass.lpszClassName  = TEXT("GettingStarted");

   RegisterClass(&wndClass);

   hWnd = CreateWindow(
      TEXT("GettingStarted"),   // window class name
      TEXT("Getting Started"),  // window caption
      WS_OVERLAPPEDWINDOW,      // window style
      CW_USEDEFAULT,            // initial x position
      CW_USEDEFAULT,            // initial y position
      CW_USEDEFAULT,            // initial x size
      CW_USEDEFAULT,            // initial y size
      NULL,                     // parent window handle
      NULL,                     // window menu handle
      hInstance,                // program instance handle
      NULL);                    // creation parameters

   ShowWindow(hWnd, iCmdShow);
   UpdateWindow(hWnd);

   while(GetMessage(&msg, NULL, 0, 0))
   {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
   }

   GdiplusShutdown(gdiplusToken);
   return msg.wParam;
}  // WinMain

LRESULT CALLBACK WndProc(HWND hWnd, UINT message,
  WPARAM wParam, LPARAM lParam)
{
   HDC          hdc;
   PAINTSTRUCT  ps;
   switch(message)
   {
   case WM_PAINT:
      hdc = BeginPaint(hWnd, &ps);
      koordinata pont1;
      koordinata pont2;
      OnPaint(hdc,pont1,pont2);
      EndPaint(hWnd, &ps);
      return 0;
   case WM_DESTROY:
      PostQuitMessage(0);
      return 0;
   default:
      return DefWindowProc(hWnd, message, wParam, lParam);
   }
} // WndProc

I suspect I can't modify the parameters of the OnPaint function, then how am I supposed to draw from run-time parameters???

Upvotes: 0

Views: 112

Answers (1)

Jerry Coffin
Jerry Coffin

Reputation: 490278

I doubt you gain anything from using GDI+ in this case. The drawing is pretty trivial just using GDI.

As far as your basic question of how to change the drawing without changing the parameters to OnPaint, it's generally pretty simple: you decide on some place the data will be stored. As the data's entered, you store it there. OnPaint retrieves the data from there, and draws it to the screen.

In this case, you probably want to make that something like std::vector<point>, where point is a type that holds an x and y coordinate.

I did a quick hack of a program roughly as you describe, letting you enter some points, then drawing them in a window (using a window class I had lying around to handle most of the window creation, initialization and such). Here's some code:

#include <iostream>
#include <string>
#include <vector>
#include <windows.h>

struct point {
    int x;
    int y;

    point() = default;
    point(int x, int y) : x(x), y(y) { }

    friend std::istream &operator>>(std::istream &is, point &p) {
        return is >> p.x >> p.y;
    }
};

struct Window {
    virtual void OnPaint(HDC) = 0;

    Window(std::string const &name) : hInstance(GetModuleHandle(NULL)) {      
        wndClass.style = CS_HREDRAW | CS_VREDRAW;
        wndClass.lpfnWndProc = WndProc;
        wndClass.cbClsExtra = 0;
        wndClass.cbWndExtra = 0;
        wndClass.hInstance = hInstance;
        wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
        wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
        wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
        wndClass.lpszMenuName = NULL;
        wndClass.lpszClassName = name.c_str();
        RegisterClass(&wndClass);

        hWnd = CreateWindow(
            TEXT(name.c_str()),  
            TEXT(name.c_str()),  
            WS_OVERLAPPEDWINDOW, 
            CW_USEDEFAULT,       
            CW_USEDEFAULT,       
            CW_USEDEFAULT,       
            CW_USEDEFAULT,       
            NULL,                
            NULL,                
            hInstance,           
            (PVOID)this);               
    }

    WPARAM operator()() {
        MSG msg;

        ShowWindow(hWnd, SW_SHOWNORMAL);
        UpdateWindow(hWnd);

        while (GetMessage(&msg, NULL, 0, 0)) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

        return msg.wParam;
    }

private:

    HINSTANCE hInstance;
    HWND hWnd;
    WNDCLASS wndClass;

    static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
        HDC          hdc;
        PAINTSTRUCT  ps;
        static Window *w;

        switch (message) {
            case WM_CREATE:
                w = static_cast<Window *>(((CREATESTRUCT *)lParam)->lpCreateParams);
                break;
            case WM_PAINT:
                hdc = BeginPaint(hWnd, &ps);
                w->OnPaint(hdc);
                EndPaint(hWnd, &ps);
                return 0;
            case WM_DESTROY:
                PostQuitMessage(0);
                return 0;
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
        }
        return 0;
    }

};

class disp_window : public Window {
    std::vector<point> points;
public:
    disp_window(std::string const &t) : Window(t) { }

    virtual void OnPaint(HDC hDC) {
        if (points.empty())
            return;
        MoveToEx(hDC, points[0].x, points[0].y, nullptr);
        for (int i = 1; i < points.size(); i++)
            LineTo(hDC, points[i].x, points[i].y);
    }

    std::vector<point> &data() { return points; }
};

int main() {
    disp_window w("Getting Started");

    std::cout << "Please enter some points: ";
    point p;
    while (std::cin >> p)
        w.data().push_back(p);

    w();
}

With Visual C++, you can compile this on the command line like:

cl simple_win.cpp user32.lib kernel32.lib gdi32.lib

With MinGW, the command line would look like this:

g++ -std=c++11 simple_win.cpp -luser32 -l gdi32 -lkernel32

When you run it, it prints out the prompt, and you enter points with the numbers just separated by spaces (or tabs or enter):

Please enter some points: 1 1
100 100
100 200
200 300
^Z

(the control-Z is just letting it know that the input has ended).

It then pops up a window like this:

enter image description here

I should probably add that this isn't really the most efficient way to do things--just something I hacked together in a few minutes. For example, if you're going to have very many points, you probably want to look up PolyLine instead of using MoveTo/LineTo. I haven't bothered to include the code to draw a square (or whatever) at each point either--adding that to the disp_window::OnPaint should be pretty trivial though.

Upvotes: 1

Related Questions