antenn-a
company profile

MFC航海日記 三十七日(About Dialogを格好よく...)

前作の Color Maker から正式な(?)デザイナーが加わった事により、いままで苦労してきたアイコンの作成やアバウト画面に華が付いた。

旧禿ソフトウェアからの読者(会員)の方はご存知かと思うが、私のつくるアイコンやロゴマークと言ったらそれはもう・・・何をあらわしているのかさっぱり...

デザイナーが加わった事により人様の前に大きくアバウトダイアログを出す事ができるようになった。

prev


ここまで読んで、アバウトダイアログ?となっている方の為に下に画面キャプチャを載せておく



この画面を「バージョン情報のダイアログ」と呼んでいる方がほとんどだと思う。 しかし、私は「アバウトダイアログ」なのである。 「なぜか?」と聞かれても「さぁ?」ぐらいの気持ちなので突っ込まないでください (^^;

prev


この画面の左下に「antenn-a」とカラフルに書かれた部分にカーソルを持っていくと指カーソルになり、押すとブラウザが立ち上がる。 そして[http://www.antenn-a.com」に繋げるよくある設定である。

その他に右下にある人名「antenn-a, Yuta, SEK, HAGERU」の部分にカーソルを持っていくとやはり指カーソルになり、押すとデフォルトで指定したメーラーが立ち上がるようになっている。

読者の方がこのようなダイアログを作成しようと思った場合どのようにして実装を試みるだろうか?

prev


私は極めてシンプルに実装を試みた。(何にも考えていないとも言う) このダイアログのリソースを下に載せておく。



ここに見えるスタティックテキストとボタンは可視属性を抜いている。 すなわち見えないウィンドウである。

ただ、マウスの位置を知る為の境界線だと思っていただいてかまわない。

prev


実装方法は以下の通りである。
  1. ダイアログの OnSetCursor をオーバーライドする
  2. OnSetCursor 関数の中で、スタティックテキストの中にマウスポインタがあるかどうかを判定する
  3. もしあったならばカーソルを変える。
  4. もし無ければカーソルを元に戻す。
  5. カーソルが変わっている間(マウスポインタがスタティックテキストの境界線の内側にある時)にボタンが押された場合はそのスタティックテキストにあわせて処理を実行する

prev


以上のようにソースを書いてやればいいはずである。 以下ソースコード
class CAboutDlg : public CDialog
{
public:
    CAboutDlg();
    ~CAboutDlg();

    void          DoAction();

    CDC*          m_pdcDisplayMemory;
    CBitmap*      m_pBitmap;
    CSize         m_sizeSource;
    CSize         m_sizeDest;
    BOOL          FingerFlag;

    short         ActionFlag;

    CRect         RctUrl;
    CRect         RctAntenna;
    CRect         RctYuta;
    CRect         RctSek;
    CRect         RctHageru;
          
// ダイアログ データ
    //{{AFX_DATA(CAboutDlg)
    enum { IDD = IDD_ABOUTBOX };
    CStatic m_StcAntenna;
    CStatic m_StcYuta;
    CStatic m_StcUrl;
    CStatic m_StcSek;
    CStatic m_StcHageru;
    //}}AFX_DATA

    // ClassWizard は仮想関数のオーバーライドを生成します
    //{{AFX_VIRTUAL(CAboutDlg)
    protected:
    virtual void DoDataExchange(CDataExchange* pDX);          
    // DDX/DDV のサポート
    //}}AFX_VIRTUAL

// インプリメンテーション
protected:
    //{{AFX_MSG(CAboutDlg)
    virtual BOOL OnInitDialog();
    afx_msg void OnPaint();
    afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
    afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
    afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
};

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
    //{{AFX_MSG_MAP(CAboutDlg)
    ON_WM_PAINT()
    ON_WM_LBUTTONDOWN()
    ON_WM_LBUTTONUP()
    ON_WM_SETCURSOR()
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
    m_pdcDisplayMemory = new CDC;
    m_pBitmap = new CBitmap;

    FingerFlag = FALSE;
}

CAboutDlg::~CAboutDlg()
{
    delete    m_pdcDisplayMemory;
    delete    m_pBitmap;
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
    //{{AFX_DATA_MAP(CAboutDlg)
    DDX_Control(pDX, IDC_STC_ANTENNA, m_StcAntenna);
    DDX_Control(pDX, IDC_STC_YUTA, m_StcYuta);
    DDX_Control(pDX, IDC_STC_URL, m_StcUrl);
    DDX_Control(pDX, IDC_STC_SEK, m_StcSek);
    DDX_Control(pDX, IDC_STC_HAGERU, m_StcHageru);
    //}}AFX_DATA_MAP
}


BOOL CAboutDlg::OnInitDialog() 
{
    CDialog::OnInitDialog();

    BITMAP          bm;

    if (m_pdcDisplayMemory->GetSafeHdc() == NULL) {
          CClientDC dc(this); 
          dc.SetBkColor( RGB( 0, 0, 0 ) );
          m_pBitmap->LoadBitmap( IDB_ABOUT );
          m_pdcDisplayMemory->CreateCompatibleDC(&dc);
          m_pdcDisplayMemory->SelectObject(m_pBitmap);
          m_pBitmap->GetObject(sizeof(bm), &bm);
          m_sizeSource.cx = bm.bmWidth;
          m_sizeSource.cy = bm.bmHeight;
          m_sizeDest = m_sizeSource;
          dc.DPtoLP(&m_sizeDest); 
    }
    //
    m_StcUrl.GetWindowRect( RctUrl );
    m_StcAntenna.GetWindowRect( RctAntenna );
    m_StcYuta.GetWindowRect( RctYuta );
    m_StcSek.GetWindowRect( RctSek );
    m_StcHageru.GetWindowRect( RctHageru );

    ScreenToClient( RctUrl );
    ScreenToClient( RctAntenna );
    ScreenToClient( RctYuta );
    ScreenToClient( RctSek );
    ScreenToClient( RctHageru );
    //
    return TRUE;    
    // コントロールにフォーカスを設定しないとき、戻り値は TRUE となります
    // 例外: OCX プロパティ ページの戻り値は FALSE となります
}

void CAboutDlg::OnPaint() 
{
    CPaintDC dc(this); // 描画用のデバイス コンテキスト
    
    dc.StretchBlt( 0, 0, 
                   m_sizeDest.cx, 
                   m_sizeDest.cy, 
                   m_pdcDisplayMemory, 
                   0, 0, 
                   m_sizeSource.cx, 
                   m_sizeSource.cy, 
                   SRCCOPY
                 );
    
    // 描画用メッセージとして CDialog::OnPaint() を呼び出してはいけません
}

#define       AN_NONE       0
#define       AN_URL        1
#define       AN_ANTENNA    2
#define       AN_YUTA       3
#define       AN_SEK        4
#define       AN_HAGERU     5

BOOL CAboutDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 
{
    CPoint        point;
    HCURSOR       m_hCursor;

    GetCursorPos( &point );
    ScreenToClient( &point );

    if( RctUrl.PtInRect( point ) )
          ActionFlag = AN_URL;
    else if( RctAntenna.PtInRect( point ) )
          ActionFlag = AN_ANTENNA;
    else if( RctYuta.PtInRect( point ) )
          ActionFlag = AN_YUTA;
    else if( RctSek.PtInRect( point ) )
          ActionFlag = AN_SEK;
    else if( RctHageru.PtInRect( point ) )
          ActionFlag = AN_HAGERU;
    else
          ActionFlag = AN_NONE;

    if( ActionFlag != AN_NONE ){
          m_hCursor = ::LoadCursor( AfxGetInstanceHandle(), 
                                    MAKEINTRESOURCE( IDC_CUR_FINGER_OFF ) 
                                  );
          SetCursor( m_hCursor );
          //
          return    TRUE;
    }
    
    return CDialog::OnSetCursor(pWnd, nHitTest, message);
}

void CAboutDlg::OnLButtonDown(UINT nFlags, CPoint point) 
{
    HCURSOR       m_hCursor;

    if( ActionFlag != AN_NONE ){
          m_hCursor = ::LoadCursor( AfxGetInstanceHandle(), 
                                    MAKEINTRESOURCE( IDC_CUR_FINGER_ON ) 
                                  );
          SetCursor( m_hCursor );
    }
    
    CDialog::OnLButtonDown(nFlags, point);
}

void CAboutDlg::OnLButtonUp(UINT nFlags, CPoint point) 
{
    HCURSOR       m_hCursor;

    if( ActionFlag != AN_NONE ){
          m_hCursor = ::LoadCursor( AfxGetInstanceHandle(), 
                                    MAKEINTRESOURCE( IDC_CUR_FINGER_OFF ) 
                                  );
          SetCursor( m_hCursor );
          //
          DoAction();
    }
    
    CDialog::OnLButtonUp(nFlags, point);
}

void CAboutDlg::DoAction()
{
    switch( ActionFlag ){
      case    AN_URL:
          ::ShellExecute( *this, 
                          "open", 
                          "http://www.antenn-a.com", 
                          NULL, 
                          NULL,
                          SW_SHOWNORMAL 
                        );
          break;
      case    AN_ANTENNA:
          ::ShellExecute( *this, 
                          "open", 
                          "mailto:contact-us@antenn-a.com", 
                          NULL, 
                          NULL,
                          SW_SHOWNORMAL 
                        );
          break;
      case    AN_YUTA:
          ::ShellExecute( *this,
                          "open", 
                          "mailto:contact-us@antenn-a.com", 
                          NULL, 
                          NULL,
                          SW_SHOWNORMAL 
                        );
          break;
      case    AN_SEK:
          ::ShellExecute( *this, 
                          "open", 
                          "mailto:sek@antenn-a.com", 
                          NULL, 
                          NULL,
                          SW_SHOWNORMAL 
                        );
          break;
      case    AN_HAGERU:
          ::ShellExecute( *this, 
                          "open", 
                          "mailto:enomoto@antenn-a.com", 
                          NULL, 
                          NULL,
                          SW_SHOWNORMAL 
                        );
          break;
    }
}

prev


今回実装を試みたプログラムはテクニック的には対した事無いが、複合技が出てるので色々な意味で勉強になると思う。

これを参考にして是非、格好よいアバウトダイアログを作ってもらいたい。 今回のサンプルはここからダウンロードできる。



antenn-a

prev next


antenn-a