読者です 読者をやめる 読者になる 読者になる

きままにブログ

プログラミングを主とした私のメモ帳です。寂しいのでコメントください笑

Windowを表示するだけのクラス

Windowsプログラミング C++

f:id:staryoshi:20150127191153p:plain

ウィンドウを複数作れるように、基本となるクラスを作ってみた。まあ、ウィンドウをたくさん作ることもあまりないし、細かいことをしようと思うとどうせプロシージャをいじる必要が出てくるのであまり使えないですが、次のように継承することで簡単にウィンドウを生成できます。ただし、ウィンドウクラスは自分で登録する必要があり、コンストラクタを呼び出す前に作らないといけません;

テストケース

int WINAPI WinMain(HINSTANCE h_instance, HINSTANCE h_prev_instance, LPSTR command_line, int command_show) {
	try {
		EditWindow::Register();
		EditWindow ew;
		ew.show();
	}

	catch(WindowException& e) {
		return -1;
	}

	return Application::Run();
}

定義

  • edit_window.h
#pragma once
#include "window.h"

class EditWindow : public Window<EditWindow> {
public:
	EditWindow();
	void onLButtonUp() override;
	static void Register();
};
  • edit_window.cpp
#include "edit_window.h"

EditWindow::EditWindow() {
	create("window name", 100, 100, 100, 100);
}

void EditWindow::onLButtonUp() {
	MessageBox(h_wnd, "TEST", "TEST", MB_OK);
}

void EditWindow::Register() {
	WNDCLASS wndc;

	wndc.style = CS_HREDRAW | CS_VREDRAW;
	wndc.lpfnWndProc = WindowProc;
	wndc.cbClsExtra = wndc.cbWndExtra = 0;
	wndc.hInstance = GetModuleHandle(NULL);
	wndc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wndc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wndc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wndc.lpszMenuName = NULL;
	class_name = wndc.lpszClassName = "MainWindow";

	if(!RegisterClass(&wndc)) {
		throw WindowException::RegisterException();
	}
}

実装

  • window.h
#pragma once
#include <Windows.h>
#include <exception>

template <typename DerivedWindow>
class Window {
public:
	Window() = default;
	
	void create(const char* title, int x, int y, int width, int height) {
		CreateWindow(
			class_name, title,
			WS_OVERLAPPEDWINDOW,
			x, y, width, height, NULL, NULL,
			GetModuleHandle(NULL), this);

		// ここに来るのはWM_CREATEメッセージの処理の後
		if(h_wnd == NULL) {
			throw std::exception();
		}
	}
	void show() {
		ShowWindow(h_wnd, SW_SHOW);
	}

protected:
	virtual void onCreate() { };
	virtual void onPaint() { };
	virtual void onLButtonUp() { };
	virtual void onCommand(WPARAM wp, LPARAM lp) { };
	
	static LRESULT CALLBACK WindowProc(HWND h_wnd, UINT msg, WPARAM wp, LPARAM lp) {
		auto self = (DerivedWindow*)(GetWindowLongPtr(h_wnd, GWLP_USERDATA));

		if(self == NULL) {
			if(msg == WM_CREATE) {
				self = (DerivedWindow*)(((LPCREATESTRUCT)lp)->lpCreateParams);

				SetWindowLongPtr(h_wnd, GWLP_USERDATA, (LONG_PTR)self);
				self->h_wnd = h_wnd;

				self->onCreate();
			}

			return DefWindowProc(h_wnd, msg, wp, lp);
		}

		else {
			return self->mainProc(h_wnd, msg, wp, lp);
		}
	}

	LRESULT mainProc(HWND h_wnd, UINT msg, WPARAM wp, LPARAM lp) {
		switch(msg) {
		case WM_DESTROY:
			PostQuitMessage(0);
			return 0;
		case WM_LBUTTONUP:
			onLButtonUp();
			break;
		case WM_PAINT:
			onPaint();
			break;
		case WM_COMMAND:
			onCommand(wp, lp);
			break;
		}

		return DefWindowProc(h_wnd, msg, wp, lp);
	}

	HWND h_wnd;
	static const char* class_name;
};

class WindowException : std::exception {
public:
	class RegisterException;
};

class WindowException::RegisterException {

};

template <typename DerivedWindow>
const char* Window<DerivedWindow>::class_name;