Timers and Animation

theForger's Win32 API教程第二版(简体中文)

主页

基础
  1. 开始学习
  2. 一个简单的窗口
  3. 处理消息
  4. 理解消息循环
  5. 使用资源
  6. 菜单和图标
  7. 对话框
  8. 非模态对话框
  9. 标准控件
  10. 对话框常见问题
创建一个简单应用
  1. 在运行时创建控件
  2. 文件与常用对话框
  3. 工具栏与状态栏
  4. 多文档界面
图形设备接口
  1. 位图,设备上下文
  2. 透明位图
  3. 定时器与动画
  4. 文本,字体与顏色
工具与文档
  1. 参考
  2. 免费的Visual C++(最新更新)
附表
  1. 常见错误的解決方法
  2. API vs. MFC
  3. 关于资源文件的说明

应用第三部分:工具栏和状态栏

[images/app_three.gif]

范例:app_three

关于通用控件的重要说明

  对于所有的通用控件,你要用它们之前都要调用InitCommonControls().还要#include <commctrl.h>以便使用函数与一些所必须的通用控件的申明与定义. 你还需要在链接设置中加上comctl32.lib,如果它不在那里的话.注意InitCommonControls()是个旧API,为了使用更多的功能你可以使用InitCommonControlsEx()(就是InitCommonControlSex()),在使用很多最近才有的通用控件的时候,你也必须要用这个函数. 这个地方因为我沒有用什么高级功能,所以就用InitCommonControls()就夠了,也简单些.

工具栏

  你可以用CreateToolbarEx()创建一个工具栏,但我在这里不这样用.第一件事情就是要实际地创建一个工具栏...

    hTool = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0,
        hwnd, (HMENU)IDC_MAIN_TOOL, GetModuleHandle(NULL), NULL);

  夠简单了吧,TOOLBARCLASSNAME是在通用控件的头文件中定义的常量.hwnd是父窗口,也就是你要放工具栏的窗口.IDC_MAIN_TOOL是一个标识,在后面如果需要的话,可以用GetDlgItem()和它来获最这个工具栏的HWND.

     // Send the TB_BUTTONSTRUCTSIZE message, which is required for
     // backward compatibility.
     SendMessage(hTool, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);

  需要这个消息来让系统算出你用的是什么版本的通用控件库.因为新版本加了一些新东西到这个结构体中去了,所以有了它的大小就知道你可以用它的哪些功能.

工具栏按钮

  基本的工具栏上按钮图片有两个来源,标準按钮是comctl32提供的,用戶定义的是你自己创建的.注意:按钮和图片是分別加到工具栏上去的...先加一些图片,再加一些按钮,最后告诉它哪个按钮用哪个图片.

添加标準按钮

  现在我们创建了一个工具栏了,我们要向它加一些按钮.最常用的图片就在通用控件库中,所以我们不需要对每个程序来创建,添加一遍就可以使用了.

  首先我们申明一个TBBUTTON和TBADDBITMAP.

    TBBUTTON tbb[3];
    TBADDBITMAP tbab;

然后我们向工具栏添加标準的图片,就用通用控件库中定义好的图片表...

    tbab.hInst = HINST_COMMCTRL;
    tbab.nID = IDB_STD_SMALL_COLOR;
    SendMessage(hTool, TB_ADDBITMAP, 0, (LPARAM)&tbab);

现在我们装入了我们的图片,我们可以添加一些按钮,使用它们...

    ZeroMemory(tbb, sizeof(tbb));
    tbb[0].iBitmap = STD_FILENEW;
    tbb[0].fsState = TBSTATE_ENABLED;
    tbb[0].fsStyle = TBSTYLE_BUTTON;
    tbb[0].idCommand = ID_FILE_NEW;

    tbb[1].iBitmap = STD_FILEOPEN;
    tbb[1].fsState = TBSTATE_ENABLED;
    tbb[1].fsStyle = TBSTYLE_BUTTON;
    tbb[1].idCommand = ID_FILE_OPEN;

    tbb[2].iBitmap = STD_FILESAVE;
    tbb[2].fsState = TBSTATE_ENABLED;
    tbb[2].fsStyle = TBSTYLE_BUTTON;
    tbb[2].idCommand = ID_FILE_SAVEAS;

    SendMessage(hTool, TB_ADDBUTTONS, sizeof(tbb)/sizeof(TBBUTTON), (LPARAM)&tbb);

  这里我们用标準图片来分別添加一个New,Open和Save As按钮,这样做一般是需要的,因为用戶已经习惯了它们,知道它们是干什么的.

  每个图片在图片表中的编号在通用控件头文件中定义好了,并在MSDN中有说明.

  我们给每个按钮配置一个标识(ID_FILE_NEW等等...),跟相应的菜单项的标识是一模一样的. 这些按钮可以如同相应的菜单项产生一样的WM_COMMAND消息,所以不用额外的处理了!如果我们添加了一个不跟相应的菜单对应的按钮,我们只需要搞个新的标识并在WM_COMMAND中加一点处理代码就行了.

  可能你会在想我传给TB_ADDBUTTONS的这个怪怪的wParam是干什么的.它是来计算在数组tbb 中的按钮数目这样我们就不用写个固定的值.如果我写个3 这里可能是正确的,但是如果我一会加了一个按钮我就要把它攺为4,这样做起来就很不好...你总是一个地方的变动引起尽可能少的別的地方的变动.比如如果sizeof(TBBUTTON)是16字节(我自己做个比喻,其实是跟平台相关)这样我们有三个按钮的话sizeof(tbb)就是16*3或48..然后48/16就是我们的按钮数目,3.

状态栏

  在程序中经常和工具栏在一起的还有状态栏,在窗口的底部显示消息的一个小块块.使用起来是很容易的,创建它们...

    hStatus = CreateWindowEx(0, STATUSCLASSNAME, NULL,
        WS_CHILD | WS_VISIBLE | SBARS_SIZEGRIP, 0, 0, 0, 0,
        hwnd, (HMENU)IDC_MAIN_STATUS, GetModuleHandle(NULL), NULL);

然后设置你需要的分段数目(可选).如果你不设置的话,它就只有一个分段,使用整个状态栏,你可以如其它的很多控件一样用SetWindowText()来设置它的文字或从其获取文字.要是有多个段的话,你就需要给出每个分段的宽度,并用SB_SETTEXT来设置每个分段的文字.

  为了设置宽度,我们声明一个整数的数组,每个值分別是各个分段的以像素为单位的宽度. 如果你想要某个分段用剩下的所有的宽度,就把它的宽度设为-1就行.

    int statwidths[] = {100, -1};

    SendMessage(hStatus, SB_SETPARTS, sizeof(statwidths)/sizeof(int), (LPARAM)statwidths);
    SendMessage(hStatus, SB_SETTEXT, 0, (LPARAM)"Hi there :)");

  这里的wParam又是用来计算中数组中有多少元素的. 一旦我们完成了添加分段,我们对第一个(序号为0)进行设置看看効果.

合适地设置大小

  跟菜单不一样,工具栏和状态栏是在父窗口的客戶区域內的独立的控件.这样一来,我们如果还是用原来的WM_SIZE处理代码,它们就会覆盖掉我们在前面的章节添加的编辑框控件.这是个显然需要更正的理由...在WM_SIZE的处理中,我们把工具栏和状态栏移到一个位置,并把它们的高度和宽度从客戶区域減去以使我们可以让编辑框填充剩下的空间...

    HWND hTool;
    RECT rcTool;
    int iToolHeight;

    HWND hStatus;
    RECT rcStatus;
    int iStatusHeight;

    HWND hEdit;
    int iEditHeight;
    RECT rcClient;

    // Size toolbar and get height

    hTool = GetDlgItem(hwnd, IDC_MAIN_TOOL);
    SendMessage(hTool, TB_AUTOSIZE, 0, 0);

    GetWindowRect(hTool, &rcTool);
    iToolHeight = rcTool.bottom - rcTool.top;

    // Size status bar and get height

    hStatus = GetDlgItem(hwnd, IDC_MAIN_STATUS);
    SendMessage(hStatus, WM_SIZE, 0, 0);

    GetWindowRect(hStatus, &rcStatus);
    iStatusHeight = rcStatus.bottom - rcStatus.top;

    // Calculate remaining height and size edit

    GetClientRect(hwnd, &rcClient);

    iEditHeight = rcClient.bottom - iToolHeight - iStatusHeight;

    hEdit = GetDlgItem(hwnd, IDC_MAIN_EDIT);
    SetWindowPos(hEdit, NULL, 0, iToolHeight, rcClient.right, iEditHeight, SWP_NOZORDER);

  不幸的是,这段代码有点长,但是很简单...工具栏可以自己调整自己的位置当向它发送TB_AUTOSIZE消息的时候,如果发送WM_SIZE 的时候状态栏也可以.(通用控件库不以一致性好而闻名

Copyright © 1998-2008, Brook Miles (forgey). All rights reserved.