ページ 1 / 1
CreateWindowExで作成したウィンドウに文字を表示
Posted: 2011年2月05日(土) 11:04
by あま
コード:
hWndLoopTxt = CreateWindowEx(WS_EX_CLIENTEDGE,"edit","",
WS_CHILD|WS_VISIBLE|WS_DISABLED,10,305,100,25,
hWnd,(HMENU)LOOP_TEXT_BOX,hInstance,NULL);
このようにウィンドウを用意しました。
ボタンを押すと、
コード:
while(i<=x)
{
sprintf(buf,"%d",i);
SetWindowText(hWndLoopTxt,buf);
i++;
}
この部分が実行されてLOOP_TEXT_BOXに値を表示させたいのですが、
最後の終了の値だけ表示されて他の値は表示されません。
私がやりたいことはリアルタイム(に近い感じ)で随時表示させたいです。
コンソールでいうと
コード:
while(i<=x)
{
printf("%d\r",i);
}
みたいな感じでやりたいです。
こんなことはできないのですか?
Re: CreateWindowExで作成したウィンドウに文字を表示
Posted: 2011年2月05日(土) 11:17
by Ciel
毎回上書きされてしまうので、Sleep(ミリ秒)を入れるしかないんじゃないでしょうか?
Re: CreateWindowExで作成したウィンドウに文字を表示
Posted: 2011年2月05日(土) 11:53
by あま
私もそう思ってSleep入れてみたのですが
やはり最後の文字しか表示されませんでした。
0-10000
とかやった場合に表示されるのは10000だけです。
本来なら
0
1
2
3
:
10000
と順番に表示してくれると助かるのですが・・・
Re: CreateWindowExで作成したウィンドウに文字を表示
Posted: 2011年2月05日(土) 12:16
by Ciel
ボタンを押したら実行っていうのは、ウィンドウプロシージャ内で実行しているということですか?
↓のWM_KEYDOWNのウィンドウメッセージが、WM_COMMANDになったような感じですかね?
私の環境ではこれでもタイトルのテキストは変わりましたが、ループ中はウィンドウプロシージャの処理が独占されてしまって、
他の処理が動かなくなってしまうのでおすすめしません。
下のコメントアウトしてる部分のように、SetTimer関数を使ってみるのはどうでしょうか。
もしくはスレッドでも。
コード:
static int i=0;
char buf[50];
switch(msg){
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_CREATE:
//SetTimer(hwnd,1,1000,NULL);
return 0;
case WM_TIMER:
//sprintf(buf,"%d",i);
//SetWindowText(hwnd,buf);
//++i;
return 0;
case WM_KEYDOWN:
while(i<200){
sprintf(buf,"%d",i);
SetWindowText(hwnd,buf);
++i;
Sleep(100);
}
return 0;
Re: CreateWindowExで作成したウィンドウに文字を表示
Posted: 2011年2月05日(土) 14:39
by あま
Ciel さんが書きました:ボタンを押したら実行っていうのは、ウィンドウプロシージャ内で実行しているということですか?
そうです。
ウィンドウプロシージャ内での実行です。
case WM_CREATE:でウィンドウやボタンを作成し、
case WM_COMMAND:内のcase START_BUTTON:で
while(i<=x)
{
sprintf(buf,"%0*d",strlen(start),i);
SetWindowText(hWndAttackTxt,buf);
i++;
}
このようにやっています。
Ciel さんが書きました:
下のコメントアウトしてる部分のように、SetTimer関数を使ってみるのはどうでしょうか。
もしくはスレッドでも。
この質問スレッドを立てる前に
case WM_COMMAND:内のcase START_BUTTON:でスレッドを作成し、
作成したスレッド内で同じように
while(i<=x)
{
sprintf(buf,"%0*d",strlen(start),i);
SetWindowText(hWndAttackTxt,buf);
i++;
}
このようにやってみたのですが、これでもダメでした。
あともう一つわからないことがあって追加の質問という形になってしまって申し訳ないのですが、
現在StartとEndの二つのウィンドウフォームを作成しています。
HTMLのテキストフォームとかですとTabを押したときに次のフォームに移動、
チェックボックスならスペースでチェックとかになりますけど、
CreateWindowEx()ではそのようなことはできないのでしょうか?
いちいちフォームにカーソルを合わせないとダメなんですかね?
Re: CreateWindowExで作成したウィンドウに文字を表示
Posted: 2011年2月05日(土) 14:43
by みけCAT
あま さんが書きました:あともう一つわからないことがあって追加の質問という形になってしまって申し訳ないのですが、
現在StartとEndの二つのウィンドウフォームを作成しています。
HTMLのテキストフォームとかですとTabを押したときに次のフォームに移動、
チェックボックスならスペースでチェックとかになりますけど、
CreateWindowEx()ではそのようなことはできないのでしょうか?
いちいちフォームにカーソルを合わせないとダメなんですかね?
ウィンドウスタイル「WS_TABSTOP」を使うとどうでしょうか?
これを使うと、これを付けたところをタブで行き来できるようになります。
Re: CreateWindowExで作成したウィンドウに文字を表示
Posted: 2011年2月05日(土) 15:07
by あま
みけCAT さんが書きました:
ウィンドウスタイル「WS_TABSTOP」を使うとどうでしょうか?
これを使うと、これを付けたところをタブで行き来できるようになります。
できないですね・・・
フォーム内でタブが反映されてしまいます。
スタイルは
WS_CHILD|WS_VISIBLE|WS_TABSTOP|ES_MULTILINE|WS_DISABLED|ES_NUMBER
こんな感じなんですが、相性が悪かったり、順番が関係するということありますか?
Re: CreateWindowExで作成したウィンドウに文字を表示
Posted: 2011年2月05日(土) 15:12
by shiro4ao
ダイアログボックスと同じキーボード選択を実現するIsDialogMessageAPIを使って
みるとうまくいくかもしれません。
メッセージループの例)
コード:
while (GetMessage(&msg , NULL , 0 , 0 )) {
if (!IsDialogMessage(hWnd, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
Re: CreateWindowExで作成したウィンドウに文字を表示
Posted: 2011年2月05日(土) 16:53
by kimuchi
横から失礼します。
あま さんが書きました:私もそう思ってSleep入れてみたのですが
やはり最後の文字しか表示されませんでした。
0-10000
とかやった場合に表示されるのは10000だけです。
本来なら
0
1
2
3
:
10000
と順番に表示してくれると助かるのですが・・・
SetWindowText関数を使うと、内容をすべて上書きしてしまうので、最後に出力したもの以外は残りません。
この場合はReplaceSel関数を使うのが最適だと思います。
具体的には、
GetWindowTextLength関数とSetSel関数で、文字終端位置を取得して、
ReplaceSel関数を使って文字列の挿入を行います。
コード:
while(i<=x)
{
sprintf(buf,"%d",i);
SetSel(,GetWindowTextLength(hWndLoopTxt));
ReplaceSel(buf);
i++;
}
追記:
これMFCでした。すみません。
MFCですらないです、本当にすみません。
正しくは
コード:
while(i<=x)
{
sprintf(buf,"%d",i);
SendMessage( hWndLoopTxt, EM_SETSEL, GetWindowTextLength(hWndLoopTxt), GetWindowTextLength(hWndLoopTxt) );
SendMessage( hWndLoopTxt, EM_REPLACESEL, 0, (LPARAM)buf );
i++;
}
のようにSendMessageを使う形になります。
Re: CreateWindowExで作成したウィンドウに文字を表示
Posted: 2011年2月05日(土) 17:32
by ISLe
UpdateWindow(hWndLoopTxt);
が使えないですかね。
とは言えアプリが応答なしになったり強制終了させられたりしないようにタイマーイベントを使うなどしてきちんとシステムに制御を返す方法をお勧めします。
ダイアログ風のキー操作を実装するにはメッセージループにIsDialogMessageを入れるだけでは不十分です。
以前同じようなやり取りがありました。IsDialogMessageで過去ログを検索してみてください。
Re: CreateWindowExで作成したウィンドウに文字を表示
Posted: 2011年2月05日(土) 23:07
by あま
コード:
while(i<=x)
{
sprintf(buf,"%d",i);
SendMessage( hWndLoopTxt, EM_SETSEL, GetWindowTextLength(hWndLoopTxt), GetWindowTextLength(hWndLoopTxt) );
SendMessage( hWndLoopTxt, EM_REPLACESEL, 0, (LPARAM)buf );
i++;
}
これを使ってみたのですが、ちょっと想像していた処理と変わってしまいました。
これだとコンソールで言う
while(i<=x)
{
printf("%d",i);
i++;
}
このようになってしまいます。
実装したいのは
while(i<=x)
{
printf("%d\r",i);
i++;
}
このような形にしたいです。
Tabでの移動はちょっとややこしいですね・・・
とりあえず、今マウスカーソルを合わせれば実行できてるので
これは置いておきます。
表示の方がうまくいかないのでこちらの知恵をお貸しください。
自分で質問追加しといて申し訳ないです。
Re: CreateWindowExで作成したウィンドウに文字を表示
Posted: 2011年2月06日(日) 01:03
by bitter_fox
あま さんが書きました:
Ciel さんが書きました:
下のコメントアウトしてる部分のように、SetTimer関数を使ってみるのはどうでしょうか。
もしくはスレッドでも。
この質問スレッドを立てる前に
case WM_COMMAND:内のcase START_BUTTON:でスレッドを作成し、
作成したスレッド内で同じように
while(i<=x)
{
sprintf(buf,"%0*d",strlen(start),i);
SetWindowText(hWndAttackTxt,buf);
i++;
}
このようにやってみたのですが、これでもダメでした。
別スレッドに持って行ってもやってることは同じなので大して変化はないと思います。
SetTimerを使った方はやってみましたか?(ちなみに軽く実装してみましたがこの方法で出来ました)
Re: CreateWindowExで作成したウィンドウに文字を表示
Posted: 2011年2月06日(日) 02:20
by あま
bitter_fox さんが書きました:
SetTimerを使った方はやってみましたか?(ちなみに軽く実装してみましたがこの方法で出来ました)
はい。やってみました。
いまWM_CREATE内でCreateWindowExを使ってウィンドウを作成しているのですが
それがいけないのでしょうか?
Re: CreateWindowExで作成したウィンドウに文字を表示
Posted: 2011年2月06日(日) 02:28
by bitter_fox
あま さんが書きました:
はい。やってみました。
いまWM_CREATE内でCreateWindowExを使ってウィンドウを作成しているのですが
それがいけないのでしょうか?
どういった風に実装したのかが解らないのでSetTimerを使った時のメッセージプロシージャを載せていただけますでしょうか?
僕もWM_CREATEでCreateWindowExを使っていますがちゃんとできています。
Re: CreateWindowExで作成したウィンドウに文字を表示
Posted: 2011年2月06日(日) 03:52
by あま
コード:
case WM_TIMER:
i = atoi(start);
x = atoi(end);
while(i<=x)
{
sprintf(buf,"%0*d",strlen(start),i);
SetWindowText(hWndLoopTxt,buf);
//SendMessage(hWndLoopTxt,EM_SETSEL,GetWindowTextLength(hWndLoopTxt),GetWindowTextLength(hWndLoop));
//SendMessage(hWndLoopTxt,EM_REPLACESEL,0,(LPARAM)buf );
i++;
}
return 0L;
case WM_COMMAND:
switch(LOWORD(wP))
{
case START_BUTTON:
{
GetWindowText(hWndStartTxt,start,1024);
GetWindowText(hWndEndTxt,end,1024);
SetTimer(hWndLoopTxt,1,1000,NULL);
KillTimer(hWndLoopTxt,1);
}
}
いまはこんな感じで書いています。
Re: CreateWindowExで作成したウィンドウに文字を表示
Posted: 2011年2月06日(日) 04:11
by bitter_fox
あま さんが書きました:コード:
case WM_TIMER:
i = atoi(start);
x = atoi(end);
while(i<=x)
{
sprintf(buf,"%0*d",strlen(start),i);
SetWindowText(hWndLoopTxt,buf);
//SendMessage(hWndLoopTxt,EM_SETSEL,GetWindowTextLength(hWndLoopTxt),GetWindowTextLength(hWndLoop));
//SendMessage(hWndLoopTxt,EM_REPLACESEL,0,(LPARAM)buf );
i++;
}
タイマーを使ってることがループになっているのでその中でループをする必要はないですよ。
僕の実装だと次のようになります。
コード:
#define MAX_COUNT 200
#define TIME 300
#define IDT_COUNT 4000
#define IDE_EDIT 4000
#define IDB_BTN 4010
//////////////////////////////////////////////////////////////////////////////////////
static int count;
static HWND hEdit, hBtn;
TCHAR str[256];
static BOOL flag_timer_exist = 0;
//////////////////////////////////////////////////////////////////////////////////////
case WM_TIMER:
switch (wp)
{
case IDT_COUNT:
wsprintf(str, "%d", count);
SetWindowText(hEdit, str);
count++;
if (count > MAX_COUNT)
{
KillTimer(hWnd, IDT_COUNT);
flag_timer_exist = 0;
}
break;
}
break;
case WM_COMMAND:
if ((HWND)lp == hBtn)
{
count = 0;
SetTimer(hWnd, IDT_COUNT, TIME, NULL);
flag_timer_exist = 1;
}
break;
case WM_CLOSE:
if (flag_timer_exist)
{
KillTimer(hWnd, IDT_COUNT);
}
DestroyWindow(hWnd);
break;
あと、
あま さんが書きました:コード:
case START_BUTTON:
{
GetWindowText(hWndStartTxt,start,1024);
GetWindowText(hWndEndTxt,end,1024);
SetTimer(hWndLoopTxt,1,1000,NULL);
KillTimer(hWndLoopTxt,1);
}
これだと、タイマーを作成して、すぐに削除しているので何も表示されなかったのでしょう・・・(WM_TIMERが発生する前にタイマーが削除されてしまいます。)
[hr][修正]
プログラムを一部修正しました(flag_timer_exist)
Re: CreateWindowExで作成したウィンドウに文字を表示
Posted: 2011年2月06日(日) 09:19
by kimuchi
sprintf(buf,"%d\r",i);
としても変わりませんか?
Re: CreateWindowExで作成したウィンドウに文字を表示
Posted: 2011年2月06日(日) 12:09
by Ciel
Re: CreateWindowExで作成したウィンドウに文字を表示
Posted: 2011年2月06日(日) 15:16
by ISLe
華麗にスルーされてますがもう一度書いてみます。
Sleepの前にUpdateWindowを入れればwhileループでも表示されますよ。
ウインドウ操作に反応しなくなるのでお勧めはしませんけど。
タイマー使うにしてもモニターのリフレッシュレートより速く書き換えると物理的に見えません。
ウチではコンソールでも最後の数字しか見えないです。
Re: CreateWindowExで作成したウィンドウに文字を表示
Posted: 2011年2月07日(月) 17:26
by あま
bitter_fox さんが書きました:
タイマーを使ってることがループになっているのでその中でループをする必要はないですよ。
僕の実装だと次のようになります。
コード:
#define MAX_COUNT 200
#define TIME 300
#define IDT_COUNT 4000
#define IDE_EDIT 4000
#define IDB_BTN 4010
//////////////////////////////////////////////////////////////////////////////////////
static int count;
static HWND hEdit, hBtn;
TCHAR str[256];
static BOOL flag_timer_exist = 0;
//////////////////////////////////////////////////////////////////////////////////////
case WM_TIMER:
switch (wp)
{
case IDT_COUNT:
wsprintf(str, "%d", count);
SetWindowText(hEdit, str);
count++;
if (count > MAX_COUNT)
{
KillTimer(hWnd, IDT_COUNT);
flag_timer_exist = 0;
}
break;
}
break;
case WM_COMMAND:
if ((HWND)lp == hBtn)
{
count = 0;
SetTimer(hWnd, IDT_COUNT, TIME, NULL);
flag_timer_exist = 1;
}
break;
case WM_CLOSE:
if (flag_timer_exist)
{
KillTimer(hWnd, IDT_COUNT);
}
DestroyWindow(hWnd);
break;
あれから編集しました。
コード:
case WM_TIMER:
switch(LOWORD(wP))
{
case 1008:
sprintf(buf,"%0*d",strlen(start),i);
SetWindowText(hWndLoopTxt,buf);
i++;
if(i > x)
{
KillTimer(hWndLoopTxt,1008);
}
break;
}
break;
case WM_COMMAND:
switch(LOWORD(wP))
{
case START_BUTTON:
{
GetWindowText(hWndStartTxt,start,1024);
GetWindowText(hWndEndTxt,end,1024);
if(strlen(start) == 0)
{
MessageBox(NULL,(LPCSTR)"Start is not input.",(LPCSTR)"ERROR!!",MB_OK);
break;
}
if(strlen(end) == 0)
{
MessageBox(NULL,(LPCSTR)"End is not input.",(LPCSTR)"ERROR!!",MB_OK);
break;
}
SetTimer(hWndLoopTxt,1008,300,NULL);
i = atoi(start);
x = atoi(end);
break;
}
break;
}
break;
今こんな感じなのですが、なにも表示されません。
Re: CreateWindowExで作成したウィンドウに文字を表示
Posted: 2011年2月07日(月) 17:26
by あま
ありがとうございます。
表示の方が完成したらやってみます。
Re: CreateWindowExで作成したウィンドウに文字を表示
Posted: 2011年2月07日(月) 17:27
by あま
kimuchi さんが書きました:sprintf(buf,"%d\r",i);
としても変わりませんか?
一番最初にやってみました。
\rの部分が文字化けしてしまってできませんでした。
Re: CreateWindowExで作成したウィンドウに文字を表示
Posted: 2011年2月07日(月) 17:30
by あま
ISLe さんが書きました:華麗にスルーされてますがもう一度書いてみます。
Sleepの前にUpdateWindowを入れればwhileループでも表示されますよ。
ウインドウ操作に反応しなくなるのでお勧めはしませんけど。
タイマー使うにしてもモニターのリフレッシュレートより速く書き換えると物理的に見えません。
ウチではコンソールでも最後の数字しか見えないです。
すみませんでした。
スルーしてたわけではないのですが・・・
ウィンドウ操作に反応しなくなるとはどういうことでしょうか?
ループ中は他の操作ができなくなるということですか?
Re: CreateWindowExで作成したウィンドウに文字を表示
Posted: 2011年2月07日(月) 18:01
by ISLe
あま さんが書きました:ウィンドウ操作に反応しなくなるとはどういうことでしょうか?
ループ中は他の操作ができなくなるということですか?
例えばボタンのクリックイベントハンドラに
Sleep(10000); /* 10秒間停止 */
というのを入れて、ボタンを押してすぐにウインドウを動かそうとしてみてください。
Re: CreateWindowExで作成したウィンドウに文字を表示
Posted: 2011年2月07日(月) 18:08
by あま
ISLe さんが書きました:
例えばボタンのクリックイベントハンドラに
Sleep(10000); /* 10秒間停止 */
というのを入れて、ボタンを押してすぐにウインドウを動かそうとしてみてください。
なるほど。
これは回避できないのですか?
Re: CreateWindowExで作成したウィンドウに文字を表示
Posted: 2011年2月07日(月) 18:26
by softya(ソフト屋)
あま さんが書きました:ISLe さんが書きました:
例えばボタンのクリックイベントハンドラに
Sleep(10000); /* 10秒間停止 */
というのを入れて、ボタンを押してすぐにウインドウを動かそうとしてみてください。
なるほど。
これは回避できないのですか?
横から失礼します。
WindowsのアプリはWindowsメッセージを処理させないとウィンドウの移動さえ出来ません。
なので、メッセージを処理させるためにWndProcを一度抜ける必要があります(メッセージ処理中に他のメッセージを処理できない)。
Sleep(10000); /* 10秒間停止 */とやると1つのメッセージ処理に10秒間専有することになりますので、ウィンドウ移動のメッセージ処理が10秒間できません。
これは仕様です。
回避する簡単な方法はありません。
どうしても高速に書き換えたいならコンソールを使ったほうが良いです。
※ それでも画面のリフレッシュレートを超えたら、その値は表示できません。
Windowsアプリなら一秒間に60回程度のWM_TIMER周期にして、その範囲で出来る処理でなるべく早くWndProcを抜ける処理を書くようにしましょう。
Re: CreateWindowExで作成したウィンドウに文字を表示
Posted: 2011年2月07日(月) 18:33
by ISLe
あま さんが書きました:これは回避できないのですか?
精度は良くないですがタイマーイベントを使えば回避できます。
SetTimer,KillTimerに指定するのはメインウインドウのウインドウハンドルですよ。
こちらで動作確認に使ったウインドウプロシージャのコードを貼り付けておきます。
コード:
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static HWND hWndLoopTxt = NULL;
static int count;
int i;
switch (uMsg) {
case WM_CREATE:
hWndLoopTxt = CreateWindowEx(
WS_EX_CLIENTEDGE,"edit","",WS_CHILD|WS_VISIBLE|WS_DISABLED,10,305,100,25,
hWnd,0,GetModuleHandle(NULL),NULL);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_LBUTTONUP:
/* 閉じループ版 ループ終了まで応答なし */
for (i = 0; i < 100; i++) {
char str[256];
sprintf(str, "%d", i);
SetWindowText(hWndLoopTxt, str);
UpdateWindow(hWndLoopTxt);
Sleep(100);
}
break;
case WM_RBUTTONUP:
/* タイマー版 */
count = 0;
SetTimer(hWnd, 1, 100, NULL);
break;
case WM_TIMER:
if (count < 100) {
char str[256];
sprintf(str, "%d", count);
SetWindowText(hWndLoopTxt, str);
count++;
} else {
KillTimer(hWnd, 1);
}
return 0;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
Re: CreateWindowExで作成したウィンドウに文字を表示
Posted: 2011年2月07日(月) 20:30
by kimuchi
また、間に失礼します。
sprintf(buf,"%d\r\n",i);
sprintf(buf,"%d\n",i);
このどちらも上手くいきませんか?
Re: CreateWindowExで作成したウィンドウに文字を表示
Posted: 2011年2月07日(月) 23:33
by あま
[quote="ISLe"
SetTimer,KillTimerに指定するのはメインウインドウのウインドウハンドルですよ。
[/quote]
あぁ、すみません。。。
勘違いしていました。
ウィンドウハンドルにしたところできました。
みなさん、ありがとうございます。