接着上次的说
上篇文章中实现了RichEdit窗口和菜单,下面来实现状态栏和每个窗口尺寸协调问题。
那个望远镜图标的按钮
以上是窗口的大体效果,下方的工具栏类似RichEdit创建方法,用CreateWindow创建。
这里有个问题,我们不知道状态栏类名怎么办(查MSDN呗,确实是好办法),这里还有个办法,用Spy++,你应该猜到什么了吧。就是用Spy++中根据窗口寻找对应信息的Find功能
中间那个靶心图标,拖到一个有状态栏的位置,你就知道了:)
这句是创建代码
hwndStatus = CreateWindow(TEXT("msctls_statusbar32"),TEXT(""),WS_CHILD | WS_VISIBLE,
0,0,800,22,
hWnd,NULL,GetModuleHandle(NULL),NULL);
到这,也许你认为窗口的构建完工了,其实不然。你如果安上述编码了,拖动一下窗口试试。就会发现RichEdit和状态栏与主窗口不协调了,有错位现象。
造成以上问题,是由于主窗口大小、位置改变时并没有通知其子窗口(在此处就是RichEdit/状态栏),需要在当主窗口改变大小、位置时通知其子窗口更新位置。
在这里我通过拦截WM_SIZE来处理子窗口变动问题,编写两个函数来分别实现对RichEdit和StatusBar调整
void AdjustStatusbar(HWND hwndMain,HWND hwndStatusbar)
{
RECT rectWindow;
RECT rectStatusBar;
GetClientRect(hwndMain,&rectWindow);
GetWindowRect(hwndStatusbar,&rectStatusBar);
int xPos = 0;
int xLen = rectWindow.right - rectWindow.left;
int yPos = (rectWindow.bottom - rectWindow.top) - (rectStatusBar.bottom - rectStatusBar.top);
int yLen = STATUSBAR_HEIGHT;
MoveWindow(hwndStatusbar,xPos,yPos,xLen,yLen,TRUE);
}
void AdjustEditWindow(HWND hwndMain,HWND hwndEdit)
{
RECT rectMain;
RECT rectEdit;
GetClientRect(hwndMain,&rectMain);
GetWindowRect(hwndEdit,&rectEdit);
int xPos = 0;
int xLen = rectMain.right - rectMain.left - 2;
int yPos = 0;
int yLen = (rectMain.bottom - rectMain.top) - STATUSBAR_HEIGHT;
MoveWindow(hwndEdit,xPos,yPos,xLen,yLen,TRUE);
}
我创建了pub.h和pub.cpp将这两个函数放到其中,添加到工程中,添加方法类似main.cpp前述添加方法(算是公共函数单元吧,呵呵)
界面已经有一个雏形了,下面实现记事本功能部分。
记事本最主要的功能是读入文本文件并显示、保存窗口中的内容到文件。
基本思想:
1.读入文本文件,显示文本文件到RichEdit。
2.读取RichEdit中的内容,保存到RichEdit。
这里我用两个函数实现读取文件中的内容到RichEdit、RichEdit内容保存到文件。
BOOL LoadFromFile(HWND hEdit,LPCTSTR lpFileName)
{
HANDLE hFile = NULL;
HANDLE hFileMapping = NULL;
LPCTSTR lpData = NULL;
hFile = CreateFile(lpFileName,GENERIC_READ,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if (INVALID_HANDLE_VALUE == hFile)
{
return FALSE;
}
hFileMapping = CreateFileMapping(hFile,NULL,PAGE_READONLY | SEC_COMMIT,0,0,NULL);
if (NULL == hFileMapping)
{
CloseHandle(hFile);
return FALSE;
}
lpData = (LPCTSTR)MapViewOfFile(hFileMapping,FILE_MAP_READ,0,0,0);
if (lpData == NULL)
{
CloseHandle(hFileMapping);
CloseHandle(hFile);
}
SetWindowText(hEdit,lpData);
UnmapViewOfFile(lpData);
CloseHandle(hFileMapping);
CloseHandle(hFile);
return TRUE;
}
BOOL SaveToFile(HWND hEdit,LPCTSTR lpFileName)
{
HANDLE hFile = NULL;
HANDLE hFileMapping = NULL;
LPTSTR lpData = NULL;
int nTextLength = 0;
hFile = CreateFile(lpFileName,GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
if (INVALID_HANDLE_VALUE == hFile)
{
return FALSE;
}
nTextLength = GetWindowTextLength(hEdit) + 1;
hFileMapping = CreateFileMapping(hFile,NULL,PAGE_READWRITE,0,nTextLength,NULL);
if (NULL == hFileMapping)
{
CloseHandle(hFile);
return FALSE;
}
lpData = (LPTSTR)MapViewOfFile(hFileMapping,FILE_MAP_WRITE,0,0,0);
if (lpData == NULL)
{
CloseHandle(hFileMapping);
CloseHandle(hFile);
}
GetWindowText(hEdit,lpData,nTextLength);
FlushViewOfFile(lpData,nTextLength);
UnmapViewOfFile(lpData);
CloseHandle(hFileMapping);
CloseHandle(hFile);
return TRUE;
}
这里我通过内存映射的办法来实现对文件的读写,内存映射在Windows中对于大文件的操作效率很高。在此处也可以通过使用文件读取函数来读取,这里有个很有意思的问题,对于文件读取,当时我第一个想法是通过分多次读取一个文件到一个固定缓冲区,然后将缓冲区的内容块写入到RichEdit。但每次读出来的内容都会有乱码,我与几个朋友研究了下,最后发现问题是在截取边界上,对于例如每次读取1024KB的内容,在MBCS编码情况下,缓冲区的1023的位置不能保证就是一个中文编码高字节(假设是GB2312编码),可能在汉字低字节就被截断了。对于Unicode编码(UCS-2)不存在此问题,因为在此环境下任何字符都占用2字节,对于处理MBCS边界问题,如有什么好建议,可以告诉我,不胜感激。最终选择的还是全部读取全部显示的办法
。对应文件保存则是全部从RichEdit获取,全部写入文件。这里可以算我偷懒吧。
下面在文件菜单的打开保存处分别调用这两个函数:
窗口过程,命令消息处理分支:
switch (LOWORD(wParam))
{
case ID_MENUITEM_FILEOPEN:
ZeroMemory(&ofn,sizeof (ofn));
ZeroMemory(szFile,MAX_PATH);
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = hWnd;
ofn.lpstrFile = szFile;
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFilter = TEXT("Text File(*.txt)/0*.txt/0All File(*.*)/0*.*");
ofn.nFilterIndex = 1;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
if (GetOpenFileName(&ofn) == FALSE)
break;
LoadFromFile(hwndRichEdit,szFile);
bSaved = true;
EnableMenuItem(GetMenu(hWnd),ID_MENUITEM_EDITUNDO,MF_GRAYED);
break;
case ID_MENUITEM_FILESAVE:
if (lstrcmp(szFile,TEXT("")) != 0)
{
SaveToFile(hwndRichEdit,ofn.lpstrFile);
bSaved = true;
break;
}
case ID_MENUITEM_FILESAVEAS:
SaveFile(szFile,256);
SaveToFile(hwndRichEdit,szFile);
bSaved = true;
break;
- //main.cpp
- #include <windows.h>
- #include <commctrl.h>
- #include <commdlg.h>
- #include <richedit.h>
- #include "resource.h"
- #include "pub.h"
- #pragma comment(lib,"comctl32")
- LRESULT CALLBACK WndProc(HWND hWnd,UINT uMessage,WPARAM wParam,LPARAM lParam);
- bool SaveFile(LPTSTR lpFileName,int nLength);
- int WINAPI WinMain( __in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in_opt LPSTR lpCmdLine, __in int nShowCmd )
- {
- WNDCLASSEX wcex = {0};
- TCHAR szAppName[] = TEXT("SigmaTera Notepad");
- MSG msg = {0};
- HWND hWnd = NULL;
- //填充窗口类结构
- wcex.cbClsExtra = 0;
- wcex.cbSize = sizeof (WNDCLASSEX);
- wcex.cbWndExtra = 0;
- wcex.hbrBackground = (HBRUSH)COLOR_WINDOW;
- wcex.hCursor = LoadCursor(NULL,IDC_ARROW);
- wcex.hIcon = LoadIcon(hInstance,IDI_APPLICATION);
- wcex.hIconSm = wcex.hIcon;
- wcex.hInstance = hInstance;
- wcex.lpfnWndProc = WndProc;
- wcex.lpszClassName = szAppName;
- wcex.lpszMenuName = (LPCTSTR)IDR_MENU_MAIN;
- wcex.style = CS_HREDRAW | CS_VREDRAW;
- InitCommonControls();
- HMODULE hRichEditLib = LoadLibrary(TEXT("RICHED32.DLL"));
- //注册窗口类
- if (RegisterClassEx(&wcex) == NULL)
- {
- return -1;
- }
- //创建窗口
- hWnd = CreateWindow(szAppName,TEXT("Notepad"),WS_OVERLAPPEDWINDOW,
- CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
- NULL,NULL,hInstance,NULL);
- if (NULL == hWnd)
- {
- return -1;
- }
- //显示并更新窗口
- ShowWindow(hWnd,SW_SHOW);
- UpdateWindow(hWnd);
- //消息循环
- while (GetMessage(&msg,NULL,0,0))
- {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- FreeLibrary(hRichEditLib);
- return 0;
- }
- LRESULT CALLBACK WndProc(HWND hWnd,UINT uMessage,WPARAM wParam,LPARAM lParam)
- {
- static HWND hwndRichEdit = NULL;
- static HWND hwndStatus = NULL;
- static OPENFILENAME ofn;
- static TCHAR szFile[MAX_PATH];
- static HFONT hFont;
- static bool bSaved = true;
- static RECT rectWindow;
- switch (uMessage)
- {
- case WM_CREATE:
- int arrPosStatusBar[2];
- hwndRichEdit = CreateWindow(TEXT("RICHEDIT"),TEXT(""),WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL |
- ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN,
- 0,0,800,600,
- hWnd,NULL,GetModuleHandle(NULL),NULL);
- hwndStatus = CreateWindow(TEXT("msctls_statusbar32"),TEXT(""),WS_CHILD | WS_VISIBLE,
- 0,0,800,22,
- hWnd,NULL,GetModuleHandle(NULL),NULL);
- hFont = CreateFont(20,10,0,0,FW_NORMAL,FALSE,FALSE,0,ANSI_CHARSET,OUT_DEFAULT_PRECIS,
- OUT_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH | FF_SWISS,TEXT("Arail"));
- SendMessage(hwndRichEdit,WM_SETFONT,(WPARAM)hFont,(LPARAM)TRUE);
- SendMessage(hwndRichEdit,EM_SETEVENTMASK,0,ENM_CHANGE | ENM_SELCHANGE);
- GetWindowRect(hWnd,&rectWindow);
- arrPosStatusBar[0] = (rectWindow.right - rectWindow.left) - 200;
- arrPosStatusBar[1] = (rectWindow.right - rectWindow.left);
- SendMessage(hwndStatus,SB_SETPARTS,2,(LPARAM)(int*)&arrPosStatusBar);
- EnableMenuItem(GetMenu(hWnd),ID_MENUITEM_EDITUNDO,MF_GRAYED);
- break;
- case WM_SIZE:
- AdjustEditWindow(hWnd,hwndRichEdit);
- AdjustStatusbar(hWnd,hwndStatus);
- break;
- case WM_NOTIFY:
- LPNMHDR lpNMHdr;
- lpNMHdr = (LPNMHDR)lParam;
- switch(lpNMHdr->code)
- {
- case EN_SELCHANGE:
- break;
- }
- break;
- case WM_COMMAND:
- switch (HIWORD(wParam))
- {
- case EN_CHANGE:
- if (bSaved)
- bSaved = false;
- if (SendMessage(hwndRichEdit,EM_CANUNDO,0,0))
- {
- EnableMenuItem(GetMenu(hWnd),ID_MENUITEM_EDITUNDO,MF_ENABLED);
- }
- else
- {
- EnableMenuItem(GetMenu(hWnd),ID_MENUITEM_EDITUNDO,MF_GRAYED);
- }
- break;
- }
- switch (LOWORD(wParam))
- {
- case ID_MENUITEM_FILEOPEN:
- ZeroMemory(&ofn,sizeof (ofn));
- ZeroMemory(szFile,MAX_PATH);
- ofn.lStructSize = sizeof(OPENFILENAME);
- ofn.hwndOwner = hWnd;
- ofn.lpstrFile = szFile;
- ofn.nMaxFile = sizeof(szFile);
- ofn.lpstrFilter = TEXT("Text File(*.txt)/0*.txt/0All File(*.*)/0*.*");
- ofn.nFilterIndex = 1;
- ofn.lpstrFileTitle = NULL;
- ofn.nMaxFileTitle = 0;
- ofn.lpstrInitialDir = NULL;
- ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
- if (GetOpenFileName(&ofn) == FALSE)
- break;
- LoadFromFile(hwndRichEdit,szFile);
- bSaved = true;
- EnableMenuItem(GetMenu(hWnd),ID_MENUITEM_EDITUNDO,MF_GRAYED);
- break;
- case ID_MENUITEM_FILESAVE:
- if (lstrcmp(szFile,TEXT("")) != 0)
- {
- SaveToFile(hwndRichEdit,ofn.lpstrFile);
- bSaved = true;
- break;
- }
- case ID_MENUITEM_FILESAVEAS:
- SaveFile(szFile,256);
- SaveToFile(hwndRichEdit,szFile);
- bSaved = true;
- break;
- case ID_MENUITEM_EDITUNDO:
- SendMessage(hwndRichEdit,EM_UNDO,0,0);
- break;
- case ID_MENUITEM_EXIT:
- PostQuitMessage(0);
- break;
- }
- break;
- case WM_CLOSE:
- if (!bSaved)
- {
- if (MessageBox(NULL,TEXT("您的文件还未保存,需要保存么?"),TEXT("提示"),MB_ICONWARNING | MB_YESNO) == IDYES)
- {
- SaveFile(szFile,256);
- SaveToFile(hwndRichEdit,szFile);
- bSaved = true;
- }
- }
- DestroyWindow(hWnd);
- break;
- case WM_DESTROY:
- PostQuitMessage(0);
- break;
- }
- /*else if (uMessage == WM_CLOSE)
- {
- }
- else if (uMessage == WM_DESTROY)
- {
- }*/
- return DefWindowProc(hWnd,uMessage,wParam,lParam);
- }
- bool SaveFile(LPTSTR lpFileName,int nLength)
- {
- OPENFILENAME ofn;
- ZeroMemory(&ofn,sizeof (ofn));
- ofn.lStructSize = sizeof(OPENFILENAME);
- ofn.hwndOwner = NULL;
- ofn.lpstrFile = lpFileName;
- ofn.nMaxFile = nLength;
- ofn.lpstrFilter = TEXT("Text File(*.txt)/0*.txt/0All File(*.*)/0*.*");
- ofn.nFilterIndex = 1;
- ofn.lpstrFileTitle = NULL;
- ofn.nMaxFileTitle = 0;
- ofn.lpstrInitialDir = NULL;
- ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
- if (GetSaveFileName(&ofn) == FALSE)
- return false;
- lstrcat(lpFileName,TEXT(".txt"));
- return true;
- }
- //pub.cpp
- #include "pub.h"
- #include <richedit.h>
- #include <stdio.h>
- #include <commctrl.h>
- #define STATUSBAR_HEIGHT 22
- void AdjustStatusbar(HWND hwndMain,HWND hwndStatusbar)
- {
- RECT rectWindow;
- RECT rectStatusBar;
- int arrPosStatusBar[2] = {0};
- GetClientRect(hwndMain,&rectWindow);
- GetWindowRect(hwndStatusbar,&rectStatusBar);
- int xPos = 0;
- int xLen = rectWindow.right - rectWindow.left;
- int yPos = (rectWindow.bottom - rectWindow.top) - (rectStatusBar.bottom - rectStatusBar.top);
- int yLen = STATUSBAR_HEIGHT;
- arrPosStatusBar[0] = rectWindow.right - rectWindow.left - 200;
- arrPosStatusBar[1] = rectWindow.right - rectWindow.left;
- SendMessage(hwndStatusbar,SB_SETPARTS,sizeof (arrPosStatusBar) / sizeof (int),(LPARAM)(LPINT)&arrPosStatusBar);
- MoveWindow(hwndStatusbar,xPos,yPos,xLen,yLen,TRUE);
- }
- void AdjustEditWindow(HWND hwndMain,HWND hwndEdit)
- {
- RECT rectMain;
- RECT rectEdit;
- GetClientRect(hwndMain,&rectMain);
- GetWindowRect(hwndEdit,&rectEdit);
- int xPos = 0;
- int xLen = rectMain.right - rectMain.left - 2;
- int yPos = 0;
- int yLen = (rectMain.bottom - rectMain.top) - STATUSBAR_HEIGHT;
- MoveWindow(hwndEdit,xPos,yPos,xLen,yLen,TRUE);
- }
- BOOL LoadFromFile(HWND hEdit,LPCTSTR lpFileName)
- {
- HANDLE hFile = NULL;
- HANDLE hFileMapping = NULL;
- LPCTSTR lpData = NULL;
- hFile = CreateFile(lpFileName,GENERIC_READ,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
- if (INVALID_HANDLE_VALUE == hFile)
- {
- return FALSE;
- }
- hFileMapping = CreateFileMapping(hFile,NULL,PAGE_READONLY | SEC_COMMIT,0,0,NULL);
- if (NULL == hFileMapping)
- {
- CloseHandle(hFile);
- return FALSE;
- }
- lpData = (LPCTSTR)MapViewOfFile(hFileMapping,FILE_MAP_READ,0,0,0);
- if (lpData == NULL)
- {
- CloseHandle(hFileMapping);
- CloseHandle(hFile);
- }
- SetWindowText(hEdit,lpData);
- UnmapViewOfFile(lpData);
- CloseHandle(hFileMapping);
- CloseHandle(hFile);
- return TRUE;
- }
- BOOL SaveToFile(HWND hEdit,LPCTSTR lpFileName)
- {
- HANDLE hFile = NULL;
- HANDLE hFileMapping = NULL;
- LPTSTR lpData = NULL;
- int nTextLength = 0;
- hFile = CreateFile(lpFileName,GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
- if (INVALID_HANDLE_VALUE == hFile)
- {
- return FALSE;
- }
- nTextLength = GetWindowTextLength(hEdit) + 1;
- hFileMapping = CreateFileMapping(hFile,NULL,PAGE_READWRITE,0,nTextLength,NULL);
- if (NULL == hFileMapping)
- {
- CloseHandle(hFile);
- return FALSE;
- }
- lpData = (LPTSTR)MapViewOfFile(hFileMapping,FILE_MAP_WRITE,0,0,0);
- if (lpData == NULL)
- {
- CloseHandle(hFileMapping);
- CloseHandle(hFile);
- }
- GetWindowText(hEdit,lpData,nTextLength);
- //FlushViewOfFile(lpData,nTextLength);
- UnmapViewOfFile(lpData);
- CloseHandle(hFileMapping);
- CloseHandle(hFile);
- return TRUE;
- }