1. 程式人生 > 實用技巧 >使用c++助手類將滾動新增到CWnd或CDialog中

使用c++助手類將滾動新增到CWnd或CDialog中

介紹 使用MFC為自定義CWnd或cdialog派生的類實現標準滾動行為是相當重要的。至少有3或4個訊息處理程式需要編寫,以及每個滾動條的許多滾動引數,每當您的視窗或對話方塊調整大小時,都需要對這些滾動條進行調整。在本文中,我介紹了一個c++助手類,它可以用於向任何CWnd或CDialog類新增水平滾動和/或垂直滾動。與您所見過的其他實現不同,沒有需要派生的可滾動對話方塊基類。使用助手類(CScrollHelper)不需要更改繼承層次結構。 背景 在詳細討論如何使用helper類之前,我想引用一些引用,它們很好地解釋了實現滾動的基礎知識。第一個引用是MSDN文章262954,“如何在Visual c++中建立具有滾動條的可調整大小的對話方塊”。本文給出了一個如何向CDialog類新增垂直滾動條支援的示例。第二個參考來自Jeff Prosise(微軟出版社)的《用MFC程式設計Windows,第二版》一書。本書的第2章解釋了在cwnd派生類中實現滾動的細節,並給出了一個支援水平和垂直滾動的簡單電子表格應用程式的示例程式碼。 對於cwnd派生的類,實現滾動的第一步是確保用視窗樣式建立視窗,WS_HSCROLL(如果您想要水平滾動條)和/或WS_VSCROLL(如果您想要垂直的、附加在右邊的滾動條)。隱藏,複製Code

Create(NULL, "CScrollWnd",
       WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL,
       CRect(0,0,0,0), parentWnd, 0, NULL);

對於對話方塊,視窗樣式通常是通過資源編輯器設定的。在VS 2003中,我通常確保為任何我想要滾動的對話方塊設定以下屬性: 邊框=“調整大小”,如果你有一個彈出的對話方塊。如果您的對話方塊是嵌入在父容器中的子視窗,您可以選擇另一種樣式,如“None”(演示專案有一個這樣的示例)。 Clip Children = "True"。此設定可幫助最小化在調整對話方塊大小時顯示的閃爍。 水平滾動條= "True"。這相當於新增視窗樣式WS_HSCROLL。 如果您的對話方塊是嵌入在父容器中的子視窗,則樣式= "Child"。 垂直滾動條= "True"。這相當於新增視窗樣式WS_VSCROLL。 可見= " True "。Visual Studio在某些情況下預設為“False”,所以您需要檢查此設定。 使用的程式碼 CScrollHelper類在兩個原始檔中實現:ScrollHelper.h和ScrollHelper.cpp。類的公共介面如下所示:收縮,複製Code

class CScrollHelper
{
public:
    CScrollHelper();
    ~CScrollHelper();

    // Attach/detach a CWnd or CDialog.
    void   AttachWnd(CWnd* pWnd);
    void   DetachWnd();

    // Set/get the virtual display size.
    // When the dialog or window
    // size is smaller than the display
    // size, then that is when
    // scrollbars will appear. Set either
    // the display width or display
    // height to zero if you don't want to
    // enable the scrollbar in the
    // corresponding direction.
    void   SetDisplaySize(int displayWidth,
                           int displayHeight);
    const CSize& GetDisplaySize() const;

    // Get current scroll position.
    // This is needed if you are scrolling
    // a custom CWnd which implements its
    // own drawing in OnPaint().
    const CSize& GetScrollPos() const;

    // Get current page size. Useful
    // for debugging purposes.
    const CSize& GetPageSize() const;

    // Scroll back to top, left, or
    // top-left corner of the window.
    void   ScrollToOrigin(bool scrollLeft,
                              bool scrollTop);

    // Message handling.
    void   OnHScroll(UINT nSBCode, UINT nPos,
                        CScrollBar* pScrollBar);
    void   OnVScroll(UINT nSBCode, UINT nPos,
                        CScrollBar* pScrollBar);
    BOOL   OnMouseWheel(UINT nFlags,
                       short zDelta, CPoint pt);
    void   OnSize(UINT nType, int cx, int cy);
};

為了向cdialog派生的類(例如CScrollDlg)新增滾動支援,我們首先向對話方塊的類定義(包括檔案)新增一個私有成員:複製Code

class CScrollHelper;    // Forward class declaration.

class CScrollDlg : public CDialog
{
...

private:
    CScrollHelper* m_scrollHelper;
};

接下來,我們向與滾動相關的類定義(包括檔案)新增四個訊息處理程式:複製Code

// Generated message map functions.
//{{AFX_MSG(CScrollDlg)
...
afx_msg void OnHScroll(UINT nSBCode,
        UINT nPos, CScrollBar* pScrollBar);
afx_msg void OnVScroll(UINT nSBCode,
        UINT nPos, CScrollBar* pScrollBar);
afx_msg BOOL OnMouseWheel(UINT nFlags,
                  short zDelta, CPoint pt);
afx_msg void OnSize(UINT nType, int cx,
                                   int cy);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()

在對話方塊原始檔中,包括ScrollHelper.h檔案,併為四個訊息處理程式新增訊息對映項:複製Code

#include "ScrollHelper.h"
...
BEGIN_MESSAGE_MAP(CScrollDlg, CDialog)
    //{{AFX_MSG_MAP(CScrollDlg)
    ...
    ON_WM_HSCROLL()
    ON_WM_VSCROLL()
    ON_WM_MOUSEWHEEL()
    ON_WM_SIZE()
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

然後在dialog建構函式中建立helper類的例項,並將該對話方塊附加到例項中:複製Code

CScrollDlg::CScrollDlg(CWnd* pParent)
    : CDialog(IDD_SCROLL_DLG, pParent)
{
    // Create the scroll helper
    // and attach it to this dialog.
    m_scrollHelper = new CScrollHelper;
    m_scrollHelper->AttachWnd(this);
}

記住在對話方塊解構函式中刪除助手類例項:複製Code

CScrollDlg::~CScrollDlg()
{
    delete m_scrollHelper;
}

接下來,通過簡單地委託給helper類來實現這四個訊息處理程式,該類具有與訊息處理程式完全相同的簽名的方法:Hide收縮,複製Code

void CScrollDlg::OnHScroll(UINT nSBCode,
                UINT nPos, CScrollBar* pScrollBar)
{
    m_scrollHelper->OnHScroll(nSBCode,
                          nPos, pScrollBar);
}

void CScrollDlg::OnVScroll(UINT nSBCode,
         UINT nPos, CScrollBar* pScrollBar)
{
    m_scrollHelper->OnVScroll(nSBCode,
                          nPos, pScrollBar);
}

BOOL CScrollDlg::OnMouseWheel(UINT nFlags,
                    short zDelta, CPoint pt)
{
    BOOL wasScrolled =
        m_scrollHelper->OnMouseWheel(nFlags,
                                      zDelta, pt);
    return wasScrolled;
}

void CScrollDlg::OnSize(UINT nType, int cx, int cy)
{
    CDialog::OnSize(nType, cx, cy);
    m_scrollHelper->OnSize(nType, cx, cy);
}

完成滾動支援的最後一步是在helper類中設定“顯示大小”。它表示對話方塊的虛擬顯示區域,是一個可以在程式碼本身中預先確定和修復的值,或者在執行時動態計算的值。如果您熟悉c#中的Windows窗體程式設計,那麼顯示大小的概念類似於可滾動控制元件中的DisplayRectangle屬性。顯示大小表示滾動條出現或消失的精確閾值或點。例如,如果使用者將對話方塊的大小調整到小於顯示的大小,則會出現滾動條,允許您滾動對話方塊來訪問整個虛擬顯示介面。如果使用者將對話方塊的大小調整到大於顯示的大小,那麼滾動條就會消失。顯示大小通常是一個固定的值,在你第一次設定它之後:Hide 複製Code

CScrollDlg::CScrollDlg(CWnd* pParent)
    : CDialog(IDD_SCROLL_DLG, pParent)
{
    // Create the scroll helper and
    // attach it to this dialog.
    m_scrollHelper = new CScrollHelper;
    m_scrollHelper->AttachWnd(this);

    // We also set the display size
    // equal to the dialog size.
    // This is the size of the dialog
    // in pixels as laid out
    // in the resource editor.
    m_scrollHelper->SetDisplaySize(701, 375);

    // Create the dialog.
    Create(IDD_SCROLL_DLG, pParent);
}

在CScrollHelper類的介面中,您可能已經注意到了GetPageSize()方法。頁面大小是另一個重要的滾動引數,由helper類在內部管理。基本上,頁面大小與對話方塊大小相同(或者更準確地說,與對話方塊的客戶區大小相同)。這類似於Win表單中的ClientRectangle屬性。ratio頁面大小的顯示器大小使用Windows確定多大的“拇指”部分滾動條。拇指的大小給你表明你正在檢視多少虛擬顯示錶面(和拇指的位置告訴你哪一部分的虛擬顯示錶面你看)。例如,假設你正在檢視很長在Microsoft Word文件(100頁)。您將看到的拇指垂直滾動條很小。另一方面,如果你正在編輯的文件比單個頁面只有一段時間,你會發現滾動條上的拇指是接近最大大小。 TestScroll應用程式 演示專案(TestScroll)演示了使用助手類。這是一個我從頭開始建立MDI應用程式使用Visual Studio。生成專案,我違約VS嚮導選項除了文件/檢視支援複選框,我不。然後我寫了兩個新類,CScrollDlg CScrollWnd。CScrollDlg是一個對話方塊類,使用輔助類來實現滾動(如上述程式碼部分所示)。它只顯示四個按鈕,一個在每個角落的虛擬顯示錶面,以及CListBox顯示當前滾動引數對話方塊被調整大小。CScrollWnd是一個自定義CWnd-derived類,向你展示瞭如何新增滾動支援non-dialog類。有趣的是這裡的實現是這個類描繪一個矩形代表固定的顯示尺寸。所以你改變視窗的大小,你可以看到正是當一個滾動條會出現或消失。 生成的MDI應用程式提供了一個類稱為CChildView,這是包含在MDI子框架視窗。CChildView是整合的起點和我上面兩個新類。CChildView提供它自己的內容,而是我修改或建立一個CScrollDlg覆蓋整個客戶區CScrollWnd例項。隱藏,複製Code

int CChildView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if ( CWnd::OnCreate(lpCreateStruct) == -1 )
        return -1;

    // We either create a CScrollWnd or a CScrollDlg.
    // We alternate using a counter.
    static int counter = 0;

    if ( counter % 2 == 0 )
        m_scrollWin = new CScrollWnd(this);
    else
        m_scrollWin = new CScrollDlg(this);
    ++counter;

    return 0;
}

測試演示應用程式,只需使用檔案|新選單項開啟MDI子視窗。第一次你會得到一個CScrollWnd例項。第二次,CScrollDlg將被建立。每一次你選擇“新”,它將替代之間的兩種型別的例子。 下面的快照顯示了滾動CWnd-derived類。MDI子視窗顯示滾動條頂部自視窗大小小於顯示大小。底部MDI子沒有滾動條,你可以清楚地看到,視窗大小大於固定顯示尺寸(由藍色矩形)。在底部MDI的孩子,請注意頁面大小是報告為0 x 0。這就是助手類能夠隱藏滾動條——通過設定內部滾動引數如滾動位置和頁面大小為零值。 下面的快照顯示了CDialog滾動的一個例子。注意底部MDI子視窗的標題欄顯示當前滾動位置,並且滾動對話方塊的右下角。滾動到最大位置時,注意到一個有趣的一點是滾動的位置(222、230)新增到頁面大小(479、145)=顯示尺寸(701、375)。 總而言之,CScrollHelper類很容易新增滾動支援CWnd或CDialog類,因為它負責實施所有必要的訊息處理程式。使用助手類的關鍵是能夠正確地設定顯示大小。CWnd類,您可能還需要進一步看GDI對映模式和邏輯,裝置座標之間的轉換。 歷史 2005年7月5日, 最初的版本。 2005年7月6日, 新增Get32BitScrollPos()函式根據MSDN文章ID 152252,“如何獲得32位滾動位置在滾動訊息”。 處理SB_THUMBPOSITION OnHScroll / OnVScroll。 添加了vc++ 6.0演示專案。(由於PJ阿倫茲建議修復。) 2005年9月8日, 新增GetClientRectSB () helper函式。 使用記憶體DC圖演示專案(CScrollWnd類),以避免閃爍的調整。 本文轉載於:http://www.diyabc.com/frontweb/news5239.html