现在的位置: 首页 > 综合 > 正文

一步步用SDK构建记事本程序(三)

2018年05月14日 ⁄ 综合 ⁄ 共 14730字 ⁄ 字号 评论关闭

接着上次的说

 

上篇文章中实现了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;

 

 

 

  1. //main.cpp
  2. #include <windows.h>
  3. #include <commctrl.h>
  4. #include <commdlg.h>
  5. #include <richedit.h>
  6. #include "resource.h"
  7. #include "pub.h"
  8. #pragma comment(lib,"comctl32")
  9. LRESULT CALLBACK WndProc(HWND hWnd,UINT uMessage,WPARAM wParam,LPARAM lParam);
  10. bool SaveFile(LPTSTR lpFileName,int nLength);
  11. int WINAPI WinMain( __in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in_opt LPSTR lpCmdLine, __in int nShowCmd )
  12. {   
  13.     WNDCLASSEX  wcex = {0};
  14.     TCHAR       szAppName[] = TEXT("SigmaTera Notepad");
  15.     MSG         msg = {0};
  16.     HWND        hWnd = NULL;
  17.     //填充窗口类结构
  18.     wcex.cbClsExtra = 0;
  19.     wcex.cbSize = sizeof (WNDCLASSEX);
  20.     wcex.cbWndExtra = 0;
  21.     wcex.hbrBackground = (HBRUSH)COLOR_WINDOW;
  22.     wcex.hCursor = LoadCursor(NULL,IDC_ARROW);
  23.     wcex.hIcon = LoadIcon(hInstance,IDI_APPLICATION);
  24.     wcex.hIconSm = wcex.hIcon;
  25.     wcex.hInstance = hInstance;
  26.     wcex.lpfnWndProc = WndProc;
  27.     wcex.lpszClassName = szAppName;
  28.     wcex.lpszMenuName = (LPCTSTR)IDR_MENU_MAIN;
  29.     wcex.style = CS_HREDRAW | CS_VREDRAW;
  30.     InitCommonControls();
  31.     HMODULE hRichEditLib = LoadLibrary(TEXT("RICHED32.DLL"));
  32.     //注册窗口类
  33.     if (RegisterClassEx(&wcex) == NULL)
  34.     {
  35.         return -1;
  36.     }
  37.     //创建窗口
  38.     hWnd = CreateWindow(szAppName,TEXT("Notepad"),WS_OVERLAPPEDWINDOW,
  39.                         CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
  40.                         NULL,NULL,hInstance,NULL);
  41.     
  42.     if (NULL == hWnd)
  43.     {
  44.         return -1;
  45.     }
  46.     //显示并更新窗口
  47.     ShowWindow(hWnd,SW_SHOW);
  48.     UpdateWindow(hWnd);
  49.     //消息循环
  50.     while (GetMessage(&msg,NULL,0,0))
  51.     {
  52.         TranslateMessage(&msg);
  53.         DispatchMessage(&msg);
  54.     }
  55.     FreeLibrary(hRichEditLib);
  56.     return 0;
  57. }
  58. LRESULT CALLBACK WndProc(HWND hWnd,UINT uMessage,WPARAM wParam,LPARAM lParam)
  59. {
  60.     static HWND hwndRichEdit = NULL;
  61.     static HWND hwndStatus = NULL;
  62.     static OPENFILENAME ofn;
  63.     static TCHAR szFile[MAX_PATH];
  64.     static HFONT hFont;
  65.     static bool bSaved = true;
  66.     static RECT rectWindow;
  67.     switch (uMessage)
  68.     {
  69.     case WM_CREATE:
  70.         int arrPosStatusBar[2];
  71.         hwndRichEdit = CreateWindow(TEXT("RICHEDIT"),TEXT(""),WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL |
  72.             ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN,
  73.             0,0,800,600,
  74.             hWnd,NULL,GetModuleHandle(NULL),NULL);
  75.         hwndStatus = CreateWindow(TEXT("msctls_statusbar32"),TEXT(""),WS_CHILD | WS_VISIBLE,
  76.             0,0,800,22,
  77.             hWnd,NULL,GetModuleHandle(NULL),NULL);
  78.         hFont = CreateFont(20,10,0,0,FW_NORMAL,FALSE,FALSE,0,ANSI_CHARSET,OUT_DEFAULT_PRECIS,
  79.                 OUT_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH | FF_SWISS,TEXT("Arail"));
  80.         SendMessage(hwndRichEdit,WM_SETFONT,(WPARAM)hFont,(LPARAM)TRUE);
  81.         SendMessage(hwndRichEdit,EM_SETEVENTMASK,0,ENM_CHANGE | ENM_SELCHANGE);
  82.         GetWindowRect(hWnd,&rectWindow);
  83.         arrPosStatusBar[0] = (rectWindow.right - rectWindow.left) - 200;
  84.         arrPosStatusBar[1] = (rectWindow.right - rectWindow.left);
  85.         SendMessage(hwndStatus,SB_SETPARTS,2,(LPARAM)(int*)&arrPosStatusBar);
  86.         EnableMenuItem(GetMenu(hWnd),ID_MENUITEM_EDITUNDO,MF_GRAYED);
  87.         break;
  88.     case WM_SIZE:
  89.         AdjustEditWindow(hWnd,hwndRichEdit);
  90.         AdjustStatusbar(hWnd,hwndStatus);
  91.         break;
  92.     case WM_NOTIFY:
  93.         LPNMHDR lpNMHdr;
  94.         lpNMHdr = (LPNMHDR)lParam;
  95.         switch(lpNMHdr->code)
  96.         {
  97.         
  98.         case EN_SELCHANGE:
  99.             
  100.             break;
  101.         }
  102.         break;
  103.     case WM_COMMAND:
  104.         
  105.         switch (HIWORD(wParam))
  106.         {
  107.         case EN_CHANGE:
  108.             if (bSaved)
  109.                 bSaved = false;
  110.             if (SendMessage(hwndRichEdit,EM_CANUNDO,0,0))
  111.             {
  112.                 EnableMenuItem(GetMenu(hWnd),ID_MENUITEM_EDITUNDO,MF_ENABLED);
  113.             }
  114.             else
  115.             {
  116.                 EnableMenuItem(GetMenu(hWnd),ID_MENUITEM_EDITUNDO,MF_GRAYED);
  117.             }
  118.             break;
  119.         
  120.         }
  121.         switch (LOWORD(wParam))
  122.         {
  123.         case ID_MENUITEM_FILEOPEN:
  124.             
  125.             
  126.             ZeroMemory(&ofn,sizeof (ofn));
  127.             ZeroMemory(szFile,MAX_PATH);
  128.             
  129.             ofn.lStructSize = sizeof(OPENFILENAME); 
  130.             ofn.hwndOwner = hWnd; 
  131.             ofn.lpstrFile = szFile; 
  132.             ofn.nMaxFile = sizeof(szFile); 
  133.             ofn.lpstrFilter = TEXT("Text File(*.txt)/0*.txt/0All File(*.*)/0*.*"); 
  134.             ofn.nFilterIndex = 1; 
  135.             ofn.lpstrFileTitle = NULL; 
  136.             ofn.nMaxFileTitle = 0; 
  137.             ofn.lpstrInitialDir = NULL; 
  138.             ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; 
  139.             if (GetOpenFileName(&ofn) == FALSE)
  140.                 break;
  141.             
  142.             LoadFromFile(hwndRichEdit,szFile);
  143.             bSaved = true;
  144.             EnableMenuItem(GetMenu(hWnd),ID_MENUITEM_EDITUNDO,MF_GRAYED);
  145.             break;
  146.         case ID_MENUITEM_FILESAVE: 
  147.             if (lstrcmp(szFile,TEXT("")) != 0)
  148.             {
  149.                 SaveToFile(hwndRichEdit,ofn.lpstrFile);
  150.                 bSaved = true;
  151.                 break;
  152.             }
  153.         case ID_MENUITEM_FILESAVEAS:
  154.             SaveFile(szFile,256);
  155.             SaveToFile(hwndRichEdit,szFile);
  156.             bSaved = true;
  157.             break;
  158.         case ID_MENUITEM_EDITUNDO:
  159.             SendMessage(hwndRichEdit,EM_UNDO,0,0);
  160.             break;
  161.         case ID_MENUITEM_EXIT:
  162.             PostQuitMessage(0);
  163.             break;
  164.         }
  165.         break;
  166.     case WM_CLOSE:
  167.         if (!bSaved)
  168.         {
  169.             if (MessageBox(NULL,TEXT("您的文件还未保存,需要保存么?"),TEXT("提示"),MB_ICONWARNING | MB_YESNO) == IDYES)
  170.             {
  171.                 SaveFile(szFile,256);
  172.                 SaveToFile(hwndRichEdit,szFile);
  173.                 bSaved = true;
  174.             }
  175.         }
  176.         DestroyWindow(hWnd);
  177.         break;
  178.     case WM_DESTROY:
  179.         PostQuitMessage(0);
  180.         break;
  181.     }
  182.     /*else if (uMessage == WM_CLOSE)
  183.     {
  184.         
  185.     }
  186.     else if (uMessage == WM_DESTROY)
  187.     {
  188.         
  189.     }*/
  190.     return DefWindowProc(hWnd,uMessage,wParam,lParam);
  191. }
  192. bool SaveFile(LPTSTR lpFileName,int nLength)
  193. {
  194.     OPENFILENAME ofn;
  195.     
  196.     ZeroMemory(&ofn,sizeof (ofn));
  197.     ofn.lStructSize = sizeof(OPENFILENAME); 
  198.     ofn.hwndOwner = NULL; 
  199.     ofn.lpstrFile = lpFileName; 
  200.     ofn.nMaxFile = nLength; 
  201.     ofn.lpstrFilter = TEXT("Text File(*.txt)/0*.txt/0All File(*.*)/0*.*"); 
  202.     ofn.nFilterIndex = 1; 
  203.     ofn.lpstrFileTitle = NULL; 
  204.     ofn.nMaxFileTitle = 0; 
  205.     ofn.lpstrInitialDir = NULL; 
  206.     ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; 
  207.     if (GetSaveFileName(&ofn) == FALSE)
  208.         return false;
  209.     lstrcat(lpFileName,TEXT(".txt"));
  210.     return true;
  211. }

 
 
  1. //pub.cpp
  2. #include "pub.h"
  3. #include <richedit.h>
  4. #include <stdio.h>
  5. #include <commctrl.h>
  6. #define STATUSBAR_HEIGHT 22
  7. void AdjustStatusbar(HWND hwndMain,HWND hwndStatusbar)
  8. {
  9.     RECT rectWindow;
  10.     RECT rectStatusBar;
  11.     int arrPosStatusBar[2] = {0};
  12.     GetClientRect(hwndMain,&rectWindow);
  13.     GetWindowRect(hwndStatusbar,&rectStatusBar);
  14.     int xPos = 0;
  15.     int xLen = rectWindow.right - rectWindow.left;
  16.     int yPos = (rectWindow.bottom - rectWindow.top) - (rectStatusBar.bottom - rectStatusBar.top);
  17.     int yLen = STATUSBAR_HEIGHT;
  18.     arrPosStatusBar[0] = rectWindow.right - rectWindow.left - 200;
  19.     arrPosStatusBar[1] = rectWindow.right - rectWindow.left;
  20.     SendMessage(hwndStatusbar,SB_SETPARTS,sizeof (arrPosStatusBar) / sizeof (int),(LPARAM)(LPINT)&arrPosStatusBar);
  21.     MoveWindow(hwndStatusbar,xPos,yPos,xLen,yLen,TRUE);
  22. }
  23. void AdjustEditWindow(HWND hwndMain,HWND hwndEdit)
  24. {
  25.     RECT rectMain;
  26.     RECT rectEdit;
  27.     GetClientRect(hwndMain,&rectMain);
  28.     GetWindowRect(hwndEdit,&rectEdit);
  29.     int xPos = 0;
  30.     int xLen = rectMain.right - rectMain.left - 2;
  31.     int yPos = 0;
  32.     int yLen = (rectMain.bottom - rectMain.top) - STATUSBAR_HEIGHT;
  33.     MoveWindow(hwndEdit,xPos,yPos,xLen,yLen,TRUE);
  34. }
  35. BOOL LoadFromFile(HWND hEdit,LPCTSTR lpFileName)
  36. {
  37.     HANDLE  hFile = NULL;
  38.     HANDLE  hFileMapping = NULL;
  39.     LPCTSTR lpData = NULL;
  40.     hFile = CreateFile(lpFileName,GENERIC_READ,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
  41.     if (INVALID_HANDLE_VALUE == hFile)
  42.     {
  43.         return FALSE;
  44.     }
  45.     
  46.     hFileMapping = CreateFileMapping(hFile,NULL,PAGE_READONLY | SEC_COMMIT,0,0,NULL);
  47.     
  48.     if (NULL == hFileMapping)
  49.     {
  50.         CloseHandle(hFile);
  51.         return FALSE;
  52.     }
  53.     
  54.     lpData = (LPCTSTR)MapViewOfFile(hFileMapping,FILE_MAP_READ,0,0,0);
  55.     
  56.     if (lpData == NULL)
  57.     {
  58.         CloseHandle(hFileMapping);
  59.         CloseHandle(hFile);
  60.     }
  61.     SetWindowText(hEdit,lpData);
  62.     
  63.     UnmapViewOfFile(lpData);
  64.     CloseHandle(hFileMapping);
  65.     CloseHandle(hFile);
  66.     
  67.     return TRUE;
  68. }
  69. BOOL SaveToFile(HWND hEdit,LPCTSTR lpFileName)
  70. {
  71.     HANDLE  hFile = NULL;
  72.     HANDLE  hFileMapping = NULL;
  73.     LPTSTR  lpData = NULL;
  74.     int nTextLength = 0;
  75.     hFile = CreateFile(lpFileName,GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
  76.     if (INVALID_HANDLE_VALUE == hFile)
  77.     {
  78.         return FALSE;
  79.     }
  80.     nTextLength = GetWindowTextLength(hEdit) + 1;
  81.     hFileMapping = CreateFileMapping(hFile,NULL,PAGE_READWRITE,0,nTextLength,NULL);
  82.     if (NULL == hFileMapping)
  83.     {
  84.         CloseHandle(hFile);
  85.         return FALSE;
  86.     }
  87.     lpData = (LPTSTR)MapViewOfFile(hFileMapping,FILE_MAP_WRITE,0,0,0);
  88.     if (lpData == NULL)
  89.     {
  90.         CloseHandle(hFileMapping);
  91.         CloseHandle(hFile);
  92.     }
  93.     GetWindowText(hEdit,lpData,nTextLength);
  94.     //FlushViewOfFile(lpData,nTextLength);
  95.     UnmapViewOfFile(lpData);
  96.     CloseHandle(hFileMapping);
  97.     CloseHandle(hFile);
  98.     
  99.     
  100.     return TRUE;
  101. }

抱歉!评论已关闭.