基础题目:用Windows编程,实现左键画矩形,右键画椭圆,刷新/最小化/改变窗口大小等动作,画面上的图形不会消失。
#include <windows.h>
#define MAX 10000
class Shape{
private:
int x1,y1;
public:
Shape(int x, int y): x1(x), y1(y) {}
virtual void draw(HDC hdc,int x1,int y1,int x2,int y2)=0;
int get_x1(){return x1;}
int get_y1(){return y1;}
};
class MyRectangle: public Shape {
public:
MyRectangle(int x, int y): Shape(x,y) {}
void draw(HDC hdc,int x1,int y1,int x2,int y2){
Rectangle(hdc,x1,y1,x2,y2);
}
};
class MyEllipse: public Shape {
public:
MyEllipse(int x, int y): Shape(x,y) {}
void draw(HDC hdc,int x1,int y1,int x2,int y2){
Ellipse(hdc,x1,y1,x2,y2);
}
};
/* This is where all the input to the window goes to */
LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
static int number=0;
static Shape* myshape[MAX];
int xPos=LOWORD(lParam),yPos= HIWORD(lParam);
HDC hdc;
switch(Message) {
case WM_LBUTTONDOWN:{
hdc = GetDC(hwnd);
myshape[number]= new MyRectangle(xPos,yPos);
//myshape[number]->draw(hdc,xPos,yPos,300,300);
number++;
ReleaseDC(hwnd,hdc);
break;
}
case WM_RBUTTONDOWN:{
hdc = GetDC(hwnd);
myshape[number]= new MyEllipse(xPos,yPos);
//myshape[number]->draw(hdc,xPos,yPos,300,300);
number++;
ReleaseDC(hwnd,hdc);
break;
}
case WM_PAINT:{
hdc = GetDC(hwnd);
for(int i=0; i<number; i++){
myshape[i]->draw(hdc,myshape[i]->get_x1(),myshape[i]->get_y1(),300,300);
}
ReleaseDC(hwnd,hdc);
break;
}
/* Upon destruction, tell the main thread to stop */
case WM_DESTROY: {
for(int i=0; i<number; i++)
delete myshape[i];
PostQuitMessage(0);
break;
}
/* All other messages (a lot of them) are processed using default procedures */
default:
return DefWindowProc(hwnd, Message, wParam, lParam);
}
return 0;
}
/* The 'main' function of Win32 GUI programs: this is where execution starts */
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
WNDCLASSEX wc; /* A properties struct of our window */
HWND hwnd; /* A 'HANDLE', hence the H, or a pointer to our window */
MSG msg; /* A temporary location for all messages */
/* zero out the struct and set the stuff we want to modify */
memset(&wc,0,sizeof(wc));
wc.cbSize = sizeof(WNDCLASSEX);
wc.lpfnWndProc = WndProc; /* This is where we will send messages to */
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
/* White, COLOR_WINDOW is just a #define for a system color, try Ctrl+Clicking it */
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszClassName = "WindowClass";
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); /* Load a standard icon */
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); /* use the name "A" to use the project icon */
if(!RegisterClassEx(&wc)) {
MessageBox(NULL, "Window Registration Failed!","Error!",MB_ICONEXCLAMATION|MB_OK);
return 0;
}
hwnd = CreateWindowEx(WS_EX_CLIENTEDGE,"WindowClass","Caption",WS_VISIBLE|WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, /* x */
CW_USEDEFAULT, /* y */
640, /* width */
480, /* height */
NULL,NULL,hInstance,NULL);
if(hwnd == NULL) {
MessageBox(NULL, "Window Creation Failed!","Error!",MB_ICONEXCLAMATION|MB_OK);
return 0;
}
/*
This is the heart of our program where all input is processed and
sent to WndProc. Note that GetMessage blocks code flow until it receives something, so
this loop will not produce unreasonably high CPU usage
*/
while(GetMessage(&msg, NULL, 0, 0) > 0) { /* If no error is received... */
TranslateMessage(&msg); /* Translate key codes to chars if present */
DispatchMessage(&msg); /* Send it to WndProc */
}
return msg.wParam;
}
根据老师的提议,修改提升了代码,用多态进行存盘,图形会变色:
因为想使用菜单进行存储,所以使用了File Editor工程。
#include <windows.h>
#include "main.h"
#include <fstream>
#define MAX 10000
using namespace std;
/*
BOOL LoadFile(HWND hEdit, LPSTR pszFileName) {
HANDLE hFile;
BOOL bSuccess = FALSE;
hFile = CreateFile(pszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
if(hFile != INVALID_HANDLE_VALUE) {
DWORD dwFileSize;
dwFileSize = GetFileSize(hFile, NULL);
if(dwFileSize != 0xFFFFFFFF) {
LPSTR pszFileText;
pszFileText = (LPSTR)GlobalAlloc(GPTR, dwFileSize + 1);
if(pszFileText != NULL) {
DWORD dwRead;
if(ReadFile(hFile, pszFileText, dwFileSize, &dwRead, NULL)) {
pszFileText[dwFileSize] = 0; // Null terminator
if(SetWindowText(hEdit, pszFileText))
bSuccess = TRUE; // It worked!
}
GlobalFree(pszFileText);
}
}
CloseHandle(hFile);
}
return bSuccess;
}
BOOL SaveFile(HWND hEdit, LPSTR pszFileName) {
HANDLE hFile;
BOOL bSuccess = FALSE;
hFile = CreateFile(pszFileName, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if(hFile != INVALID_HANDLE_VALUE) {
DWORD dwTextLength;
dwTextLength = GetWindowTextLength(hEdit);
if(dwTextLength > 0) {
LPSTR pszText;
pszText = (LPSTR)GlobalAlloc(GPTR, dwTextLength + 1);
if(pszText != NULL) {
if(GetWindowText(hEdit, pszText, dwTextLength + 1)) {
DWORD dwWritten;
if(WriteFile(hFile, pszText, dwTextLength, &dwWritten, NULL))
bSuccess = TRUE;
}
GlobalFree(pszText);
}
}
CloseHandle(hFile);
}
return bSuccess;
}
BOOL DoFileOpenSave(HWND hwnd, BOOL bSave) {
OPENFILENAME ofn;
char szFileName[MAX_PATH];
ZeroMemory(&ofn, sizeof(ofn));
szFileName[0] = 0;
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hwnd;
ofn.lpstrFilter = "Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0\0";
ofn.lpstrFile = szFileName;
ofn.nMaxFile = MAX_PATH;
ofn.lpstrDefExt = "txt";
if(bSave) {
ofn.Flags = OFN_EXPLORER|OFN_PATHMUSTEXIST|OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT;
if(GetSaveFileName(&ofn)) {
if(!SaveFile(GetDlgItem(hwnd, IDC_MAIN_TEXT), szFileName)) {
MessageBox(hwnd, "Save file failed.", "Error",MB_OK|MB_ICONEXCLAMATION);
return FALSE;
}
}
} else {
ofn.Flags = OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY;
if(GetOpenFileName(&ofn)) {
if(!LoadFile(GetDlgItem(hwnd, IDC_MAIN_TEXT), szFileName)) {
MessageBox(hwnd, "Load of file failed.", "Error",MB_OK|MB_ICONEXCLAMATION);
return FALSE;
}
}
}
return TRUE;
}
*/
class Shape {
private:
int x1,y1;
public:
Shape(int x, int y): x1(x), y1(y) {}
virtual void draw(HDC hdc,int x1,int y1,int x2,int y2)=0;
virtual void save(ofstream& Outfile)=0;
int get_x1() {return x1;}
int get_y1() {return y1;}
};
class MyRectangle: public Shape {
public:
MyRectangle(int x, int y): Shape(x,y) {}
void draw(HDC hdc,int x1,int y1,int x2,int y2) {
Rectangle(hdc,x1,y1,x2,y2);
}
void save(ofstream& Outfile) {Outfile << 1 << " " << get_x1() << " " << get_y1() << endl;}
};
class MyEllipse: public Shape {
public:
MyEllipse(int x, int y): Shape(x,y) {}
void draw(HDC hdc,int x1,int y1,int x2,int y2) {
Ellipse(hdc,x1,y1,x2,y2);
}
void save(ofstream& Outfile) {Outfile << 2 << " " << get_x1() << " " << get_y1() << endl;}
};
static int number=0;
static Shape* myshape[MAX];
void Restore(HWND hwnd) {
ifstream infile(".\\file.txt", ios::app|ios::in);
int xPos,yPos;
while(!infile.eof()) {
int type;
infile >> type;
if(type==1) {
infile >> xPos >> yPos;
myshape[number]= new MyRectangle(xPos,yPos);
number++;
}
else if(type==2) {
infile >> xPos >> yPos;
myshape[number]= new MyEllipse(xPos,yPos);
number++;
}
}
infile.close();
}
void Save(HWND hwnd) {
ofstream outfile(".\\file.txt", ios::out);
for(int i=0; i<number; i++){
myshape[i]->save(outfile);
}
outfile.close();
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
int xPos=LOWORD(lParam),yPos= HIWORD(lParam);
HDC hdc = GetDC(hwnd);
PAINTSTRUCT ps;
HPEN hpen;
switch(Message) {
case WM_CREATE: {
//CreateWindow("EDIT", "",WS_CHILD|WS_VISIBLE|WS_HSCROLL|WS_VSCROLL|ES_MULTILINE|ES_WANTRETURN,CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,hwnd, (HMENU)IDC_MAIN_TEXT, GetModuleHandle(NULL), NULL);
SendDlgItemMessage(hwnd, IDC_MAIN_TEXT, WM_SETFONT,(WPARAM)GetStockObject(DEFAULT_GUI_FONT), MAKELPARAM(TRUE,0));
SetTimer(hwnd,1,1000,NULL);
break;
}
case WM_SIZE: {
if(wParam != SIZE_MINIMIZED)
MoveWindow(GetDlgItem(hwnd, IDC_MAIN_TEXT), 0, 0, LOWORD(lParam),HIWORD(lParam), TRUE);
break;
}
case WM_SETFOCUS: {
SetFocus(GetDlgItem(hwnd, IDC_MAIN_TEXT));
break;
}
case WM_COMMAND: {
switch(LOWORD(wParam)) {
case CM_FILE_OPEN:
Restore(hwnd);
break;
case CM_FILE_SAVEAS:
Save(hwnd);
break;
case CM_FILE_EXIT:
PostMessage(hwnd, WM_CLOSE, 0, 0);
break;
case CM_ABOUT:
MessageBox (NULL, "File Editor for Windows!\nCreated using the Win32 API" , "About...", 0);
break;
}
break;
}
case WM_TIMER: {
switch (wParam) {
case 1: {
InvalidateRect(hwnd, NULL, true);
break;
}
default:
break;
}
break;
}
case WM_LBUTTONDOWN: {
hdc = GetDC(hwnd);
myshape[number]= new MyRectangle(xPos,yPos);
number++;
ReleaseDC(hwnd,hdc);
break;
}
case WM_RBUTTONDOWN: {
hdc = GetDC(hwnd);
myshape[number]= new MyEllipse(xPos,yPos);
number++;
ReleaseDC(hwnd,hdc);
break;
}
case WM_PAINT: {
hdc = BeginPaint (hwnd, &ps);
HPEN hpen = CreatePen(PS_SOLID, 5, RGB(rand()%256,rand()%255,rand()%254));
SelectObject(hdc, hpen);
for(int i=0; i<number; i++){
myshape[i]->draw(hdc,myshape[i]->get_x1(),myshape[i]->get_y1(),300,300);
}
EndPaint (hwnd, &ps);
DeleteObject(hpen);
ReleaseDC(hwnd,hdc);
break;
}
/* Upon destruction, tell the main thread to stop */
case WM_DESTROY: {
KillTimer (hwnd, 1);
for(int i=0; i<number; i++)
delete myshape[i];
PostQuitMessage(0);
break;
}
case WM_CLOSE:
DestroyWindow(hwnd);
break;
/* All other messages (a lot of them) are processed using default procedures */
default:
return DefWindowProc(hwnd, Message, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow) {
WNDCLASSEX wc;
HWND hwnd;
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 = "MAINMENU";
wc.lpszClassName = "WindowClass";
wc.hIconSm = LoadIcon(hInstance,"A"); /* A is name used by project icons */
if(!RegisterClassEx(&wc)) {
MessageBox(0,"Window Registration Failed!","Error!",MB_ICONEXCLAMATION|MB_OK|MB_SYSTEMMODAL);
return 0;
}
hwnd = CreateWindowEx(WS_EX_CLIENTEDGE,"WindowClass","File Editor Example Program",WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
600,480,
NULL, NULL, hInstance, NULL);
if(hwnd == NULL) {
MessageBox(0, "Window Creation Failed!", "Error!",MB_ICONEXCLAMATION|MB_OK|MB_SYSTEMMODAL);
return 0;
}
ShowWindow(hwnd,1);
UpdateWindow(hwnd);
while(GetMessage(&Msg, NULL, 0, 0) > 0) {
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}