線をマウスでドラッグして移動する

[戻る]
EIGHT 2005/07/27(水) 10:30:13
こんにちわ。
VC6でMFCのダイアログベースのプログラムを書いています。
やりたいことは、
 ・ダイアログ上に線を引く。
 ・その線をマウスでドラッグ移動する。
 ・ドラッグ終了した位置で線を固定する。
です。

線をLineToで書いて、GetCursorPos()でマウス位置を取得し、
そこでWM_LBUTTONDOWNが押された場合は、線移動モードに入る。
という風にコーディングしようと思ったのですが、
以下のことが分かりませんでした。
 ・OnPaint()以外のタイミングで描画する方法
 ・線移動モード中の元線の消し方
 ・線移動モード中は線がマウスについて来るようにする方法

2日ほどかけていろいろHPを探したのですが、
なかなか見当たらず困っています。
よろしくお願いします。

リンク 2005/07/27(水) 12:19:28
>・OnPaint()以外のタイミングで描画する方法
普通にGetDCでとったhDCに描き込めば描けたと思います。
ただ、線の開始点と終了点を計算、保存し
InvalidateRect,UpdateWindowなどをしてやれば描画はOnPaint内オンリーでもいけま
す。
これをすると前の線を消すという作業は必要なくなります。

OnPaint以内で描画すると他のウィンドウが自ウィンドウに重なったりしたら
描画が消えるので注意が必要ですが、今回はドラッグ移動中のことだから
いいのかな?(厳密にはだめですけど)

>・線移動モード中の元線の消し方
線の開始点と終了点を保存していますか?
保存してない限り無理です。
MOUSEMOVE中に新しい開始点と終了点を計算しInvalidateRect,UpdateWindowし
OnPaint内で現在の位置だけを書けば勝手に消えています。
GetDCでやるにしても保存してない限り無理です。

>・線移動モード中は線がマウスについて来るようにする方法
以上のことを組み合わせれば一応できると思います。

とっさに答えたのでこれで実際にできるかどうかはわかりませんが
考え方はこんな感じだと思います。
とりあえず、線の開始点と終了点を保存してください。

どの程度のプログラムかわかりませんが、ちらつきなどをきちんと考慮するなら
裏画面に描画したりしてやったほうがいいと思います。

リンク 2005/07/27(水) 12:21:21
間違い
(誤)OnPaint以内で描画すると他のウィンドウが自ウィンドウに重なったりしたら
(正)OnPaint以外で描画すると他のウィンドウが自ウィンドウに重なったりしたら
以内と以外を間違えました。

PATIO 2005/07/27(水) 17:25:03
いずれにしてもウインドウの再描画をOSが指示してきた時はOnPaintが呼ばれますから
OnPaintがその時点で描画するべき全ての内容をいつでも描画できるように準備しておく
必要があります。
その為には、リンクさんが指摘しているように描画に必要な始点と終点の座標を保持して
おく必要があります。まずはWM_MOUSEMOVEで新しい視点と終点を計算して
Invalidateを呼ぶ所から始めてはどうでしょう。
これだと毎回、クライアント領域の全面が再描画対象になるのでちらつくとは思いますが、
一応目的の動作にはなると思います。
そこまで出来た時点でちらつき対策を考えた方が得策でしょう。

PATIO 2005/07/27(水) 17:28:27
補足

始点と終点は、ダイアログクラスのメンバー変数にでもしておけば、
ダイアログクラスのメンバー変数からなら何処からでも参照できます。
取り敢えずはそこから手をつけてはどうでしょうか。
WM_MOUSEMOVEで計算した値もこのメンバー変数に設定しておいて
Invalidateを呼ぶようにしておけば、取り敢えずは目的の動きになると思います。

PATIO 2005/07/27(水) 17:29:34
ああ、誤字

誤)
ダイアログクラスのメンバー変数からなら何処からでも参照できます。

正)
ダイアログクラスのメンバー関数からなら何処からでも参照できます。

EIGHT 2005/07/27(水) 23:32:54
リンクさん、PATIOさん
早速ご回答頂きありがとうございます。
教えて頂いた内容を早速試してみます。

初心者なもので、時間がかかるかも知れませんが、
解決した際に改めて書き込みさせて頂こうと思います。
ではでは。

ars 2005/07/28(木) 10:46:15
そういう場合は線を描画するチャイルドウィンドウを作ったほうが後々の修正とか機能追
加も楽ですよ。
CWndの派生クラスを作って始点と終点の情報を与えたら自分自身の大きさを変えて、
OnPaintで線を表示する
マウスは線に沿った座標でドラッグされた場合はウィンドウをマウスに合わせて移動する
というクラスを作っておいて、線が引かれたら線を消してその上にそのウィンドウクラス
を貼り付ければいい

EIGHT 2005/07/29(金) 02:12:01
>リンクさん、PATIOさん
ありがとうございます。
無事解決できました。
教えて頂いた通り開始点、終了点の保存と
Invalidate()でズバッと解決でした。
本当にありがとうございました。
ちなみに作っているプログラムが
簡単なものなので、ちらつきは気にならないレベルでした。

>arsさん
今書き込み頂いた内容を読みました。
アドバイスありがとうございます。
チャイルドウィンドウ&派生クラスという処理を
使ったことがないので、勉強してトライしてみます!
派生クラスにしておくと確かに便利そうですね。

で、動作は実現できたのですが、
リンクさんがおっしゃった通り他のウィンドウが重なると
線が消えてしまい、またまた困っています。
それらしいメッセージがないかと探してみましたが発見出来ませんでした。
よろしければ、ウィンドウが重なっても線が消えないようにする方法を
教えて頂けないでしょうか?よろしくお願いいたします。

リンク 2005/07/29(金) 12:24:32
結局どこで描画しているのでしょう?
といっても消えるということはWM_MOUSEMOVEで描画しているんでしょう。
WM_PAINTで描画していたら開始点と終了点をきちんと保存しておけば
消えることはありません。

自分が前回GetDCでと言ったのはOnPaint()以外のタイミングで描画したいと言うことに
答えたまでで、
これだけだとウィンドウが重なったりすると消えるのできちんとWM_PAINT内で
描画してください。

つまり、
WM_MOUSEMOVE内で点の計算をし、Invalidate、
WM_PAINT内で計算された位置の描画
これをすれば大丈夫です。

WM_PAINT内でやっているのなら位置の計算が何かおかしいのでは?
きちんとドラッグ中だけの計算になっていますか?

点を保存する変数は大丈夫ですよね。とりあえずメンバかグローバルですよね。
ローカルってことはないですよね。

EIGHT 2005/07/30(土) 02:48:51
[[解決]]
>リンクさん
無事解決できました。
ご指摘通り、位置の計算をドラッグ中以外で行っていました。
何度もアドバイスを頂き本当にありがとうございます。
感謝!!

古いスレッドには追加発言できません。