Wtl guide for MFC programmers: Part VII-separated windows

Source: Internet
Author: User

Wtl guide for MFC programmers: Part VII-separated windows

Original:Michael Dunn[Original ENGLISH]
Translation: Orbit [www.winmsg.com]

Download DEMO code

Content of this Chapter

  • Introduction
  • Windows separated by wtl
    • Related Classes
    • Create a separation window
    • Basic Method
    • Data Member
  • Start an example project
  • Create a window in the pane
  • Message Processing
  • Pane container
    • Related Classes
    • Basic Method
    • Use the pane container in the separation window
    • Close button and Message Processing
  • Advanced functions
    • Nested window Separation
    • Use ActiveX control in the pane
    • Special plot
  • Special drawing in the pane container
  • Display progress bar in the status bar
  • Continue
  • Reference
  • Modify record

Introduction

As the resource manager that uses two separated views to manage the file system appears for the first time in Windows 95, the separation window gradually becomes a popular interface element. MFC also has a complex and powerful separation window class, but it is really difficult to master its usage, and it is closely related to the document/view framework. In chapter 7, I will introduce the separation window of wtl, Which is simpler than the separation window of MFC. Windows separated by wtl are not as easy to use and expand as MFC.

The example project in this chapter is clipspy rewritten with wtl. If you are not familiar with this program, you can quickly browse the content of this chapter, because I just copied the clipspy function and didn't explain how it works in depth. After all, the focus of this article is to separate windows, not the clipboard.

Windows separated by wtl

The header file atlsplit. h contains all wtl separated window classes. There are three classes: csplitterimpl, csplitter1_wimpl, and csplitter1_wt. However, you usually only use one of them. The following describes these classes and their basic methods.

Related Classes

Csplitterimpl is a template class with two parameters. One is the class name of the window interface class, and the other is a Boolean variable that separates the window direction: True indicates the vertical direction, and false indicates the horizontal direction. The csplitterimpl class contains almost all the implementation code for window separation. Many of its methods can be reloaded. You can reload these methods to draw the appearance of the separator bar or achieve other effects. The csplitterjavaswimpl class is derived from the csf-wimpl and csplitterimpl classes, but it does not have much code. There is an empty wm_erasebkgnd message processing function and a wm_size processing function used to reposition the separation window.

The last one is the csplitterjavaswt class, which is derived from the csplitterimpl class and its window class name is "wtl_splitterwindow ". Two other custom data types are usually used to replace the preceding three classes: csplitterwindow is used to vertically separate windows, and chorsplitterwindow is used to horizontally separate windows.

Create split window

Since csplitterwindow is derived from the csf-wimpl class, you can create separate windows like creating other subwindows. The split window will exist throughout the lifecycle of the main frame window. A csplitterwindow variable should be added to the cmainframe class. In the cmainframe: oncreate () function, you can create a split window as a subwindow of the Main Window and set it as the customer window of the main window:

LRESULT CMainFrame::OnCreate ( LPCREATESTRUCT lpcs ){// ...const DWORD dwSplitStyle = WS_CHILD | WS_VISIBLE |                              WS_CLIPCHILDREN | WS_CLIPSIBLINGS,            dwSplitExStyle = WS_EX_CLIENTEDGE;     m_wndSplit.Create ( *this, rcDefault, NULL,                         dwSplitStyle, dwSplitExStyle );     m_hWndClient = m_wndSplit;}

After creating a separation window, you can specify a window for each pane or perform other necessary initialization work.

Basic Method

bool SetSplitterPos(int xyPos = -1, bool bUpdate = true)int GetSplitterPos()

You can call the setsplitterpos () function to set the position of the separator. This position indicates the number of pixel points between the split bars and the upper border of the separated window (horizontally separated window) or the left border (vertical separated window. You can use the default value-1 to set the separation bar to the middle of the separation window, so that the size of the two panes is the same. Generally, pass true to the bupdate parameter to indicate that the size of the two panes is changed after the separation bar is moved. Getsplitterpos () returns the position of the current separator, which is also relative to the upper or left boundary of the separator window.

bool SetSinglePaneMode(int nPane = SPLIT_PANE_NONE)int GetSinglePaneMode()

The setsinglepanemode () function can be called to change the window separation mode so that the single-pane mode or double-pane mode. in single-pane mode, only one pane is visible and the separation bar is hidden, this is similar to the dynamic separation window of MFC (except that there is no small pliers-shaped handle, which is used to re-separate the window ). The available values for the npane parameter are split_pane_left, split_pane_right, split_pane_top, split_pane_bottom, and split_pane_none. The first four indicators show the pane (for example, use the split_pane_left parameter to display, hide the right pane), and use split_pane_none to display both the pane. Getsinglepanemode () returns one of the five split_pane _ * values to indicate the current mode.

DWORD SetSplitterExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)DWORD GetSplitterExtendedStyle()

The separation window has its own style used to control how to move the separation bar when the entire separation window changes. There are the following styles:

  • Split_proportional: The two panes change the size together.
  • Split_rightaligned: the size of the right pane remains unchanged. Only the size of the left pane is changed.
  • Split_bottomaligned: Keep the size of the lower pane unchanged. Only the size of the upper pane is changed.

If neither split_proportional nor split_rightaligned/split_bottomaligned is specified, the split window is left aligned or up aligned. If split_proportional and split_rightaligned/split_bottomaligned are used together, the split_proportional style is preferred.

There is also an additional style to control whether the separator bar can be moved by the user:

  • Split_noninteractive: The separator bar cannot be moved and the mouse does not apply.

The default value of the extended style is split_proportional.

bool SetSplitterPane(int nPane, HWND hWnd, bool bUpdate = true)void SetSplitterPanes(HWND hWndLeftTop, HWND hWndRightBottom, bool bUpdate = true)HWND GetSplitterPane(int nPane)

You can call setsplitterpane () to assign a subwindow to the pane of the window. npane is a value of the split_pane _ * type, indicating to set a pane. Hwnd is the window handle of the subwindow. You can use setsplitterpane () to specify a subwindow to two panes at the same time. The default value is usually used for the bupdate parameter, that is, to tell the split window to immediately adjust the size of the subwindow to fit the size of the pane. You can call getsplitterpane () to obtain the subwindow handle of a pane. If the pane does not assign a subwindow, getsplitterpane () returns NULL.

bool SetActivePane(int nPane)int GetActivePane()

The setactivepane () function separates a subwindow in the window and sets it to the current focus window. The npane is a value of the split_pane _ * type, indicating which pane to activate, this function can also set the default activity pane (described later ). The getactivepane () function is used to view all windows with focus. If the window with focus is a pane or a subwindow with a focus, a value of the split_pane _ * type is returned, indicating which pane is used. If the current window with focus is not a subwindow of the pane, getactivepane () returns split_pane_none.

bool ActivateNextPane(bool bNext = true)

If the split window is in single-pane mode, the focus is set to the visible pane. Otherwise, the activatenextpane () function calls getactivepane () to view the window with focus. If a pane (or a subwindow In the pane) has checkpoints, the focus of the split window is set to another pane. Otherwise, activatenextpane () determines the value of bnext, if it is true, the Left/top pane is activated. If it is false, the right/bottom pane is activated.

bool SetDefaultActivePane(int nPane)bool SetDefaultActivePane(HWND hWnd)int GetDefaultActivePane()

Call the setdefaactivactivepane () function to set the default activity pane. Its parameter can be a value of the split_pane _ * type or a window handle. If you separate the focus of the window, you can call setfocus () to transfer the focus to the default pane. The getdefaactivactivepane () function returns the value of the split_pane _ * type to indicate which pane is the current default activity pane.

void GetSystemSettings(bool bUpdate)

Getsystemsettings () reads system settings and sets data members accordingly. The separation window automatically calls this function in the oncreate () function. You do not need to call this function by yourself. Of course, your main framework window should respond to wm_settingchange and pass it to the separation window. csplitterwindow calls getsystemsettings () in the processing function of the wm_settingchange message (). Pass true to the bupdate parameter. The separation window redraws itself based on the new settings.

Data Member

Other features can be set by directly accessing the public members of csplitterwindow. As long as getsystemsettings () is called, these public members are reset accordingly.

M_cxysplitbar: controls the width (vertical separator bar) and height (horizontal separator bar) of the separator bar ). The default value is obtained by calling getsystemmetrics (sm_cxsizeframe) or getsystemmetrics (sm_cysizeframe.

M_cxymin: controls the minimum width (vertical separation) and minimum height (horizontal separation) of each pane. Separate windows with less width or height. If the separation window has the ws_ex_clientedge extension property, the default value of this variable is 0. Otherwise, the default value is 2 * getsystemmetrics (sm_cxedge) or 2 * getsystemmetrics (sm_cyedge) (horizontal separation ).

M_cxybaredge: controls the width (vertical) or height (horizontal) of the 3D border drawn on both sides of the separator bar. The default value is exactly the opposite of m_cxymin.

M_bfulldrag: if it is true, the size of the pane is adjusted when the separator bar is dragged. If it is false, only the shadow of the separator bar is displayed when the drag is stopped. The default value is the return value of the systemparametersinfo (spi_getdragfullwindows) function.

Start an example project

Now that we have a basic understanding of the separation window, let's take a look at how to create a framework window that contains the separation window. Use the wtl Wizard to start a new project. On the first page, select SDI application and click Next. On the second page, remove the toolbar and select the do not use View window, as shown in:

We do not use a separation window because the separation window and Its pane will serve as a "View window" and add a data member of the csplitterwindow type in the cmainframe class:

class CMainFrame : public ...{//...protected:    CSplitterWindow  m_wndVertSplit;};

Create a separation window in oncreate () and set it as a View window:

LRESULT CMainFrame::OnCreate ( LPCREATESTRUCT lpcs ){//...    // Create the splitter windowconst DWORD dwSplitStyle = WS_CHILD | WS_VISIBLE |                           WS_CLIPCHILDREN | WS_CLIPSIBLINGS,            dwSplitExStyle = WS_EX_CLIENTEDGE;     m_wndVertSplit.Create ( *this, rcDefault, NULL,                            dwSplitStyle, dwSplitExStyle );     // Set the splitter as the client area window, and resize    // the splitter to match the frame size.    m_hWndClient = m_wndVertSplit;    UpdateLayout();     // Position the splitter bar.    m_wndVertSplit.SetSplitterPos ( 200 );     return 0;}

You must set m_hwndclient and call the cframeworkwimpl: updatelayout () function before setting the location of the window to be separated. updatelayout () sets the size of the window to the initial size. If you skip this step, the size of the split window will be uncertain and may be smaller than the width of 200 pixel points, resulting in unexpected results in setsplitterpos. Another way to do not call the updatelayout () function is to first obtain the client Region coordinates of the Framework Window, and then use the client Region coordinates to replace the rcdefault coordinates to create a separation window. The split window created in this way is located at the correct initial position at the beginning, and then functions (such as setsplitterpos () for location adjustment can work normally.

Now we can run our program to see the separation bar, even if no pane window is created, it still has basic behavior. You can drag the separator bar and double-click it to move it to the middle of the window.

To demonstrate how to separate windows, I will use a clistviewctrl derived class and a simple cricheditctrl. The following is the code extracted from the class cclipspylistctrl. We use this class in the left pane:

typedef CWinTraitsOR<LVS_REPORT | LVS_SINGLESEL | LVS_NOSORTHEADER>          CListTraits; class CClipSpyListCtrl :    public CWindowImpl<CClipSpyListCtrl, CListViewCtrl, CListTraits>,    public CCustomDraw<CClipSpyListCtrl>{public:    DECLARE_WND_SUPERCLASS(NULL, WC_LISTVIEW)     BEGIN_MSG_MAP(CClipSpyListCtrl)        MSG_WM_CHANGECBCHAIN(OnChangeCBChain)        MSG_WM_DRAWCLIPBOARD(OnDrawClipboard)        MSG_WM_DESTROY(OnDestroy)        CHAIN_MSG_MAP_ALT(CCustomDraw<CClipSpyListCtrl>, 1)        DEFAULT_REFLECTION_HANDLER()    END_MSG_MAP()//...};

If you have read the previous articles, you can easily read the code of this class. It responds to the wm_changecbchain message, so that it can know whether other clipboard viewing programs are started and disabled, and it also responds to the wm_drawclipboard message, so that it can know whether the clipboard content has changed.

Since the child windows in the window pane exist all the time while the program is running, we can also set them as members of the cmainframe class:

class CMainFrame : public ...{//...protected:    CSplitterWindow  m_wndVertSplit;    CClipSpyListCtrl m_wndFormatList;    CRichEditCtrl    m_wndDataViewer;};

Create a window in the pane

Since there are already member variables for the separation window and the Child Window, it is easy to fill the separation window. First create a separation window, and then create two child windows, use the separation window as their parent window:

LRESULT CMainFrame::OnCreate ( LPCREATESTRUCT lpcs ){//...    // Create the splitter windowconst DWORD dwSplitStyle = WS_CHILD | WS_VISIBLE |                           WS_CLIPCHILDREN | WS_CLIPSIBLINGS,            dwSplitExStyle = WS_EX_CLIENTEDGE;     m_wndVertSplit.Create ( *this, rcDefault, NULL,                            dwSplitStyle, dwSplitExStyle );     // Create the left pane (list of clip formats)    m_wndFormatList.Create ( m_wndVertSplit, rcDefault );     // Create the right pane (rich edit ctrl)const DWORD dwRichEditStyle =               WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL |              ES_READONLY | ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE;     m_wndDataViewer.Create ( m_wndVertSplit, rcDefault,                              NULL, dwRichEditStyle );    m_wndDataViewer.SetFont ( AtlGetStockFont(ANSI_FIXED_FONT) );     // Set the splitter as the client area window, and resize    // the splitter to match the frame size.    m_hWndClient = m_wndVertSplit;    UpdateLayout();     m_wndVertSplit.SetSplitterPos ( 200 );     return 0;}

Note that the CREATE () function of the two classes uses m_wndvertsplit as the parent window. The rect parameter does not matter, because the split window will re-adjust their size, so you can use cwindow: rcdefault.

The last step is to pass the window handle to the pane of the separated window. This step also needs to be completed before calling updatelayout (), so that all the windows will have the correct size.

LRESULT CMainFrame::OnCreate ( LPCREATESTRUCT lpcs ){//...    m_wndDataViewer.SetFont ( AtlGetStockFont(ANSI_FIXED_FONT) );     // Set up the splitter panes    m_wndVertSplit.SetSplitterPanes ( m_wndFormatList, m_wndDataViewer );     // Set the splitter as the client area window, and resize    // the splitter to match the frame size.    m_hWndClient = m_wndVertSplit;    UpdateLayout();     m_wndVertSplit.SetSplitterPos ( 200 );     return 0;}

Now, a few columns are added to the list control, and the result looks like this:

Note that there is no limit on the type of the window that is placed into the pane for separating windows. Unlike MFC, it must be a cview derived class. As long as the ws_child style exists in the pane window, there are no other restrictions.

Message Processing

Because a separate window is added between the main frame window and our pane window, you may want to know how the notification message works now, for example, in the main framework window, how does one receive the nm_customdraw notification message and reflect it to the list control? The answer is in the message chain of csplitterjavaswimpl:

  BEGIN_MSG_MAP(thisClass)    MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)    MESSAGE_HANDLER(WM_SIZE, OnSize)    CHAIN_MSG_MAP(baseClass)    FORWARD_NOTIFICATIONS()  END_MSG_MAP()

Which of the final forward_notifications () macros is the most important? In chapter 4, there are some parent windows of the subwindows where notification messages are always sent. forward_notifications () is to do this, it forwards these messages to the parent window of the separation window. That is, when the list window sends a wm_notify message to the split window (it is the parent window of the list ), the split window forwards the wm_notify message to the main frame window (which is the parent window of the split window ). When the main framework window is reflected back to the message, the message is reflected to the original sender of the wm_notify message, that is, the List window. Therefore, the separation window is not involved in message reflection.

The message transfer between the List window and the main frame window does not affect the work of the separation window, which makes it easy to add and remove the separation window in the program, because the child window can continue to work without any changes.

Pane container

Wtl also has a component called a pane container. Like the left pane of explorer, there is a text area on the top and a close button that can be selected for display:

Just like the window separation Management window, this pane container also manages a sub-window. When the size of the container window changes, the size of the sub-window is also changed to fill the internal space of the container window.

Related Classes

The implementation of this pane container requires two classes: cpanecontainerimpl and cpanecontainer, both declared in atlctrlx. h. Cpanecontainerimpl is a csf-wimpl derived class that contains the complete implementation of the pane container. cpanecontainer only provides a class name, unless cpanecontainerimpl is overloaded or the container's appearance is changed, cpanecontainer is generally enough.

Basic Method

HWND Create(    HWND hWndParent, LPCTSTR lpstrTitle = NULL,    DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,    DWORD dwExStyle = 0, UINT nID = 0, LPVOID lpCreateParam = NULL)HWND Create(    HWND hWndParent, UINT uTitleID,    DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,    DWORD dwExStyle = 0, UINT nID = 0, LPVOID lpCreateParam = NULL)

Creating a cpanecontainer window is the same as creating other subwindows. There are two create () functions. The difference is that the second parameter is different. The first function needs to pass a string as the text displayed in the top area of the container. The second parameter needs to pass the resource ID of a string. Other parameters only need to use the default value.

DWORD SetPaneContainerExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)DWORD GetPaneContainerExtendedStyle()

Cpanecontainer also has some extended styles to control the layout of the close button on the container window:

  • Panecnt_noclosebutton: Use the style to remove the close button at the top.
  • Panecnt_vertical: After setting this style, the text area on the top is placed vertically along the left border of the container window.

The default value of the extended style is 0, indicating that the container window is placed horizontally and there is a close button.

HWND SetClient(HWND hWndClient)HWND GetClient()

You can call setclient () to assign a sub-window to the pane container, which is similar to calling the setsplitterpane () method of the csplitterwindow class. Setclient () returns the original client window handle and calls getclient () to obtain the current client window handle.

BOOL SetTitle(LPCTSTR lpstrTitle)BOOL GetTitle(LPTSTR lpstrTitle, int cchLength)int GetTitleLength()

Call settitle () to change the text displayed at the top of the container window. Call gettitle () to obtain the text displayed in the top area of the current window. Call gettitlelength () you can obtain the number of characters displayed (excluding the trailing null characters ).

BOOL EnableCloseButton(BOOL bEnable)

If the container in the pane uses the close button, you can call enableclosebutton () to control the status of this button.

Use the pane container in the separation window

To illustrate how to use the pane container, we will add a pane container to the left pane of the clipspy separation window. We will assign a pane container to the left pane to replace the previously used list control, the list control is assigned to the pane container. The following code is added in cmainframe: oncreate () to support the pane container.

LRESULT CMainFrame::OnCreate ( LPCREATESTRUCT lpcs ){//...    m_wndVertSplit.Create ( *this, rcDefault, NULL, dwSplitStyle, dwSplitExStyle );     // Create the pane container.    m_wndPaneContainer.Create ( m_wndVertSplit, IDS_LIST_HEADER );     // Create the left pane (list of clip formats)    m_wndFormatList.Create ( m_wndPaneContainer, rcDefault );//...    // Set up the splitter panes    m_wndPaneContainer.SetClient ( m_wndFormatList );    m_wndVertSplit.SetSplitterPanes ( m_wndPaneContainer, m_wndDataViewer );

Note: the parent window of the list control is m_wndpanecontainer, and m_wndpanecontainer is set to the left pane of the component separation window.

The following figure shows the exterior of the modified left pane. As the pane container draws a three-dimensional border in the text area on the top, I need to slightly modify the border style. This does not look very nice. You can adjust the style by yourself until you are satisfied. (Of course, You need to test on Windows XP which interface topic can make the separation window look "more interesting ".)

Close button and Message Processing

When you click the close button, the pane container sends a wm_command message to the parent window. The command ID is id_pane_close. If you use a pane container in the separation window, you need to respond to the entire message and call setsinglepanemode () to hide this pane. (However, do not forget to provide you with a method to re-display the pane !)

The message chain of cpanecontainer also uses the forward_notifications () Macro. Like csplitterwindow, the pane container transmits notification messages between the customer window and its parent window. In the clipspy example, two windows (PANE container and separation window) are separated between the list control and the main frame window, but forward_configurications () macros ensure that all notification messages are sent to the main frame window.Advanced functions

In this section, I will introduce how to use the advanced interface features of wtl.

Nested window Separation

If you want to write an email client program, you may need to use nested separators, a horizontal separator and a vertical separator. Wtl makes it easy to do this: Create a split window as a Child Window of another split window.

To demonstrate this effect, I will add a horizontal separation window for clipspy. First, add a member of The chorsplitterwindow type named m_wndhorzsplitter to create the horizontal split window like creating the Vertical Split Window m_wndvertsplitter, so that the horizontal split window m_wndhorzsplitter becomes the top-level window, create m_wndvertsplitter as a subwindow of m_wndhorzsplitter. Finally, set m_hwndclient to m_wndhorzsplitter, because the horizontal split window occupies the customer zone of the entire main frame window.

LRESULT CMainFrame::OnCreate(){//...    // Create the splitter windows.    m_wndHorzSplit.Create ( *this, rcDefault, NULL,                            dwSplitStyle, dwSplitExStyle );     m_wndVertSplit.Create ( m_wndHorzSplit, rcDefault, NULL,                            dwSplitStyle, dwSplitExStyle );//...    // Set the horizontal splitter as the client area window.    m_hWndClient = m_wndHorzSplit;    // Set up the splitter panes    m_wndPaneContainer.SetClient ( m_wndFormatList );    m_wndHorzSplit.SetSplitterPane ( SPLIT_PANE_TOP, m_wndVertSplit );    m_wndVertSplit.SetSplitterPanes ( m_wndPaneContainer, m_wndDataViewer );//...}

The final result is like this:

Use ActiveX control in the pane

Using ActiveX controls in the window separation pane is similar to using ActiveX controls in the dialog box. Using the caxwindow class method, you can create a control at runtime, and then specify this caxwindow to the window separation pane. The following shows how to use browser controls in the pane below the horizontal separation window:

    // Create the bottom pane (browser)CAxWindow wndIE;const DWORD dwIEStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN |                        WS_HSCROLL | WS_VSCROLL;    wndIE.Create ( m_wndHorzSplit, rcDefault,                   _T("http://www.codeproject.com"), dwIEStyle );    // Set the horizontal splitter as the client area window.    m_hWndClient = m_wndHorzSplit;    // Set up the splitter panes    m_wndPaneContainer.SetClient ( m_wndFormatList );    m_wndHorzSplit.SetSplitterPanes ( m_wndVertSplit, wndIE );    m_wndVertSplit.SetSplitterPanes ( m_wndPaneContainer, m_wndDataViewer );

Special plot

If you want to change the appearance of the separator bar, for example, using some materials above, you can derive a new class from csplitterjavaswimpl and reload the drawsplitterbar () function. If you just want to adjust the appearance of the separator bar, you can copy the function of the csplitterwimpl class and then make some modifications. The following example uses a diagonal crossover pattern in the separator bar.

template <bool t_bVertical = true>class CMySplitterWindowT :     public CSplitterWindowImpl<CMySplitterWindowT<t_bVertical>, t_bVertical>{public:    DECLARE_WND_CLASS_EX(_T("My_SplitterWindow"),                          CS_DBLCLKS, COLOR_WINDOW)     // Overrideables    void DrawSplitterBar(CDCHandle dc)    {    RECT rect;         if ( m_br.IsNull() )            m_br.CreateHatchBrush ( HS_DIAGCROSS,                                     t_bVertical ? RGB(255,0,0)                                                 : RGB(0,0,255) );         if ( GetSplitterBarRect ( &rect ) )        {            dc.FillRect ( &rect, m_br );             // draw 3D edge if needed            if ( (GetExStyle() & WS_EX_CLIENTEDGE) != 0)                dc.DrawEdge(&rect, EDGE_RAISED,                             t_bVertical ? (BF_LEFT | BF_RIGHT)                                         : (BF_TOP | BF_BOTTOM));        }    } protected:    CBrush m_br;}; typedef CMySplitterWindowT<true>    CMySplitterWindow;typedef CMySplitterWindowT<false>   CMyHorSplitterWindow;

This is the result (widening the separator to make it easier to see the effect ):

Special drawing in the pane container

Cpanecontainer also has several functions that can be reloaded to change the appearance of the pane container. You can derive a new class from cpanecontainerimpl and reload the methods you need, for example:

class CMyPaneContainer :    public CPaneContainerImpl<CMyPaneContainer>{public:    DECLARE_WND_CLASS_EX(_T("My_PaneContainer"), 0, -1)//... overrides here ...};

Some more interesting methods are as follows:

void CalcSize()

The calcsize () function is called only to set m_cxyheader. This variable controls the width and height of the top area of the pane container. However, the setpanecontainerextendedstyle () function has a bug. As a result, when the pane switches from horizontal to vertical, the calcsize () method of the derived class is not called. You can change the calcsize () call to Pt-> calcsize () to fix this bug.

HFONT GetTitleFont()

This method returns a hfont, which is used to draw the text in the top area. The default value is the font obtained by calling getstockobject (default_gui_font), that is, Ms sans serif. If you want to rename a more modern tahoma font, You can reload the gettitlefont () method and return the tahoma font you created.

BOOL GetToolTipText(LPNMHDR lpnmh)

Reload this method to provide the prompt information that pops up when you move the cursor to the close button. This function is actually the corresponding function of ttn_getdispinfo. You can convert lpnmh to nmttdispinfo *, and set the corresponding member variables in the data structure. Remember, you must check the notification code, which may be ttn_getdispinfo or ttn_getdispinfow. You need to access these two data structures differently.

void DrawPaneTitle(CDCHandle dc)

You can reload this method to draw the top area by yourself. You can use getclientrect () and m_cxyheader to calculate the range of the top area. The following example demonstrates a gradient filling background in the top area of the horizontal container:

void CMyPaneContainer::DrawPaneTitle ( CDCHandle dc ){RECT rect;     GetClientRect(&rect); TRIVERTEX tv[] = {     { rect.left, rect.top, 0xff00 },    { rect.right, rect.top + m_cxyHeader, 0, 0xff00 } };GRADIENT_RECT gr = { 0, 1 };     dc.GradientFill ( tv, 2, &gr, 1, GRADIENT_FILL_RECT_H );}

The example project code demonstrates the overloading of these methods to make the results look like this:

As shown in the preceding figure, this demo has a splitters menu, which allows you to switch between various style separators (including the self-drawn style) and pane containers to compare their similarities and differences. You can also lock the separator bar location, which is achieved by setting and canceling the split_noninteractive extension style.

Display progress bar in the status bar

As I have done in the previous articles, the new clipspy demonstrates how to create a progress bar on the status bar. It has the same functionality as the MFC version. Several related steps are as follows:

  1. Obtain the status bar. The first pane obtains the coordinate range rect.
  2. Create a progress bar as a status bar subwindow. The window size is the size of the status bar pane.
  3. Update the position of the progress bar when the Edit Control is filled

These codes are in the cmainframe: createprogressctrlinstatusbar () function.

Continue

In chapter 8, I will introduce the usage of the properties page and Wizard dialog box.

Reference

Wtl splitters and pane containers by Ed gadziemski

Modify record

July 9, 2003: the first release of the article.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.