Tom Knowlton
asked on
Drawing program - refreshing objects without redrawing the ENTIRE screen
My questions are in the 2nd comment below this question:
Consider the following code:
#include <windows.h>
#include "resource.h"
#include "ObjectsDrawn.h"
#define ID_TIMER 1
int xCoordStart,
yCoordStart,
xCoordEnd,
yCoordEnd,
CollectionIndex;
bool FirstClick;
ObjectsDrawn Collection[100];
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
TCHAR szAppName[] = TEXT ("MenuDemo") ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
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 = szAppName ;
wndclass.lpszClassName = szAppName ;
if (!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT ("This program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}
hwnd = CreateWindow (szAppName, TEXT ("Menu Demonstration"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL) ;
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static int idColor [5] = { WHITE_BRUSH, LTGRAY_BRUSH, GRAY_BRUSH,
DKGRAY_BRUSH, BLACK_BRUSH } ;
static int iSelection = IDM_BKGND_WHITE ;
HMENU hMenu ;
HDC hdc;
switch (message)
{
case WM_COMMAND:
hMenu = GetMenu (hwnd) ;
switch (LOWORD (wParam))
{
case IDM_APP_EXIT:
SendMessage (hwnd, WM_CLOSE, 0, 0) ;
return 0 ;
}
break ;
case WM_CREATE:
FirstClick = false;
CollectionIndex = 0;
case WM_LBUTTONDOWN:
if (!FirstClick)
{
xCoordStart = LOWORD(lParam);
yCoordStart = HIWORD(lParam);
Collection[CollectionIndex ].SetLineS tart(xCoor dStart,yCo ordStart);
hdc = GetDC(hwnd);
MoveToEx(hdc,xCoordStart,y CoordStart ,NULL);
ReleaseDC(hwnd, hdc);
FirstClick = true;
}
else if (FirstClick)
{
//InvalidateRect(hwnd,NULL ,TRUE);
xCoordEnd = LOWORD(lParam);
yCoordEnd = HIWORD(lParam);
Collection[CollectionIndex ].SetLineE nd(xCoordE nd,yCoordE nd);
Collection[CollectionIndex ].DrawObje ct(hwnd);
FirstClick = false;
CollectionIndex++;
}
return 0;
case WM_MOUSEMOVE:
if (FirstClick)
{
int counter;
xCoordEnd = LOWORD(lParam);
yCoordEnd = HIWORD(lParam);
Collection[CollectionIndex ].SetLineE nd(xCoordE nd,yCoordE nd);
Collection[CollectionIndex ].DrawObje ct(hwnd);
Sleep(100);
InvalidateRect(hwnd,NULL,T RUE);
for(counter = 0; counter < CollectionIndex; counter++)
Collection[counter].DrawOb ject(hwnd) ;
}
else if (!FirstClick)
{
int counter;
InvalidateRect(hwnd,NULL,T RUE);
for(counter = 0; counter < CollectionIndex; counter++)
Collection[counter].DrawOb ject(hwnd) ;
}
case WM_DESTROY:
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
Consider the following code:
#include <windows.h>
#include "resource.h"
#include "ObjectsDrawn.h"
#define ID_TIMER 1
int xCoordStart,
yCoordStart,
xCoordEnd,
yCoordEnd,
CollectionIndex;
bool FirstClick;
ObjectsDrawn Collection[100];
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
TCHAR szAppName[] = TEXT ("MenuDemo") ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
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 = szAppName ;
wndclass.lpszClassName = szAppName ;
if (!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT ("This program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}
hwnd = CreateWindow (szAppName, TEXT ("Menu Demonstration"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL) ;
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static int idColor [5] = { WHITE_BRUSH, LTGRAY_BRUSH, GRAY_BRUSH,
DKGRAY_BRUSH, BLACK_BRUSH } ;
static int iSelection = IDM_BKGND_WHITE ;
HMENU hMenu ;
HDC hdc;
switch (message)
{
case WM_COMMAND:
hMenu = GetMenu (hwnd) ;
switch (LOWORD (wParam))
{
case IDM_APP_EXIT:
SendMessage (hwnd, WM_CLOSE, 0, 0) ;
return 0 ;
}
break ;
case WM_CREATE:
FirstClick = false;
CollectionIndex = 0;
case WM_LBUTTONDOWN:
if (!FirstClick)
{
xCoordStart = LOWORD(lParam);
yCoordStart = HIWORD(lParam);
Collection[CollectionIndex
hdc = GetDC(hwnd);
MoveToEx(hdc,xCoordStart,y
ReleaseDC(hwnd, hdc);
FirstClick = true;
}
else if (FirstClick)
{
//InvalidateRect(hwnd,NULL
xCoordEnd = LOWORD(lParam);
yCoordEnd = HIWORD(lParam);
Collection[CollectionIndex
Collection[CollectionIndex
FirstClick = false;
CollectionIndex++;
}
return 0;
case WM_MOUSEMOVE:
if (FirstClick)
{
int counter;
xCoordEnd = LOWORD(lParam);
yCoordEnd = HIWORD(lParam);
Collection[CollectionIndex
Collection[CollectionIndex
Sleep(100);
InvalidateRect(hwnd,NULL,T
for(counter = 0; counter < CollectionIndex; counter++)
Collection[counter].DrawOb
}
else if (!FirstClick)
{
int counter;
InvalidateRect(hwnd,NULL,T
for(counter = 0; counter < CollectionIndex; counter++)
Collection[counter].DrawOb
}
case WM_DESTROY:
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
ASKER
Now my questions:
This is how I want the program to function:
1) Program starts.
2) User left clicks somewhere in the client area, setting the starting endpoint of the line.
3) As the user moves the mouse around on the screen, the LINE "rubber-bands" to each new mouse location, showing the user where the line will be drawn to if the mouse is clicked a second time.
4) When the user clicks a second time, the line is drawn permanently and the information is stored in an array of "Objects".
5) More lines can be drawn and the old line will still be preserved.
I hope this gives you an idea of what I am trying to do.
Now, as I have run the program, I can tell that the line information for each object is being preserved and all of the lines I have drawn previously are being stored and reproduced on demand during this for loop:
for(counter = 0; counter < CollectionIndex; counter++)
Collection[counter].DrawOb ject(hwnd) ;
But I am refreshing the ENTIRE screen each time I draw. I want a more elegant solution to all of this but I don't know what to do.
I have thought about passing in an OBJECT COLOR each time I draw the lines on the screen. I could pass in the COLOR white to "erase" lines and the color black to drawn the lines, but this also seems like a hack for a better way.
I would appreciate any help someone could give me.
This is how I want the program to function:
1) Program starts.
2) User left clicks somewhere in the client area, setting the starting endpoint of the line.
3) As the user moves the mouse around on the screen, the LINE "rubber-bands" to each new mouse location, showing the user where the line will be drawn to if the mouse is clicked a second time.
4) When the user clicks a second time, the line is drawn permanently and the information is stored in an array of "Objects".
5) More lines can be drawn and the old line will still be preserved.
I hope this gives you an idea of what I am trying to do.
Now, as I have run the program, I can tell that the line information for each object is being preserved and all of the lines I have drawn previously are being stored and reproduced on demand during this for loop:
for(counter = 0; counter < CollectionIndex; counter++)
Collection[counter].DrawOb
But I am refreshing the ENTIRE screen each time I draw. I want a more elegant solution to all of this but I don't know what to do.
I have thought about passing in an OBJECT COLOR each time I draw the lines on the screen. I could pass in the COLOR white to "erase" lines and the color black to drawn the lines, but this also seems like a hack for a better way.
I would appreciate any help someone could give me.
Add a "if" condition to lines in WM_MOUSEMOVE:
like:
if(firsttime){
InvalidateRect(hwnd,NULL,T RUE);
firsttime=false;
}
like:
if(firsttime){
InvalidateRect(hwnd,NULL,T
firsttime=false;
}
But better.You need do all the drawing into a mem DC and bitblt() into your window'DC.This will prevent the refreshing.
Regards
W.Yinan
Regards
W.Yinan
ASKER
Wyn:
I am rejecting your answer because I want to leave the question open to other comments. I am sorry I should have explained that I just wanted comments for the time-being.
I understand what you mean about bitblt and the memDC, although I haven't actually tried this in Win32 I have done this type of thing in Delphi. And yes, it does work quite well.
My one concern is how can I acheive the "rubberband" effect while I am drawing moving the mouse around prior to the second mouse-click?
Thanks!
Tom
I am rejecting your answer because I want to leave the question open to other comments. I am sorry I should have explained that I just wanted comments for the time-being.
I understand what you mean about bitblt and the memDC, although I haven't actually tried this in Win32 I have done this type of thing in Delphi. And yes, it does work quite well.
My one concern is how can I acheive the "rubberband" effect while I am drawing moving the mouse around prior to the second mouse-click?
Thanks!
Tom
ASKER
Can I still show the line "rubber-banding" while using the memDC and bitblt techniques?
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
How about this?
ASKER
I will try your suggestions.
This may take me a few hours. I am still learning this stuff.
Tom
This may take me a few hours. I am still learning this stuff.
Tom
ASKER
Wyn:
I appreciate your help, BUT I still don't get it.
What I need to do is draw and erase the line rapidly until the use clicks the left mouse button again.
I have made some changes to my code in an effort to use the memDc and BitBlit:
Here is my code as it stands now:
/*------------------------ ---------- -------
MENUDEMO.C -- Menu Demonstration
(c) Charles Petzold, 1998
-------------------------- ---------- -----*/
#include <windows.h>
#include "resource.h"
#include "ObjectsDrawn.h"
int xCoordStart,
yCoordStart,
xCoordEnd,
yCoordEnd,
CollectionIndex,
object_type;
const int INVALID = 0;
const int LINE = 1;
const int SQUARE = 2;
const int ELLIPSE = 3;
bool FirstClick;
ObjectsDrawn Collection[100];
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
TCHAR szAppName[] = TEXT ("MenuDemo") ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
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 = szAppName ;
wndclass.lpszClassName = szAppName ;
if (!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT ("This program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}
hwnd = CreateWindow (szAppName, TEXT ("Menu Demonstration"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL) ;
if (hwnd == NULL)
{
MessageBox(NULL, TEXT("Not enough memory to create bitmap!"),
szAppName, MB_ICONERROR);
return 0;
}
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
void GetLargestDisplayMode (int * pcxBitmap, int * pcyBitmap)
{
DEVMODE devmode ;
int iModeNum = 0 ;
* pcxBitmap = * pcyBitmap = 0 ;
ZeroMemory (&devmode, sizeof (DEVMODE)) ;
devmode.dmSize = sizeof (DEVMODE) ;
while (EnumDisplaySettings (NULL, iModeNum++, &devmode))
{
* pcxBitmap = max (* pcxBitmap, (int) devmode.dmPelsWidth) ;
* pcyBitmap = max (* pcyBitmap, (int) devmode.dmPelsHeight) ;
}
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static BOOL fLeftButtonDown, fRightButtonDown;
static HBITMAP hBitmap;
static HDC hdcMem;
static int cxBitmap, cyBitmap, cxClient, cyClient, xMouse, yMouse;
HMENU hMenu ;
HDC hdc;
PAINTSTRUCT ps;
switch (message)
{
case WM_COMMAND:
hMenu = GetMenu (hwnd) ;
switch (LOWORD (wParam))
{
case IDM_CLEAR:
return 0 ;
case IDM_APP_EXIT:
SendMessage (hwnd, WM_CLOSE, 0, 0) ;
return 0 ;
case IDM_EDIT_DRAWLINE:
int iFlag;
iFlag = GetMenuState(hMenu,IDM_EDI T_DRAWLINE ,MF_BYCOMM AND);
if(iFlag == 0)
{
CheckMenuItem(hMenu,IDM_ED IT_DRAWLIN E,MF_CHECK ED);
CheckMenuItem(hMenu,IDM_ED IT_DRAWCIR CLE,MF_UNC HECKED);
CheckMenuItem(hMenu,IDM_ED IT_DRAWREC T,MF_UNCHE CKED);
object_type = LINE;
}
return 0;
case IDM_EDIT_DRAWCIRCLE:
iFlag = GetMenuState(hMenu,IDM_EDI T_DRAWCIRC LE,MF_BYCO MMAND);
if(iFlag == 0)
{
CheckMenuItem(hMenu,IDM_ED IT_DRAWCIR CLE,MF_CHE CKED);
CheckMenuItem(hMenu,IDM_ED IT_DRAWLIN E,MF_UNCHE CKED);
CheckMenuItem(hMenu,IDM_ED IT_DRAWREC T,MF_UNCHE CKED);
object_type = LINE;
}
return 0;
case IDM_EDIT_DRAWRECT:
iFlag = GetMenuState(hMenu,IDM_EDI T_DRAWRECT ,MF_BYCOMM AND);
if(iFlag == 0)
{
CheckMenuItem(hMenu,IDM_ED IT_DRAWREC T,MF_CHECK ED);
CheckMenuItem(hMenu,IDM_ED IT_DRAWLIN E,MF_UNCHE CKED);
CheckMenuItem(hMenu,IDM_ED IT_DRAWCIR CLE,MF_UNC HECKED);
object_type = SQUARE;
}
return 0;
case IDM_APP_HELP:
MessageBox (hwnd, TEXT ("Help not yet implemented!"),
szAppName, MB_ICONEXCLAMATION | MB_OK) ;
return 0 ;
case IDM_APP_ABOUT:
MessageBox (hwnd, TEXT ("Menu Demonstration Program\n")
TEXT ("(c) Charles Petzold, 1998"),
szAppName, MB_ICONINFORMATION | MB_OK) ;
return 0 ;
}
break ;
case WM_CREATE:
object_type = LINE;
GetLargestDisplayMode (&cxBitmap, &cyBitmap);
hdc = GetDC(hwnd);
hBitmap = CreateCompatibleBitmap(hdc , cxBitmap, cyBitmap);
hdcMem = CreateCompatibleDC(hdc);
ReleaseDC(hwnd, hdc);
if (!hBitmap)
{
DeleteDC(hdcMem);
return - 1;
}
SelectObject(hdcMem, hBitmap);
PatBlt(hdcMem, 0, 0, cxBitmap, cyBitmap, WHITENESS);
return 0;
case WM_SIZE:
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
return 0;
case WM_LBUTTONDOWN:
if(!fRightButtonDown)
SetCapture(hwnd);
if(!Collection[CollectionI ndex].GetF irstCoords Status())
{
xMouse = LOWORD (lParam);
yMouse = HIWORD (lParam);
Collection[CollectionIndex ].SetLineS tart(xMous e,yMouse);
Collection[CollectionIndex ].SetFirst CoordsStat us(true);
MoveToEx(hdc,xMouse,yMouse ,NULL);
MoveToEx(hdcMem,xMouse,yMo use,NULL);
}
else
{
xMouse = LOWORD (lParam);
yMouse = HIWORD (lParam);
MoveToEx(hdc,xMouse,yMouse ,NULL);
MoveToEx(hdcMem,xMouse,yMo use,NULL);
Collection[CollectionIndex ].SetLineE nd(xMouse, yMouse);
Collection[CollectionIndex ].SetFirst CoordsStat us(false);
Collection[CollectionIndex ].DrawObje ct(hwnd);
CollectionIndex++;
}
return 0;
case WM_LBUTTONUP:
if (fLeftButtonDown)
SetCapture(NULL);
fLeftButtonDown = FALSE;
return 0;
case WM_RBUTTONDOWN:
if (!fLeftButtonDown)
SetCapture(hwnd);
xMouse = LOWORD(lParam);
yMouse = HIWORD(lParam);
fRightButtonDown = TRUE;
return 0;
case WM_RBUTTONUP:
if(fRightButtonDown)
SetCapture(NULL);
fRightButtonDown = FALSE;
return 0;
case WM_MOUSEMOVE:
if(Collection[CollectionIn dex].GetFi rstCoordsS tatus())
{
hdc = GetDC(hwnd);
SelectObject(hdc,GetStockO bject(fLef tButtonDow n ? BLACK_PEN : WHITE_PEN));
SelectObject(hdcMem,GetSto ckObject(f LeftButton Down ? BLACK_PEN : WHITE_PEN));
xMouse = (short) LOWORD(lParam);
yMouse = (short) HIWORD(lParam);
Collection[CollectionIndex ].SetLineE nd(xMouse, yMouse);
Collection[CollectionIndex ].DrawObje ct(hwnd);
ReleaseDC(hwnd, hdc);
}
if(!fLeftButtonDown && !fRightButtonDown)
return 0;
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
int result;
//PatBlt(hdc, 0, 0, cxBitmap, cyBitmap, WHITENESS);
BitBlt(hdc, 0, 0, cxClient, cyClient, hdcMem, 0,0, SRCCOPY);
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
DeleteDC(hdcMem);
DeleteObject(hBitmap);
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
I appreciate your help, BUT I still don't get it.
What I need to do is draw and erase the line rapidly until the use clicks the left mouse button again.
I have made some changes to my code in an effort to use the memDc and BitBlit:
Here is my code as it stands now:
/*------------------------
MENUDEMO.C -- Menu Demonstration
(c) Charles Petzold, 1998
--------------------------
#include <windows.h>
#include "resource.h"
#include "ObjectsDrawn.h"
int xCoordStart,
yCoordStart,
xCoordEnd,
yCoordEnd,
CollectionIndex,
object_type;
const int INVALID = 0;
const int LINE = 1;
const int SQUARE = 2;
const int ELLIPSE = 3;
bool FirstClick;
ObjectsDrawn Collection[100];
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
TCHAR szAppName[] = TEXT ("MenuDemo") ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
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 = szAppName ;
wndclass.lpszClassName = szAppName ;
if (!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT ("This program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}
hwnd = CreateWindow (szAppName, TEXT ("Menu Demonstration"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL) ;
if (hwnd == NULL)
{
MessageBox(NULL, TEXT("Not enough memory to create bitmap!"),
szAppName, MB_ICONERROR);
return 0;
}
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
void GetLargestDisplayMode (int * pcxBitmap, int * pcyBitmap)
{
DEVMODE devmode ;
int iModeNum = 0 ;
* pcxBitmap = * pcyBitmap = 0 ;
ZeroMemory (&devmode, sizeof (DEVMODE)) ;
devmode.dmSize = sizeof (DEVMODE) ;
while (EnumDisplaySettings (NULL, iModeNum++, &devmode))
{
* pcxBitmap = max (* pcxBitmap, (int) devmode.dmPelsWidth) ;
* pcyBitmap = max (* pcyBitmap, (int) devmode.dmPelsHeight) ;
}
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static BOOL fLeftButtonDown, fRightButtonDown;
static HBITMAP hBitmap;
static HDC hdcMem;
static int cxBitmap, cyBitmap, cxClient, cyClient, xMouse, yMouse;
HMENU hMenu ;
HDC hdc;
PAINTSTRUCT ps;
switch (message)
{
case WM_COMMAND:
hMenu = GetMenu (hwnd) ;
switch (LOWORD (wParam))
{
case IDM_CLEAR:
return 0 ;
case IDM_APP_EXIT:
SendMessage (hwnd, WM_CLOSE, 0, 0) ;
return 0 ;
case IDM_EDIT_DRAWLINE:
int iFlag;
iFlag = GetMenuState(hMenu,IDM_EDI
if(iFlag == 0)
{
CheckMenuItem(hMenu,IDM_ED
CheckMenuItem(hMenu,IDM_ED
CheckMenuItem(hMenu,IDM_ED
object_type = LINE;
}
return 0;
case IDM_EDIT_DRAWCIRCLE:
iFlag = GetMenuState(hMenu,IDM_EDI
if(iFlag == 0)
{
CheckMenuItem(hMenu,IDM_ED
CheckMenuItem(hMenu,IDM_ED
CheckMenuItem(hMenu,IDM_ED
object_type = LINE;
}
return 0;
case IDM_EDIT_DRAWRECT:
iFlag = GetMenuState(hMenu,IDM_EDI
if(iFlag == 0)
{
CheckMenuItem(hMenu,IDM_ED
CheckMenuItem(hMenu,IDM_ED
CheckMenuItem(hMenu,IDM_ED
object_type = SQUARE;
}
return 0;
case IDM_APP_HELP:
MessageBox (hwnd, TEXT ("Help not yet implemented!"),
szAppName, MB_ICONEXCLAMATION | MB_OK) ;
return 0 ;
case IDM_APP_ABOUT:
MessageBox (hwnd, TEXT ("Menu Demonstration Program\n")
TEXT ("(c) Charles Petzold, 1998"),
szAppName, MB_ICONINFORMATION | MB_OK) ;
return 0 ;
}
break ;
case WM_CREATE:
object_type = LINE;
GetLargestDisplayMode (&cxBitmap, &cyBitmap);
hdc = GetDC(hwnd);
hBitmap = CreateCompatibleBitmap(hdc
hdcMem = CreateCompatibleDC(hdc);
ReleaseDC(hwnd, hdc);
if (!hBitmap)
{
DeleteDC(hdcMem);
return - 1;
}
SelectObject(hdcMem, hBitmap);
PatBlt(hdcMem, 0, 0, cxBitmap, cyBitmap, WHITENESS);
return 0;
case WM_SIZE:
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
return 0;
case WM_LBUTTONDOWN:
if(!fRightButtonDown)
SetCapture(hwnd);
if(!Collection[CollectionI
{
xMouse = LOWORD (lParam);
yMouse = HIWORD (lParam);
Collection[CollectionIndex
Collection[CollectionIndex
MoveToEx(hdc,xMouse,yMouse
MoveToEx(hdcMem,xMouse,yMo
}
else
{
xMouse = LOWORD (lParam);
yMouse = HIWORD (lParam);
MoveToEx(hdc,xMouse,yMouse
MoveToEx(hdcMem,xMouse,yMo
Collection[CollectionIndex
Collection[CollectionIndex
Collection[CollectionIndex
CollectionIndex++;
}
return 0;
case WM_LBUTTONUP:
if (fLeftButtonDown)
SetCapture(NULL);
fLeftButtonDown = FALSE;
return 0;
case WM_RBUTTONDOWN:
if (!fLeftButtonDown)
SetCapture(hwnd);
xMouse = LOWORD(lParam);
yMouse = HIWORD(lParam);
fRightButtonDown = TRUE;
return 0;
case WM_RBUTTONUP:
if(fRightButtonDown)
SetCapture(NULL);
fRightButtonDown = FALSE;
return 0;
case WM_MOUSEMOVE:
if(Collection[CollectionIn
{
hdc = GetDC(hwnd);
SelectObject(hdc,GetStockO
SelectObject(hdcMem,GetSto
xMouse = (short) LOWORD(lParam);
yMouse = (short) HIWORD(lParam);
Collection[CollectionIndex
Collection[CollectionIndex
ReleaseDC(hwnd, hdc);
}
if(!fLeftButtonDown && !fRightButtonDown)
return 0;
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
int result;
//PatBlt(hdc, 0, 0, cxBitmap, cyBitmap, WHITENESS);
BitBlt(hdc, 0, 0, cxClient, cyClient, hdcMem, 0,0, SRCCOPY);
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
DeleteDC(hdcMem);
DeleteObject(hBitmap);
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
ASKER
Wyn:
Here is my new ObjectsDrawn class:
#include "ObjectsDrawn.h"
ObjectsDrawn::ObjectsDrawn ()
{
type = 1;
}
void ObjectsDrawn::SetType(int temptype)
{
type = temptype;
StartCoordsSet = false;
}
int ObjectsDrawn::GetType()
{
return type;
}
bool ObjectsDrawn::GetFirstCoor dsStatus()
{
return StartCoordsSet;
}
void ObjectsDrawn::SetFirstCoor dsStatus(b ool tempstatus)
{
StartCoordsSet = tempstatus;
}
void ObjectsDrawn::SetLineStart (int tempX,int tempY)
{
xCoordStart = tempX;
yCoordStart = tempY;
}
void ObjectsDrawn::SetLineEnd(i nt tempX, int tempY)
{
xCoordEnd = tempX;
yCoordEnd = tempY;
}
int ObjectsDrawn::GetLineXStar t()
{
return xCoordStart;
}
int ObjectsDrawn::GetLineYStar t()
{
return yCoordStart;
}
int ObjectsDrawn::GetLineXEnd( )
{
return xCoordEnd;
}
int ObjectsDrawn::GetLineYEnd( )
{
return yCoordEnd;
}
void ObjectsDrawn::DrawLine(HWN D &hwnd)
{
HDC hdc;
hdc = GetDC(hwnd);
MoveToEx(hdc, xCoordEnd, yCoordEnd, NULL);
LineTo(hdc, xCoordStart, yCoordStart);
ReleaseDC(hwnd, hdc);
}
void ObjectsDrawn::DrawObject(H WND &hwnd)
{
if(type == 1)
DrawLine(hwnd);
}
Here is my new ObjectsDrawn class:
#include "ObjectsDrawn.h"
ObjectsDrawn::ObjectsDrawn
{
type = 1;
}
void ObjectsDrawn::SetType(int temptype)
{
type = temptype;
StartCoordsSet = false;
}
int ObjectsDrawn::GetType()
{
return type;
}
bool ObjectsDrawn::GetFirstCoor
{
return StartCoordsSet;
}
void ObjectsDrawn::SetFirstCoor
{
StartCoordsSet = tempstatus;
}
void ObjectsDrawn::SetLineStart
{
xCoordStart = tempX;
yCoordStart = tempY;
}
void ObjectsDrawn::SetLineEnd(i
{
xCoordEnd = tempX;
yCoordEnd = tempY;
}
int ObjectsDrawn::GetLineXStar
{
return xCoordStart;
}
int ObjectsDrawn::GetLineYStar
{
return yCoordStart;
}
int ObjectsDrawn::GetLineXEnd(
{
return xCoordEnd;
}
int ObjectsDrawn::GetLineYEnd(
{
return yCoordEnd;
}
void ObjectsDrawn::DrawLine(HWN
{
HDC hdc;
hdc = GetDC(hwnd);
MoveToEx(hdc, xCoordEnd, yCoordEnd, NULL);
LineTo(hdc, xCoordStart, yCoordStart);
ReleaseDC(hwnd, hdc);
}
void ObjectsDrawn::DrawObject(H
{
if(type == 1)
DrawLine(hwnd);
}
ASKER
Okay.
Now what my program does is this:
I left click with my mouse. This sets the START coordiates of the line.
As I move my mouse around the screen AFTER this first mouse click, a line is continuously REDRAWN from the START to the new mouse location.
When I click the mouse a second time, the final line is drawn and the entire process is reset. The only PROBLEM is ALL of the previous lines are still there on the screen! I want those extra lines to disappear as I move the mouse around until finally I left click again and the final (and ONLY) line is then drawn on the screen.
Can you explain your BitBlit code in more detail. Explain each line to me, please:
YOU WROTE PREVIOUSLY:
change the code around DrawObject,for example:
HDC memdc;
RECT rect;
HBITMAP bitmap;
case WM_MOUSEMOVE:
if (FirstClick)
{
memdc=CreateCompatibleDC(0 );
GetWindowRect(hwnd,&rect) ;
bitmap=CreateCompatibleBit map(memdc, rect.rigth -rect.left ,rect.bott om-rect.to p);
HBITMAP oldbitmap=SelectObject(mem dc,bitmap) ;
for(counter = 0; counter < CollectionIndex; counter++)
Collection[counter].DrawOb ject(memdc );
BltBit(....);
DeleteObject(SelectObjet(m emdc,oldbi tmap));
DeleteDC(memdc);
}
//.........
You should rewrite the DrawLine function,pass the memdc into it:
void ObjectsDrawn::DrawLine(HDC hdc)
{
MoveToEx(hdc, xCoordEnd, yCoordEnd, NULL);
LineTo(hdc, xCoordStart, yCoordStart);
}
============
How does this code allow me to "rubberband" the line around the screen as i move the mouse? Do you understand what I mean by rubberbanding?
Thanks for your help! I think with a little more explanation I can get this!
Tom
Now what my program does is this:
I left click with my mouse. This sets the START coordiates of the line.
As I move my mouse around the screen AFTER this first mouse click, a line is continuously REDRAWN from the START to the new mouse location.
When I click the mouse a second time, the final line is drawn and the entire process is reset. The only PROBLEM is ALL of the previous lines are still there on the screen! I want those extra lines to disappear as I move the mouse around until finally I left click again and the final (and ONLY) line is then drawn on the screen.
Can you explain your BitBlit code in more detail. Explain each line to me, please:
YOU WROTE PREVIOUSLY:
change the code around DrawObject,for example:
HDC memdc;
RECT rect;
HBITMAP bitmap;
case WM_MOUSEMOVE:
if (FirstClick)
{
memdc=CreateCompatibleDC(0
GetWindowRect(hwnd,&rect) ;
bitmap=CreateCompatibleBit
HBITMAP oldbitmap=SelectObject(mem
for(counter = 0; counter < CollectionIndex; counter++)
Collection[counter].DrawOb
BltBit(....);
DeleteObject(SelectObjet(m
DeleteDC(memdc);
}
//.........
You should rewrite the DrawLine function,pass the memdc into it:
void ObjectsDrawn::DrawLine(HDC
{
MoveToEx(hdc, xCoordEnd, yCoordEnd, NULL);
LineTo(hdc, xCoordStart, yCoordStart);
}
============
How does this code allow me to "rubberband" the line around the screen as i move the mouse? Do you understand what I mean by rubberbanding?
Thanks for your help! I think with a little more explanation I can get this!
Tom
ASKER
Wyn:
I think I finally figured it out!
Here is my current WM_MOUSEMOVE:
case WM_MOUSEMOVE:
if(Collection[CollectionIn dex].GetFi rstCoordsS tatus())
{
int counter;
hdc = GetDC(hwnd);
SelectObject(hdc,GetStockO bject(fLef tButtonDow n ? BLACK_PEN : WHITE_PEN));
SelectObject(hdcMem,GetSto ckObject(f LeftButton Down ? BLACK_PEN : WHITE_PEN));
xMouse = (short) LOWORD(lParam);
yMouse = (short) HIWORD(lParam);
Collection[CollectionIndex ].SetLineE nd(xMouse, yMouse);
PatBlt(hdc, 0, 0, cxBitmap, cyBitmap, WHITENESS);
for(counter = 0; counter < CollectionIndex; counter++)
Collection[counter].DrawOb ject(hwnd) ;
Collection[CollectionIndex ].DrawObje ct(hwnd);
ReleaseDC(hwnd, hdc);
}
if(!fLeftButtonDown && !fRightButtonDown)
return 0;
return 0;
There is a tiny bit of flicker, but the line rubber bands now!
Thanks for your help. You get the points!
I think I finally figured it out!
Here is my current WM_MOUSEMOVE:
case WM_MOUSEMOVE:
if(Collection[CollectionIn
{
int counter;
hdc = GetDC(hwnd);
SelectObject(hdc,GetStockO
SelectObject(hdcMem,GetSto
xMouse = (short) LOWORD(lParam);
yMouse = (short) HIWORD(lParam);
Collection[CollectionIndex
PatBlt(hdc, 0, 0, cxBitmap, cyBitmap, WHITENESS);
for(counter = 0; counter < CollectionIndex; counter++)
Collection[counter].DrawOb
Collection[CollectionIndex
ReleaseDC(hwnd, hdc);
}
if(!fLeftButtonDown && !fRightButtonDown)
return 0;
return 0;
There is a tiny bit of flicker, but the line rubber bands now!
Thanks for your help. You get the points!
Why you give me the points?
Is my comments helpful?
However,thank you.
Best Regards
W.Yinan
Btw:what's rubberband exactly meaning?
(You told me and ,then,I can rehash the my code and try to explain it to you)
Thank for the pts ,i blush to get:)
Is my comments helpful?
However,thank you.
Best Regards
W.Yinan
Btw:what's rubberband exactly meaning?
(You told me and ,then,I can rehash the my code and try to explain it to you)
Thank for the pts ,i blush to get:)
ASKER
Rubberbanding is like when you take a rubberband and stretch it between your fingers. You can make it bigger or smaller but the basic object is still a rubberband.
When drawing a rectangle in a drawing program, rubberbanding refers to clicking with the mouse at a location, then dragging the mouse around the screen. The rectangle grows bigger as you move the cursor away from the origin point, and smaller as you approach it, but the rectangle does not get permanently drawn until you click the mouse again. Make sense?
Don't worry about the points. You actually were quite helpful with your bitblt idea.
When drawing a rectangle in a drawing program, rubberbanding refers to clicking with the mouse at a location, then dragging the mouse around the screen. The rectangle grows bigger as you move the cursor away from the origin point, and smaller as you approach it, but the rectangle does not get permanently drawn until you click the mouse again. Make sense?
Don't worry about the points. You actually were quite helpful with your bitblt idea.
ASKER
#include "ObjectsDrawn.h"
ObjectsDrawn::ObjectsDrawn
{
type = 1;
}
void ObjectsDrawn::SetType(int temptype)
{
type = temptype;
}
int ObjectsDrawn::GetType()
{
return type;
}
void ObjectsDrawn::SetLineStart
{
xCoordStart = tempX;
yCoordStart = tempY;
}
void ObjectsDrawn::SetLineEnd(i
{
xCoordEnd = tempX;
yCoordEnd = tempY;
}
int ObjectsDrawn::GetLineXStar
{
return xCoordStart;
}
int ObjectsDrawn::GetLineYStar
{
return yCoordStart;
}
int ObjectsDrawn::GetLineXEnd(
{
return xCoordEnd;
}
int ObjectsDrawn::GetLineYEnd(
{
return yCoordEnd;
}
void ObjectsDrawn::DrawLine(HWN
{
HDC hdc;
hdc = GetDC(hwnd);
MoveToEx(hdc, xCoordEnd, yCoordEnd, NULL);
LineTo(hdc, xCoordStart, yCoordStart);
ReleaseDC(hwnd, hdc);
}
void ObjectsDrawn::DrawObject(H
{
if(type == 1)
DrawLine(hwnd);
}