导航侧边栏






4.93/5 (25投票s)
2006 年 5 月 1 日
7分钟阅读

176108

8216
左下角有一个模仿 Outlook 2003 侧边栏的侧边栏。还实现了其他功能,包括主题、吸附按钮、独特的按钮系统等。
目录
引言
最近,一位客户要求为他的 WTL 项目创建一个 Outlook 2003 风格的导航栏。在 CodeProject 上找不到合适的 WTL 控件,我决定创建一个。我希望您发现这个控件对您自己的项目有用;如果能适当归功于我,我将不胜感激。
Outlook 2003 导航栏相当于一个制表符窗口系统,可以同时更改两个视图。它可以容纳任意数量的“选项卡”,尽管在相对适中的数量下效果最好。
此项目需要
- WTL 7.5 或更高版本。
- 来自 www.viksoe.dk 的 atlgdix.h。
- Microsoft 的 GDI+。
功能
Outlook 风格视图切换 -- Outlook 会处理大量细节,以妥善处理工具提示、窗口大小调整、固定分隔器等。我尝试实现了这些功能中的每一个,并在某些情况下进行了改进。
箭头菜单 -- 类似于 Outlook 版本,命令栏上有一个箭头菜单(但它不是主题化的……这可能会在将来的版本中添加)。无法在命令栏上作为大按钮显示的按钮会放在“导航窗格选项”下方。
导航窗格选项 -- 导航窗格选项对话框允许您交换和禁用视图中的按钮,以根据您的喜好自定义布局。导航窗格选项已完全投入使用(除了热键系统与其他同类 Windows 列表框的工作方式相同……这并不好),具有悬停和适当的选择功能。其列表视图是自定义的,可以在 ChecklistView.h 中访问。
主题支持 -- 此程序具有基本的主题支持。这里没什么可说的,除了它会根据 Windows 主题而变化,这对于为您的程序添加额外的视觉效果可能很有用。大部分内容是从 Roger Headrick 的主题代码中提取的。
使用方法
所需代码
在您创建了所有状态栏并更新了布局之后,需要将此代码放在这里。首先,我们需要获取客户矩形,设置窗口创建前必须设置的参数,然后创建窗口。
RECT ClientRect;
GetClientRect(&ClientRect);
// Set the button parameters. You must set
// these before you create the navwindow.
// If you don't, don't expect it to work ;)
// The button height is the height
// of the big buttons and the command bar
m_navwindow.SetButtonHeight(31);
// The small button width is the width
// of the little buttons on the command bar.
m_navwindow.SetSmallButtonWidth(24);
// Drop in our control.
m_hWndClient = m_navwindow.Create(m_hWnd, ClientRect,
L"Nav_Main", WS_CHILD | WS_VISIBLE |
WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
然后,我们设置按钮从顶部开始弹回的距离(这样就不会覆盖任何重要内容)。这可以在程序中的任何位置设置,因为它在未设置时总是默认为零(实际上,您可以编辑制表符按钮,使其根据它显示的视图设置不同的弹回距离)。下面的 for
循环用于定义由制表符按钮使用的窗口及其 HWND
。
// Set the distance from the top of the client
// rect of the window where the buttons start popping back.
// If not set or set to 0, the buttons will pop back
// when the buttons are pushed past the top of the window.
m_navwindow.SetPopBack(150);
// For the sake of example, there is only one sample window for all the buttons.
// If you want a different window for each button (you probably do),
// you will want a different line and class for each window in your Mainframe.
// As these are for example, the following two lines
// and the for loop are to be erased and replaced with whatever you want.
button_view.resize(9);
button_view_top.resize(9);
for (size_t view_increment = 0; view_increment <
button_view.size(); view_increment++)
{
button_view[view_increment].Create(m_navwindow, rcDefault,
NULL, WS_CHILD | WS_VISIBLE |
WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
button_view_top[view_increment].Create(
m_navwindow.m_HorizontalSplitter, rcDefault,
NULL, WS_CHILD | WS_VISIBLE |
WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
std::wostringstream vertical_caption;
vertical_caption << L"Vertical " << view_increment;
button_view[view_increment].window_caption = vertical_caption.str();
button_view[view_increment].is_horizontal = false;
std::wostringstream horizontal_caption;
horizontal_caption << L"Horizontal " << view_increment;
button_view_top[view_increment].window_caption =
horizontal_caption.str();
button_view_top[view_increment].is_horizontal = true;
button_view_top[view_increment].pop_back_amount =
m_navwindow.m_HorizontalSplitter.pop_back_y;
}
// Don't erase anything past here...it contains
// the rest of the parameters needed ;)
然后,我们设置按钮的字体,然后,最重要的是,创建它们。第一个参数是按钮的标题,第二个是它用作大按钮的图像路径,第三个是它用作命令栏按钮的图像路径,最后两个分别是将出现在垂直条右侧的窗口句柄和将出现在水平条上方的窗口句柄。
然后,我们将垂直分隔器的分隔器位置设置为选定的宽度,并将默认按钮设置为我们想要显示的内容……值为 5 表示我们将看到前四个通过 AddButtonWithView
添加的按钮,在显示其他五个按钮的命令栏之上。作为另一个例子,如果您 SetDefaultButtons(4)
,您将看到三个大按钮位于显示其他六个按钮的命令栏之上。
// Set the button font.
m_navwindow.SetButtonFont(L"Arial", 8, FontStyleBold);
// Add all of our buttons to our button view.
// Use a for loop if you have
// the necessary arrays of strings.
m_navwindow.AddButtonWithView(L"Print",
L"RolloutIcons\\Print_2.tif",
L"RolloutIcons\\Print_2_Small.tif",
button_view[0], button_view_top[0]);
m_navwindow.AddButtonWithView(L"Add",
L"RolloutIcons\\Add_2.tif",
L"RolloutIcons\\Add_2_Small.tif",
button_view[1], button_view_top[1]);
m_navwindow.AddButtonWithView(L"Edit",
L"RolloutIcons\\Edit_2.tif",
L"RolloutIcons\\Edit_2_Small.tif",
button_view[2], button_view_top[2]);
m_navwindow.AddButtonWithView(L"Delete",
L"RolloutIcons\\Delete_2.tif",
L"RolloutIcons\\Delete_2_Small.tif",
button_view[3], button_view_top[3]);
m_navwindow.AddButtonWithView(L"Search",
L"RolloutIcons\\Search_2.tif",
L"RolloutIcons\\Search_2_Small.tif",
button_view[4], button_view_top[4]);
m_navwindow.AddButtonWithView(L"Back",
L"RolloutIcons\\Back_2.tif",
L"RolloutIcons\\Back_2_Small.tif",
button_view[5], button_view_top[5]);
m_navwindow.AddButtonWithView(L"Forward",
L"RolloutIcons\\Forward_2.tif",
L"RolloutIcons\\Forward_2_Small.tif",
button_view[6], button_view_top[6]);
m_navwindow.AddButtonWithView(L"Save",
L"RolloutIcons\\Save_2.tif",
L"RolloutIcons\\Save_2_Small.tif",
button_view[7], button_view_top[7]);
m_navwindow.AddButtonWithView(L"Exit",
L"RolloutIcons\\Exit_2.tif",
L"RolloutIcons\\Exit_2_Small.tif",
button_view[8], button_view_top[8]);
// Set this to be where the vertical
// splitter will be located on your window.
m_navwindow.SetSplitterPos(242);
// Set this to be 1 higher than the buttons
// you want to show initially. If none at all,
// put 1. If not even the command bar, put 0.
m_navwindow.SetDefaultButtons(5);
杂项说明
- 如果您不设置默认按钮,它将默认为 0。
- 如果您不指定较大的图像路径,按钮上将只有文本,并且它将与按钮视图的左侧对齐。
- 如果您不指定较小的图像路径,按钮仍会显示在命令栏上,但除非将鼠标移到那里,否则人眼将看不到它们。
ButtonView_Tabbed
应被视为一个垂直分隔器。- 如果条的大小太小,图标将不会被绘制。
- 此程序中有几个部分,其中一些是可选的,但有些是绝对必需的。绝对必需的代码部分位于“按钮视图项”和“必需项”过滤器/文件夹中。ButtonView 制表符版本是为了实际使用而提供的,并演示了您如何通过继承和一些必要的重写来使用我的代码,并在需要时添加功能。但是,如果您选择使用实现 ButtonView 模板的另一个类,您必须提供对水平和垂直分隔器的支持,否则 ButtonView 将无法正常工作。
- 如果您想创建一个不作为选项卡而是执行功能的按钮列表,请重写
OnSelect
函数。它接受一个整数作为参数,即按钮的 ID,其中 0 是最上面的一个。然后,您可以根据i
的值检查并运行各种函数。
文档
以下是您可以从 ButtonView_Tabbed 使用的函数的文档。还有其他函数,但它们是内部函数。这些是您会使用的函数。
AddButtonWithView(std::wstring caption, std::wstring imagepath, std::wstring imagepath_small, HWND right_side, HWND top_side)
-- 在“按钮”列表的底部添加一个按钮。caption
不言自明,并且在命令栏上的按钮的工具提示中也会显示;imagepath
和imagepath_small
不言自明,而right_side
和top_side
是将在按钮视图的右侧和上方显示的窗口的句柄。AddButton(std::wstring caption, std::wstring imagepath, std::wstring imagepath_small)
-- ButtonView 核心函数。与AddButtonWithView
相同,但不带视图添加。AddButtonWithView
调用此函数,然后自行添加视图。SetButtonFont(std::wstring type, Gdiplus::REAL size, INT style)
-- 设置按钮的样式(type
是字体,size
是字体大小,style
是按钮的附加样式,例如粗体)。SetDefaultButtons(int i)
-- 设置窗口启动时将看到的按钮数量(i
- 1,因为在此设置下,命令栏被视为一个按钮)。SetPopBack(int pop_back_amount)
-- 设置距离客户端窗口顶部的像素距离。如果未设置,则默认为 0,即客户端窗口的顶部。SetButtonHeight(int i)
-- 设置大按钮和命令栏的像素高度。SetSmallButtonWidth(int i)
-- 设置命令栏上按钮的像素宽度。箭头始终保持 24 像素宽度。OnSelect(int i)
-- ButtonView 核心函数。当选择一个按钮时调用的函数。此函数被故意留空,并且在每个使用 ButtonView 模板的类中都需要重写。如果您将 ButtonView 的button_is_selected
参数设置为i
,您将获得“打印”按钮上的选定选项卡效果。否则,点击按钮就像点击普通按钮一样……点击时会闪烁,松开后会恢复正常。Swap_Buttons(int i, int j)
-- ButtonView 核心函数。当对“导航窗格选项”进行更改时调用的函数,其中i
是旧按钮,j
是新按钮。它默认故意留空,因为必要的交换已提前完成。您应该重写它并添加交换按钮功能和视图等所需的行。ButtonView_Tabbed
会重写它并用切换按钮视图的代码替换它。
鸣谢
我想感谢 Viksoe 提供的 atlgdix.h 用于离屏绘制(按钮和我的示例 exe 及其示例窗口没有闪烁),感谢 Roger Headrick 提供的颜色主题代码,感谢 Terry Denham 提供的吸附分隔器,最后,感谢 Firefox 和 tom-cat.com 提供了我能够修改并集成到我的示例程序中的图标。我还想感谢任何我忘记点名感谢的人。
历史
- 版本 1.0 -- 导航侧边栏发布!