( Win98 VC++ API で作成)
データをFileDialogで メモリデバイス読み込み
Common DialogBoxで隠れていた所にBitBltで表示しようとしても
できません
(できるときもあります)
表示用のボタンを作りクリックすれば表示しますが
フアイル読み取り後に、そのボタンをSendMessageでよんでも
表示できません
BitBlt後 Sleepを使用すると、Sleepの経過後に画面が消えてしまいます
理由がわかりません
よろしくお願いします
WM_PAINTに対して描画処理をしていないために、せっかく
描画してもダイアログにクリップされてしまっていて、ダ
イアログが消えても再描画していないから現れない。
というのではないのでしょうか?
はずしていたらごめんなさい。
WM_PAINT内でBitBltしてみましたが、同じでした
何度も確かめてみましたが。駄目でした
なぜなのでしょうか
Wandererさん ありがとうございます
書き忘れていました
一旦は描画されるのですが、すぐに消えてしまいます
Sleep()で確認すると、その時間だけ表示されています
WM_PAINT内でBitBltしてみましたが、同じでした
何度も確かめてみましたが駄目でした
DialogBoxが消え、グラフが描画され、再びDialogBoxの亡霊が画面を消しているようです
なぜなのでしょうか
InvalidateRect()で画面全領域を無効化してもだめでしょうか?
肝心のBitBltの転送元を破棄してしまっているとか。
FileDialog でファイルのパス名を取得するところから、画像を画面に表示するところまでの
一連の流れがわかるようにソースを示して下さい
一応、こちらの予想では[ファイル]-[開く]で FileDialog を使おうとなさっているだろうと
見ていて、このハンドラー内で画像ファイルを読み取って、ウィンドーに BitBlt() している
可能性が大きいとも感じていますが、どうでしょうか?
ソースの一部です
IDM_YOMIKOMIで読み込み、IDM_UEボタンをクリックすればグラフを表示します
しかし、DM_YOMIKOMIの中でSendMessage()を送ってもグラフは瞬間的に表示されるだけです
Sleep(1000)では1秒間だけ表示されます
InvalidateRect()もtryしてみました
case IDM_YOMIKOMI:
GetCurrentDirectory(sizeof(buf),buf);
memset( &ofn, 0, sizeof( OPENFILENAME ) );
ofn.lStructSize = sizeof( OPENFILENAME );
ofn.hwndOwner = hwnd;
ofn.lpstrFilter = datファイル(ニ現象*.dat)\0*.dat\0任意ファイル
(*.*)\0*.*\0\0;
ofn.lpstrFile = szFileName;
ofn.nMaxFile = MAX_PATH;
ofn.lpstrFileTitle = szFileTitle;
ofn.nMaxFileTitle = MAX_PATH;
ofn.Flags = OFN_PATHMUSTEXIST;
ofn.lpstrDefExt = dat;
ofn.lpstrInitialDir= buf;
GetOpenFileName( &ofn );
;//InvalidateRect( hwnd, NULL, TRUE );
hFile = CreateFile( szFileName, GENERIC_READ, 0, NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL );
dwSize=GetFileSize(hFile,NULL);
_splitpath(szFileName,drive,dir,ffname,ext);
if(dwSize==0)return 0;
if(dwSize>MAXBUF)dwSize=MAXBUF;
if(!ReadFile( hFile, pBuffer[0], dwSize,&dW, NULL )){
SetTextColor(hDC,RGB(240,0,0));
wsprintf(buf,ファイル %s%s がありません,ffname,ext);
DrawText(hDC,buf,strlen(buf),&rectzenp[0],DT_CENTER |
DT_VCENTER | DT_SINGLELINE );
}
CloseHandle(hFile);
//InvalidateRect( hzenPict[0], NULL, FALSE );
SendMessage(hwnd,WM_COMMAND,IDM_UE,0); //????瞬間だけグラフが現れ
る
Sleep(1000);
return 0;
case IDM_UE:
//---------グラフを描く
hDC=GetDC(hzenPict[0]); //hzenPict[0] はdialogBoxに隠れる
領域のRECTです
SelectObject(hDC,hPenBlack);
MoveToEx(hDC,0,66-(int)(pBuffer[0][0] /256)/4,NULL);
for(x=1;x<saigo ;x++)
LineTo(hDC,(int)(x * SCRMAX / hyouji) , 66-(int)(pBuffer[0]
[x] /256)/4);
ReleaseDC(hzenPict[0],hDC);
return 0;
/*
hzenPict[0] = CreateWindow(STATIC,
",WS_CHILD | WS_VISIBLE | WS_BORDER | ES_RIGHT,
.......);
*/
結局これだと、IDM_UEメッセージを受けた時にしかグラフを描く処理が動きませんよね?
WM_PAINTメッセージの時、何かしてます?
この時にグラフ描かないといけないんですよ、
と、Wandererさんは申しております。
WM_PAINTで描画処理を行っていますか?
WM_PAINTで描画処理をせず、独自コマンドハンドラ内で描画処理を行うのはなぜですか?
ダイアログが隠していた領域が見えるようになれば、WM_ERASEBKGND、WM_PAINTが発生し
てデフォルトの動作ではその領域が白く塗りつぶされるでしょう。
ボタンを押した事にするのに SendMessage() していますが、PostMessage() に変えて、
Sleep(1000); はそうすると不要になりますから、削除するなり、コメントアウトして下さい
おそらく、これでなさりたい事は実現するでしょうが、適切な方法とはいえません
これについては sugar さんや tnd さんや Wanderer さんが仰っている事なのですが、
再描画でも(つまりこのウィンドーが最小化した後、元のサイズに戻したり、別のウィンドー
で隠れていた部分が(別のウインドーが移動したり、消えたりして)出てきた場合)せっかく
のグラフが消えたり欠けたりしないように出来ないと困りませんかと言う事です
WM_PAINT でも、一旦ファイルを読み込んで、表示するためのボタンを押した場合に備えて
フラグを用意しておいて、フラグの状態に応じて、WM_PAINT でグラフを表示するような
コードになっていれば再描画に対しても困らないでしょう
上のことが出来たら、再描画の度にグラフを描くのではなくて、メモリーDCとビットマップ
とを用意しておけば、ビットマップをメモリーDCに選択しておいて、このメモリーDCに
グラフを描く事で、WM_PAINT では BitBlt() だけで済むように出来るでしょう
(オフスクリーンなどと呼ぶ技法です)
ダイアログが隠していた領域が見えるようになれば、WM_ERASEBKGND case WM_PAINT:
が発生し
の記述で少し理解ができました
プログラムは、 WM_PAINT の働きがときどき分からなくなりますので
使用しないで作成しました
無効になる可能性のある部分だけ再描画するには
どうすればよいのでしょうか
・WM_PAINTでなければ、無効化されたエリアは描画されない
・従って、メモリデバイスに保存しておいたデータを、無効化されたエリアに
BitBltしても、無効
・WM_PAINTが記述されていると、File Dialogを呼び出した時点で
全画面が消去されてしまうのは、WM_ERASEBKGNDのせい
という理解でよいのでしょうか
WM_PAINT内で通常BeginPaintを使うのは御存知ですよね。
その引数LPPAINTSTRUCTを調べれば再描画しなくてはいけない領域が分かるはずです。
> ・WM_PAINTでなければ、無効化されたエリアは描画されない
WM_PAINTは画面が無効化され再描画が必要であることを伝えるためのメッセージですの
で、ここで再描画するのが普通です。
> ・WM_PAINTが記述されていると、File Dialogを呼び出した時点で
> 全画面が消去されてしまうのは、WM_ERASEBKGNDのせい
DefWindowProcがWM_ERASEBKGNDを処理した場合、ウィンドウクラス登録時に指定したブラ
シ(通常は白)で塗りつぶされます。
皆さん ありがとうございます
この画面は、結果をみてすぐに消してもよい内容なので
再描画は考えていませんでした
ご指摘のあった周辺を調べます
1.実行結果
△FileDialog 呼び出し で無効化領域ができる
PostMessage( IDM_UE );
UpdateWindow(hwnd); //hwnd はstatic コントロールのhandle
return 0; // このコントロールは無効化領域にある
case IDM_UE:
hDC=GetDC(hwnd);
hDCに描画
で描画できました
△PAINTSTRUCT rcPaintで無効化領域を調べてみましたが
(0,0,0,0)となってしまいました
2.ここでの PostMessage の働きは
・IDM_UE Messagaがキューに入る
・すぐに制御を返されたWndProcは、DialogBoxで無効化された
エリアにWM_ERASEBKGND WM_PAINTを処理
・その後、キューに入っていた IDM_UEが 実行される
SenMessageでは
メッセージを処理し終わった後で、制御を返します
と書いてありますが
・FileDialog 呼び出し で無効化領域ができる
・メッセージ IDM_UE を処理し、無効化領域に一旦グラフが描かれる
・制御を返された WndProc は
WM_PAINTが記述されていれば全画面を
いなければ無効化領域だけをWM_ERASEBKGND
その後 WM_PAINTを処理する
でよいのでしょうか