タイトルバーの制御

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
h1j1k1
記事: 37
登録日時: 6年前

タイトルバーの制御

#1

投稿記事 by h1j1k1 » 6年前


WINDOWのタイトルバーの自作がしたいです。
例をとってみるとCHROMEのように丸みを帯びていたり、IEのように複数ボタンを置いたり画像を張ったりなどです。
調べても「WM_NCHITTESTと自分でゴリゴリ描画」などという曖昧なことしかわかりませんでした。
タイトルバーに描画をする方法・タイトルバーに子ウィンドウのようにオブジェクトを置く方法・イベントを設置・検出する方法・タイトルバーの場所や大きさの変更方法が知りたいです。

また、DXLIBは使わない方法でお願いします。

OS: WINDOWS7
コンパイラ: GCC (MINGW-W64)
です

Bull
記事: 149
登録日時: 9年前

Re: タイトルバーの制御

#2

投稿記事 by Bull » 6年前

あまり詳しくないのですが、回答がないようなので概要だけ。

タイトルバーなどの非クライアントエリアを描画するためには、幾つか方法があるようです。
GetWindowDC() 関数で取得したデバイスコンテキストは、ウィンドウ全体に描画出来ます。
WM_NCPAINT をハンドルして、描画する方法もあります。Windows 標準でないデザインにするので、「自分でゴリゴリ描画」するしかないですね。

Chrome は全体の枠(フレーム)がひとつのウィンドウで、各タブも一つ一つがウィンドウです。
Chrome が使用しているかどうかは分かりませんが、矩形以外のウインドウはリージョンを設定すれば出来ます。

IE でもそうなのですが、Chrome ではページ内に表示されているボタンやエディットボックスのように見えるものは Windows 標準のコントロールではありません。すべてプログラムで描画しているようです。

h1j1k1
記事: 37
登録日時: 6年前

Re: タイトルバーの制御

#3

投稿記事 by h1j1k1 » 6年前

返信遅れてすいません。

chromeは各タブがウィンドウだったのですね。知りませんでした。
矩形以外のウィンドウはリージョンを使えばできたのですか。
ボタンやエディットボックスなどは子ウィンドウみたいなのを使って描画してるんですかね?あれも全部プログラムで描画していたのですか
ありがとうございました

Bull
記事: 149
登録日時: 9年前

Re: タイトルバーの制御

#4

投稿記事 by Bull » 6年前

あらかじめお断りします。以前に書いたことやこれから書くとは私が独自で調査したものあるいは、想像で書いているもので、必ずしも正しいとは限りません。
その点、ご承知置きください。

まず訂正からになってしまってすいません。
h1j1k1 さんが書きました:
6年前
chromeは各タブがウィンドウだったのですね。知りませんでした。
これは違いました。タブの部分を含めて子ウインドウだと思っていたのですが、親ウインドウ(フレーム)に書かれていました。タブのクリックで表示するページが切り替わりますが、これらは Windows のタブコントロールといったものは使ってないようです。自前でやっているのでしょうが、具体的な方法はわかりません。

タブの部部をドラッグするとタブを分離できるので、子ウインドウの一部かと思っていましたが、そうではなく移動を始めた瞬間に別に外枠となるウインドウを用意しているのだと思います。あくまでも想像ですが。

繰り返しになりますが、Chrome はウィドウに関しては非常にシンプルな作りです。外枠である親ウインドウと、現在開いているページを表示するための複数の子ウインドウから成り立ちます。つまり、現在開いているページ+1のウインドウしか使っていません。
h1j1k1 さんが書きました:
6年前
ボタンやエディットボックスなどは子ウィンドウみたいなのを使って描画してるんですかね?あれも全部プログラムで描画していたのですか
いえ、ウインドウではありません。ボタンはたぶんビットマップか直接描画しているのでしょう。エディットボックスは枠だけ書いているのでしょうね。文字の入力とかは全部自前でプログラムでやっていると思われます。
もちろん、プログラムをべた書きしているわけではなく、Google 独自のクラスライブラリあるいはフレームワークのようものを作って、使っているんだと思いますが、詳細はわかりません。

各ページのリンクとか動画の再生とかボリュームのスライダーとかすべて独自に一つのウィンドウの中で描画/処理しているようですね。デザインの自由度は高くなりますが、プログラミングの難易度は相当高そうです。


IE に関しては、ウィンドウをふんだんに使用しています。しかしやっぱり Windows 標準のボタンコントロールやエディットコントロールは使用していません。家のマーク(ホーム)や星のマーク(お気に入り)や歯車のマーク(ツール)もたぶんビットマップだと思います。(リソースに見つからなかったので違うかもしれませんが)
これらは一つのウインドウ内に書かれていますが、イベントに関しては正直よく分りません。

かずま

Re: タイトルバーの制御

#5

投稿記事 by かずま » 6年前

h1j1k1 さんが書きました:
6年前
タイトルバーに描画をする方法・タイトルバーに子ウィンドウのようにオブジェクトを置く方法・イベントを設置・検出する方法・タイトルバーの場所や大きさの変更方法が知りたいです。
タイトルバーをなくして、全部クライアント領域にすれば、
なんでも置けるのではありませんか?

試しにこんなのを書いてみました。

コード:

#include <windows.h>

HWND hButton;

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
	switch (msg) {
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	case WM_COMMAND:
		if ((HWND)lp == hButton) DestroyWindow(hwnd);
		return 0;
	case WM_LBUTTONDOWN:
		ReleaseCapture();
		SendMessage(hwnd, WM_NCLBUTTONDOWN, HTCAPTION, 0);
		return 0;
	case WM_NCHITTEST:
		{
			LRESULT res = DefWindowProc(hwnd, WM_NCHITTEST, wp, lp);
			return (res == HTCLIENT) ? HTCAPTION : res;
	    }
	case WM_PAINT:
		{
			PAINTSTRUCT ps;
			HDC hdc = BeginPaint(hwnd, &ps);
			RECT rect { 20, 40, 400, 65 };
			DrawText(hdc, "タイトルバーはありません", -1, &rect, DT_CENTER);
			EndPaint(hwnd, &ps);
			return 0;
		} 
	}
	return DefWindowProc(hwnd, msg, wp, lp);
}

int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, PSTR ln, int sh)
{
	WNDCLASS winc;
	winc.style          = CS_HREDRAW | CS_VREDRAW;
	winc.lpfnWndProc    = WndProc;
	winc.cbClsExtra     = winc.cbWndExtra = 0;
	winc.hInstance      = inst;
	winc.hIcon          = LoadIcon(NULL, IDI_APPLICATION);
	winc.hCursor        = LoadCursor(NULL, IDC_ARROW);
	winc.hbrBackground  = (HBRUSH)WHITE_BRUSH;
	winc.lpszMenuName   = NULL;
	winc.lpszClassName  = "Class";
	if (!RegisterClass(&winc)) return -1;

	HWND hwnd = CreateWindow(
		"Class", NULL, WS_BORDER | WS_VISIBLE,
		CW_USEDEFAULT, CW_USEDEFAULT, 640, 480,
		NULL, NULL, inst, NULL
	);
	if (hwnd == NULL) return -1;

	LONG style = GetWindowLong(hwnd, GWL_STYLE);
	style &= ~WS_CAPTION;
	style |= WS_BORDER;
	style = SetWindowLong(hwnd, GWL_STYLE, style);

	hButton = CreateWindow("BUTTON", "X",
		WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
		600, 20, 25, 25, hwnd, NULL, inst, NULL);
	if (hButton == NULL) return -1;

	MSG msg;
	while(GetMessage(&msg, NULL, 0, 0)) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}
cygwin の GCC ではコンパイルできました。

h1j1k1
記事: 37
登録日時: 6年前

Re: タイトルバーの制御

#6

投稿記事 by h1j1k1 » 6年前


>> Bullさん
私の環境でコンパイルしてみたのですが、タイトルバーは消えることなくしっかり残ってしまっていました,,,
Win7 64bit, MinGW GCCでコンパイル、実行しております


少し話ずれますが、27行目RECT rect直後のイコール抜けてますよ

かずま

Re: タイトルバーの制御

#7

投稿記事 by かずま » 6年前

h1j1k1 さんが書きました:
6年前
>> Bullさん
私の環境でコンパイルしてみたのですが、タイトルバーは消えることなくしっかり残ってしまっていました,,,
Win7 64bit, MinGW GCCでコンパイル、実行しております
Bullさんはコードを示していません。
あなたが書いたタイトルバーが消えるそのプログラムを貼り付けてください。
h1j1k1 さんが書きました:
6年前
少し話ずれますが、27行目RECT rect直後のイコール抜けてますよ
#5 のプログラムですね。
これは、C++11 以降の C++プログラムなので、= なしで初期化できます。
gcc の代わりに g++ でコンパイルするか、ソースファイルの拡張子を
.c ではなく .cpp にして gcc でコンパイルしてみてください。
MingW GCC に C++コンパイラが含まれないのであれば、= を付けてください。

このプログラムは、~WS_CAPTION でタイトルバーが出ないようになっています。
全部がクライアント領域であることを示すために、そこを灰色にしたコードに
変更します。これでどうですか?

コード:

#include <windows.h>

HWND hButton;

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
	switch (msg) {
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	case WM_COMMAND:
		if ((HWND)lp == hButton) DestroyWindow(hwnd);
		return 0;
	case WM_LBUTTONDOWN:
		ReleaseCapture();
		SendMessage(hwnd, WM_NCLBUTTONDOWN, HTCAPTION, 0);
		return 0;
	case WM_NCHITTEST:
		{
			LRESULT res = DefWindowProc(hwnd, WM_NCHITTEST, wp, lp);
			return (res == HTCLIENT) ? HTCAPTION : res;
	    }
	case WM_PAINT:
		{
			PAINTSTRUCT ps;
			HDC hdc = BeginPaint(hwnd, &ps);
			RECT rect = { 100, 200, 400, 300 };
			DrawText(hdc, "ここは、クライアント領域です", -1, &rect, DT_CENTER);
			EndPaint(hwnd, &ps);
			return 0;
		} 
	}
	return DefWindowProc(hwnd, msg, wp, lp);
}

int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, PSTR ln, int sh)
{
	WNDCLASS winc;
	winc.style          = CS_HREDRAW | CS_VREDRAW;
	winc.lpfnWndProc    = WndProc;
	winc.cbClsExtra     = winc.cbWndExtra = 0;
	winc.hInstance      = inst;
	winc.hIcon          = LoadIcon(NULL, IDI_APPLICATION);
	winc.hCursor        = LoadCursor(NULL, IDC_ARROW);
	winc.hbrBackground  = (HBRUSH)LTGRAY_BRUSH;
	winc.lpszMenuName   = NULL;
	winc.lpszClassName  = "Class";
	if (!RegisterClass(&winc)) return -1;

	HWND hwnd = CreateWindow(
		"Class", "TITLE", WS_BORDER | WS_VISIBLE,
		CW_USEDEFAULT, CW_USEDEFAULT, 640, 480,
		NULL, NULL, inst, NULL
	);
	if (hwnd == NULL) return -1;

	LONG style = GetWindowLong(hwnd, GWL_STYLE);
	style &= ~WS_CAPTION;
	style |= WS_BORDER;
	style = SetWindowLong(hwnd, GWL_STYLE, style);

	hButton = CreateWindow("BUTTON", "終了",
		WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
		100, 400, 60, 30, hwnd, NULL, inst, NULL);
	if (hButton == NULL) return -1;

	MSG msg;
	while(GetMessage(&msg, NULL, 0, 0)) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}

h1j1k1
記事: 37
登録日時: 6年前

Re: タイトルバーの制御

#8

投稿記事 by h1j1k1 » 6年前

>>かずまさん
申し訳ございません。
かずまさんのプログラムでした。
C++11以降ですと = なしで初期化可能という使用があったのですね、知りませんでした。
画像
このように表示されていたため、青い部分がタイトルバーだと勘違いしていました。
ありがとうございました。

返信

“C言語何でも質問掲示板” へ戻る