VC6 MFCで、自作の画像表示ツールに虫眼鏡の機能を付けようとしています。
マウス位置を中心に、表示画像ウィンドウの上に、
虫眼鏡ウィンドウ(拡大画像やテキスト情報を持たせたモードレスダイアログ)を
かぶせるという方法です。
マウス移動に合わせて拡大画像を更新し、虫眼鏡ウィンドウも追尾します。
この場合、表示画像ウィンドウのWM_MOUSEMOVEメッセージに合わせて
虫眼鏡ウィンドウを移動、更新させることになると思いますが、
マウス位置に虫眼鏡ウィンドウをかぶせるため、
マウス関連のメッセージはすべてそちらに行ってしまいます。
虫眼鏡ウィンドウではマウスメッセージを一切受け取らない
(すべて裏のウィンドウにそのまま通過させる)という方法はありますでしょうか?
WM_NCHITTESTメッセージでHTTRANSPARENTを返す方法を見つけたのですが、
これはダイアログ上のスタティックテキストのような
親子関係を持ったウィンドウでのスタイルですよね?
やはり表示画像ウィンドウのほうで
SetCaptureをコールしてしまうしかないのでしょうか?
やってることはただのマウス移動対応(ドラッグではない)ですし、
アクセラレータキーで虫眼鏡ウィンドウの表示オンオフを切り替えたいので、
できればマウスキャプチャをせずに
裏にメッセージ(WM_MOUSELEAVEも)が来るようにしたいのですが…。
以下のような案を思いつきましたが、いかがでしょうか。
1)EnumWindows/ChildWindowFromPointでカーソル下のウィンドウを探し、
メッセージを丸投げする。
(WindowFromPointは一番上のウィンドウしか見つけてくれないので、
自分自身が見つかってしまい、使えないと思われる。)
WM_MOUSELEAVEは難しいかも。
2)SetWindowRgnで、自分自身の真ん中に穴を開ける。
カーソルが常に穴の部分を指すように自ウィンドウを移動させる。
ただし、素早い操作に反応できるかは不明。
3)自分自身をウィンドウとせず、デスクトップに直接描画する。
ちらつきが心配。
いろいろな方法を提示していただき、ありがとうございます。
> 1)EnumWindows/ChildWindowFromPointでカーソル下のウィンドウを探し、
> メッセージを丸投げする。
> WM_MOUSELEAVEは難しいかも。
やはりこのメッセージ丸投げ方法だと、
WM_MOUSELEAVEは来なくなってしまいますよね。
でもこの場合は、逆に虫眼鏡側で「マウス位置が表示画像から離れた」こと自体は
ChildWindowFromPointの結果でわかるでしょうし、
そのときに虫眼鏡を非表示にすればよいかもしれません。
2~3についても情報ありがとうございます。
リージョンやデスクトップへの描画は恥ずかしながらまだ詳しくないので、
「素早い操作」や「ちらつき」の問題も含めてじっくり調べてみたいと思います。
すみません、今回の件の関連でもう一つお伺いしたいことがあります。
ダイアログベースのプロジェクトを作成し、
void CTestDlg::OnPaint()
{
if (IsIconic())
{
...
}
else
{
/* 描画更新処理のかわり */
CPaintDC dc(this);
for (int i = 0; i < 10000; i++) {
dc.MoveTo(0, 0);
dc.LineTo(100, 100);
}
}
}
void CTestDlg::OnMouseMove(UINT nFlags, CPoint point)
{
CRect rect;
GetWindowRect(rect);
ClientToScreen(&point);
MoveWindow(point.x - 300, point.y - 300, 600, 600);
CWnd::GetDesktopWindow()->RedrawWindow(rect, NULL, RDW_ALLCHILDREN | RDW_ERASE
| RDW_ERASENOW | RDW_INVALIDATE | RDW_UPDATENOW);
CDialog::OnMouseMove(nFlags, point);
}
と、虫眼鏡移動の試作をしてみたのですが、
マウスを動かしつづけている間は、デスクトップや
エクスプローラなどの他のウィンドウ上に残像が出てしまいます。
停めたりした時点で再描画されるようです。
デスクトップにRedrawWindowをコールしても、再描画はかからないものなのでしょうか?