选项卡控件和分割器 - 混合使用






4.89/5 (12投票s)
2003年12月31日
4分钟阅读

104699

4016
WTL 类,可以在您的 SDI 应用程序中为子视图添加选项卡和分割。
引言
尽管有很多关于选项卡视图和分割器视图使用及实现的例子,但我找不到一个能够将它们混合在一起的解决方案。因此,我开发了一个WTL类来简化使用选项卡和分割视图的SDI应用程序的构建。起初,我尝试使用标准的窗口选项卡控件。但后来我无法抗拒使用由 Bjarke Viksoe(CCustomTabCtrl
)和 Daniel Bowen(CDotNetTabCtrl
)实现的令人惊叹的选项卡控件实现。
它的作用
该类具有三个主要功能。通过拖放操作,您可以
- 更改选项卡控件中选项卡的位置
- 将选项卡式客户端视图拖放到其他客户端视图窗格中
- 将选项卡式客户端视图排列在另一个选项卡式窗格的边缘(与其余的垂直或水平分割)
使用代码
实现以上所有功能的主要类是SplitPane
。在您的应用程序中使用它应该不会遇到任何困难。首先,您需要在编译器可以访问的地方包含以下文件:
atlgdix.h | 额外的GDI/USER包装器。由Bjarke Viksoe编写 |
CustomTabCtrl.h | 一个帮助实现具有不同外观的选项卡控件的基类。由 Bjarke Viksoe 编写。由 Daniel Bowen 进行了一些改进。 |
DotNetTabCtrl.h | 从CCustomTabCtrl 派生的选项卡控件,旨在模仿VS.Net中的选项卡(MDI选项卡、解决方案浏览器选项卡等)。由 Daniel Bowen 编写。 |
DockTabPane.h | 选项卡控件和选项卡窗格实现。使用以上所有包含文件。 |
DockTabSplitPane.h | 分割窗格实现。包含DockTabPane.h 。 |
然后使用ATL/WTL向导创建一个SDI应用程序项目。您需要关闭“Minimize CRT use in ATL”配置选项。通过以下步骤将Split Pane类添加为其中的主视图:
- 包含DockTabSplitPane.h,例如,在stdafx.h文件中。
- 为您的
CMainFrame
类添加SplitPane
类成员,并继承自CallBackListener
接口类。
class CMainFrame
: public CFrameWindowImpl< CMainFrame>
, public CUpdateUI< CMainFrame>
, public CMessageFilter
, public CIdleHandler
, public DockSplitTab::CallBackListener
....
DockSplitTab::SplitPane mainPane;
....
public:
CMainFrame();
CallBackListener
类的目的是向所有者或父对象提供Split Pane通知。我认为这比win32消息更简单。除了继承自MainFrame
类之外,您还可以设计一个特殊的类适配器,实现SplitPane
与其所有者之间的所有通信需求。所以,请不要忘记像下面这样初始化mainPane
,使其指向这个类。
...
CMainFrame::CMainFrame()
: mainPane( this, true)
...
{}
...
mainPane
构造函数的第二个参数为Split Pane包含的所有选项卡窗格设置顶部的选项卡控件栏。要完成mainPane
的设置,请在CMainFrame::OnCreate
事件处理程序中放置Split Pane窗口创建代码,并将其分配给m_hWndClient
属性。
LRESULT CMainFrame::OnCreate(UINT, WPARAM, LPARAM, BOOL&) {
...
this->m_hWndClient = this->mainPane.create( this->m_hWnd);
...
}
就是这样。我们已经完成了Split Pane作为应用程序主视图窗口的定义。不要忘记为CallBackListener
接口定义函数处理程序。如何做到这一点,请参见演示项目。
我在所有定义中使用DockSplitTab
命名空间。当然,您可以 대신使用以下代码行,而不是为每个名称使用命名空间说明符。
using namespace DockSplitTab;
SplitPane
类
公共方法
// creates a new Split Pane window with parentWnd and rect parameters
HWND create( parentWnd, rect);
// adds the new client view window to Split Pane.
// The new client view is added into the focused tab pane
bool append( caption, clientViewWnd, tooltip, imageIndex);
// detaches the client view window from Split Pane.
// This method changes a parent window of the client window view
// to the Split Pane parent one.
bool detachClientView( clientViewWnd);
// returns the client view window that receives the keyboard focus
HWND focusedClientView();
// sets the keyboard focus to a tab pane at the specified position
bool setFocusTo( x, y)
// sets the keyboard focus to the specified client view window
bool setFocusTo( clientViewWnd) {
// returns the number of client view windows in Split Pane
int getClientViewCount();
// returns the rectangle of tab pane, if any, is at a specified position
bool getClientViewRect( point, &rect);
// move the client view window (sourceWnd) to the same
// tab pane where the specified client view window is located
void moveClientView( HWND sourceWnd, HWND targetWnd);
// move all client view windows to the specified split pane.
void moveClientViewsTo( SplitPane* targetPane);
// splits source client view window (sourceWnd) with the target client view
void splitClientView( sourceWnd, targetWnd, targetArea);
// set and get Image List
void setImageList( HIMAGELIST imgList);
HIMAGELIST getImageList();
CallBackListener
接口类
此类提供SplitPane
与其所有者类之间的通知接口。
// triggered when client view client view wnd has gained the keyboard focus
virtual void clientActivate( childWnd, clientViewWnd) = 0;
// triggered when client view client view wnd
// got doble mouse click on the tab button
virtual void clientDblClick( childWnd, clientViewWnd) = 0;
// triggered the close button was pushed for the client view client
virtual void clientCloseClick( childWnd, clientViewWnd) = 0;
// drag and drop notifications
virtual void dragStart( childWnd, clientViewWnd, x, y, keysPressed) = 0;
virtual void dragOver( childWnd, clientViewWnd, x, y, keysPressed) = 0;
virtual void dragDrop( childWnd, clientViewWnd, x, y, keysPressed) = 0;
virtual void dragCancel( childWnd, clientViewWnd) = 0;
// performs the drag and drop tracking with drag and drop notifications
void trackDragAndDrop( HWND hWnd, POINT startPoint,
bool lockWindowUpdate = false);
里面有什么
我不相信“黑箱”的概念。我认为了解内部原理总是更好的,所以我试图解释SplitPane
类内部的结构。基本构建块是Pane
类,它可以在您的应用程序中独立使用,就像SplitPane
那样,如果您只需要选项卡窗格以及更改选项卡视图选项卡位置的功能。SplitPane
拥有选项卡窗格对象的层次结构,使用VSpliter
和HSpliter
类,它们是标准WTL::CSplitterWindowImpl<>
类模板的特化。您可以使用Spy++实用程序进行检查。
class ClientProperties |
- 提供三个客户端视图属性:标题、工具提示和图像索引。Pane::get 方法的必需参数。 |
class TabControlItem |
- 继承自CCustomTabItem 类,并包含客户端视图窗口句柄成员。 |
class TabControl |
- 特化了CDotNetTabCtrlImpl<> 类模板。 |
class Pane |
- 选项卡控件和与选项卡控件相关的所有客户端视图窗口的容器类。 |
class RectTracker |
- 绘制拖放操作期间跟踪矩形的辅助类。 |
class VSplitter |
- 垂直分割窗口。特化了CSplitterWindowImpl<> 类模板。 |
class HSplitter |
- 水平分割窗口。特化了CSplitterWindowImpl<> 类模板。 |
class SplitPane::DragContext |
- 继承自RectTracker 类。 |
接下来做什么
显然,这需要某种序列化机制。还有其他想法吗?;-)