円の描画方法 – プログラミング – Home

通知
すべてクリア

[解決済] 円の描画方法


とんぼ
 とんぼ
(@とんぼ)
ゲスト
結合: 21年前
投稿: 27
Topic starter  

いつもお世話になっております。

今回はドラッグによる円の描画方法について教えていただきたく質問させていただきま
した。

透明ウィンドウ上(TOPMOSTになってます)での検知として
・WM_LBUTTONDOWNのとき、キャプチャを開始(Cap_flag = true)
・WM_LBUTTONMOVEの間、円を描画(←Cap_flag = trueのとき)
・WM_LBUTTONUPのとき、キャプチャを解く(Cap_flag = false)
と以上のような形でドラッグして円を描画しようと考えています。

そこで、WM_LBUTTONMOVE(Cap_flag = true)のときの処理なんですが
円の描画を随時書き直すような感じでSetTimerで次のように書いてみました↓

void CALLBACK Ges_TimerProc(HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime)
{
 HDC hdc;
 HBRUSH hBrush;

 //キャプチャ開始地点(ges.x, ges.y)
 //キャプチャ終了地点(koko.x, koko.y)

//画面のデバイスコンテキストを取得
hdc = GetDC(hWnd);

//ペン作成、設定
SelectObject(hdc, CreatePen(PS_SOLID, 0, RGB(0, 55, 0)));

hBrush = (HBRUSH)GetStockObject(NULL_BRUSH); //空のブラシを取得
SelectObject(hdc, hBrush);

//始点と終点との距離計算
float A = (float)abs(koko.x - ges.x);
float B = (float)abs(koko.y - ges.y);
float C = (float)(sqrt(pow(A,2) + pow(B,2)));

//上記の距離Cを直径とした円弧を描く
if(koko.x > ges.x){
if(koko.y > ges.y){
AngleArc(hdc, (int)(ges.x+(A/2)), (int)(ges.y+(B/2)), (DWORD)C/2, (float)
0, (float)360);
}
else{
AngleArc(hdc, (int)(ges.x+(A/2)), (int)(koko.y+(B/2)), (DWORD)C/2,
(float)0, (float)360);
}
}else{
if(koko.y > ges.y){
AngleArc(hdc, (int)(koko.x+(A/2)), (int)(ges.y+(B/2)), (DWORD)C/2,
(float)0, (float)360);
}
else{
AngleArc(hdc, (int)(koko.x+(A/2)), (int)(koko.y+(B/2)), (DWORD)C/2,
(float)0, (float)360);
}
}
ReleaseDC(hWnd, hdc);
}

ちなみにLBUTTONDOWN時の始点と、LBUTTONUP時の終点を結んだ線を直径とする
円弧を描画したかったので、AngleArcを使ってみました。

と、このような感じですが円が描画されません。

どうすれば円が描画されるのか、基本的なところが間違っているのかもしれませんが
お分かりの方いましたらご教授の方よろしくお願いいたします。


引用未解決
トピックタグ
とんぼ
 とんぼ
(@とんぼ)
ゲスト
結合: 21年前
投稿: 27
Topic starter  

環境は、WinXP, Visual Studio2005, VC++ Win32です。


返信引用
PATIO
(@patio)
Famed Member
結合: 3年前
投稿: 2660
 

円が描画されないと言う内容についてもっと具体的に書いた方が良いと思います。

全く何も描画されないのか?
描画されるけれど、目的の円ではない物が描画されるのか?
目的の物ではない物が描画されるのであれば、どんな物が描画されているのか?

文章でのやり取りになるので出来る限り詳しく書かないと伝わらないですよ。


返信引用
PATIO
(@patio)
Famed Member
結合: 3年前
投稿: 2660
 

ああ、このコードってタイマーイベントの中ですよね。

画面が無効化されていない状態で描画しているからじゃないかなぁ。
描画する部分は、WM_PAINTイベントが来た所でするべきだと思います。
タイマーイベント内でやるとしたら描画の為の座標の計算とか
画面の再描画を促す為に無効化を行なうとかじゃないかなぁ。

Windowsでの描画の仕組みを調べて見たほうが良いですよ。
Windowsではただ単にDCに対して描けば良いと言うわけでは有りませんから。


返信引用
とんぼ
 とんぼ
(@とんぼ)
ゲスト
結合: 21年前
投稿: 27
Topic starter  

PATIOさん

>円が描画されないと言う内容についてもっと具体的に書いた方が良いと思います。

そうですよね。すいません↓
円の描画は全く何も表示されない状態です。

WM_LBUTTONMOVEの処理に入り、Cap_flag = trueのときに
SetTimer(cl_hwnd, 0, 1, Ges_TimerProc)で描画処理へ飛ばすようにしていて
その条件(Cap_flag = true)に入っていることは確認できたのですが…。


返信引用
wclrp ( 'o')
 wclrp ( 'o')
(@wclrp ( 'o'))
ゲスト
結合: 18年前
投稿: 287
 

WM_LBUTTONMOVEなんていつの間にかできたのか。
バグの切り分けとかいうのをすることになるな。
他人にはあなたのプログラムなんてわからんから。
AngleArcの戻り値がエラーを示していないかとか何で調べないの?
hdcは妥当なの?
ges.xは妥当なの?
SelectObjectの戻り値?解放?
CreatePenの戻り値?解放?
などなど


返信引用
たいちう
 たいちう
(@たいちう)
ゲスト
結合: 23年前
投稿: 662
 

> ちなみにLBUTTONDOWN時の始点と、LBUTTONUP時の終点を結んだ線を直径とする
> 円弧を描画したかったので、AngleArcを使ってみました。

まずは始点と終点を結ぶ直線を描けるようになってはどうかと。
一歩ずつ行こうよ。


返信引用
金魚ちゃん
 金魚ちゃん
(@金魚ちゃん)
ゲスト
結合: 16年前
投稿: 52
 

>WM_LBUTTONMOVEなんていつの間にかできたのか。
僕は WM_MOUSEMOVE なら知っているよ。
WM_LBUTTONMOVE は自分で作ったメッセージですか?

試しに Ges_TimerProc 関数の最後に次の2行を追加してみる。

void CALLBACK Ges_TimerProc(HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime)
{
 HDC hdc;
 HBRUSH hBrush;
 :
 省略
 :
 InvalidateRect( hWnd, NULL, TRUE );
 UpdateWindow( hWnd );
}
これで描画されるかどうか確認してみること。
これでも描画されないなら Ges_TimerProc の描画ロジックにバグがあるかもね。

>どうすれば円が描画されるのか、基本的なところが間違っているのかもしれませんが
>お分かりの方いましたらご教授の方よろしくお願いいたします。
普通描画は WM_PAINT で処理すべきだと思うな。

タイマー関数では描画を促す InvalidateRect() や
InvalidateRect()+UpdateWindow()を送れば良いんじゃないの。


返信引用
ITO
 ITO
(@ITO)
ゲスト
結合: 22年前
投稿: 1235
 

うーーん、
WM_PAINT内で描かないので、
ウインドウが重なったときに描画したのが消えてしまったとか?
WM_PAINT内で描かない場合は、WM_PAINT内でまとめて再描画しないとだめですね。


返信引用
ITO
 ITO
(@ITO)
ゲスト
結合: 22年前
投稿: 1235
 

まずは、XY座興、直径固定でマウスの操作関係なしで描いてみたらどうですか。
はじめは、たいちうさんのご意見通り直線を描いてみるのがいいですね。


返信引用
とんぼ
 とんぼ
(@とんぼ)
ゲスト
結合: 21年前
投稿: 27
Topic starter  

PATIOさん、wclrp ( 'o')さん、たいちうさん、金魚ちゃんさん、ITOさん
ご意見ありがとうございます。

>WM_LBUTTONMOVEなんていつの間にかできたのか。
自分の書き間違いでした。すいません、WM_MOUSEMOVEのメッセージです。

>試しに Ges_TimerProc 関数の最後に次の2行を追加してみる。
>
>void CALLBACK Ges_TimerProc(HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime)
>{
> HDC hdc;
> HBRUSH hBrush;
> :
> 省略
> :
> InvalidateRect( hWnd, NULL, TRUE );
> UpdateWindow( hWnd );
>}
と追加しても描画はされませんでした。やはり書き方が間違っているのですね。

まずは、皆さんのご指摘の通り
始点と終点を結ぶ直線から、WM_PAINTでの描画をしてみたいと思います。


返信引用
ITO
 ITO
(@ITO)
ゲスト
結合: 22年前
投稿: 1235
 

> まずは、皆さんのご指摘の通り
> 始点と終点を結ぶ直線から、WM_PAINTでの描画をしてみたいと思います。
最初は、マウスの動き関係なしで、座標は固定で、他のウインドウ(メモ帳等)
を重ねても消えないことを確認するといいです。


返信引用
+
 +
(@ )
ゲスト
結合: 17年前
投稿: 50
 

この回答は解決方法では無いです。

1、目的を鑑みて、描画にタイマー使うのは×。
2、マウスイベントでは座標計算して変数にいれるだけ。あと、
  再描画イベントを発生させるだけにする。
3、再描画のハンドラ内で、表示領域クリア。そして円描画。

と変更したほうが、後々うれしいかもしれません。
プログラミングでご飯食おうと思うなら・・・。


返信引用
とんぼ
 とんぼ
(@とんぼ)
ゲスト
結合: 21年前
投稿: 27
Topic starter  

ITOさん、+さん、ありがとうございました。

透明ウィンドウ上に描くということでなかなか描画されなかったのですが
ウィンドウの設定を
SetLayeredWindowAttributes(hWnd, RGB(0xff, 0xff, 0xff), 255, LWA_COLORKEY |
LWA_ALPHA);
に変更し、WM_PAINTで描画処理することで描画させることができました。

また
>1、目的を鑑みて、描画にタイマー使うのは×。
>2、マウスイベントでは座標計算して変数にいれるだけ。あと、
>  再描画イベントを発生させるだけにする。
>3、再描画のハンドラ内で、表示領域クリア。そして円描画。

を参考にさせていただき、タイマーを使わずにWM_MOUSEMOVEで
座標計算・再描画イベントを発生させ、ドラッグ中の円描画もできるようになりまし
た。

皆さん、とても丁寧でわかりやすいご指摘、本当にありがとうございました。
またご質問させていただくこともあるかと思いますが、その際はよろしくお願いしま
す。


返信引用

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました