上一篇我们学习了解了如何使用Windows GDI画图,该应用程序都是光光的静态窗口,我们使用Windows应用程序,但凡稍微复杂一点的程序都会有工具栏和状态栏,工具栏主要用于一些快捷功能按钮。比如典型的windows应用程序的上面是菜单栏,从菜单栏我们可以选择应用程序提供的各种功能,但是有的功能比较常用,且不能放在第一级菜单,需要进入二级、三级甚至更多的菜单才能选择。显然这样使用起来比较麻烦,于是这时候工具栏的作用就体现出来了,一般工具栏位于菜单栏的下面,但是位于客户窗口的上面。下面就是windows的文本编辑器的工具栏:

Statusbar主要用于显示应用程序的运行状态,统计信息,操作信息等提示作用,一般是只读状态。典型的状态栏放在窗口的最下面,比如下面就是我正在使用的Word应用程序的状态栏:

我们这次要一起学习的就是使用纯Windows API函数创建基本的状态栏和菜单栏。如果属性MFC的朋友知道,如果用MFC来做工具栏和菜单栏很简单。但是使用纯API就麻烦一些了,当然带来的感觉是不一样的,比如要动态创建,使用MFC的资源编辑器就无能为力,但是对于我们今天要使用的API创建方式来说,就显示出他的强大了。

首先,前面我们在讲解Windows常用控件的创建时就知道,所有带窗口的控件创建实际上都是调用Windows提供的CreateWindow或者CreateWindowEx(以下以CreateWindowEx为例)这两个函数,当然今天的菜单栏和状态栏一样需要这两个函数来创建。由于工具栏和状态栏都是Windows的通用控件组中的控件,有默认的类名。创建工具栏时,类名为TOOLBARCLASSNAME,创建状态栏时,类名为STATUSCLASSNAME,这两个宏定义在commctrl.h文件中根据是否使用UNICODE编码分别是“ToolbarWindow32”和“msctls_statusbar32”的宽字符版本和ANSI版本。

  • 创建工具栏

除了使用CreateWindowEx创建好工具栏后,作为一个更好看一点,我们还可以给工具栏加上图标以及功能提示。为了加图标,最方便的方法是使用一些列图像列表API来加载和管理工具栏的图片。ImageList_Create可以创建一个图片列表,它的原型为:

HIMAGELIST ImageList_Create(int cx, int cy, UINT flags,  int cInitial, int cGrow);

该函数用法在MSDN上说的比较清楚。这个列表创建后并没有图片,只是一个列表管理的容器,还需要加载图片集。加入图片所需API如下:

int ImageList_AddMasked(HIMAGELIST himl, HBITMAP hbmImage, COLORREF crMask);

图片加载后,还可以设置图片的显示属性,包括显示图片、文本以及信息提示功能。工具按钮的响应是通过向窗口处理程序发送WM_COMMAND消息实现的,有用户处理按钮事件。工具栏的提示信息是通过WM_NOTIFY消息,由用户设置,工具栏的创建实例请参看后面的应用实例。

  • 创建状态栏

装具状态栏相比工具栏要简单很多,用CreateWindowEx建立状态栏后,默认情况下,状态栏只有一个显示面板(panel),要创建多个面板,只要向状态栏把配置好个面板的长度发送SB_SETPARTS消息即可,消息参数分别是面板个数和个面板的终点数组。比如:

int array[3]={120,120*2,-1};
SendMessage(hWndStatus,SB_SETPARTS,(WPARAM)3,(LPARAM)array);

表示将状态栏面板分为3各部分,第一部分到120像素为止,第二部分到240像素为止,剩下的(-1)全部分到第三部分中。

设置面板文本内容,可以给状态栏发送SB_SETTEXT消息;要在状态栏面板中增加小图标,可以给状态发送SB_SETICON消息。

上面的工具栏和状态栏只是介绍了最基本的情况,更多的设置和消息处理都可以参考MSDN。本系列专注在基本编程和使用上,只是介绍常见的用法,不过这些用法也够初学者编程使用。

  • 使用实例

下面我们通过一个基本的实例程序说明如何采用纯Windows API创建、使用工具栏和状态栏。程序中创建的Toolbar有三个图标,当程序正常显示,鼠标在某个工具栏按钮上移动,或者处于Disable状态是,会有不同的图片显示,读者可以自己更换其他自己喜欢的图标。

#include <windows.h>
#include <commctrl.h>
#include <tchar.h> #pragma comment(lib, "comctl32.lib") // Windows XP sytle button
#pragma comment(linker,"\"/manifestdependency:type='win32' "\
"name='Microsoft.Windows.Common-Controls' "\
"version='6.0.0.0' processorArchitecture='*' "\
"publicKeyToken='6595b64144ccf1df' language='*'\"") #define IDC_TOOLBAR 1001
#define IDC_STATUSBAR 1002
//#define PIC_RESOURCE_USED #ifdef PIC_RESOURCE_USED
#define IDB_NEW 110
#define IDB_OPEN 111
#define IDB_SAVE 112
#endif
#define ID_FOPEN 1111
#define ID_FCLOSE 1112
#define ID_FSAVE 1113 static TCHAR szAppName[] = TEXT("toolbar");
static LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
HWND hWnd;
MSG msg;
WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName; if (!RegisterClass(&wndclass))
{
MessageBox (NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR);
return 0;
}
//初始化公共空间
INITCOMMONCONTROLSEX icc;
icc.dwSize = sizeof(INITCOMMONCONTROLSEX);
icc.dwICC = ICC_BAR_CLASSES;
InitCommonControlsEx(&icc);
hWnd = CreateWindow(szAppName, // window class name
szAppName, // window caption
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // initial x position
CW_USEDEFAULT, // initial y position
400, // initial x size
300, // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL); // creation parameters ShowWindow(hWnd, iCmdShow);
UpdateWindow(hWnd); while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
} return msg.wParam;
} HWND CreateToolbar(HWND hParentWnd)
{
HWND hWndTB;
TBBUTTON tbb[3];
HIMAGELIST hImageList,hHotImageList,hDisableImageList;
HBITMAP hBitmap; HINSTANCE hInst = GetModuleHandle(NULL);
//创建Toolbar控件
hWndTB = CreateWindowEx(0, TOOLBARCLASSNAME,TEXT(""),
WS_CHILD|WS_VISIBLE|WS_BORDER|TBSTYLE_LIST|TBSTYLE_AUTOSIZE|TBSTYLE_TOOLTIPS,
0,0,0,0,
hParentWnd,
(HMENU)IDC_TOOLBAR,
hInst,
NULL);
if(!hWndTB)
{
return NULL;
}
SendMessage(hWndTB, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
//下面创建三组24x24像素大小的位图图像列表,用于工具栏图标
hImageList = ImageList_Create(24,24,ILC_COLOR24|ILC_MASK,3,1);
#ifdef PIC_RESOURCE_USED
hBitmap = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_COLOR3));
#else
hBitmap = (HBITMAP)LoadImage(NULL, TEXT("color24x3.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE|LR_CREATEDIBSECTION); //加载一组图片
#endif
ImageList_AddMasked(hImageList, hBitmap, RGB(255,255,255));
DeleteObject (hBitmap);
SendMessage(hWndTB,TB_SETIMAGELIST,0,(LPARAM)hImageList); //正常显示时的图像列表 hHotImageList = ImageList_Create(24,24,ILC_COLOR24|ILC_MASK,3,1);
#ifdef PIC_RESOURCE_USED
hBitmap = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_GREEN3));
#else
   hBitmap = (HBITMAP)LoadImage(NULL, TEXT("green24x3.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE|LR_CREATEDIBSECTION);
#endif
ImageList_AddMasked(hHotImageList,hBitmap, RGB(255,255,255));
DeleteObject (hBitmap);
SendMessage(hWndTB,TB_SETHOTIMAGELIST,0,(LPARAM)hHotImageList); //鼠标悬浮时的图像列表 hDisableImageList = ImageList_Create(24,24,ILC_COLOR24|ILC_MASK,3,1);
#ifdef PIC_RESOURCE_USED
hBitmap = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_GRAY3));
#else
   hBitmap = (HBITMAP)LoadImage(NULL, TEXT("gray24x3.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE|LR_CREATEDIBSECTION);
#endif
ImageList_AddMasked(hDisableImageList,hBitmap, RGB(255,255,255));
DeleteObject (hBitmap);
SendMessage(hWndTB,TB_SETDISABLEDIMAGELIST,0,(LPARAM)hDisableImageList); //当工具栏button失能是的图像列表 ZeroMemory(tbb, sizeof(tbb));
tbb[0].iBitmap =MAKELONG(0,0) ;
tbb[0].fsState = TBSTATE_ENABLED;
tbb[0].fsStyle = TBSTYLE_BUTTON|BTNS_AUTOSIZE;
tbb[0].idCommand = ID_FOPEN;
tbb[0].iString = (INT_PTR)TEXT("打开");
tbb[1].iBitmap =MAKELONG(1,0);
tbb[1].fsState = TBSTATE_ENABLED;
tbb[1].fsStyle = TBSTYLE_BUTTON|BTNS_AUTOSIZE;
tbb[1].idCommand = ID_FCLOSE;
tbb[1].iString = (INT_PTR)TEXT("关闭");
tbb[2].iBitmap =MAKELONG(2,0);
tbb[2].fsState = TBSTATE_ENABLED;
tbb[2].fsStyle = TBSTYLE_BUTTON|BTNS_AUTOSIZE;
tbb[2].idCommand = ID_FSAVE;
tbb[2].iString = (INT_PTR)TEXT("保存");
SendMessage(hWndTB, TB_ADDBUTTONS, sizeof(tbb)/sizeof(TBBUTTON), (LPARAM)&tbb); //配置工具栏按钮信息
SendMessage(hWndTB,WM_SIZE,0,0); return hWndTB;
} HWND CreateStatusBar(HWND hParentWnd)
{
#define PANEL_NUM 3
int array[PANEL_NUM]={120,120*2,-1};
HINSTANCE hInst = GetModuleHandle(NULL);
//创建Statusbar控件
HWND hWndStatus = CreateWindowEx(0, STATUSCLASSNAME, TEXT(""), WS_CHILD|WS_BORDER|WS_VISIBLE, 0, 0, 0, 0, hParentWnd, (HMENU)IDC_STATUSBAR, hInst, NULL);
if (hWndStatus)
{
SendMessage(hWndStatus,SB_SETPARTS,(WPARAM)PANEL_NUM,(LPARAM)array); //设置面板个数
SendMessage(hWndStatus,SB_SETTEXT,(LPARAM)1,(WPARAM)TEXT("panel-1")); //设置第二个面板内容
SendMessage(hWndStatus,SB_SETTEXT,(LPARAM)2,(WPARAM)TEXT("panel-2")); //设置第三个面板内容
}
#undef PANEL_NUM return hWndStatus;
} static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hDC;
PAINTSTRUCT ps;
static HWND hToolbar;
static HWND hStatusbar; switch (message)
{
case WM_CREATE:
hToolbar = CreateToolbar(hWnd);
hStatusbar = CreateStatusBar(hWnd);
return 0; case WM_COMMAND:
{
int wmId = LOWORD(wParam);
int wmEvent = HIWORD(wParam); // 分析菜单选择:
switch (wmId)
{
case ID_FOPEN:
SendMessage(hToolbar, TB_ENABLEBUTTON, (WPARAM)ID_FOPEN, (LPARAM)MAKELONG(FALSE,0));
SendMessage(hToolbar, TB_ENABLEBUTTON, (WPARAM)ID_FSAVE, (LPARAM)MAKELONG(TRUE,0));
break;
case ID_FSAVE:
SendMessage(hToolbar, TB_ENABLEBUTTON, (WPARAM)ID_FSAVE, (LPARAM)MAKELONG(FALSE,0));
SendMessage(hToolbar, TB_ENABLEBUTTON, (WPARAM)ID_FOPEN, (LPARAM)MAKELONG(TRUE,0));
break;
case ID_FCLOSE:
MessageBox(hWnd, TEXT("click!"), TEXT("hint"), MB_OK);
break;
}
}
return 0; case WM_NOTIFY:
{
LPNMHDR lpnmhdr=(LPNMHDR)lParam;
LPTOOLTIPTEXT lpttext; if(lpnmhdr->code==TTN_GETDISPINFO)
{
          //处理鼠标在工具栏上悬浮移动时的文本提示
lpttext=(LPTOOLTIPTEXT)lParam;
switch(lpttext->hdr.idFrom)
{
case ID_FOPEN:
lpttext->lpszText=TEXT("打开文件");
break; case ID_FCLOSE:
lpttext->lpszText=TEXT("关闭文件");
break; case ID_FSAVE:
lpttext->lpszText=TEXT("保存为文件");
break;
}
}
}
return 0; case WM_SIZE:
{
SendMessage(hToolbar, TB_AUTOSIZE, 0, 0);
SendMessage(hStatusbar, WM_SIZE, 0, 0);
}
return 0; case WM_MOUSEMOVE:
{
TCHAR szBuf[MAX_PATH];
_stprintf(szBuf,TEXT("Mouse(%d,%d)"),LOWORD(lParam),HIWORD(lParam));
SendMessage(hStatusbar, SB_SETTEXT, 0, (LPARAM)(LPSTR)szBuf);
}
return 0; case WM_PAINT:
hDC = BeginPaint(hWnd, &ps);
;
EndPaint(hWnd, &ps);
return 0; case WM_DESTROY:
PostQuitMessage(0);
return 0 ;
}
return DefWindowProc (hWnd, message, wParam, lParam);
}

该实例程序后,结果显示如下图:

该程序的工具栏按下“打开”按钮后,自己后变成Disable状态,点击“保存”后,“打开”按钮会再次激活。可以看到,在鼠标移到“保存”按钮上时,出现提示“保存为文件”的文本提示。

状态栏一共有三个面板,后面两个在创建时静态赋字符串,第一个则实时捕获鼠标在客户区中的坐标位置并显示出来。

总体来说工具栏和状态栏的基本用法还是比较简单,只是由于这两个控件属于微软的通用控件,创建之前需要调用InitCommonControlsEx初始化通用控件库并设置需要使用的控件。本篇就写到这里,感兴趣的读者请继续关注Windows编程基础系列的后续文章。

更多经验交流可以加入Windows编程讨论QQ群454398517

关注微信公众平台:程序员互动联盟(coder_online),你可以第一时间获取原创技术文章,和(java/C/C++/Android/Windows/Linux)技术大牛做朋友,在线交流编程经验,获取编程基础知识,解决编程问题。程序员互动联盟,开发人员自己的家。

转载请注明出处,谢谢合作!

【Windows编程】系列第六篇:创建Toolbar与Statusbar的更多相关文章

  1. 学习ASP.NET Core Razor 编程系列十六——排序

    学习ASP.NET Core Razor 编程系列目录 学习ASP.NET Core Razor 编程系列一 学习ASP.NET Core Razor 编程系列二——添加一个实体 学习ASP.NET ...

  2. 走进windows编程的世界-----入门篇

    1   Windows编程基础 1.1Win32应用程序基本类型 1)  控制台程序 不须要完好的windows窗体,能够使用DOS窗体方式显示 2)  Win32窗体程序 包括窗体的程序,能够通过窗 ...

  3. 《windows核心编程系列 》六谈谈线程调度、优先级和关联性

    线程调度.优先级和关联性 每个线程都有一个CONTEXT结构,保存在线程内核对象中.大约每隔20ms windows就会查看所有当前存在的线程内核对象.并在可调度的线程内核对象中选择一个,将其保存在C ...

  4. [C入门 - 游戏编程系列] 贪吃蛇篇(六) - 蛇实现

    这一篇是关于设置蛇的属性的,接上一篇(五). 设置蛇的速度,很简单,只要不是负数就行了. void SNK_SetSnakeSpeed(Snake *snake, int speed) { ) sna ...

  5. [C# 网络编程系列]专题六:UDP编程

    转自:http://www.cnblogs.com/zhili/archive/2012/09/01/2659167.html 引用: 前一个专题简单介绍了TCP编程的一些知识,UDP与TCP地位相当 ...

  6. Python高级网络编程系列之第一篇

    在上一篇中我们简单的说了一下Python中网络编程的基础知识(相关API就不解释了),其中还有什么细节的知识点没有进行说明,如什么是TCP/IP协议有几种状态,什么是TCP三次握手,什么是TCP四次握 ...

  7. [C入门 - 游戏编程系列] 贪吃蛇篇(五) - 蛇实现

    因为已经写了食物的实现,所以我不知道到底是该先写世界的实现还是蛇的实现.因为世界就是一个窗口,可以立刻在世界中看到食物的样子,对于大多数人来说,如果写完代码立刻就能看到效果,那就再好不过了.可是,我最 ...

  8. MongoDB基础教程系列--第六篇 MongoDB 索引

    使用索引可以大大提高文档的查询效率.如果没有索引,会遍历集合中所有文档,才能找到匹配查询语句的文档.这样遍历集合中整个文档的方式是非常耗时的,特别是处理大数据时,耗时几十秒甚至几分钟都是有可能的. 创 ...

  9. Python高级网络编程系列之终极篇---自己实现一个Web框架

    通过前面几个小节的学习,现在我们想要把之前学到的知识点给串联起来,实现一个很小型的Web框架.虽然很小,但是用到的知识点都是比较多的.如Socket编程,装饰器传参在实际项目中如何使用.通过这一节的学 ...

随机推荐

  1. SQL统计

    --按周统计SELECT TOP 10DATENAME(year,AddDate) 年,DATENAME(week,AddDate) 周,COUNT(1) 单量,SUM(total) 总金额,AVG( ...

  2. 关于Sa系列用户不能登录,只能本地windows身份验证的说明

  3. 软件工程的引入:Scrum开发框架总结

    俗话说,自己写的代码,6个月后也是别人的代码……复习!复习!复习!涉及的知识点如下: 软件工程概念 敏捷开发过程scrum 一.什么是软件工程?请用一句话描述. 软件工程是一门研究性的学科:它用工程化 ...

  4. 常用数据结构-线性表及Java 动态数组 深究

    [Java心得总结六]Java容器中——Collection在前面自己总结的一篇博文中对Collection的框架结构做了整理,这里深究一下Java中list的实现方式 1.动态数组 In compu ...

  5. 自己动手,实现一种类似List<T>的数据结构(二)

    前言: 首先,小匹夫要祝各位看官圣诞快乐,新年愉快-.上一篇文章<自己动手,实现一种类似List<T>的数据结构(一)> 介绍了一下不依靠List<T>实现的各种接 ...

  6. Angular2 小贴士-多级注入器

    angular2 的依赖注入包含了太多的内容,其中的一个重点就是注入器,而注入器又非常难理解,今天我们不深入介绍注入器的内容,可以参考官方文档,我们今天来说注入器的层级. 也就是组件获取服务的容器会选 ...

  7. awk使用说明

    原文地址:http://www.cnblogs.com/verrion/p/awk_usage.html Awk使用说明 运维必须掌握的三剑客工具:grep(文件内容过滤器),sed(数据流处理器), ...

  8. [unity]UGUI界面滑动,ScrollRect嵌套滑动

    原因:老板蛋痛,让我去抄皇室战争. 思路:我大概知道ngui(后来改成UGUI的)里面有个ScrollView.于是我就想一个横着的SV加上5个竖的SV不就好了吗. 过程: 于是 但是有个问题就是UI ...

  9. C语言计算2个数的最小公倍数

    #include<stdio.h>int main(){   int a,b,i=1,temp,lcm;   scanf("%d %d",&a,&b); ...

  10. MySQL引擎、索引和优化(li)

    一.存储引擎 存储引擎,MySQL中的数据用各种不同的技术存储在文件(或者内存)中.这些技术中的每一种技术都使用不同的存储机制.索引技巧.锁定水平并且最终提供广泛的不同的功能和能力.通过选择不同的技术 ...