ホームに戻る
ウインドウのクラス化
0、はじめに
ウインドウをクラス化します。
クラス化することによりコードの見た目をすっきりさせて、
インターフェイス部分の開発効率の向上を目指します。
使用例としてライツアウトというゲームを作成しました。
1、ファイルの構成
本体ウインドウを nmWindow と名づけました。
また、本体ウインドウのクライアントに貼る
子ウインドウを nmCanvas と名付けました。
ともに、nmWindow.cpp というファイル内に記述します。
そのヘッダは nmWindow.h になります。
実行ファイルは LightsOut.cpp です。
LightsOut.cpp から nmWindow.h を読んでます。
bcc32 でのコンパイルは以下のようです。
bcc32 -W LightsOut.cpp nmWindow.cpp
2、工夫について
まず、クラス内にはプロシージャを static でしか定義できません。
プロシージャを継承、拡張できるようにするために。
static のプロシージャから
仮想関数のメソッドプロシージャを呼ぶようにしています。
次に、プロシージャを呼んだオブジェクトを
拾ってこれないという問題があります。
これは WM_CREATE のところで SetWindowLong を使い。
次に呼ばれたときには GetWindowLong を呼ぶことで解決します。
最後に、クラス内のマウスクリック処理を本体の処理に返す構造です。
これは addMouseListener で本体のポインタを渡しておき、
イベントが起こったら本体の処理を呼べるようにしています。
ここは MouseListener というインターフェイスで実装しています。
3、コード本体
/*
* LightsOut.cpp
*/
#include <windows.h>
#include "nmWindow.h"
#define WIDTH 5
#define HEIGHT 5
class nmPanel : public nmCanvas{
int num;
int state_flag;
public:
nmPanel():num(0), state_flag(0), nmCanvas(){};
virtual ~nmPanel(){};
int getNum(){return num;}
void setNum(int num){this->num = num;}
void reverseState();
virtual LRESULT CanvasProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
};
void nmPanel::reverseState(){
if(state_flag == 1){
state_flag = 0;
}
else{
state_flag = 1;
}
repaint();
}
// 描画
int DrawGr(HWND hWnd, HDC hdc, int color)
{
HPEN hPen, hOldPen;
HBRUSH hBrush, hOldBrush;
RECT rt;
GetClientRect(hWnd, &rt);
hPen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
hOldPen = (HPEN)SelectObject(hdc, (HPEN)hPen);
hBrush = CreateSolidBrush(RGB(0, 0, color));
hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);
Rectangle(hdc, 0, 0, rt.right, rt.bottom);
SelectObject(hdc, hOldPen);
SelectObject(hdc, hOldBrush);
DeleteObject(hPen);
DeleteObject(hBrush);
return 0;
}
LRESULT nmPanel::CanvasProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message){
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
if(state_flag == 1){
DrawGr(hWnd, hdc, 255);
}
else{
DrawGr(hWnd, hdc, 0);
}
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0L;
}
class LightsOut : public MouseListener{
nmWindow *testWnd;
nmPanel *testPanel;
public:
LightsOut():testWnd(NULL), testPanel(NULL){};
void init(HINSTANCE hInstance);
void deinit(){
if(testWnd != NULL){
delete testWnd;
testWnd = NULL;
}
if(testPanel != NULL){
delete [] testPanel;
testPanel = NULL;
}
}
virtual void mouseLButtonDown(int x, int y, LPVOID p){
nmPanel* nmc = (nmPanel*)p;
int num = nmc->getNum();
testPanel[num].reverseState();
// 上の判定
if((num / WIDTH) >= 1){
testPanel[num - WIDTH].reverseState();
}
// 左の判定
if((num % WIDTH) >= 1){
testPanel[num - 1].reverseState();
}
// 右の判定
if((num % WIDTH) < (WIDTH - 1)){
testPanel[num + 1].reverseState();
}
// 下の判定
if((num / WIDTH) < (WIDTH - 1)){
testPanel[num + WIDTH].reverseState();
}
}
virtual void mouseRButtonDown(int x, int y, LPVOID p){};
};
void LightsOut::init(HINSTANCE hInstance){
int i, t;
testWnd = new nmWindow();
testWnd->registerWindow(hInstance);
testWnd->createWindow(hInstance, "LightsOut");
testWnd->setWindowPos(100, 100, 400, 400);
testPanel = new nmPanel[WIDTH * HEIGHT];
for(i = 0; i < WIDTH * HEIGHT; i++){
testPanel[i].setNum(i);
}
for(t = 0; t < HEIGHT; t++){
for(i = 0; i < WIDTH; i++){
int index = t * WIDTH + i;
int w = 400 / WIDTH;
int h = 400 / HEIGHT;
testPanel[index].createWindow(testWnd->gethWnd(), 100 + index);
testPanel[index].setWindowPos(i * w, t * h, w, h);
testPanel[index].addMouseListener(this);
}
}
}
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPreInstance,
LPSTR cmdLine,
int cmdShow)
{
LightsOut *lo = new LightsOut();
lo->init(hInstance);
MSG msg;
while(GetMessage(&msg, NULL, NULL, NULL))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
lo->deinit();
return msg.wParam;
}
/*
* nmWindow.h
*/
#ifndef NM_WINDOW
#define NM_WINDOW
class MouseListener{
public:
virtual ~MouseListener(){}
virtual void mouseLButtonDown(int x, int y, LPVOID p) = 0;
virtual void mouseRButtonDown(int x, int y, LPVOID p) = 0;
};
class nmWindow{
HWND hWnd;
static char *class_name;
public:
nmWindow(){hWnd = NULL;}
virtual ~nmWindow(){};
HWND gethWnd(void){return hWnd;}
HINSTANCE gethInstance(void){return (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE);}
int registerWindow(HINSTANCE hInstance);
int createWindow(HINSTANCE hInstance, char *title);
void setWindowPos(int x, int y, int w, int z);
void SetPointer(HWND hWnd);
static LRESULT CALLBACK CallProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
virtual LRESULT MainProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
};
class nmCanvas{
HWND hCanvas;
MouseListener *ml;
static int regist_flag;
static char *class_name;
int registerWindow(HINSTANCE hInstance);
public:
nmCanvas():hCanvas(NULL), ml(NULL){};
virtual ~nmCanvas(){};
int createWindow(HWND hWnd, int id);
void setWindowPos(int x, int y, int w, int z);
void repaint(){InvalidateRect(hCanvas, NULL, TRUE);}
void SetPointer(HWND hWnd);
void mouseLButtonDown(int x, int y){
if(ml){
ml->mouseLButtonDown(x, y, this);
}
}
void mouseRButtonDown(int x, int y){
if(ml){
ml->mouseRButtonDown(x, y, this);
}
}
void addMouseListener(MouseListener *ml){this->ml = ml;}
static LRESULT CALLBACK CallProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
virtual LRESULT CanvasProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
};
#endif
/*
* nmWindow.cpp
*/
#include <windows.h>
#include "nmWindow.h"
/*
* nmWindow
*/
char *nmWindow::class_name = "nmwin";
int nmWindow::registerWindow(HINSTANCE hInstance){
WNDCLASS wd;
wd.style = CS_HREDRAW | CS_VREDRAW;
wd.lpfnWndProc = nmWindow::CallProc;
wd.cbClsExtra = wd.cbWndExtra = 0;
wd.hInstance = hInstance;
wd.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wd.hCursor = LoadCursor(NULL, IDC_ARROW);
wd.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wd.lpszMenuName = NULL;
wd.lpszClassName = class_name;
if(!RegisterClass(&wd)){
return 0;
}
return 1;
}
int nmWindow::createWindow(HINSTANCE hInstance, char *title){
this->hWnd = CreateWindow(
class_name, title,
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
0, 0,
300,
200,
NULL, NULL, hInstance,
(LPVOID)this);
return 1;
}
void nmWindow::setWindowPos(int x, int y, int w, int z){
RECT rect;
rect.left = x;
rect.top = y;
rect.right = x + w;
rect.bottom = y + z;
AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
SetWindowPos(hWnd, HWND_TOP, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, 0);
}
void nmWindow::SetPointer(HWND hWnd){
SetWindowLong(hWnd, GWL_USERDATA, (LONG)this);
}
LRESULT CALLBACK nmWindow::CallProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){
nmWindow* nmw = (nmWindow*)GetWindowLong(hWnd, GWL_USERDATA);
if(!nmw){
if(message == WM_CREATE){
nmw = (nmWindow*)((LPCREATESTRUCT)lParam)->lpCreateParams;
}
if(nmw){
nmw->SetPointer(hWnd);
}
}
if(nmw){
LRESULT lResult = nmw->MainProc(hWnd, message, wParam, lParam);
return lResult;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
LRESULT nmWindow::MainProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){
switch(message){
case WM_DESTROY:
PostQuitMessage(0);
return 0L;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
/*
* nmCanvas
*/
char *nmCanvas::class_name = "nmcan";
int nmCanvas::regist_flag = 0;
int nmCanvas::registerWindow(HINSTANCE hInstance){
WNDCLASS wd;
wd.style = CS_HREDRAW | CS_VREDRAW;
wd.lpfnWndProc = nmCanvas::CallProc;
wd.cbClsExtra = wd.cbWndExtra = 0;
wd.hInstance = hInstance;
wd.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wd.hCursor = LoadCursor(NULL, IDC_ARROW);
wd.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wd.lpszMenuName = NULL;
wd.lpszClassName = class_name;
if(!RegisterClass(&wd)){
return 0;
}
return 1;
}
int nmCanvas::createWindow(HWND hWnd, int id){
HINSTANCE hInst = (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE);
if(regist_flag == 0){
int result = registerWindow(hInst);
if(result == 0){
return 0;
}
regist_flag = 1;
}
hCanvas = CreateWindow(
class_name, "", WS_CHILD | WS_VISIBLE,
0, 0, 10, 10,
hWnd, (HMENU)id, hInst,
(LPVOID)this);
return 1;
}
void nmCanvas::setWindowPos(int x, int y, int w, int z){
SetWindowPos(hCanvas, HWND_TOP, x, y, w, z, 0);
}
void nmCanvas::SetPointer(HWND hWnd){
SetWindowLong(hWnd, GWL_USERDATA, (LONG)this);
}
LRESULT CALLBACK nmCanvas::CallProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){
nmCanvas* nmc = (nmCanvas*)GetWindowLong(hWnd, GWL_USERDATA);
if(!nmc){
if(message == WM_CREATE){
nmc = (nmCanvas*)((LPCREATESTRUCT)lParam)->lpCreateParams;
}
if(nmc){
nmc->SetPointer(hWnd);
}
}
if(nmc){
if(message == WM_LBUTTONDOWN){
int xPos, yPos;
xPos = LOWORD(lParam);
yPos = HIWORD(lParam);
nmc->mouseLButtonDown(xPos, yPos);
}
else if(message == WM_RBUTTONDOWN){
int xPos, yPos;
xPos = LOWORD(lParam);
yPos = HIWORD(lParam);
nmc->mouseRButtonDown(xPos, yPos);
}
LRESULT lResult = nmc->CanvasProc(hWnd, message, wParam, lParam);
return lResult;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
LRESULT nmCanvas::CanvasProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){
switch(message){
case WM_DESTROY:
PostQuitMessage(0);
return 0L;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}