Postmessageの動作

[戻る]
初心者 2008/12/08(月) 02:19:05
環境:
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);
}


どなたかお知恵を拝借させてください。よろしくお願いします。

2008/12/08(月) 04:09:17
たいした知恵はありませんが、気になった点を示します

>>pWnd->PostMessage( WM_LBUTTONDOWN);
>> pWnd->PostMessage( WM_MOUSEWHEEL);

これでは CWnd::PostMessage() の第2引数、第3引数が既定値になっています
ところで何故(なぜ)、 Document/View の仕組みを使わないのでしょうか?


>>Invalidate();

CWnd::Invalidate() は再描画のための範囲指定をする(クライアント領域全体)だけ
なので再描画するかどうかは状況しだいです

Invalidate();
UpdateWindow();

または
RedrawWindow();
なら確実に再描画できると思います
ただし、CxxView::OnDraw() で回転や、拡大縮小の再描画をしている場合です
(提示されているソースには回転縮小拡大の部分がないので当てはまるかどうかは不明
ですが...)

初心者 2008/12/08(月) 08:14:21
し さん、ご意見ありがとうございます。

ソースを見直したところ、ペイン同士が回転が同期していたのは回転に使われる変数が
グローバル変数のために同期していただけでした・・・。
また、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);
}

wclrp ( 'o') 2008/12/08(月) 08:42:33
更新がなめらか、更新がなめらかではないってどういうのかイメージできないので推測。

グローバル変数にしろ、別の方法にしろ
PostMessageとInvalidateは呼びだしたときにメッセージ処理が行われるわけではない。
非同期なので同期できるわけがない。

PostMessageは、メッセージキューの最後に追加し、
キューに貯めてあるメッセージを順番に処理する。
言い変えると
PostMessageを呼びだしたときは隣のペインのOnMouseMoveは実行されない。
自ペインからreturnした後に、キューに貯めてあるメッセージを順番に処理する。

Invalidateは、再描画が必要なリージョンを覚えておき、
メッセージキューに(WM_TIMER以外の)メッセージがなくなったらWM_PAINTを処理する。
言い変えると
Invalidateを続けて二度呼んでも、一つの更新リージョンに合成する。
メッセージキューにメッセージがなく更新リージョンがあればWM_PAINTを処理する。

2008/12/08(月) 12:44:28
>>    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() でビューで受け取ったのと同じメッセージをペインに
送ることが適切なのかどうか私には分かりません

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