ページ 11

モードレスダイアログボックス

Posted: 2012年2月23日(木) 02:18
by s707
現在デスクトップクロックを作成しています。

ダイアログボックスを出力している間も
時計の針を動かしたいので
モードレスダイアログボックスで出力させたいです。

下のコードで時計の針は動くようになりましたが
ダイアログボックスをクリックした時の反応が
おかしいです。

ご助力の程、よろしくお願いします。

コード:

//main.cpp
#include <windows.h>
#include "DxLib.h"
#include "dayData.h"
#include "draw_clock.h"
#include "Setup.h"
#include "resource.h"

#define APP_NAME TEXT("clock")
#define chara_width 64

void jihou(struct dayData* day);
void plan(struct dayData* day);
void Time(struct dayData* day);
void date(struct dayData* day);
void version(struct dayData* day);
int  title(int,struct dayData* day);


HINSTANCE hInst;
HWND hWnd;//メインのウィンドウハンドル
HWND hDlg;//モードレスダイアログボックスのハンドル

struct dayData day[450];

BOOL CALLBACK MyDlgProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp){
	switch(msg){
	case WM_COMMAND:
		switch(LOWORD(wp) ){
		case IDOK:
			EndDialog(hDlg,IDOK);
			return TRUE;
		case IDCANCEL:
			EndDialog(hDlg,IDCANCEL);
			return TRUE;
		case IDC_BUTTON1:
			version(day);
			return TRUE;			
		}
		return FALSE;
	}
	return FALSE;
}

LRESULT CALLBACK WindowProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
	static int top = 0;

	switch(uMsg) {
	case WM_MOVING:
		{		
			LPRECT p = (LPRECT)lParam;
			top = p -> top;
			break;
		}
	case WM_WINDOWPOSCHANGING:		
		{
			WINDOWPOS* p = (WINDOWPOS*)lParam;
			p -> y = top;
			break;
		}
	case WM_NCHITTEST:
		return HTCAPTION;
    case WM_RBUTTONDOWN:
		hDlg = CreateDialog( hInst, MAKEINTRESOURCE(IDD_DIALOG1), hWnd, (DLGPROC)MyDlgProc );
		ShowWindow(hDlg,SW_NORMAL);
		break;
	case WM_CLOSE:
		if(IsWindow(hDlg)){
			DestroyWindow(hDlg);
		}
		break;
	}
	return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ){
	hInst = hInstance;
	if(FindWindow(APP_NAME , NULL) != NULL ){
		MessageBox(NULL , TEXT("多重起動を確認しました") , NULL , MB_OK);
		return 0;
	}

	// マウス状態管理用変数
	int nClickNow = 0 , nClickPrev = 0;
	int nClickNow_R = 0 , nClickPrev_R = 0;
	int nClickR_Count = 0;

	int status = 0,temp = 0;
	bool menu_flg = false;
	
	// 画面モードの変更
	SetGraphMode( 1680 , 1050 , 32 ) ;//パソコンの解像度に合わせる

	SetMainWindowText("clock");
	ChangeWindowMode( TRUE );

	SetUseBackBufferTransColorFlag( TRUE );// ウインドウの透過色モードON
	SetWindowStyleMode(0);
	SetAlwaysRunFlag( TRUE );

	SetHookWinProc( WindowProc );
	if ( DxLib_Init( ) == -1 ) return -1;

	SetDrawScreen(DX_SCREEN_BACK);

	Load_Graph();
	Setup_load(day);//設定を読み込む
	plan(day);//予定を音声再生する	

	MSG msg;

	int NewMouse = 0, OldMouse = GetMouseInput();
	while ( ProcessMessage( ) == 0 && CheckHitKey( KEY_INPUT_ESCAPE ) == 0 ) {
		if(!hDlg || !IsDialogMessage(hDlg,&msg)){
			TranslateMessage(&msg);
			DispatchMessage(&msg);
        }
    }

        //処理を省略

	DxLib_End( );
	return (int)msg.wParam;
}

Re: モードレスダイアログボックス

Posted: 2012年2月23日(木) 03:31
by ISLe
114~117行目ですが、変数msgの中身が不定ですけど。

DXライブラリではProcessMessageにメッセージループが隠蔽されているので実装不可能なのでは。

Re: モードレスダイアログボックス

Posted: 2012年2月23日(木) 13:47
by s707
ISLe様、ご返信ありがとうございます。

コード:

while ( ProcessMessage( ) == 0 && CheckHitKey( KEY_INPUT_ESCAPE ) == 0 ) {
                          ↓ゲットメッセージ関数を追加しました。追加後もダイアログと時計の動作が安定しません。
while ( GetMessage(&msg,NULL,0,0) && ProcessMessage( ) == 0 && CheckHitKey( KEY_INPUT_ESCAPE ) == 0 ) {
試しに、ここからプロセスメッセージ関数を消すと
ダイアログボックスは正常になりますが
時計が安定しなくなります。

絶対に必要な関数なので抜けませんけど。

Re: モードレスダイアログボックス

Posted: 2012年2月23日(木) 16:48
by ISLe
GetMessageでメッセージを横取りすると、今度は本来DXライブラリが処理しなければならないメッセージがProcessMessageに届かなくなります。
結果としてDXライブラリに不具合が発生します。

ウィンドウズのメッセージキューはスレッドごとに独立するので、新たにスレッドを生成して、そちらでダイアログを生成してメッセージループを回す処理を行えば可能かもしれません。

Re: モードレスダイアログボックス

Posted: 2012年2月25日(土) 03:46
by s707
ダイアログプロシージャの中に時計を描画する
関数を呼んでみました。

毎秒ではありませんでしたが時計が動きました。
この方法では無理でしょうか?

コード:

BOOL CALLBACK MyDlgProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp){
	time_t timer;
	struct tm *local;
	timer = time(NULL);//現在時刻を取得
	local = localtime(&timer); //地方時に変換
	
	ClearDrawScreen( );//以下は時計描画関数です。
	DrawGraph( clock_x , clock_y , GHandle[0] , TRUE ) ;//文字盤
	DrawRotaGraph2( needle_x, needle_y, 1, 1, 1.0,( (local->tm_hour%12)*30 + (local->tm_min/2) + 180)*PI/180, GHandle[1], TRUE ) ;//短針  時間*30度%12時間 + 分/2   1分毎に0.5度づつ進む為/2
	DrawRotaGraph2( needle_x, needle_y, 1, 1, 1.0,( (local->tm_min*6) + 180)*PI/180, GHandle[2], TRUE ) ;//長針
	DrawRotaGraph2( needle_x, needle_y, 1, 1, 1.0,( (local->tm_sec*6) + 180)*PI/180, GHandle[3], TRUE ) ;//秒針
	ScreenFlip( );

	switch(msg){
	case WM_COMMAND:
		switch(LOWORD(wp) ){
		case IDOK:
			EndDialog(hDlg,IDOK);
			return TRUE;
		case IDCANCEL:
			EndDialog(hDlg,IDCANCEL);
			return TRUE;
		case IDC_BUTTON1:
			DialogBox( hInst, MAKEINTRESOURCE(IDD_DIALOG2), hWnd, (DLGPROC)MyDlgProc );
			return TRUE;			
		}
		return FALSE;
	}
	return FALSE;
}

Re: モードレスダイアログボックス

Posted: 2012年2月25日(土) 17:43
by ISLe
s707 さんが書きました:ダイアログプロシージャの中に時計を描画する
関数を呼んでみました。

毎秒ではありませんでしたが時計が動きました。
この方法では無理でしょうか?
わたしの個人的な感想としては危険なコードだと思います。
たまたま動いているレベルで保証された動作ではないです。

Re: モードレスダイアログボックス

Posted: 2012年2月25日(土) 20:54
by s707
http://www.kumei.ne.jp/c_lang/intro/no_99.htm
こちらを参考にスレッド生成を試してみました。

コード:

//main.cpp
#include <windows.h>
#include <time.h>
#include "DxLib.h"
#include "dayData.h"
#include "draw_clock.h"
#include "Setup.h"
#include "resource.h"
#include <stdio.h>//追加
#include <process.h>//追加

#define APP_NAME TEXT("clock")
#define chara_width 64

void jihou(struct dayData* day);
void plan(struct dayData* day);
void Time(struct dayData* day);
void date(struct dayData* day);
void version(struct dayData* day);
int  title(int,struct dayData* day);
unsigned __stdcall mythread(void *);//追加


HINSTANCE hInst;
HWND hWnd;//メインのウィンドウハンドル
HWND hDlg;//モードレスダイアログボックスのハンドル

struct dayData day[450];
int status = 0,temp = 0;

unsigned __stdcall mythread(void *lpx)
{
    int i;
    for (i = 0; i < 4; i++)
        //printf("スレッドです[%d]\n", i);
    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ){
	DWORD thID;
    HANDLE hTh;
    int i;

    hTh = (HANDLE)_beginthreadex(NULL, 0, mythread, NULL, 0, &thID);
    
    for (i = 0; i < 20; i++) {
        //printf("Mainです[%d]\n", i);
    }
        
    if (hTh != NULL) {
        CloseHandle(hTh);
        //printf("ハンドルクローズしました\n");
    }

    while ( ProcessMessage( ) == 0 && CheckHitKey( KEY_INPUT_ESCAPE ) == 0 ) {
        //処理を省略
    }
    return 0;
}
C2664: '_beginthreadex' : 6 番目の引数を 'DWORD *' から 'unsigned int *' に変換できません。(新しい機能 ; ヘルプを参照)
1> 指示された型は関連がありません。変換には reinterpret_cast、C スタイル キャストまたは関数スタイルのキャストが必要です。


エラーが出たので下記の様に変えましたが駄目でした。
hTh = (HANDLE)_beginthreadex(NULL, 0, mythread, NULL, 0, reinterpret_cast<DWORD>(&thID) );

Re: モードレスダイアログボックス

Posted: 2012年2月25日(土) 23:41
by ISLe
'unsigned int *'を要求しているところに'DWORD *'を渡してエラーになっているのだから、'unsigned int *'にキャストするのだと思いますけど。

Re: モードレスダイアログボックス

Posted: 2012年2月26日(日) 18:08
by ISLe
サンプルコード書いてみました。
エラー処理とか抜けているのでコピペは危険です。

コード:

#include "DxLib.h"
#include <process.h>

HANDLE hThread;
HWND hDlg;

BOOL CALLBACK MyDlgProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp)
{
	switch(msg) {
	case WM_COMMAND:
		switch(LOWORD(wp)) {
		case IDOK:
			PostQuitMessage(IDOK);
			return TRUE;
		case IDCANCEL:
			PostQuitMessage(IDCANCEL);
			return TRUE;
		}
		return FALSE;
	}
	return FALSE;
}

unsigned __stdcall mythread(void *lpx)
{
	MSG msg;
	hDlg = CreateDialog(GetModuleHandle(NULL), "DIALOG", GetMainWindowHandle(), MyDlgProc);
	ShowWindow(hDlg, SW_NORMAL);
	while (GetMessage(&msg, NULL, 0, 0)) {
		if (!IsDialogMessage(hDlg, &msg)) {
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}
	return msg.wParam;
}


LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch(uMsg) {
	case WM_RBUTTONDOWN:
		if (hThread == NULL) {
			hThread = (HANDLE)_beginthreadex(NULL, 0, mythread, NULL, 0, NULL);
		}
		break;
	}
	return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	ChangeWindowMode(TRUE);
	SetAlwaysRunFlag(TRUE);
	SetHookWinProc(WindowProc);
	if (DxLib_Init() == -1) return 0;
	SetDrawScreen(DX_SCREEN_BACK);

	DWORD ExitCode = -1;
	while (ProcessMessage( ) == 0) {
		ClearDrawScreen();

		DrawFormatString(0,0,GetColor(255,255,255),"%d",(int)GetNowCount());
		DrawString(0,50,
			ExitCode == IDOK ? "OKボタンが押された" :
			ExitCode == IDCANCEL ? "CANCELボタンが押された" :
			ExitCode == STILL_ACTIVE ? "実行中" : "",
			GetColor(255,255,255)
		);

		if (hThread) {
			GetExitCodeThread(hThread, &ExitCode);
			if (ExitCode != STILL_ACTIVE) {
				CloseHandle(hThread);
				hThread = NULL;
			}
		}
		ScreenFlip();
	}
	DxLib_End( );
	return 0;
}

Re: モードレスダイアログボックス

Posted: 2012年2月26日(日) 19:51
by s707
ISLe様、コード作成ありがとうございます。

先ほど試した後にすぐ返信すればよかったです。
こちらで成功しました。

コードの方も参考にしてみますね。
これから試してみます。

今回も助かりました。ありがとうございます。

コード:

LRESULT CALLBACK WindowProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
	static int top = 0;

	switch(uMsg) {
	case WM_MOVING:
		{		
			LPRECT p = (LPRECT)lParam;
			top = p -> top;
			break;
		}
	case WM_WINDOWPOSCHANGING:		
		{
			WINDOWPOS* p = (WINDOWPOS*)lParam;
			p -> y = top;
			break;
		}
	case WM_NCHITTEST:
		return HTCAPTION;
	case WM_RBUTTONDOWN:
		DWORD thID;
		HANDLE hTh;
		int i;

		hTh = (HANDLE)_beginthreadex(NULL, 0, mythread, NULL, 0, reinterpret_cast<unsigned int*>(&thID) );

		break;
	case WM_CLOSE:
		if(IsWindow(hDlg)){
			DestroyWindow(hDlg);
		}
		break;
	}
	return 0;
}

unsigned __stdcall mythread(void *lpx){
	DialogBox( hInst, MAKEINTRESOURCE(IDD_DIALOG1), hWnd, (DLGPROC)MyDlgProc );
	return 0;
}