MFC programmer's WTL Guide: Part VII - Separated Window

xiaoxiao2021-03-06  44

MFC programmer's WTL Guide: Part VII - Separated Window

Original: Michael Dunn [English] Translation: Orbit (Orange skin dried) [www.winmsg.com]

Download Demonstration Code

This chapter

Introducing the wtl separator window

Related Class Creating Separation Windows Basic Method Data Members Start an example of an example of a window message processing pane container in a pane

Related basic methods Using pane containers in separate windows to close buttons and messages to process advanced features

Nested Separation Window In the pane, use the ActiveX control Special drawing pane container special drawing in the status bar display progress bar Continue reference Modification Record

Introduction

With the use of two separate view management file systems, the resource manager in Windows 95 appears in Windows 95, the separator is gradually become a popular interface element. The MFC also has a complex functional separator window, but it is really difficult to master its usage, and it is closely related to the document / view framework. In Chapter VII I will introduce the WTL separator, it is simpler than the Separation window of the MFC. WTL's separated window does not have an MFC so multi-characterity, but it is easy to use and expand.

The example of this chapter is written with WTL, if you are not familiar with this program, you can now quickly browse this chapter content, because I just copied the character of Clipspy and did not use in-depth explanations how it works. After all, after all, after all, The focus of this article is to separate the window, not a clipboard.

WTL's separator window

Header file ATLSPLIT.H contains all WTL separated window classes, a total of three classes: CSPLitterImpl, CSplitterWindowImpl, and CSplitterWindowt, but you usually use one of them. These classes and their basic methods will be described below.

Related class

CSplitterIMPL is a template class with two parameters, one is a class name of the window interface, and the other is the Boolean variable indicates the direction of the separator window: True represents the vertical direction, and false represents the horizontal direction. The CSPLitterIMPL class contains almost all separated windows implementation code, which is over-duty, overloaded these methods can draw their own appearance or implement other effects. The CSplitterWindowIMPL class is derived from CWindowImpl and CSPLitterImpl, but its code is not much, there is an empty WM_ERASEBKGND message processing function and a WM_SIZE handler for repositioning the separator window.

The last is a CSPLitterWindowt class, which is derived from the CSPLitterImpl class, and its window class name is "wtl_splitterwindow". There are also two custom data types that are often used to replace the above three classes: CSPLitterWindow is used to vertical separation windows, and ChorsplitterWindow is used for horizontal separation windows.

Create a split window

Since CSPLitterWindow is derived from the CWindowImpl class, you can create a separate window like you have created other sub-windows. The separator window will exist in the lifecycle of the entire main frame window, and a variable of a CSPLitterWindow type should be added to the CMAINFRAME class. In the cmainframe :: oncreate () function, you can create the separated window as the sub-window of the main window, and then set it to the customer area 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 separated window, you can specify a window for each pane or do 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, which indicates how many pixels of the upper boundary (horizontal separator window) or the left boundary (vertical separator window) of the split bar distance. You can use the default value -1 to set the separator to the middle of the separator, the two panes are the same, usually transmitted to the BUPDATE parameter indicates the size of the two panes after moving the separator. GetSplitterpos () returns the position of the current partition, which is also the upper bound or left boundary relative to the separated window.

Bool setSinglePaneMode (int npane = split_pane_none)

Int getsinglepanemode ()

Calling the setSinglePaneMode () function can change the mode of the separated window to make the single-pane mode or dual-window mode, in single-pane mode, only one pane makes visible and hides the separator, which is similar to the dynamic separator window of the MFC. (Only no handle of the small plunger shape is used to resize the separator window). The value available for the NPANE parameter is split_pane_left, split_pane_right, split_pane_top, split_pane_bottom, and split_pane_none, the first four indications show that pane (for example, using the split_pane_left parameter will display the left pane, hide the right pane), use split_pane_none to express two The pane is displayed. GetSinglePaneMode () Returns one of the five split_pane_ * values ​​representing the current mode.

DWORD SETSPLITTEREXTENDEDSTYLE (DWORD DWEXTENDSTYLE, DWORD DWMASK = 0)

DWORD getSplitterextendedStyle ()

Separation windows have their own style for control how to move the separator when the entire separator window changes the size. There are several styles:

Split_proportional: Two panes Change the size split_rightaligned: On the right pane remains the size, only change the left pane size split_bottomaligned: The lower pane remains unchanged, only change the upper pane size

If no split_proportion is specified, no split_rightaligned / split_bottomaligned, the separator window will turn left align or aligned. If you use split_proportional and split_rightaligned / split_bottomaligned, give priority to Split_Proportional style.

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

Split_nonInteractive: Separator cannot be moved and no corresponding mouse

The default value of the extended style is split_proportional.

Bool Setsplitterpane (int NPane, HWND HWND, BOOL BUPDATE = true)

Void setsplitterpanes (hwnd hwndrightbottom, bool bupdate = true) hwnd getsplitterpane (int npane)

You can call the setSplitterPane () to the pane of the Separation window, and nPane is a value of a split_pane_ * type, indicating that the setting takes a pane. HWND is the window handle of the sub-window. You can use setSplitterpane () to simultaneously assign a sub-window to two panes, usually using the default value for the BUPDATE parameter, that is, tell the Separator to immediately adjust the size of the sub-window to accommodate the size of the pane. You can call getSplitterPane () to get the sub-window handle of a pane. If the pane does not finger a sub-window, getSplitterPane () returns NULL.

Bool SetActivePane (int NPane)

Int getActivePane ()

The setActivePane () function sets a sub-window in the Separation window to the current focus window, NPANE is the value of the split_pane_ * type, indicating which pane you need to activate, this function can also set the default activity pane (later introduction). The getActivePane () function view all windows with focus. If the window with focus is the sub-window of the pane or the sub-window of the pane, returns a value of a split_pane_ * type, which is indicated by which pane. If the current ownership window is not a sub-window of the pane, then getActivePane () returns split_pane_none.

Bool ActivateNextPane (Bool Bnext = True)

If the separator window is single-pane mode, the focus is set to the visible pane, otherwise, the activateNextPane () function calls getActivePane () View the window with focus. If a pane (or the sub-window in the pane) has a checkpoint, the separator is set to another pane, otherwise ActivateNextPane () will determine the value of BNEXT, if it is true, activate the Left / TOP pane, if It is false to activate the Right / Bottom pane.

Bool setDefaultactivepane (int NPane)

Bool setDefaultactivepane (HWND HWND)

Int getDefaultactivepane ()

Calling the setfaultactivePane () function can set the default active pane, which can be the value of the split_pane_ * type, or the handle of the window. If the focus obtained by separating the window itself, the focus can be transferred to the default pane by calling setfocus (). GetDefaultActivePane () Function Returns the value of the split_pane_ * The value indicates which pane is the current default active pane.

Void getSystemSettings (BOOL BUPDATE)

GetSystemSettings () reads the system settings and sets the data member. Separation window automatically calls this function in the oncreate () function, you don't need to call this function yourself. Of course, your main frame window should respond to WM_SETTINGCHANGE and pass it to the separator window, CSPLitterWindow calls getSystemSettings () in the process of the WM_SETTINGCHANGE message. Pass True to the BUPDATE parameter, the separator window will call yourself according to the new settings.

Data member

Other features can be set by directly accessing the public member of CSPLitterWindow, as long as getSystemSettings () is called, these public members will be reset accordingly.

m_cxysplitbar: Control the width (vertical separator) and height (horizontal separation) of the separator. The default value is obtained by calling getSystemMetrics (SM_CXSIZEFRAME) or GetSystemMetrics (SM_CysizeFrame) (horizontal separator). M_CXYMIN: Control minimum width (vertical separation) and minimum height (horizontal separation) per pane (horizontal separation), and the separator window does not allow drag than this smaller width or height. If the separator has a WS_EX_CLIENTEDGE extension attribute, the default value of this variable is 0, otherwise its default value is 2 * getSystemMetrics (SM_CXEDGE) (vertical separation) or 2 * getSystemMetrics (SM_CYEDGE).

m_cxybaredge: Controls the width (vertical separation) or height (vertical separation) or height of the 3D boundary on both sides of the partition strip, and its default value is just the opposite of M_CXYMIN.

m_bfulldrag: If it is true, the pane is followed when the partition is dragged, and if it is false, only one shadow is displayed until the drag stops adjusts the size of the pane. The default value is the return value of calling the SystemParametersInfo (spi_getdragfulwindows) function.

Start an example project

Since we have already had a basic understanding of the separated window, let's take a look at how to create a frame window that contains the separated window. Use the WTL Wizard to start a new project, select SDI Application in the first page and click Next, in the second page, the toolbar is canceled as shown below and selecting the view window:

We don't use the separator window because the separator window and its pane will be used as a "view window", add a CSPLitterWindow type data member in the CMAINFRAME class:

Class CMAINFRAME: PUBLIC ...

{

// ...

protected:

CsplitterWindow M_WndvertSplit;

}

Then create a separator window in OnCreate () and set it to the view window:

LResult CMAINFRAME :: OnCreate (LPCReatestruct LPCS)

{

// ...

// Create the splitter window

Const 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;

}

It should be noted that M_HWndClient is set before setting the location of the separated window and calls the cframeWindowImpl :: updateLayout () function, and updateLayout () sets the separator window to the initial size. If this step is skipped, the size of the separator will be uncertain, it may be less than 200 pixel points, eventually leading to setSplitterpos () unexpected results. There is also a party that does not call the UpDateLayout () function, just get the client area coordinates of the frame window, and then replaces the RCDefault coordinate to create a separator window using this client area coordinate. The separated window created in this way is started at the correct initial location at the beginning, and then the function of the position adjustment (for example, setsplitterpos ()) can work. Now run our program, you can see the separator, even if you don't create any pane windows, it still has basic behavior. You can drag the partition and double-click the separator to move it to the intermediate position of the window.

In order to demonstrate different ways of separation windows, I will use a CLISTVIEWCTRL to derive class and a simple cricheditctrl. The following is the code extracted from the cclipspylistctrl class, and we use this class on the left pane:

Typedef CWINTraitsor

CListTraits;

Class CclipspylistCtrl:

Public CWindowImpl ,

Public CCustomDraw

{

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 , 1)

Default_reflection_handler ()

END_MSG_MAP ()

// ...

}

If you read a few articles, you will easily read this class code. It responds to WM_CHANGECBCHAIN ​​messages so you can know if other clipboard view programs are started and closed, which also responds to WM_DRAWCLIPBOARD messages so that you can know if the contents of the clipboard changes.

Since the sub-window in the separated window pane has always been existed during the program, we can also set them as a member of the CMAINFRAME class:

Class CMAINFRAME: PUBLIC ...

{

// ...

protected:

CsplitterWindow M_WndvertSplit;

CclipspylistCtrl M_WndFormatList;

CRICHEDITCTRL M_WNDDATAVIEWER;

}

Create a window within a pane

Since there is already a member variable of separated window and sub-window, the filling of the fills is a simple thing. Create a separated window first, then create two sub-windows, use the separated window as their parent window:

LResult CMAINFRAME :: OnCreate (LPCReatestruct LPCS)

{

// ...

// Create the splitter window

Const 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_READOSLY | ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE

M_WndDataViewer.create (m_wndvertsplit, rcdefault,

Null, dwricheditstyle;

M_WndDataViewer.SetFont (ATLGETSTOCKFONT);

// 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 both class Create () functions are used as a parent window with m_wndvertsplit, and the Rect parameter is irrelevant because the separator window will re-adjust their size, so you can use CWindow :: RcDefault.

Finally, pass the handle of the window to the pane of the separated window, which also needs to be done before the updateLayout () call, so that all windows have the correct size.

LResult CMAINFRAME :: OnCreate (LPCReatestruct LPCS)

{

// ...

M_WndDataViewer.SetFont (ATLGETSTOCKFONT);

// 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, the list control adds a few columns, and it looks like this:

It should be noted that the separated window has no restrictions on the window type of the places, unlike the MFC, must be a CVIEW derived class. The window window is only available in the WS_CHILD style, without any other restrictions.

Message processing

Since adding a separate window between the main frame window and our pane window, you may want to know how the notification message works, for example, how the main frame window receives the NM_CUSTOMDRAW notification message and reflected it to the List control of? The answer is in the message chain of CSPLitterWindowImpl:

Begin_msg_map (thisclass) message_handler (WM_RASEBKGND, OneRasebackground)

Message_handler (WM_SIZE, Onsize)

CHAIN_MSG_MAP (BaseClass)

Forward_notifications ()

END_MSG_MAP ()

Which forward_notifications () macro is most important, recalls the fourth chapter, there are some notification messages that are always sent by the parent window of the sub-window, forward_notifications () is to do this, forward these messages to the parent of the separated window window. That is, when the List window sends a WM_NOTIFY message (which is the parent window of the List), the separated window forwards this WM_NOTIFY message to the main frame window (which is a parent window of the separated window). When the main frame window reflects the message, the message reflects the message to the WM_NOTIFY message, that is, the List window, so the separator window does not participate in the message reflection.

These messaging between the List window and the main frame window does not affect the work of the separated window, which makes it easy to add and remove the separator window in the program because the child window does not need to do any changes.

Pane container

WTL has a component called a pane container, which is like a pane on the left of Explorer, and there is a region where the text can be displayed, and there is a CLOSE button that can be displayed:

Like the two pane windows in the Separation window, this pane container also manages a sub-window that changes the size of the sub-window to be able to fill the internal space of the container window when the size of the container window changes.

Related class

The implementation of this pane container requires two classes: CPAneContainerImpl and CPaneContainer, they are declared in AtlCtrlx.h. CPAneContainerImpl is a CWindowIMPL derived class that contains a complete implementation of the pane container. The CPAneContainer only provides a class name unless the method of reloading the CPaneContainerImpl or changing the appearance of the container, it is generally used.

basic method

HWND CREATE

HWND HWNDPARENT, LPCTSTR LPSTRTILE = 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 UTILEID,

DWORD DWSTYLE = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,

DWORD DWEXSTYLE = 0, uint nid = 0, lpvoid lpcreateparam = null)

Create a CPAneContainer window and create other sub-windows. There are two Create () functions, and their difference is only the second parameter. The first function needs to pass a string as text displayed on the top area of ​​the container, the second parameter needs to pass a string resource ID, and other parameters will only be used to use the default.

DWORDSTPANECONTAINEREXTENDEDSTYLE (DWORD DWEXTENDEDSTYLE, DWORD DWMASK = 0)

DWORD getPaneContaineRextendedStyle ()

CPaneContainer also has some extension style to control the layout of the Close button on the container window: PanecNT_noclosebutton: Use the style to remove the top of the top. PANECNT_VERTICAL: After setting this style, the top text area will be placed vertically along the left boundary 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 ()

Call setClient () can assign a sub-window to the pane container, which is similar to the setSplitterPane () method that calls the CSPLitterWindow class. SetClient () simultaneously returns the original client area window handle and calls getClient () to get the current client area window handle.

Bool SetTitle (LPCTSTR LPSTRTILE)

Bool getTitle (LPTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTRTILE, INT CCHLENGTH)

int gettitLength ()

Calling setTitle () can change the text displayed at the top of the container window, calling gettitle () to get the text displayed on the top area of ​​the current window, call gettitLength () to get the number of characters currently displayed (not included Empty characters).

Bool EnableClosebutton (Bool Benable)

If the CLOSE button used by the pane container, you can call EnableCloseButton () to control the status of this button.

Use a pane container in a separate window

To illustrate the method of use of the pane container, we will add a pane container to the left pane of the Clipspy Separation window. We assign a pane container to the left pane to replace the original List control, and assign the List control to Pow container. Here is the code added to the support pane container in cmainframe :: oncreate ().

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 that the parent window of the List control is now m_wndpanecontainer, and the M_WndPaneContainer is set to the left pane of the package.

Here is the appearance of the revised left pane, because the pane container draws a three-dimensional border on top of the text area yourself, so I have to modify the style of the border. This looks not very nice, you can adjust your own satisfaction. (Of course, you need to test which interface topics on Windows XP can make the separated window look "more interest".

Turn off buttons and messages

When the user clicks on the Close button with the mouse, the pane container sends a WM_COMMAND message to the parent window, the ID of the command is id_pane_close. If you use a pane container in a separate window, you need to respond to the entire message, call SetSinglePaneMode () hide this pane. (However, don't forget to provide users with a reset pane!) The message chain of the CPaneContainer also uses the forward_notifications () macro, like CSPLitterWindow, pane container delivery notification messages between the client window and its parent window. In the case of Clipspy, two windows are separated between the List control and the main frame window, but the forward_notifications () macro ensures that all notification messages are sent to the main frame window. Advanced Features

In this section, I will introduce some advanced interface features of WTL.

Nested separator window

If you want to write an email client program, you may need to use nested partitions, a horizontal and a vertical partition. Use WTL is easy to do this: Create a separated window as another sub-window for another separated window.

In order to demonstrate this effect, I will add a horizontal separator window for Clipspy. First, add a member named m_wndHorzSplitter of CHorSplitterWindow type, create this level separate window as separate window m_wndVertSplitter like to create a vertical, horizontal separate window m_wndHorzSplitter become a top-level window is created m_wndVertSplitter into m_wndHorzSplitter child window. Finally, M_HWndClient is set to m_wndhorzsplitter because the horizontal separation window currently occupies the client area of ​​the entire main frame window.

LResult CMAINFRAME :: OnCreate ()

{

// ...

// Create the splitter window.

M_Wndhorzsplit.create (* this, rcdefault, null,

DWSPLITSTYLE, DWSPLITEXSTYLE

M_WndvertSplit.create (m_wndhorzsplit, rcdefault, null,

DWSPLITSTYLE, DWSPLITEXSTYLE

// ...

// set the horizontal splitter as the client isa 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 this look:

Use an ActiveX control in the pane

Using the ActiveX control in the pane of the separated window and similar to the ActiveX control in the dialog box, the method of using the CaxWindow class is running is a creation control, and then specifying this CaxWindow to the pane of the separated window. The following demonstrates how to use the browser control in the pane under the horizontal separator 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 isa 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 drawing

If you want to change the appearance of the separator, for example, you can derive new classes from CSPLitterWindowImpl and overload the DrawSplitterbar () function. If you just want to adjust the appearance of the partition, you can copy the function of the CSPLitterWindowImpl class and then make a modification. The following example uses a ramps for arsenal line pattern in the partition.

Template

Class CMYSPLITTERWINDOWT:

Public CSPLitterWindowImpl , T_Bvertical>

{

PUBLIC:

Declare_wnd_class_ex (_t ("my_splitterWindow),

CS_DBLCLKS, Color_Window)

// Overrideables

Void DrawSplitterbar (CDCHANDLE DC)

{

RECT;

IF (m_br.isnull ()))

M_br.createhatchbrush (hs_diagcross,

T_Bvertical? RGB (255, 0, 0)

: RGB (0,0,255));

GetSplitterBarRect (& Rect))

{

Dc.FillRect (& Rect, M_br);

// DRAW 3D Edge If Needed

IF ((getExStyle () & ws_ex_clientedge)! = 0)

Dc.drawedge (& Rect, Edge_raiad,

T_bvertage? (bf_left | bf_right)

: (BF_TOP | BF_BOTTOM));

}

}

protected:

CBRUSH M_BR;

}

TypedEf CMYSPLITTERWINDOWT CMYSPLITTERWINDOW;

Typedef CMYSPLITTERWINDOWT CMYHORSPLITTERWINDOW;

This is the result (the separation strip is widening to see the effect more easily):

Special drawings in the pane container

CpaneContainer also has several functions to be overloaded to change the appearance of the pane container. You can derive new classes from CPaneContainerImpl and overload the methods you need, for example:

Class CMYPANECONTAINER:

Public CPANECONTAINERIMPL

{

PUBLIC:

DECLARE_WND_CLASS_EX (_T ("my_panecontainer"), 0, -1) // ... Overrides Here ...

}

Some more interesting methods are:

Void Calcsize ()

The call calcsize () function is just to set M_CXYHeader, which controls the width and height of the top area of ​​the pane container. However, there is a bug in the setPanelectrontaineRextendedStyle () function that causes the pane to switch from horizontal to vertical CalcSize () methods, you can change the calcsize () call to Pt-> Calcsize () to patch this bug.

HFONT GETTILEFONT ()

This method returns an HFont that is used to draw the text of the top area, the default value is to call getStockObject (default_gui_font) to get the font, which is MS Sans Serif. If you want to rename more modern Tahoma fonts, you can override the GetTitleFont () method, return to the TAHOMA font you created.

BOOL GetTooltiptext (LPNMHDR LPNMH)

Overloading this method, the prompt information that provides the mouse moves to the Close button, which is actually the corresponding function of TTN_GETDISPINFO, you can convert LPNMH to NMTTDISPINFO *, and set the corresponding member variables within this data structure. Remember, you have to check the notification code, which may be ttn_getdispinfo or ttn_getdispinfow, you need to distinguish between these two data structures.

Void Drawpanetitle (CDCHANDLE DC)

You can overload this method you can draw your top area, you can use getClientRect () and M_CXyHeader to calculate the range of the top area. The following example demonstrates a background in the top area of ​​the horizontal container:

Void CMYPANECONTAINER :: DrawPanetitle (CDCHANDLE DC)

{

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);

}

Examples of the project code demonstrates the overload of these methods, making the results look like:

As can be seen from the above graph, this demo has a splitters menu that switches between various styles (including self-drawing style) and pane containers, compares the difference between them. You can also lock the position of the partition, which is achieved by setting up and canceling the split_noninteractive extension style.

Display progress bar in the status bar

As I made in the first few articles, the new clipspy also demonstrates how to create progress on the status bar, which is the same as the MFC version, and several related steps are:

Get the first pane of the status strip RECT RECT Create a progress bar as a status strip window, the window size is which status strip size is updated while the EDIT control is filled with the progress of the progress bar

These codes are in the CMAINFRAME :: CreateProgressCtrlinStatusbar () function.

carry on

In Chapter VII I will introduce the usage of the property page and the wizard dialog

reference

WTL Splitters and Pane Containers by Ed Gadziemski Modify Record

JULY 9, 2003: The article was first released.

转载请注明原文地址:https://www.9cbs.com/read-68321.html

New Post(0)