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. 关于资源文件的说明

对话框图形界面设计者的好朋友

范例: dlg_one

[images/dlg_one.gif]

  很难找到一个沒有使用对话框的程序在任何文本编辑器或其它的什么编辑器之类的东西 文件->打开 菜单你就会看到一个对话框很可能就要你选择一要打开的文件

  对话框不限于标準的打开文件框可以是任意外观和任意功能对话框的吸引人的地方在于它提供了一种快捷的方式来创建一个图形界面和一些认的处理工作大大地減少了你所需要写的代码

  要记住的一点就是对话框其实就是窗口对话框与普通的窗口的区別在于系统为对话框作了一些额外的处理工作比如创建并初始化控件并处理tab顺序几乎所有用于普通窗口的API函数都可以用于对话框

  第一步是创建对话框资源.对于任何的资源而言如何处理它们都与你用的编译器/IDE相关这里我向你展示.rc文件中的对话框的文本并让你将其整合到你的项目中去

IDD_ABOUT DIALOG DISCARDABLE  0, 0, 239, 66
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "My About Box"
FONT 8, "MS Sans Serif"
BEGIN
    DEFPUSHBUTTON   "&OK",IDOK,174,18,50,14
    PUSHBUTTON      "&Cancel",IDCANCEL,174,35,50,14
    GROUPBOX        "About this program...",IDC_STATIC,7,7,225,52
    CTEXT           "An example program showing how to use Dialog Boxes\r\n\r\nby theForger",
                    IDC_STATIC,16,18,144,33
END

  第一行中IDD_AGOUTDLG为资源的标识DIALOG是资源的类型四个数字为左高坐标它们不是像素而是基于系统的字体由用戶选择的大小对话框单位如果你选择了一个大的字体对话框就大如果选择了小点的字体对话框就相应的小些这一点很重要因为要确保所有的控件用当前的字体以合适的大小显示你可以用MapDialogRect()在运行的时候把对话框单位转換为像素DISCARDABLE告诉系统在不用此资源的时候将其交換至磁盘以节省系统资源这是不用说的).

  第二行以STYLE开头然后在后面跟上用来创建此对话框的窗口风格这些在你的帮助文档中的关于CreateWindow()说明中会有解释为了使用已定义好的那些常量你需要在你的.rc文件中加上#include "windows.h"或者如果你使用VC++的话winres.hafxres.h也可以如果你使用资源编辑器的话这些文件则在需要的时候自动被加上去

  CAPTION那行应该一看就知道是什么意思

  FONT行指明了你想用来创建此对话框的字体的大小和名字因为不同的人有不同的字体并可能指定不同的字体所以这行在不同的计算机上可能看起来不一样当然你一般不用为此操心

  现在我们用控件的列表来创建此对话框

    DEFPUSHBUTTON   "&OK",IDOK,174,18,50,14

  这行指定OK按扭这里的&有点像菜单项的那个有下划線的那个字母O”所以用戶可以按下Alt+O来激活这个控件这就我上面所提到的对话框所做的默认处理的一部分).IDOK是控件的标识IDOK是己经定义好的所以我们不需要自己用#define来定义它了最后的四个数字为左高坐标都是对话框单位

  这些息太过于学术化了所以你一般都用一个资源编辑器来创建对话框但是知道如何用文本的方式来做这些事情还是很有必要的尤其在你沒有一个图形化的编辑器的情況下

  有两个控件的标识为IDC_STATIC就是-1),这表明我们永远并不需要去读写它们所以它们并不需要一个标识但是给它们一个标识也沒有什么害处而且资源编辑器会自动为你做一点

  靜态控件中的文本中的"\r\n"是一个CR-LF对表示換一个新行

  至此把这些加到.rc文件中去后我们要写一个对话框的过程来处理这个对话框的消息不要担心这不是什么很新的知识实际上它跟我们的主窗口的窗口的过程差不多(不是完全一样).

BOOL CALLBACK AboutDlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
    switch(Message)
    {
        case WM_INITDIALOG:

        return TRUE;
        case WM_COMMAND:
            switch(LOWORD(wParam))
            {
                case IDOK:
                    EndDialog(hwnd, IDOK);
                break;
                case IDCANCEL:
                    EndDialog(hwnd, IDCANCEL);
                break;
            }
        break;
        default:
            return FALSE;
    }
    return TRUE;
}

  对话框过程跟窗口过程有一些重要的差別其中一个就是对于你不处理的消息不调用DefWndowProc()在对话框中这是自动完成的你要是真的要自己调用的话会有问题).

  第二通常上你不处理的消息就返回一个FALSE处理的话就是TRUE除非那个消息指明了你要返回一个別的值注意这就是我们在上面做的,默认的就是什么都不做并返回一个FALSE而我们处理的消息就跳出switch()并返回TRUE

  第三不调用DestroyWindow()来关闭一个对话框而调用EndDialog()第二个参数是返回给调用DialogBox()的那个地方的代码的

  最后不处理WM_CREATE消息取而代之处理WM_INITDIALOG消息来做对话框出现之前的任何操作并返回TRUE以使键盘将焦点置于点的控件之上.你确实可以处理WM_CREATE消息但那是在所有控件被创建之前就发送了这样你就不能访问它们了而在WM_INITDIALOG消息来的时候控件己经创建好了).

  叽叽歪歪的半天了现在创建它...

case WM_COMMAND:
    switch(LOWORD(wParam))
    {
        case ID_HELP_ABOUT:
        {
            int ret = DialogBox(GetModuleHandle(NULL), 
                MAKEINTRESOURCE(IDD_ABOUT), hwnd, AboutDlgProc);
            if(ret == IDOK){
                MessageBox(hwnd, "Dialog exited with IDOK.", "Notice",
                    MB_OK | MB_ICONINFORMATION);
            }
            else if(ret == IDCANCEL){
                MessageBox(hwnd, "Dialog exited with IDCANCEL.", "Notice",
                    MB_OK | MB_ICONINFORMATION);
            }
            else if(ret == -1){
                MessageBox(hwnd, "Dialog failed!", "Error",
                    MB_OK | MB_ICONINFORMATION);
            }
        }
        break;
        // Other menu commands...
    }
break;

  这就是我用来创建我的关于对话框的代码你应该看出来这应该移到你的WM_COMMAND消息处理的代码中去如果你对这点还不清楚你可能需要复习关于菜单的那些章节ID_HELP_ABOUT是我的Help->About菜单项的标识

  因为我们要我们的主窗口的菜单来创建这个对话话我们显然需要把这些代码放到我们主窗口的WndProc()中去而不是对话框的过程中

  现在我存储了调用DialogBox()的返回值这样你就可以观察你点击两个按钮的效果在对话框中按EscEnter等等...这样做也展示了如何通过对话框的返回值来判断是否调用成功和用戶用选择或是你想从你的对话框过程中想返回给调用者的任何消息

DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_ABOUT), hwnd, AboutDlgProc);

  这是唯一重要的地方你可以把这段代码放到你想要对话框出现的任何地方IDD_ABOUT是对话框资源的标识hwnd是对话框的父窗口的句柄.AboutDlgProc()当然是用来控制对话框的对话过程

  搞定了Sit IDD_UBUsit.

  某些特別敏感的读者可能会问如果DialogBox()直到对话关闭才返回的话我们在它显示的时候不能处理消息它怎么工作的这是因为DialogBox()有个特点就是有自己的消息循环所以当对话框显示的时候我们的消息循环正在进行并且窗口处理了认的消息循环这个消息循环也处理类似当你按下Tab键时在控件之间移动键盘的焦点的事情

  另外一个使用对话框的效果就是在对话框关闭之前你的主窗口将被禁止有时候你就是要这种效果有时你不是想这样比如有时我们想要我们的对话框作为一个浮动的工具栏这种情況下我们想要能夠同时操作我们的对话框与主窗口这也是下面的章节要讲的內容

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