環境:
WindowsXP SP2
MicrosoftVisualStudio2005 VisualC++ MFC SDI(CView)
こんばんは。またお世話になります。
こちらのページを参考に、スプリッタウィンドウを持つSDIビューアを作成しています。
http://kot9a.hp.infoseek.co.jp/ALICE9/extra/vcpp/vcpp_02.html
2つのペインを持ち、マウス操作で拡大・縮小、描画対象の回転ができるアプリを作成し
ました。
互いのペインの描画内容を同期させたいので、Postmessegeを使い隣のペインにウィンド
ウメッセージを送っていますが、Postmessegeを送っているペインの描画内容の更新がな
めらかに出来ません(送られたペインの更新はなめらかに出来ています)。また、マウ
スホイールでの拡大・縮小に至っては送られたペインの反応は全くありません。
ソースは以下になります。
回転
void CTest4Viewb::OnLButtonDown(UINT nFlags, CPoint point)
{
//回転させる動作の定義
Invalidate(FALSE);
CWnd* pWnd =((CMainFrame*)AfxGetMainWnd())->m_wndSplitter.GetPane(0,0);
pWnd->PostMessage( WM_LBUTTONDOWN);
pWnd->Invalidate(FALSE);
CView::OnLButtonDown(nFlags, point);
}
拡大・縮小
BOOL CTest4View::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
//拡大・縮小させる動作
Invalidate(FALSE);
CWnd* pWnd =((CMainFrame*)AfxGetMainWnd())->m_wndSplitter.GetPane(0,0);
pWnd->PostMessage( WM_MOUSEWHEEL);
pWnd->Invalidate(FALSE);
return CView::OnMouseWheel(nFlags, zDelta, pt);
}
どなたかお知恵を拝借させてください。よろしくお願いします。
たいした知恵はありませんが、気になった点を示します
>>pWnd->PostMessage( WM_LBUTTONDOWN);
>> pWnd->PostMessage( WM_MOUSEWHEEL);
これでは CWnd::PostMessage() の第2引数、第3引数が既定値になっています
ところで何故(なぜ)、 Document/View の仕組みを使わないのでしょうか?
>>Invalidate();
CWnd::Invalidate() は再描画のための範囲指定をする(クライアント領域全体)だけ
なので再描画するかどうかは状況しだいです
Invalidate();
UpdateWindow();
または
RedrawWindow();
なら確実に再描画できると思います
ただし、CxxView::OnDraw() で回転や、拡大縮小の再描画をしている場合です
(提示されているソースには回転縮小拡大の部分がないので当てはまるかどうかは不明
ですが...)
し さん、ご意見ありがとうございます。
ソースを見直したところ、ペイン同士が回転が同期していたのは回転に使われる変数が
グローバル変数のために同期していただけでした・・・。
また、RedrawWindow()としたところ、グローバル変数を使って同期するというお粗末な
ものですが、両ペインとも滑らかに動かせることが出来ました。
一応同期自体はできているのですが、後学のためにもPostMessageを使っての同期をさせ
たいです。
しばらく調べてみましたが、引き数に与えるパラメータをどう決めればいいのかわかり
ません。
ソースは以下になります。
void CTest4Viewb::OnLButtonDown(UINT nFlags, CPoint point)
{ m_ptMouse.x = point.x; // マウスポイント位置のX座標を始点にセット
m_ptMouse.y = point.y; // マウスポイント位置のY座標を始点にセット
m_bMouseFlug = TRUE; // マウスが押されている
Invalidate(FALSE);
CWnd* pWnd =((CMainFrame*)AfxGetMainWnd())->m_wndSplitter.GetPane(0,0);
pWnd->PostMessage( WM_LBUTTONDOWN);
pWnd->Invalidate(FALSE);
CView::OnLButtonDown(nFlags, point);
}
void CTest4Viewb::OnLButtonUp(UINT nFlags, CPoint point)
{
m_bMouseFlug = FALSE; // マウスが離されている
/* 回転の保存 */
eq[0] = tq[0];
eq[1] = tq[1];
eq[2] = tq[2];
eq[3] = tq[3];
CWnd* pWnd =((CMainFrame*)AfxGetMainWnd())->m_wndSplitter.GetPane(0,0);
pWnd->PostMessage( WM_LBUTTONUP);
pWnd->Invalidate(FALSE);
CView::OnLButtonUp(nFlags, point);
}
void CTest4Viewb::OnMouseMove(UINT nFlags, CPoint point)
{
if((nFlags & MK_LBUTTON) != 0){
if((nFlags & MK_SHIFT) == 0 && (nFlags & MK_CONTROL) == 0){
double dx, dy, a;
/* マウスポインタの位置のドラッグ開始位置からの変位 */
dx = (point.x - m_ptMouse.x) *sx*0.5;
dy = (point.y - m_ptMouse.y) *sy*0.5;
/* マウスポインタの位置のドラッグ開始位置からの距離 */
a = sqrt(dx * dx + dy * dy);
if (a != 0.0) {
/* マウスのドラッグに伴う回転のクォータニオン dq を求める */
double ar = a * SCALE * 0.5;
double as = sin(ar) / a;
double dq[4] = { cos(ar), dy * as, dx * as, 0.0 };
/* 回転の初期値 cq に dq を掛けて回転を合成 */
qmul(tq, dq, eq);
/* クォータニオンから回転の変換行列を求める */
qrot(rtb, tq);
}
}
CWnd* pWnd =((CMainFrame*)AfxGetMainWnd())->m_wndSplitter.GetPane(0,0);
pWnd->PostMessage( WM_MOUSEMOVE,point.x,point.y);
pWnd->RedrawWindow();
RedrawWindow();
}
CView::OnMouseMove(nFlags, point);
}
BOOL CTest4Viewb::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{scaleb=scaleb-zDelta*0.0001f;
if(scaleb<0.0001f) scaleb=0.1f;
CWnd* pWnd =((CMainFrame*)AfxGetMainWnd())->m_wndSplitter.GetPane(0,0);
pWnd->PostMessage( WM_MOUSEWHEEL,zDelta,0);
Invalidate(FALSE);
pWnd->Invalidate(FALSE);
return CView::OnMouseWheel(nFlags, zDelta, pt);
}
更新がなめらか、更新がなめらかではないってどういうのかイメージできないので推測。
グローバル変数にしろ、別の方法にしろ
PostMessageとInvalidateは呼びだしたときにメッセージ処理が行われるわけではない。
非同期なので同期できるわけがない。
PostMessageは、メッセージキューの最後に追加し、
キューに貯めてあるメッセージを順番に処理する。
言い変えると
PostMessageを呼びだしたときは隣のペインのOnMouseMoveは実行されない。
自ペインからreturnした後に、キューに貯めてあるメッセージを順番に処理する。
Invalidateは、再描画が必要なリージョンを覚えておき、
メッセージキューに(WM_TIMER以外の)メッセージがなくなったらWM_PAINTを処理する。
言い変えると
Invalidateを続けて二度呼んでも、一つの更新リージョンに合成する。
メッセージキューにメッセージがなく更新リージョンがあればWM_PAINTを処理する。
>> pWnd->PostMessage( WM_LBUTTONDOWN);
>>pWnd->PostMessage( WM_LBUTTONUP);
>> pWnd->PostMessage( WM_MOUSEMOVE,point.x,point.y);
>>pWnd->PostMessage( WM_MOUSEWHEEL,zDelta,0);
WM_xxxx の次の引数、その次の引数についてそれぞれのメッセージ毎に調べましょう
wParam, lParam の構成方法についても学びましょう
それには、msdn のオンラインマニュアルか Google かでいいので調べてください
今のソースで
>>CWnd* pWnd =((CMainFrame*)AfxGetMainWnd())->m_wndSplitter.GetPane(0,0);
>> pWnd->PostMessage( WM_MOUSEMOVE,point.x,point.y);
で送ったメッセージがどう受け取れているか試しましたか?
ところで
>> http://kot9a.hp.infoseek.co.jp/ALICE9/extra/vcpp/vcpp_02.html
は私の環境では見えないのでどういう構成(ビューとペインとの関係)なのかが
分かりません
ですので、PostMessage() でビューで受け取ったのと同じメッセージをペインに
送ることが適切なのかどうか私には分かりません