DXライブラリのウィンドウ関係で

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
L'z

DXライブラリのウィンドウ関係で

#1

投稿記事 by L'z » 14年前

ウィンドウ関係のことで質問が3つあります

1.ウィンドウモードをタイトルバーなしの1または2にしたいと思っています
  数字はSetWindowStyleMode関数の引数です
  しかし、このモードでは最小化ができません
  タスクバーの右クリックでも最小化が使えないようになっていました
  ウィンドウモードでタイトルバーなしを使って最小化を許可するにはどうすればいいのでしょうか?

2.タイトルバーなしにするとウィンドウの移動もできなくなります
  つくろうとしているものはマウス操作を使わないのでゲーム内でマウスをクリックしたまま動かせば
  ウィンドウも動くようにしたいです
  ゲームではないですがGOM Playerのような感じです
  これを可能にする方法が知りたいです
  調べてみましたが具体的な方法がみつからなかったのでプログラム例も書いていただけると幸いです

3.ウィンドウサイズを640x360と960x540で作成しています
  これは縦横倍にするとHD,FullHDになりフルモードにしたときになめらかになると思ったからなのですが
  モニターにこの解像度の設定がなくフルモードにしてもウィンドウモードで実行されてしまいます
  なのでフルモードにした場合は1280x720または1920x1080のウィンドウサイズしてフル画面になるように
  したいと思っています
  ゲーム中のオプションから切り替えるようにしたいと思っています
  実行中に画面サイズの変更とウィンドウからフル画面の切り替えを行うときに特殊な操作がいるのでしょうか?
    普通に ChangeWindowMode 関数とSetGraphMode 関数を実行するだけでいいのか
    それとも変更後に DxLib_Init 関数などを呼ぶ必要があるのか
    もし呼ぶならそのときにゲームの開始時点に戻す必要があるのか
    ウィンドウサイズを変えると出力するときに2倍にするためにいったんMakeScreenして
    それをDrawExtendGraphで2倍にするというような操作が増えるのか
  などを教えていただきたいです


以上です
いつもながくてすみません

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: DXライブラリのウィンドウ関係で

#2

投稿記事 by softya(ソフト屋) » 14年前

L'z さんが書きました:1.ウィンドウモードをタイトルバーなしの1または2にしたいと思っています
  数字はSetWindowStyleMode関数の引数です
  しかし、このモードでは最小化ができません
  タスクバーの右クリックでも最小化が使えないようになっていました
  ウィンドウモードでタイトルバーなしを使って最小化を許可するにはどうすればいいのでしょうか?
本家掲示板より。あちらの掲示板も検索されたほうが良いでしょう。
「縁無しウィンドウ」
http://hpcgi2.nifty.com/natupaji/bbs/pa ... ast&no=578
L'z さんが書きました:2.タイトルバーなしにするとウィンドウの移動もできなくなります
  つくろうとしているものはマウス操作を使わないのでゲーム内でマウスをクリックしたまま動かせば
  ウィンドウも動くようにしたいです
  ゲームではないですがGOM Playerのような感じです
  これを可能にする方法が知りたいです
  調べてみましたが具体的な方法がみつからなかったのでプログラム例も書いていただけると幸いです
どちらかと言うとウィンドウの処理なんですよね。
これだとDXライブラリの処理は逸脱するのでSetHookWinProc などでWin32APIを自分で処理しないといけないと思います。
本家掲示板の方が詳しい人がいるので質問してみて下さい。
L'z さんが書きました:3.ウィンドウサイズを640x360と960x540で作成しています
  これは縦横倍にするとHD,FullHDになりフルモードにしたときになめらかになると思ったからなのですが
  モニターにこの解像度の設定がなくフルモードにしてもウィンドウモードで実行されてしまいます
  なのでフルモードにした場合は1280x720または1920x1080のウィンドウサイズしてフル画面になるように
  したいと思っています
  ゲーム中のオプションから切り替えるようにしたいと思っています
  実行中に画面サイズの変更とウィンドウからフル画面の切り替えを行うときに特殊な操作がいるのでしょうか?
    普通に ChangeWindowMode 関数とSetGraphMode 関数を実行するだけでいいのか
    それとも変更後に DxLib_Init 関数などを呼ぶ必要があるのか
    もし呼ぶならそのときにゲームの開始時点に戻す必要があるのか
    ウィンドウサイズを変えると出力するときに2倍にするためにいったんMakeScreenして
    それをDrawExtendGraphで2倍にするというような操作が増えるのか
  などを教えていただきたいです
SetGraphMode → ChangeWindowMode で切り替えられるはずです。
ただし、SetGraphMode でデータが全て破棄されるので注意して下さい。
「DXライブラリ置き場 リファレンスページ SetGraphMode 」
http://homepage2.nifty.com/natupaji/DxL ... .html#R4N1

あと描画時の2倍は自分で直接DrawExtendGraphするかMakeScreen先に描画してからDrawExtendGraphのどちらかとなります。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

ISLe
記事: 2650
登録日時: 15年前
連絡を取る:

Re: DXライブラリのウィンドウ関係で

#3

投稿記事 by ISLe » 14年前

2.は、SetHookWinProcでは実現できないようです。

以下のように自前でサブクラス化すればできました。

コード:

#include "DxLib.h"

static WNDPROC pPrevWndProc;

static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg) {
	case WM_NCHITTEST:
		// ウインドウの枠の上にカーソルがあることにする
		return HTCAPTION;
	}
	return CallWindowProc(pPrevWndProc, hWnd ,uMsg ,wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	ChangeWindowMode(TRUE);
	if (DxLib_Init() != 0) return 0;

	// ウィンドウのサブクラス化(ウィンドウプロシージャのフック)
	pPrevWndProc = (WNDPROC)GetWindowLongPtr(GetMainWindowHandle(), GWLP_WNDPROC);
	SetWindowLongPtr(GetMainWindowHandle(), GWLP_WNDPROC , (LONG_PTR)WndProc);

	while (ProcessMessage() == 0) {
	}

	DxLib_End();
	return 0;
}

L'z

Re: DXライブラリのウィンドウ関係で

#4

投稿記事 by L'z » 14年前

softya(ソフト屋) さん
softya(ソフト屋) さんが書きました: どちらかと言うとウィンドウの処理なんですよね。
これだとDXライブラリの処理は逸脱するのでSetHookWinProc などでWin32APIを自分で処理しないといけないと思います。
DXライブラリの範囲ではできないのですね
Win32APIでやってみることにします
softya(ソフト屋) さんが書きました: SetGraphMode → ChangeWindowMode で切り替えられるはずです。
ただし、SetGraphMode でデータが全て破棄されるので注意して下さい。
「DXライブラリ置き場 リファレンスページ SetGraphMode 」
<a href="http://homepage2.nifty.com/natupaji/DxL ... .html#R4N1" target="_blank" rel="noreferrer" style="text-decoration:none;color:#009CE8;cursor:help;display:inline !important;">http://homepage2.nifty.com/natupaji/DxL ... ml#R4N1</a>

あと描画時の2倍は自分で直接DrawExtendGraphするかMakeScreen先に描画してからDrawExtendGraphのどちらかとなります。
画像やサウンドのロードをしなおせばいいのですね

各処理ごとに2倍にするのはめんどうなのでMakeScreenしたものを最後に倍にする方法にしたいと思います

ありがとうございました


ISLe さん

教えていただいたコードでウィンドウを動かすことが出来ました
すごく助かりました
ありがとうございました

L'z

Re: DXライブラリのウィンドウ関係で

#5

投稿記事 by L'z » 14年前

前回「解決!」を押しましたが同じウィンドウのことでまた疑問がありましたのでここに書くことにします。

前回の回答でタイトルバーなし、縁なし、のウィンドウでウィンドウの移動と最小化ができるようになりました。

今回タイトルバーと縁のあり、なしをユーザーが設定で変更できるようにしたいと思いました。
前回はSetWindowStyleModeに2を設定し、SetWindowLongPtrで最小化ボタン(WS_MINIMIZEBOX)をつけていました。
これに縁をつけようとWS_BORDERを設定したのですが縁が出ません。拡張ウィンドウスタイルのWS_EX_DLGMODALFRAME
なども試してみましたがでませんでした。
SetWindowStyleModeを0にして縁ありのものから縁を消そうという方法も試したのですがタイトルバーは消えるのに
縁は消えません。それどころか縁の四隅で変なものが出たり出なかったりします。

SetWindowStyleModeではウィンドウスタイル以外にどこを変更してウィンドウのデザインを変えているのでしょうか?
DXライブラリのソースを読んでもよくわかりませんでした。
どこを変更しているからウィンドウスタイルを変えても縁のあり、なしが変更できないのか、どこを変えれば
ウィンドウスタイルの変更が反映されるようになるのかを教えて欲しいです。

よろしくおねがいします。

L'z

Re: DXライブラリのウィンドウ関係で

#6

投稿記事 by L'z » 14年前

半分自己解決できました

一定時間ごとにウィンドウタイプ切り替えるようにしていたのですが
2つめ以降でSetWindowPosが抜けていました。初歩的なミスでした。

これでためしてみるとSetWindowStyleModeが2のときは縁、タイトルバーともに正しく動きました
しかしSetWindowStyleModeが0の場合は縁無し、タイトルバーなしにしたときに前の縁やタイトルバーが
一部残ったような状態になります。四隅に残った変なものというのは後ろのウィンドウの一部でした。

質問を
 SetWindowStyleModeが2のときは縁とタイトルバーのあり、なしを切り替えても問題ないのに
 SetWindowStyleModeが0になると縁とタイトルバーのあり、なしを切り替えると後ろのウィンドウの
 一部や縁やタイトルバーの一部が残るのでしょうか?
に変更します。
よろしくおねがいします。

ISLe
記事: 2650
登録日時: 15年前
連絡を取る:

Re: DXライブラリのウィンドウ関係で

#7

投稿記事 by ISLe » 14年前

L'z さんが書きました: SetWindowStyleModeが2のときは縁とタイトルバーのあり、なしを切り替えても問題ないのに
 SetWindowStyleModeが0になると縁とタイトルバーのあり、なしを切り替えると後ろのウィンドウの
 一部や縁やタイトルバーの一部が残るのでしょうか?
SetWindowStyleModeって途中で切り替えられないのでしたっけ。
L'zさんがどのようにウィンドウスタイルを切り替えているのか分からないので回答のしようがありません。
再現可能な最低限のコードで書かれた、実行ファイルを作成できるソースコードを貼っていただくことはできないでしょうか。

L'z

Re: DXライブラリのウィンドウ関係で

#8

投稿記事 by L'z » 14年前

ISLe さんが書きました: SetWindowStyleModeって途中で切り替えられないのでしたっけ。
途中で切り替えれるかではなくどうして0の場合にはおかしくなるのかが気になり質問しました
ISLe さんが書きました: L'zさんがどのようにウィンドウスタイルを切り替えているのか分からないので回答のしようがありません。
再現可能な最低限のコードで書かれた、実行ファイルを作成できるソースコードを貼っていただくことはできないでしょうか。
SetWindowStyleModeを2にした場合の正しく動くときと
SetWindowStyleModeが0のおかしい場合の2種類のソースを載せます。
ソースの違いは
SetWindowStyleModeの引数と
else if( loopcount == 300 )内のSetWindowLongPtrの引数の2箇所です。
SetWindowStyleModeが0の場合はタイトルバーと境界線を消すように、
SetWindowStyleModeが2の場合はタイトルバーと境界線をつけるようにしています。

境界線とタイトルバーの「あり」から「なし」へのウィンドウ切替時におかしくなるので
SetWindowStyleModeで設定されたウィンドウスタイルと変更後(「あり」なら「なし」、「なし」なら「あり」)のウィンドウスタイルを時間で交互に切り替えるようにしています。


実行はXP SP3のVC++2010で行っています。



SetWindowStyleModeを2にした場合
問題なく動きます

コード:

#include "DxLib.h"

int Init(){
	
	SetGraphMode( 960 , 540 , 32 );
	ChangeWindowMode( TRUE );
	SetWindowStyleMode( 2 );
	if( DxLib_Init() ) return -1;
	SetDrawScreen( DX_SCREEN_BACK );
	
	return 0;
}


void MainLoop(){

	HWND handle = GetMainWindowHandle();
	int loopcount = 0;
	LONG swsm = GetWindowLongPtr( handle, GWL_STYLE ); // SetWindowStyleModeの初期のウィンドウスタイル
	
	while( !ScreenFlip() && !ClearDrawScreen() && !ProcessMessage() ){

		// 5秒で交互にウィンドウモードを切り替える
		if( loopcount == 0 ){
			SetWindowLongPtr( handle, GWL_STYLE, swsm );
			SetWindowPos( handle, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED );
			
		}else if( loopcount == 300 ){
			SetWindowLongPtr( handle, GWL_STYLE, WS_SYSMENU | WS_MINIMIZEBOX | WS_BORDER | WS_DLGFRAME | WS_VISIBLE );
			SetWindowPos( handle, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED );
			
		}

		// 今どっちか表示
		if( loopcount>=0 && loopcount<300 ){
			DrawString( 0, 0, "SetWindowStyleMode2の初期のウィンドウスタイル", GetColor(255,255,255));
		}else{
			DrawString( 0, 0, "境界線あり", GetColor(255,255,255));
		}

		loopcount = (loopcount+1)%600;
	}
}


int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
						LPSTR lpCmdLine, int nCmdShow )
{

	if( Init() ) return -1;
	MainLoop();
	DxLib_End();
	return 0;

}
SetWindowStyleModeを0にした場合
境界線とタイトルバーが消えた時に右のほうにタイトルバーや×ボタンの赤いのなどが残ると思います

コード:

#include "DxLib.h"

int Init(){
	
	SetGraphMode( 960 , 540 , 32 );
	ChangeWindowMode( TRUE );
	SetWindowStyleMode( 0 );
	if( DxLib_Init() ) return -1;
	SetDrawScreen( DX_SCREEN_BACK );
	
	return 0;
}


void MainLoop(){

	HWND handle = GetMainWindowHandle();
	int loopcount = 0;
	LONG swsm = GetWindowLongPtr( handle, GWL_STYLE ); // SetWindowStyleModeの初期のウィンドウスタイル
	
	while( !ScreenFlip() && !ClearDrawScreen() && !ProcessMessage() ){

		// 5秒で交互にウィンドウモードを切り替える
		if( loopcount == 0 ){
			SetWindowLongPtr( handle, GWL_STYLE, swsm );
			SetWindowPos( handle, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED );
			
		}else if( loopcount == 300 ){
			SetWindowLongPtr( handle, GWL_STYLE, WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE );
			SetWindowPos( handle, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED );
			
		}

		// 今どっちか表示
		if( loopcount>=0 && loopcount<300 ){
			DrawString( 0, 0, "SetWindowStyleMode0の初期のウィンドウスタイル", GetColor(255,255,255));
		}else{
			DrawString( 0, 0, "境界線なし", GetColor(255,255,255));
		}

		loopcount = (loopcount+1)%600;
	}
}


int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
						LPSTR lpCmdLine, int nCmdShow )
{

	if( Init() ) return -1;
	MainLoop();
	DxLib_End();
	return 0;

}

ISLe
記事: 2650
登録日時: 15年前
連絡を取る:

Re: DXライブラリのウィンドウ関係で

#9

投稿記事 by ISLe » 14年前

#ウィンドウスタイルの指定が滅茶苦茶ですけどそれは置いといて…

SetWindowStyleModeを0からはじめるほうがおかしい原因は2つありました。
  1. WS_EX_CLIENTEDGE拡張スタイルが残っていて、ウィンドウ(正確にはクライアント領域)の周りにくぼみを付ける縁が描かれる。
  2. 最初に表示されたときの枠の分だけウィンドウサイズが大きいままなので、DXライブラリ(DirectX)の描画領域をはみ出した部分が見えてしまっている。
SetGraphModeで指定するサイズはクライアント領域のサイズなので、枠の分は含まれません。
なので枠を付けたり消したりするときは枠の分を考慮してウィンドウサイズを調整する必要があります。

というわけなので、SetWindowStyleModeを2から始めるほうもウィンドウサイズが期待どおりではないと思います。

L'z

Re: DXライブラリのウィンドウ関係で

#10

投稿記事 by L'z » 14年前

ISLe さんが書きました:#ウィンドウスタイルの指定が滅茶苦茶ですけどそれは置いといて…
ウィンドウスタイルの指定は調べたのですが「WS_~~」がどういう意味かというのは
たくさんあったのですが良い指定例というのは見つけられませんでした。

良い例を教えていただけませんか?

ISLe さんが書きました: SetWindowStyleModeを0からはじめるほうがおかしい原因は2つありました。
  1. WS_EX_CLIENTEDGE拡張スタイルが残っていて、ウィンドウ(正確にはクライアント領域)の周りにくぼみを付ける縁が描かれる。
  2. 最初に表示されたときの枠の分だけウィンドウサイズが大きいままなので、DXライブラリ(DirectX)の描画領域をはみ出した部分が見えてしまっている。
SetGraphModeで指定するサイズはクライアント領域のサイズなので、枠の分は含まれません。
なので枠を付けたり消したりするときは枠の分を考慮してウィンドウサイズを調整する必要があります。

というわけなので、SetWindowStyleModeを2から始めるほうもウィンドウサイズが期待どおりではないと思います。
試してみたところSetWindowStyleModeが0のときは960x540の外に枠があり、枠を消したときにもともとタイトルバーが
あった位置から960x540だけ更新され960x540を超えた部分が残っていました。

SetWindowStyleModeが2のときは960x540の中に枠ができ、ゲームを表示する部分が960x540よりも小さくなっていました。

枠を考えてウィンドウサイズを調節する必要がある分SetWindowStyleModeを途中で切り替える方法が楽なのですね。
SetWindowStyleModeを途中で切り替えるとウィンドウ位置がずれるのでそこを自分で調節する必要はありますけど。

SetWindowStyleModeの疑問がはれました。
ありがとうございました。

ISLe
記事: 2650
登録日時: 15年前
連絡を取る:

Re: DXライブラリのウィンドウ関係で

#11

投稿記事 by ISLe » 14年前

L'z さんが書きました:ウィンドウスタイルの指定は調べたのですが「WS_~~」がどういう意味かというのは
たくさんあったのですが良い指定例というのは見つけられませんでした。

良い例を教えていただけませんか?
良い例というか実際にSetWindowStyleModeで設定されるスタイルを参照して、シンボルの意味合いを考慮して決めるのが良いと思います。
あとからコードを見たときに意味が分かるように。
WS_DLGFRAMEとか何がしたかったのか分からなくなる可能性大だと思います。

ウィンドウのスタイルを調べるツールがあります。
有償版のVisual StudioにはSpy++というツールが付属しています。
ライセンス上問題あるでしょうけど、試用版や古いWindowsSDKからぶっこ抜くこともできます。
Winspector Spyというフリーソフトもあります。
Winspector Spyは公式サイトが無くなっているのでミラーサイトを探してください。

L'z

Re: DXライブラリのウィンドウ関係で

#12

投稿記事 by L'z » 14年前

ISLe さんが書きました: 良い例というか実際にSetWindowStyleModeで設定されるスタイルを参照して、シンボルの意味合いを考慮して決めるのが良いと思います。
あとからコードを見たときに意味が分かるように。
WS_DLGFRAMEとか何がしたかったのか分からなくなる可能性大だと思います。
SetWinowStyleModeを設定し、GetWindowLongPtrの値を16進表示して
その値からどれを使っているのかを調べて必要そうなものだけを書いたのですが…

WS_DLGFRAMEをつけることでタイトルバーが表示されるようになったので
タイトルバーをつけるために使いました。
しかし、
ISLe さんが書きました:WS_DLGFRAMEとか何がしたかったのか分からなくなる可能性大
と書かれていることからタイトルバーをつけるために使うのではないようですね。
もう少し調べてみます。
ISLe さんが書きました: ウィンドウのスタイルを調べるツールがあります。
有償版のVisual StudioにはSpy++というツールが付属しています。
ライセンス上問題あるでしょうけど、試用版や古いWindowsSDKからぶっこ抜くこともできます。
Winspector Spyというフリーソフトもあります。
Winspector Spyは公式サイトが無くなっているのでミラーサイトを探してください。
便利なものがあるのですね。
無料のVC++Expressを使っているのでフリーのものを使って見ることにします。

ありがとうございました。

閉鎖

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