vc逐次漸進的にQQインタフェースを模倣する(二):マップボタンの三状態シミュレーション

6033 ワード

プレゼンテーションにはRingSDKライブラリが必要です.コンパイルに問題がある場合は、本明細書の元のリンクを参照してください.http://blog.csdn.net/ringphone/archive/2010/01/10/5171490.aspxここでは、マップボタンの三状態シミュレーションをどのように実現するかを説明します.三状態とは、ボタンの正常な状態、マウスを動かしたハイライト状態、および押した状態のことです.実際にはもう1つのDisable状態があるはずですが、このプログラムには使用できないボタンがないので、この効果は実現しません.マップであり、実際のボタンではないため、マウスメッセージを自分で処理して3つの状態の描画を行う必要があります.まず、マウスの位置検出関数HitTestが必要です.マウスがどのボタンの上にあるかを検出します.プログラムの非顧客領域はサイズ2の園角矩形枠で、タイトルバーは顧客領域で実現されるシミュレーションなので、このHitTest関数はWM_です.MOUSEMOVEメッセージでの呼び出し判断は,PtInRectが各ボタン座標の検出を行うことにほかならないので,このHitTest関数の実現はここでは説明せず,コードを見れば分かる.マウスがボタン領域にある場合、この関数はボタンID、システムボタン領域、HTMINBUUTTON、HTMAXBUTTON、HTCLOSEに戻り、直接システムコマンドを送信するのに便利で、ボタンがなく、HTCAPTIONに戻り、ウィンドウをドラッグすることができます.
HitTestがボタンIDを返した場合、ユーザはマウスを押さずに、ボタンのハイライト状態を描画すべきである.ここで問題があります.描画が終わった後、ユーザーはマウスを移動し続けましたが、このボタンは移動しませんでした.WM_MOUSEMOVEメッセージはまた、ハイライトを描画する必要があることを検出し、描画を続けるとマウスが点滅するため、m_を定義する必要があります.nCurWhereのメンバー変数は、マウスの前回のHitTest検出値を記録します.
C/C++ code
int nWhere = HitTest(...);
if(nWhere != m_nCurWhere)
{
 //      ,       

 if(nWhere != HTCAPTION)
  CheckAndDrawButtons(nWhere,4);  //  nWhere       
 else
  CheckAndDrawButtons(m_nCurWhere,0); //           
}
m_nCurWhere = nWhere;

これにより、一度だけ描画するだけで、さまざまな状態の変化が保証されます.
ボタン押下状態を実現するには、WM_LUTTONDOWNメッセージでの処理は,まずもちろんHitTest検出を行い,ここでもメンバ変数m_を定義する.nCurSysCmdは、現在どのボタンが押されているかをマークし、ボタンの押下状態を描画します.ユーザはボタンを押してマウスを離さずに移動する可能性があるため、メンバー変数m_を定義する必要があるbInCapture,WM_LUTTONDOWNメッセージにこの変数をTRUEとし、SetCaptureはマウスをキャプチャし、WM_LUTTONUPメッセージの中でReleaseCaptureはマウスを放して、この変数をFALSEに置いて、このようにWM_MOUSEMOVEで呼び出されたボタン描画関数はm_bInCaptureは、この描画が押下された状態かハイライトされた状態かを判断する.WM_LBUUTTONUPメッセージは、このフラグに基づいてボタン動作を実行すべきか否かを判断してもよい.そうしないと、別の場所でマウスボタンを押して一つのボタンに移動してマウスを離す.bInCaptureはTRUEでありm_nCurSysCmdは、HitTestで検出されたボタンと等しい場合にのみ、このボタンの機能を実行します.マウスボタンを押したときの移動は、m_のみnCurSysCmdタグのボタンは押した状態と正常な状態の描画を行い、残りのボタンは一切無視します.QQ 2009はこの点では実現しておらず,ボタンを押した後にマウスボタンを離さずにボタンを外すと,ボタンの状態は変化しないことが分かった.
このメカニズムで、WM_MOUSEMOVEでの判断は修正すべきで、ボタンの押下状態の判断を追加します.
C/C++ code
RINGMAINMSG(WM_MOUSEMOVE)
{
 int nWhere = HitTest(param);

 if(m_bInCapture)
 {
  //          
  if(m_nCurSysCmd == nWhere && m_nCurWhere != nWhere)
  {
   //          ,        
   CheckAndDrawButtons(nWhere,8);
  }
  else if(m_nCurSysCmd != nWhere && m_nCurSysCmd == m_nCurWhere)
  {
   //      ,      
   CheckAndDrawButtons(m_nCurSysCmd,0);
  }
  m_nCurWhere = nWhere;
  return 0;
 }
 else
 {
  LRESULT res;
  if(nWhere != m_nCurWhere)
  {
   //      ,       
   if(nWhere != HTCAPTION)
    CheckAndDrawButtons(nWhere,4); //    
   else
    CheckAndDrawButtons(m_nCurWhere,0); //    
  }
  res = DefaultProc(param);
  m_nCurWhere = nWhere;
  return res;
 }
}

これで、マウスのボタン検出機能は完了し、残りはボタンの描画作業です.ボタンの描画作業は3つに分けられます.システムボタンの描画、ユーザーのアイコンの横にあるポップアップメニューのボタンと個性的な署名ボタンの編集([オンライン上]もボタンですが、これは個性的な署名ボタンの実現と同じで、ここでは手間が省けます.実現しません)、ユーザーのアイコンの下のツールバーのボタンの列です.システムボタンの描画は最も一般的な方法を採用しており、ここではシステムボタンリソースの画像を貼るとわかりますが、必要に応じて描画した状態で、画像上の対応する領域をターゲットに描画すればいいのです.図:
これで、マウスのボタン検出機能は完了し、残りはボタンの描画作業です.ボタンの描画作業は3つに分けられます.システムボタンの描画、ユーザーのアイコンの横にあるポップアップメニューのボタンと個性的な署名ボタンの編集([オンライン上]もボタンですが、これは個性的な署名ボタンの実現と同じで、ここでは手間が省けます.実現しません)、ユーザーのアイコンの下のツールバーのボタンの列です.システムボタンの描画は最も一般的な方法を採用しており、ここではシステムボタンリソースの画像を貼るとわかりますが、必要に応じて描画した状態で、画像上の対応する領域をターゲットに描画すればいいのです.図:
しかし、ここではやはりテクニックが必要です.一番下の列は通常の状態ボタンで、将来のインタフェースの色を変える必要があります.透明に処理されています.枠と線だけが不透明です.このように通常の状態ボタンを描くときは背景色を回復し、通常の状態のボタンを透明に描く必要があります.少し面倒です.そこでプログラム初期化時にシステムボタン領域サイズのメモリピクチャを初期化し、WM_PAINTメッセージにマップするついでに、この通常のシステムボタン領域の画像をこのメモリ画像に描画し、システムボタン状態を復元するには、このメモリ画像を1回だけ描画すればよい.
次に、ツールバーのボタンの列を描いて、必要なリソースの画像を見てみましょう.全部で2枚です.
ボタンの3つの状態の効果を実現し、2つ目はハイライト状態で、3つ目は押した状態です.
うん?これはどうやって実現したのですか?肝心なのは2枚目のリソース画像で、左右の2つの部分に分けて、左側はハイライト状態で、右側は押した状態で、各部分の画像は5つの画素幅で、左右の各2画素はそれぞれボタンの左右の枠で、中間の1画素はボタンの中間の図案で、描く時にボタンが左右の枠の幅を除去するまで横に伸ばす必要があります.バックグラウンドパターンを復元し、ハイライトボタンを描画し、最後にツールバー全体の画像を透明に描画すれば、描画したバックグラウンドに影響しません.押した状態の描画は少し違いますが、押したボタンの画像を右下に1画素ずらして押す必要があるので、ボタンが押されているように見えます.そうすると、ツールバー全体の画像を一気に描くことができません.押したボタンの画像を描画し、このボタンの左右側のボタンを描画する必要があります.
ユーザーのアイコンの横のボタンはツールバーの描画と似ていて、説明しないで、ソースコードを見て知っていて、コードの中の画像のソース領域の座標、描画の目的の座標は少し迂回して、頭がはっきりしなければ混乱しません.画像ライブラリのDrawTo,StretchToのいくつかの関数のパラメータ定義を明らかにする必要があります.具体的にはRingSDKのヘルプファイルを見てみましょう.
ちなみに、画像ライブラリのデュアルバッファ描画操作は直接操作される画像データであり、はっきり言ってCOLORREF配列データの移動だけであり、描画文字以外にHDCの関与は全く必要ないため、速度と効率が高い.
これでマップボタンの3状態シミュレーションが完了し、他の機能も実現する必要があります.ツールヒントは、ツールバーボタンのツールヒントを追加しますが、右端の2つの「メッセージボックスを開く」ボタンと「外観を変更する」ボタンのツールヒントには追加の処理が必要です.ウィンドウのサイズを調整できるため、サイズを変更すると元の座標が間違っています.座標を動的に変更する必要があります.どこで変更しますか.WM_SIZEニュース?ユーザーがウィンドウサイズを変更するときは、この2つのボタンにマウスを移動することはできません.そしてWM_SIZEメッセージは頻繁すぎて、サイズ調整が終わった時に座標を更新すればいいだけです.このメッセージはWMです.EXITSIZEMOVE:
C/C++ code
TOOLINFO ti; CopyRect(&ti.rect,&rc);//rcは更新座標m_tip->SetToolInfo(&ti);
実際のプログラムのコードは複雑です.システムボタンのツールチップは付いていませんが、興味があれば自分で完成することができます.この2つのツールバーボタンと同じ処理をして、座標を更新する必要があります.
また、ユーザーのアイコン横ボタンを押してメニューをポップアップすると、QQ 2009というメニューの最後の2つは、システムバーアイコンにポップアップされたメニューとは異なり、ここでは面倒ではなく、システムバーアイコンにポップアップされたメニューを直接ポップアップします.
個性的な署名ボタンは、押すと編集ボックスが表示され、署名の編集が許可されます.これは難しくありません.面倒なことに、この編集ボックスは自動的に非表示になり、EN_を処理する必要があります.KILLFOCUSメッセージは完全に効果を実現することはできません.インタフェースには他のコントロールが焦点を奪うことができないため、プログラムが焦点を失ってこそこのメッセージがあるので、WM_LUTTONDOWNに判断処理を追加し、WMを受け取った以上LUTTONDOWNメッセージは、編集ボックスの外でマウスを押して、隠すことができることを示しています.残念ながらこのようにするのはまだ足りなくて、ウィンドウのサイズを調整する時非取引先区をクリックしたので、WMがありませんLUTTONDOWNメッセージなので、WM_EnterSIZEMOVEメッセージに判断処理を追加することで、個性的な署名を編集する機能が充実します.
これで,このプログラムはすべてのボタンの三状態シミュレーション,システムボタンの機能応答,ツールバーボタンのツールヒント,個性的な署名の編集,メニューのポップアップを実現した.WSが追加されましたEX_TOOLWINDOWの拡張タイプで、プログラムはタスクバーに表示されず、一度だけプログラムを実行する機能に制限はありません.小さいBUGがあって、マウスはシステムのボタンの領域に移動して、システムのボタンはハイライトの状態を表示して、この時マウスを急速に上へウィンドウを移動して、ボタンの状態は回復しないで、WMがないためですMOUSEMOVEメッセージ、この問題を解決するにはTrackMouseEventが必要で、WM_MOUSELEAVEメッセージではボタンの状態を回復し、興味があれば自分で解決できます.
最後にプログラムのスクリーンショットを見てみましょう.
インタフェースの下のツールバーは後で異なる方法で実現され、次の編では、インタフェースの色調を実現する方法について説明します.プログラムリソースを開くと、外観を変更する設定ダイアログボックスが表示されます.後で、コントロールを自分で描き、QQのこの外観を変更するダイアログボックスを実現する方法を説明します.
投稿:http://www.icache.me/vc-step-by-step-copy-qqface-2.html