可以用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.
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; GetClientRect(hwnd, &rcClient); iEditHeight = rcClient.bottom - iToolHeight - iStatusHeight; hEdit = GetDlgItem(hwnd, IDC_MAIN_EDIT); SetWindowPos(hEdit, NULL, 0, iToolHeight, rcClient.right, iEditHeight, SWP_NOZORDER);
#include <windows.h> #include <commctrl.h> #include "resource.h" const char g_szClassName[] = "myWindowClass"; #define IDC_MAIN_EDIT 101 #define IDC_MAIN_TOOL 102 #define IDC_MAIN_STATUS 103 BOOL LoadTextFileToEdit(HWND hEdit, LPCTSTR pszFileName) { HANDLE hFile; BOOL bSuccess = FALSE; hFile = CreateFile(pszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if(hFile != INVALID_HANDLE_VALUE) { DWORD dwFileSize; dwFileSize = GetFileSize(hFile, NULL); if(dwFileSize != 0xFFFFFFFF) { LPSTR pszFileText; pszFileText = (LPSTR)GlobalAlloc(GPTR, dwFileSize + 1); if(pszFileText != NULL) { DWORD dwRead; if(ReadFile(hFile, pszFileText, dwFileSize, &dwRead, NULL)) { pszFileText[dwFileSize] = 0; // Add null terminator if(SetWindowText(hEdit, pszFileText)) bSuccess = TRUE; // It worked! } GlobalFree(pszFileText); } } CloseHandle(hFile); } return bSuccess; } BOOL SaveTextFileFromEdit(HWND hEdit, LPCTSTR pszFileName) { HANDLE hFile; BOOL bSuccess = FALSE; hFile = CreateFile(pszFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if(hFile != INVALID_HANDLE_VALUE) { DWORD dwTextLength; dwTextLength = GetWindowTextLength(hEdit); // No need to bother if there's no text. if(dwTextLength > 0) { LPSTR pszText; DWORD dwBufferSize = dwTextLength + 1; pszText = (LPSTR)GlobalAlloc(GPTR, dwBufferSize); if(pszText != NULL) { if(GetWindowText(hEdit, pszText, dwBufferSize)) { DWORD dwWritten; if(WriteFile(hFile, pszText, dwTextLength, &dwWritten, NULL)) bSuccess = TRUE; } GlobalFree(pszText); } } CloseHandle(hFile); } return bSuccess; } void DoFileOpen(HWND hwnd) { OPENFILENAME ofn; char szFileName[MAX_PATH] = ""; ZeroMemory(&ofn, sizeof(ofn)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hwnd; ofn.lpstrFilter = "Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0"; ofn.lpstrFile = szFileName; ofn.nMaxFile = MAX_PATH; ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; ofn.lpstrDefExt = "txt"; if(GetOpenFileName(&ofn)) { HWND hEdit = GetDlgItem(hwnd, IDC_MAIN_EDIT); LoadTextFileToEdit(hEdit, szFileName); } } void DoFileSave(HWND hwnd) { OPENFILENAME ofn; char szFileName[MAX_PATH] = ""; ZeroMemory(&ofn, sizeof(ofn)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hwnd; ofn.lpstrFilter = "Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0"; ofn.lpstrFile = szFileName; ofn.nMaxFile = MAX_PATH; ofn.lpstrDefExt = "txt"; ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT; if(GetSaveFileName(&ofn)) { HWND hEdit = GetDlgItem(hwnd, IDC_MAIN_EDIT); SaveTextFileFromEdit(hEdit, szFileName); } } LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_CREATE: { HFONT hfDefault; HWND hEdit; HWND hTool; TBBUTTON tbb[3]; TBADDBITMAP tbab; HWND hStatus; int statwidths[] = {100, -1}; // Create Edit Control hEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "", WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL, 0, 0, 100, 100, hwnd, (HMENU)IDC_MAIN_EDIT, GetModuleHandle(NULL), NULL); if(hEdit == NULL) MessageBox(hwnd, "Could not create edit box.", "Error", MB_OK | MB_ICONERROR); hfDefault = (HFONT)GetStockObject(DEFAULT_GUI_FONT); SendMessage(hEdit, WM_SETFONT, (WPARAM)hfDefault, MAKELPARAM(FALSE, 0)); // Create Toolbar hTool = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, hwnd, (HMENU)IDC_MAIN_TOOL, GetModuleHandle(NULL), NULL); if(hTool == NULL) MessageBox(hwnd, "Could not create tool bar.", "Error", MB_OK | MB_ICONERROR); SendMessage(hTool, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0); 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_NEWONE; tbb[1].iBitmap = STD_FILEOPEN; tbb[1].fsState = TBSTATE_ENABLED; tbb[1].fsStyle = TBSTYLE_BUTTON; tbb[1].idCommand = ID_FILE_OPENTWO; 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); // Create Status bar hStatus = CreateWindowEx(0, STATUSCLASSNAME, NULL, WS_CHILD | WS_VISIBLE | SBARS_SIZEGRIP, 0, 0, 0, 0, hwnd, (HMENU)IDC_MAIN_STATUS, GetModuleHandle(NULL), NULL); SendMessage(hStatus, SB_SETPARTS, sizeof(statwidths)/sizeof(int), (LPARAM)statwidths); SendMessage(hStatus, SB_SETTEXT, 0, (LPARAM)"Hi there :)"); } break; case WM_SIZE: { HWND hTool; RECT rcTool; int iToolHeight; HWND hStatus; RECT rcStatus; int iStatusHeight; HWND hEdit; RECT rcClient; int iEditHeight; // 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); } break; case WM_CLOSE: DestroyWindow(hwnd); break; case WM_DESTROY: PostQuitMessage(0); break; case WM_COMMAND: switch(LOWORD(wParam)) { case ID_FILE_EXIT: PostMessage(hwnd, WM_CLOSE, 0, 0); break; case ID_FILE_NEWONE: SetDlgItemText(hwnd, IDC_MAIN_EDIT, ""); break; case ID_FILE_OPENTWO: DoFileOpen(hwnd); break; case ID_FILE_SAVEAS: DoFileSave(hwnd); break; } break; default: return DefWindowProc(hwnd, msg, wParam, lParam); } return 0; } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASSEX wc; HWND hwnd; MSG Msg; wc.cbSize = sizeof(WNDCLASSEX); wc.style = 0; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wc.lpszMenuName = MAKEINTRESOURCE(IDR_MAINMENU); wc.lpszClassName = g_szClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); if(!RegisterClassEx(&wc)) { MessageBox(NULL, "Window Registration Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK); return 0; } hwnd = CreateWindowEx( 0, g_szClassName, "theForger's Tutorial Application", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 480, 320, NULL, NULL, hInstance, NULL); if(hwnd == NULL) { MessageBox(NULL, "Window Creation Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK); return 0; } ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); while(GetMessage(&Msg, NULL, 0, 0) > 0) { TranslateMessage(&Msg); DispatchMessage(&Msg); } return Msg.wParam; }