Archived

This topic is now archived and is closed to further replies.

Map Drawing Tool - Help!

This topic is 5148 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi. As research for my Ph.D, I''ve decided to write a map-drawing tool using C++ (and Win32). Eventually I will tie this in with my area of expertise, 3D landscapes. Anyway, I''m very confused at the moment (well, inexperienced might be a better term). I''m working my way through Win32 tutorials. I''m perticularly interested in the painting onto a DC. The map tool I am writing will eventually allow for the user to draw bezier curves on a canvas to create contour lines. Anyway, if you look at the code below :
LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    HDC hDC;
    PAINTSTRUCT Ps;

    switch(Msg)
    {
    case WM_PAINT:
	hDC = BeginPaint(hWnd, &Ps);
	MoveToEx(hDC, 60, 20, NULL);
	LineTo(hDC, 264, 122);
	EndPaint(hWnd, &Ps);
	break;
    case WM_DESTROY:
        PostQuitMessage(WM_QUIT);
        break;
    default:
        return DefWindowProc(hWnd, Msg, wParam, lParam);
    }
    return 0;
}
 
http://www.functionx.com/win32/images/line2.gif You can see a very simple instuctions to draw a single line in a window. The part I''m confused with is the WM_PAINT case. Is this required for drawing lines/shapes to screen? Does all the drawing have to be done from within this switch statement (which handles the window messages). I mean, obviously if this is the case then there will be a lot of code here. What I want to do is have a lot of functions dealing with the various paint instructions (draw straight line tool, draw bezier curve tool etc). Is it possible to split this code from the switch case? I''m sorry if this is vague or completely wrong, but I''ve only started to learn Win32 programing! I would be very grateful for any help! Super Furry Animal.

Share this post


Link to post
Share on other sites
Oopd, you posted a different question. WM_PAINT is called everytime the window is repainted, I think. Obviously, you should make a function that handles the painting, and call that single function from WM_PAINT in the switch statement.

Share this post


Link to post
Share on other sites
It''s not necessary, it is merely very convenient to handle all drawing when the WM_PAINT message comes. That''s basically MS Windows telling your program "you need to update/redraw your window graphics now. some part of it might be out of date". The operating system keeps track of when other programs'' windows overlaps your own, and when your program receives focus again, you get your WM_PAINT message.
But it is possible to paint with a DC at any time in your application.

That said, it is as MDI said... You could, but shouldn''t have all the drawing-code in WndProc. It would simply be bad disposition... Call a function, but keep WndProc short so it''s easy to grasp and overview.

Good luck with your PhD!

Note: If you wish to do animated graphics I''d recommend a different design

Share this post


Link to post
Share on other sites
Thanks for the replies guys. I've managed to get things working now, but I think I've got a problem with re-drawing to the DC.

Here's the code, in its entirity (which isn't very much!)


#include <windows.h>



#define ID_FILE_EXIT 9001
#define ID_STUFF_GO 9002
#define ID_FILE_FUCK 9003
#define ID_FILE_SHIT 9004

int x_window_size = 480;
int y_window_size = 640;
int scale = 10;
bool DrawFlag = true;

const char g_szClassName[] = "myWindowClass";
HBITMAP g_hbmBall = NULL;
HWND hwnd;
HDC hDC;
PAINTSTRUCT Ps;




void StartDrawing()
{
hDC = BeginPaint(hwnd, &Ps);
}



void EndDrawing()
{
EndPaint(hwnd, &Ps);
}




void DrawGrid()
{
for(int grid_p =0; grid_p < y_window_size; grid_p+=scale)
{
MoveToEx(hDC, 0, grid_p, NULL);
LineTo(hDC, x_window_size, grid_p);
}

for(int grid_p =0; grid_p < x_window_size; grid_p+=scale)
{
MoveToEx(hDC, grid_p, 0, NULL);
LineTo(hDC, grid_p, y_window_size );
}
}




void Draw()
{
StartDrawing();
if(DrawFlag == true)
DrawGrid();
EndDrawing();
}





LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{

switch(msg)
{
case WM_KEYDOWN:
switch(wParam)
{
case VK_ADD:
{
DrawFlag = true;
break;
}

case VK_SUBTRACT:
{
DrawFlag = false;
break;
}
}
break;


case WM_PAINT:
Draw();
break;


case WM_CREATE:
{
HMENU hMenu, hSubMenu;
HICON hIcon, hIconSm;

hMenu = CreateMenu();

hSubMenu = CreatePopupMenu();
AppendMenu(hSubMenu, MF_STRING, ID_FILE_FUCK, "O&pen");
AppendMenu(hSubMenu, MF_STRING, ID_FILE_SHIT, "N&ew");
AppendMenu(hSubMenu, MF_STRING, ID_FILE_EXIT, "E&xit");
AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu, "&File");

hSubMenu = CreatePopupMenu();
AppendMenu(hSubMenu, MF_STRING, ID_STUFF_GO, "&Go");
AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu, "&Stuff");

SetMenu(hwnd, hMenu);
}
break;

case WM_COMMAND:
switch(LOWORD(wParam))
{
case ID_FILE_EXIT:
PostQuitMessage(0);
break;
case ID_FILE_FUCK:

break;

case ID_STUFF_GO:

break;
}


case WM_LBUTTONDOWN:
{
// char szFileName[MAX_PATH];
// HINSTANCE hInstance = GetModuleHandle(NULL);

// GetModuleFileName(hInstance, szFileName, MAX_PATH);
// MessageBox(hwnd, szFileName, "This program is:", MB_OK | MB_ICONINFORMATION);
}
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
MSG Msg;

wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

if(!RegisterClassEx(&wc))
{
MessageBox(NULL, "Window Registration Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}

hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
g_szClassName,
"SFA's Amazing Program",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, x_window_size, y_window_size,
NULL, NULL, hInstance, NULL);

if(hwnd == NULL)
{
MessageBox(NULL, "Window Creation Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}

ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);

while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;

}




What the program does is draw a grid in the window. The grid is scalable, so changing the scale allows for zooming in and out.

What I want to do is allow the user to use the + and - keys to zoom in and out of the map.

I've tried changing the value of the global variable 'scale' when the user hits the + key, but that does absolutely nothing. So what I've done here is have a draw flag just as a test to see if the window updates properly. Which it doesn't. What should happen is that hitting the - key will turn the flag off, and nothing should be drawn. Hitting the + key again draws the grid to screen. But it doesn't work.

Any help would be cool!
SFA.

[edited by - SFA on November 12, 2003 6:29:53 PM]

[edited by - SFA on November 12, 2003 6:30:50 PM]

[edited by - SFA on November 12, 2003 6:31:18 PM]

Share this post


Link to post
Share on other sites

As you said, you DO need to change the value of ''scale'' when the + and - messages come across. But the actual problem is that your window is not being refreshed. You either need to clear/fill the DC before each redraw or force the window to repaint. If you put the change to ''scale'' back in and hit the + or - a few times then minimize and restore your window you will see that for the most part your code is working.

Share this post


Link to post
Share on other sites
Oh Yeah! Thanks for that. If I minimize and then maximize, the scale does indeed change!

Question - What''s the command for refreshing the window, and where would I put it?

Share this post


Link to post
Share on other sites
quote:
Original post by SFA
Oh Yeah! Thanks for that. If I minimize and then maximize, the scale does indeed change!

Question - What''s the command for refreshing the window, and where would I put it?


I was affraid you would ask that

I''m sorry but it''s been so long since I''ve done WinGDI that I honestly don''t remember how to do it.

Hopefully someone else will have the answer for you.

Share this post


Link to post
Share on other sites
I have found that scaling is much easier when double buffering in GDI. I always draw the same scale to the back buffer and then scale when flipping by using StretchBlit. Of course this limits me to powers of 2 (2x,4x,6x,8x...) zoom like MS Paint but it is easy to reduce the size of the source rect by powers of 2 when "flipping".


Evillive2
E-Mail

Share this post


Link to post
Share on other sites
quote:
Original post by RuneLancer
Just send a WM_PAINT message to your program

A better option is to call .invalidate() on the component that needs redrawing. This means that the redraw event comes in at a suitable time (and may be merged with an already queued repaint event).

Share this post


Link to post
Share on other sites
Another thing you might want to change is the use of BeginPaint - it is a special function that sets clipping values so you only update the part of the window that needs repainting (when the WM_PAINT message is called). If you want to draw anywhere on the window, you probably want to use GetDC and ReleaseDC instead.

Also, as has been mentioned, you might want to do double buffering to avoid flicker. In order to do that, you need to use CreateCompatibleDC to make a new DC, then CreateCompatableBitmap to make a buffer for it, then SelectObject to tell the compatable DC to use the compatable Bitmap:

HDC memDC = CreateCompatibleDC ( hDC );
HBITMAP memBM = CreateCompatibleBitmap ( hDC );
SelectObject ( memDC, memBM );

Then you can draw into memDC and use BitBlt to copy its image to the window.

Share this post


Link to post
Share on other sites