-
Draw Program Not Working
This program is supposed to draw a randomly colored dot (connected by a line of the same color) at a random location on the screen when I click "Start", then exit when I click ESCAPE. When I click "Start", though, nothing happens. :mad:
Code:
//FILE: main.c
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <wingdi.h>
#include <stdlib.h>
#include "resource.h"
#include <stdio.h>
#define WM_START 12342649
HINSTANCE hInst;
void draw(HDC, int, int, int, int);
int x=1, y=1;
HDC me;
WINDOWPLACEMENT wp;
BOOL CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_INITDIALOG:
//SetBkColor(GetDC(NULL), RGB(0,0,0));
return TRUE;
case WM_CLOSE:
EndDialog(hwndDlg, 0);
return TRUE;
case WM_COMMAND:
switch(LOWORD(lParam))
{
case 2222:
MessageBox(hwndDlg, "start", "", MB_OK);
while(!(GetKeyState(VK_ESCAPE)&0b10000000)) {
while(((x=rand())<1024)&&(x>1));
while(((y=rand())<685)&&(x>23));
draw(me, 10, 10, x, y);
Sleep(300);
}
EndDialog(hwndDlg, 0);
return TRUE;
}
}
return FALSE;
}
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
hInst = hInstance;
// The user interface is a modal dialog box
return DialogBox(hInstance, MAKEINTRESOURCE(DLG_MAIN), NULL, (DLGPROC)DialogProc);
}
void draw(HDC dc, int x, int y, int xpos, int ypos)
{
srand(xpos*ypos);
//int ca=0, cb=0, cd=0;
COLORREF color;
//HPEN pen=CreatePen(PS_SOLID, 20);
LOGBRUSH mbrush;
/*while((ca=rand())<=0xFF);
while((ca=rand())<=0xFF);
while((ca=rand())<=0xFF);*/
COLORREF rnd=RGB(rand()&0xFF, rand()&0xFF, rand()&0xFF);
mbrush.lbStyle=BS_SOLID;
mbrush.lbColor=rnd;
mbrush.lbHatch=0;
HBRUSH brush=CreateBrushIndirect(&mbrush);
SelectObject(dc, (HGDIOBJ)brush);
LineTo(dc, xpos, ypos);
color=rnd;
//color=RGB(xpos, 0, 0);
int xx, yy;
for(xx=0; xx<x; xx++)
{
for(yy=0; yy<y; yy++)
{
SetPixel(dc, xx+xpos, yy+ypos, color);
}
}
}
Code:
//FILE: resource.h
#include <windows.h>
// ID of Main Dialog
#define DLG_MAIN 101
Code:
//FILE: resource.rc
#include "resource.h"
DLG_MAIN DIALOGEX 6, 5, 194, 106
CAPTION ""
STYLE DS_MODALFRAME | DS_SHELLFONT | WS_CAPTION | WS_VISIBLE | WS_POPUP | WS_SYSMENU
BEGIN
PUSHBUTTON "Start", 2222/*ID*/, 7, 7, 47, 22
END
What is wrong????? (Probably alot)
NOTE: Some of these functions I have just started using today.
-
Take a look at some Win API reference manual, it will be a great help.
Why the MessageBox is not displayed on start-click? See the WM_COMMAND composition:
Code:
WM_COMMAND
wNotifyCode = HIWORD(wParam); // notification code
wID = LOWORD(wParam); // item, control, or accelerator identifier
hwndCtl = (HWND) lParam; // handle of control
You have to check out the LOWORD(wParam). Now you have the MessageBox right.
The next is the drawing part: do not block the program on a 'while' loop, use instead a timer and a global flag, and of course check the WM_PAINT message. The start button will set the flag to TRUE (or to a value that means: 'yeah, you can draw now'), and the stop will reset the flag to FALSE (or 'hey, do not draw please'). But why the timer? Because you need to refresh the window to receive the WM_PAINT message (that's not completelly true, because you can get the HDC whenever you want, but for the moment will be ok for us):
Code:
UINT SetTimer(
HWND hWnd, // handle of window for timer messages
UINT nIDEvent, // timer identifier
UINT uElapse, // time-out value
TIMERPROC lpTimerFunc // address of timer procedure, set it to NULL to process the WM_TIMER message
);
You have to decide if you want to set the timer on program startup (and kill timer on shutdown), or only set the timer between start-stop commands (I think the second is better). When you have the timer running you can checkout the WM_TIMER message: refresh the window. Ok, not the whole window, only the old position and the new position: use two RECT structures to store the dot positions (old and new), and call InvalidateRect
Code:
BOOL InvalidateRect(
HWND hWnd, // handle of window with changed update region
CONST RECT *lpRect, // address of rectangle coordinates
BOOL bErase // erase-background flag
);
Now you can checkout the WM_PAINT message; even the message have to do all the drawing stuff, the InvalidateRect will ensure that only the selected area will be modifyed (a big area means a big flickering). To process that message use BeginPaint and EndPaint (BeginPaint returns the display HDC handler, note that in your code you never setted up it). Use this HDC to fill in the background color the old dot position, and draw the new dot.
Hope that will help; I think that the more important thing is to not block a message loop process with a 'while' loop
Niara
-
Drawing the dots each paint msg will be very slow, using SetPixel will make it even slower. The drawing will also not remain after the system generates a paint msg (ie another window overlaps your window).
You should create a back buffer, draw the dots to this and when you get a paint msg BitBlt() the back buffer to the screen buffer ('Double Buffer').
I have posted plenty of code before showing exactly how do do this.
PS Make sure your START button ID is the same in the RESOURCE.H file and CALLBACK, better to use the actual ID name [ie IDC_START] (as currently you appear to be using both 12342649 and 2222)
Use the correct CASE ..... BREAK syntax (even if you have a return). It will make your code much more readable and prone to less errors.
Do not call srand() more than once in the whole program. rand is a big list of numbers, srand is the index to start at. If you keep reseting it, you will get exactly the same 'random' number.
Use the modulus function to get a number in the correrct range the first time [int iPercent = (int)(rand() % 100);//return a whole number between 0 and 99 ]