在开发SDI应用程序时,经常需要实现标签和分割视图的功能。虽然市面上有许多现成的解决方案,但往往难以找到一个能够将两者完美结合的方案。因此,开发了一个WTL类来简化构建使用标签和分割视图的SDI应用程序的过程。最初,尝试使用标准的窗口标签控件,但后来发现Bjarke Viksoe的CCustomTabCtrl和Daniel Bowen的CDotNetTabCtrl这两个令人惊叹的标签控件实现,决定采用它们。
这个类有三个主要功能:
主要类是SplitPane,它添加了上述所有功能。在应用程序中使用它应该不会遇到任何困难。首先,需要在编译器可以访问的地方包含以下文件:
atlgdix.h
- Bjarke Viksoe编写的额外GDI/USER包装器。CustomTabCtrl.h
- 帮助实现具有不同外观的标签控件的基类。由Bjarke Viksoe编写,Daniel Bowen进行了几项改进。DotNetTabCtrl.h
- 从CCustomTabCtrl派生的标签控件,旨在看起来像VS.Net中的标签(MDI标签、解决方案资源管理器标签等)。由Daniel Bowen编写。DockTabPane.h
- 标签控件和标签窗格实现。使用上述所有包含文件。DockTabSplitPane.h
- 分割窗格实现。包括DockTabPane.h。然后使用ATL/WTL向导创建SDI应用程序项目。必须关闭"在ATL中最小化CRT使用"配置选项。按照以下步骤将SplitPane类添加为主视图:
DockTabSplitPane.h
。
class CMainFrame
: public CFrameWindowImpl
, public CUpdateUI
, public CMessageFilter
, public CIdleHandler
, public DockSplitTab::CallBackListener
{
DockSplitTab::SplitPane mainPane;
public:
CMainFrame();
};
CallBackListener类的目的在于为SplitPane提供分割窗格通知给所有者或父对象。认为这比win32消息更简单。与MainFrame类继承的同时,可以设计一个特殊的类适配器来实现SplitPane与其所有者之间的所有通信需求。因此,不要忘记像下面这样初始化mainPane:
CMainFrame::CMainFrame()
: mainPane(this, true)
{
// ...
}
mainPane构造函数的第二个参数为所有SplitPane包含的标签控件栏设置顶部。要完成mainPane,请将SplitPane窗口创建代码放入CMainFrame::OnCreate事件处理程序,并将其分配给m_hWndClient属性:
LRESULT CMainFrame::OnCreate(UINT, WPARAM, LPARAM, BOOL&)
{
// ...
this->m_hWndClient = this->mainPane.create(this->m_hWnd);
// ...
}
就是这样。已经完成了作为应用程序主视图窗口的SplitPane定义。不要忘记定义CallBackListener接口的函数处理程序。如何做到这一点,请参考演示项目。
公共方法:
// 创建一个新的Split Pane窗口,带有parentWnd和rect参数
HWND create(parentWnd, rect);
// 将新的客户视图窗口添加到Split Pane。
// 新的客户视图被添加到焦点标签窗格中
bool append(caption, clientViewWnd, tooltip, imageIndex);
// 将客户视图窗口从Split Pane分离。
// 此方法将客户窗口视图的父窗口更改为Split Pane父窗口。
bool detachClientView(clientViewWnd);
// 返回接收键盘焦点的客户视图窗口
HWND focusedClientView();
// 将键盘焦点设置到指定位置的标签窗格
bool setFocusTo(x, y);
// 将键盘焦点设置到指定的客户视图窗口
bool setFocusTo(clientViewWnd);
// 返回Split Pane中客户视图窗口的数量
int getClientViewCount();
// 返回指定位置的标签窗格的矩形,如果有的话
bool getClientViewRect(point, ▭);
// 将客户视图窗口(sourceWnd)移动到指定客户视图窗口所在的相同标签窗格
void moveClientView(HWND sourceWnd, HWND targetWnd);
// 将所有客户视图窗口移动到指定的分割窗格。
void moveClientViewsTo(SplitPane* targetPane);
// 用目标客户视图分割源客户视图窗口(sourceWnd)
void splitClientView(sourceWnd, targetWnd, targetArea);
// 设置和获取图像列表
void setImageList(HIMAGELIST imgList);
HIMAGELIST getImageList();
此类提供了SplitPane与其所有者类之间的通知接口。
// 当客户视图客户视图wnd获得键盘焦点时触发
virtual void clientActivate(childWnd, clientViewWnd) = 0;
// 当客户视图客户视图wnd在标签按钮上双击鼠标时触发
virtual void clientDblClick(childWnd, clientViewWnd) = 0;
// 当客户视图客户视图wnd的关闭按钮被按下时触发
virtual void clientCloseClick(childWnd, clientViewWnd) = 0;
// 拖放通知
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;
// 使用拖放通知执行拖放跟踪
void trackDragAndDrop(HWND hWnd, POINT startPoint, bool lockWindowUpdate = false);