青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

兔子的技術博客

兔子

   :: 首頁 :: 聯系 :: 聚合  :: 管理
  202 Posts :: 0 Stories :: 43 Comments :: 0 Trackbacks

留言簿(10)

最新評論

閱讀排行榜

評論排行榜

轉自:http://blog.csdn.net/skyever2100/archive/2008/11/13/3292480.aspx

一、             概述

在Windows Form應用中,Windows界面系統通過消息與應用程序進行交互,每個窗口都有相應的消息處理器,處理各自的用戶輸入及界面重繪等邏輯。窗口都有自己的類名,需要先把該類名及它對應的消息處理器注冊到Windows界面系統中,再根據該類名來創建自己的窗口。

Windows也為我們準備了文本輸入框,對于簡單的文本輸入,這個功能已經很完美了,不過如果我們要做一個功能強大的文本編輯器,就像開發環境的IDE那樣,那么從頭來寫它會更好,可以實現我們想要的任何邏輯。

文本框是這樣一個窗口,它響應鍵盤消息,并實時重繪窗口中的文本,還要響應鼠標消息來移動光標位置。

我嘗試著用Windows API來實現了一個簡單的單行文本框,它僅有以下幾個功能:

1、  響應用戶的普通字符輸入

2、  可以用光標鍵及HOME、END鍵來移動光標

3、  可以用鼠標鍵來移動光標

4、  可以用BACKSPACE及DELETE鍵來刪除輸入的內容

另外,它不具有選擇文本的功能及剪切、復制、粘貼等功能,這個文本框是用純C來寫的,不具有對象化的特征,也就是說,沒有將代碼封裝成類,不能在界面上放置兩個文本框,這是為了簡化代碼,只說明它的原理,如果要封裝成類,可以采用MFC等類庫來編寫這個文本框。

在本文的最后,附帶了本程序的全部代碼,為了書寫方便,把所有的代碼都放在了一個代碼文件中了。

本文本框運行界面如下:

 

 

 

二、             技術要點

1、 注冊文本框類并創建文本框窗口

可以使用API函數RegisterClassEx來注冊文本框類,如下:

WNDCLASSEX wc;

     ::ZeroMemory(&wc, sizeof(wc));

     wc.cbSize     = sizeof(wc);

     wc.style      = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;   // 指定當窗口尺寸發生變化時重繪窗口,并且響應鼠標雙擊事件

     wc.hInstance  = _HInstance;

     wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); // 指定窗口背景顏色為系統顏色“窗口背景”

     wc.lpszClassName = _T("MySimpleTextBox"); // 指定要注冊的窗口類名,創建窗口時要以此類名為標識符

     wc.lpfnWndProc     = _TextBoxWndProc; // 處理窗口消息的函數

::RegisterClassEx(&wc);              // 調用API函數注冊文本框窗口

在注冊文本框類的時候,需要為其指定消息處理過程,就是那個名為_TextBoxWndProc的函數,函數原型如下:

LRESULT CALLBACK _TextBoxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

使用類名“MySimpleTextBox”來注冊了一個文本框類,并且為其指定了消息處理過程,下一步就是要使用這個類名來創建一個文本框了,使用CreateWindow可以創建該窗口:

HWND hWnd = ::CreateWindow(__T("MySimpleTextBox"), NULL, WS_CHILDWINDOW | WS_VISIBLE,

left, top, width, height, hParentWnd, NULL, _HInstance, NULL);

其中的left、top為、width、height為文本框的位置及尺寸,_HInstance為父窗口的句柄。

 

2、 繪制文本框及文本

在文本框的消息處理過程中,響應消息WM_PAINT,可以實現對文本的繪制,假設使用默認的字體及字號,則代碼如下:

     static PAINTSTRUCT ps;

     static RECT rect;

     HDC hDC = ::BeginPaint(hWnd, &ps);  // 開始繪制操作

     ::GetClientRect(hWnd, &rect);        // 獲取客戶區的尺寸

     ::DrawEdge(hDC, &rect, EDGE_SUNKEN, BF_RECT);  // 繪制邊框,EDGE_SUNKEN表示繪制樣式為內嵌樣式,BF_RECT表示繪制矩形邊框

     int len = ::_tcslen(_String);

::TextOut(hDC, 4, 2, _String, len);

::EndPaint(hWnd, &ps);               // 結束繪制操作

其中,_String為定義的一個全局變量:TCHAR _String[TEXTBOX_MAXLENGTH+1];

其中API函數DrawEdge可以繪制文本框的邊緣。

 

3、 光標操作

我們可以自己一繪制閃爍的光標,不過Windows為我們提供了一套和光標有關的API函數,可以省去我們繪制光標的繁瑣過程:

CreateCaret(HWND hWnd, HBITMAP hBitmap, int width, int height);

該API函數用于創建一個光標,第一個參數是窗口的句柄,第二個參數是光標的位圖,用于定義光標的形狀,第三、四個參數為光標的尺寸。

我們通常見到的光標是一個黑色的豎線,在Insert模式下(按了Insert鍵)為一個黑色的方塊,如果是使用這種簡單的光標,就把第二個參數設置為NULL就可以了。

ShowCaret(HWND hWnd);

該API函數用于顯示光標,其中并沒有指定顯示哪個光標的參數,這是因為光標是與當前線程有關的資源,一個線程只能創建一個光標,在該線程中創建的光標,可以在該線程中對它執行其它的操作。

SetCaretPos(int x, int y);

該API函數用于設置光標的位置,當輸入字符后或響應光標鍵時,可以調用該函數重新設置光標的位置。

在調用CrateCaret創建了光標時,它是隱藏狀態,要顯示它需要調用ShowCaret函數。

HideCaret(HWND hWnd);

該API函數用于隱藏光標。如果兩次調用了HideCaret來隱藏光標,也需要調用兩次ShowCaret才能顯示它。

DestroyCaret(HWND hWnd);

該API函數用于銷毀光標。

 

通常來說,我們需要在文本框得到焦點的時候創建并顯示光標,而在文本框失去焦點的時候隱藏并銷毀光標。

通過處理兩個Windows Form消息可以實現上面的邏輯:

處理WM_SETFOCUS消息創建并顯示光標:

::CreateCaret(hWnd, (HBITMAP)NULL, 1, TEXTBOX_HEIGHT-5); // 創建光標

::SetCaretPos(x, y);                  // 設置光標位置

::ShowCaret(hWnd);                    // 顯示光標

 

處理WM_KILLFOCUS消息隱藏并銷毀光標:

::HideCaret(hWnd);                    // 隱藏光標

::DestroyCaret();                     // 銷毀光標

在窗口繪制之前,我們需要先隱藏光標,繪制完成之后再顯示光標,否則屏幕上將會殘留光標的痕跡,但在處理WM_PAINT消息時我們并沒有這樣做,是因為BeginPaint和EndPaint已經為我們做了這件事情。

 

4、 響應按鍵消息

Windows有若干與鍵盤相關的消息,例如:WM_KEYDOWN、WM_KEYUP、WM_CHAR等,我們需要處理WM_CHAR消息在光標的位置顯示所輸入的字符,消息處理過程的參數wParam即為所輸入的字符,顯示出字符之后,需要調用SetCaretPos來重新設置光標位置。

如何將字符立即顯示出來呢,首先要指定文本框上的無效區域,按照Windows Form的編程約定,當Windows發現某個窗口上出現無效區域時,會向該窗口發送WM_PAINT消息來通知消息處理過程重繪這個區域。

API函數InvalidateRect可以指定窗口的某個區域無效,最簡單的辦法是讓整個窗口都無效,如下:

     RECT rect;

     ::GetClientRect(hWnd, &rect);

     ::InvalidateRect(hWnd, &rect, TRUE);

::UpdateWindow(hWnd);

API函數UpdateWindow在執行時會立即重繪窗口,以便讓用戶的輸入會在界面上及時做出響應。

光標鍵及HOME、END等鍵不會產生WM_CHAR消息,我們可以響應WM_KEYDOWN消息來移動光標的位置。

 

5、 響應鼠標消息

我們需要處理鼠標的單擊消息WM_LBUTTONDOWN來移動光標,如何知道鼠標點擊在哪個字符上呢,也就是如何取得指定位置處的字符呢?Windows API并沒有為我們提供現成的功能,好在寫一個這樣的功能也不復雜,API函數GetTextExtentPoint(HDC hDc, LPCSTR lpString, int count, LPSIZE lpSize)可以獲取指定的設置描述表下,指定字符串的尺寸。

基于這樣的原理,我們可以逐漸求得每個字符所在的位置,與鼠標單擊的位置來對照,便可以計算出鼠標是單擊了哪個字符,如下:

     int x = LOWORD(lParam);

     HDC hDc = ::GetDC(hWnd);

     int strLen = ::_tcslen(_String), strPos = 0;

     SIZE size;

     for (strPos=0; strPos<strLen; strPos++)

     {

         ::GetTextExtentPoint(hDc, _String, strPos, &size);

         if(size.cx + 4 >= x)

              break;

     }

     _StringPosition = strPos;

     ::GetTextExtentPoint(hDc, _String, strPos, &size);

     ::SetCaretPos(size.cx + 4, 3);

     ::ReleaseDC(hWnd, hDc);

 

三、             遺留問題

1、 文本緩沖區問題

本示例中為了簡單起見,定義了一個固定大小的文本緩沖區,當輸入的字符數量到達固定大小時,將忽略字符消息的處理。顯然這種處理方式不實用,當文本較少時會造成內存緩存區的浪費,當文本較多時內存緩沖區不能夠滿足要求,并且插入和刪除字符時,都會移動大量的文本,效率也比較慢。

我們需要用變長的字符串來解決字符緩沖區大小這個問題,變長字符串會有許多邏輯,可以用類來封裝這些邏輯,例如MFC中的CString類。

 

2、 如何用面向對象的思維來寫一個文本框

本簡單的文本框顯示不具有重用特征,字符串緩沖區、光標位置等數據都定義為全局變量,這導致無法在界面上放置兩個文本框。如果采用面向對象的邏輯,應該把這些數據封裝在一個類中,之所以沒有采用面向對象的方式來寫,是因為Windows API本身就是面向過程的,從整體架構上來講,我們需要實現一套面向對象的開發框架,定義各種窗口共有的基類,在這個基類上派出生各種窗口,例如MFC就是這樣做的。

 

3、 文本選擇的邏輯

實現這個邏輯的關系在于以下兩點:

一是當用戶拖拽鼠標或用Shift+光標鍵等進行選擇時,消息處理過程需要對這些鼠標和鍵盤的消息正確地響應,確定出當前所選擇的區域

二是如何向用戶呈現所選擇的文本區域,通常它們具有指定顏色的底色,這牽涉到界面重繪的問題。可以對這部分文本設置好背景色和前景色進行繪制。

 

4、 重繪的效率問題

本示例中每次輸入和刪除都要重繪整個文本區域,實際上,我們可以判斷窗口哪個位置無效了,一般是光標后面的文本無效。在繪制時先取得其無效區域,僅對這一小部分進行繪制,可以提高重繪效率。

 

5、 多行文本的問題

顯然,該示例程序只能輸入單行文本,如果要輸入多行文本,可以響應回車鍵另起一行,在窗口繪制時,如果遇到回車鍵,便跳到下一行的最左側區域進行繪制。

也可以采取每行文本使用一個字符串緩沖區的辦法,以防止在大量文本時引起的大量內存移動,這需要定義一個文本管理器的類來處理多個緩沖區的邏輯。

 

6、 其它問題

圍繞文本編輯器可以展開若干問題,例如字體、字號、顏色、行間距等,更高級的,像開發環境的IDE,會自動把關鍵字突出顯示,如果要做這樣一個文本編輯器,就是非常復雜的事情了,不過辦法總比問題多,這些有激情的問題會帶領我們進入一個廣闊的思維空間。

 

  為了書寫方便,把所有的代碼都放在了一個代碼文件中了。

 

  關于對該代碼技術要點的解釋,請參見:《用Windows API實現一個簡單的文本輸入框(上)》

 

  該代碼中大部分地方都加了注釋,有不妥之處,敬請批評指正:

  1 #include <tchar.h>
  2 
  3 #include <windows.h>
  4 
  5  
  6 
  7 HINSTANCE _HInstance;                              // 應用程序句柄
  8 
  9 TCHAR _Title[] = _T("簡單文本框");                 // 定義窗口的標題
 10 
 11  
 12 
 13 TCHAR _WindowClass[] = _T("MySimpleTextBoxApp");// 主窗口類名
 14 
 15 ATOM _RegisterClass();                             // 注冊主窗口類
 16 
 17 HWND _CreateWindow(int nCmdShow);                  // 創建主窗口
 18 
 19 LRESULT CALLBACK _WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);   // 主窗口消息處理函數
 20 
 21  
 22 
 23 TCHAR _TextBoxClass[] = _T("MySimpleTextBox"); // 文本框的類名
 24 
 25 ATOM _RegisterTextBoxClass();                      // 注冊文本框的類
 26 
 27 HWND _CreateTextBoxWindow(HWND hParentWnd);        // 創建文本框
 28 
 29 LRESULT CALLBACK _TextBoxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); // 文本框窗口消息處理函數
 30 
 31 void _DrawText(HDC hDC);                           // 繪制文本
 32 
 33 void _SetCaretPos(HWND hWnd);                      // 設置光標位置
 34 
 35 void _UpdateWindow(HWND hWnd);                     // 更新窗口
 36 
 37  
 38 
 39  
 40 
 41 // 一些常量定義
 42 
 43 #define MAINWINDOW_WIDTH    400      // 主窗口寬度
 44 
 45 #define MAINWINDOW_HEIGHT   200      // 主窗口高度
 46 
 47 #define TEXTBOX_WIDTH       300      // 文本框寬度
 48 
 49 #define TEXTBOX_HEIGHT      20       // 文本框高度
 50 
 51 #define TEXTBOX_MAXLENGTH   1024 // 文本框中文本的最大長度
 52 
 53  
 54 
 55 TCHAR _String[TEXTBOX_MAXLENGTH + 1= _T("");     // 文本
 56 
 57 int    _StringPosition = ::_tcslen(_String);        // 光標插入點所在的位置
 58 
 59  
 60 
 61 int APIENTRY _tWinMain(HINSTANCE hInstance,        // 當前的應用程序句柄
 62 
 63                           HINSTANCE hPrevInstance, // 前一個應用程序實例的句柄(在Win32上,始終為NULL)
 64 
 65                           LPTSTR lpCmdLine,        // 命令行參數
 66 
 67                           int        nCmdShow     // 窗口的顯示樣式
 68 
 69                           )
 70 
 71 {
 72 
 73      _HInstance = hInstance;
 74 
 75  
 76 
 77      _RegisterClass();                         // 注冊窗口類
 78 
 79      if(_CreateWindow(nCmdShow) == NULL)       // 創建窗口
 80 
 81          return FALSE;
 82 
 83  
 84 
 85      MSG msg;
 86 
 87      while (::GetMessage(&msg, NULL, 00))    // 從消息隊列中獲取消息
 88 
 89      {
 90 
 91          ::TranslateMessage(&msg);            // 轉譯一些特殊的消息
 92 
 93          ::DispatchMessage(&msg);             // 執行消息處理
 94 
 95      }
 96 
 97  
 98 
 99      return (int)msg.wParam;
100 
101 }
102 
103  
104 
105  
106 
107 // 注冊應用程序窗口類
108 
109 ATOM _RegisterClass()
110 
111 {
112 
113      WNDCLASSEX wc;
114 
115      ::ZeroMemory(&wc, sizeof(wc));                 // 作為一步清空,是為了讓未賦值的字段的默認值為(或NULL)
116 
117  
118 
119      wc.cbSize     = sizeof(wc);
120 
121      wc.style      = CS_HREDRAW | CS_VREDRAW;  // 指定當窗口橫向和縱向的尺寸發生變化時都會重繪窗口
122 
123      wc.hInstance  = _HInstance;
124 
125      wc.hbrBackground = (HBRUSH)( COLOR_APPWORKSPACE + 1);  // 指定主窗口背景為“工作區域”系統顏色
126 
127      wc.lpszClassName = _WindowClass;          // 此為要注冊的類名,創建窗口時要以此類名為標識符
128 
129      wc.lpfnWndProc     = _WndProc;                      // 此為處理窗口消息的函數
130 
131  
132 
133      return ::RegisterClassEx(&wc);                 // 調用API函數注冊窗口類
134 
135 }
136 
137  
138 
139 // 創建窗口
140 
141 HWND _CreateWindow(int nCmdShow)
142 
143 {
144 
145      HWND hWnd = ::CreateWindow(_WindowClass, _Title, WS_OVERLAPPEDWINDOW, 
146 
147          CW_USEDEFAULT, CW_USEDEFAULT, MAINWINDOW_WIDTH, MAINWINDOW_HEIGHT, NULL, NULL, _HInstance, NULL);
148 
149  
150 
151      if(hWnd == NULL)
152 
153          return NULL;
154 
155  
156 
157      ::ShowWindow(hWnd, nCmdShow);
158 
159      ::UpdateWindow(hWnd);
160 
161  
162 
163      return hWnd;
164 
165 }
166 
167  
168 
169 // 窗口處理過程
170 
171 LRESULT CALLBACK _WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
172 
173 {
174 
175      static HWND hTextBoxWnd;
176 
177  
178 
179      switch (message)
180 
181      {
182 
183      case WM_CREATE: {
184 
185          _RegisterTextBoxClass();    // 注冊文本框的類
186 
187          hTextBoxWnd = _CreateTextBoxWindow(hWnd); // 創建文本框
188 
189          } break;
190 
191  
192 
193      case WM_ACTIVATE:                // 當窗口被激活時,將焦點設置在文本框上
194 
195          ::SetFocus(hTextBoxWnd);
196 
197          break;
198 
199  
200 
201      case WM_SETCURSOR: {  // 設置光標形狀
202 
203          static HCURSOR hCursor = ::LoadCursor(NULL, IDC_ARROW);
204 
205          ::SetCursor(hCursor);
206 
207          } break;
208 
209  
210 
211      case WM_DESTROY:   // 應用程序被關閉
212 
213          ::PostQuitMessage(0);
214 
215          break;
216 
217  
218 
219      default:
220 
221          return ::DefWindowProc(hWnd, message, wParam, lParam);
222 
223      }
224 
225  
226 
227      return (LRESULT)0;
228 
229 }
230 
231  
232 
233 // 注冊文本框的類
234 
235 ATOM _RegisterTextBoxClass()
236 
237 {
238 
239      WNDCLASSEX wc;
240 
241      ::ZeroMemory(&wc, sizeof(wc));
242 
243  
244 
245      wc.cbSize     = sizeof(wc);
246 
247      wc.style      = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;   // 指定當窗口尺寸發生變化時重繪窗口,并且響應鼠標雙擊事件
248 
249      wc.hInstance  = _HInstance;
250 
251      wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); // 指定窗口背景顏色為系統顏色“窗口背景”
252 
253      wc.lpszClassName = _TextBoxClass;                  // 指定要注冊的窗口類名,創建窗口時要以此類名為標識符
254 
255      wc.lpfnWndProc     = _TextBoxWndProc;               // 處理窗口消息的函數
256 
257  
258 
259      return ::RegisterClassEx(&wc);                     // 調用API函數注冊文本框窗口
260 
261 }
262 
263  
264 
265  
266 
267 // 創建文本框
268 
269 HWND _CreateTextBoxWindow(HWND hParentWnd)
270 
271 {
272 
273      // 之下代碼是為了讓文本框顯示在父窗口中央,而計算位置
274 
275      RECT parentWndRect;
276 
277      ::GetClientRect(hParentWnd, &parentWndRect);  // 獲取父窗口客戶區的位置
278 
279      int left = (parentWndRect.right - TEXTBOX_WIDTH) / 2, top = (parentWndRect.bottom - TEXTBOX_HEIGHT) / 2;
280 
281  
282 
283      // 創建文本框
284 
285      HWND hWnd = ::CreateWindow(_TextBoxClass, NULL, WS_CHILDWINDOW | WS_VISIBLE,
286 
287          left, top, TEXTBOX_WIDTH, TEXTBOX_HEIGHT, 
288 
289          hParentWnd, NULL, _HInstance, NULL);
290 
291  
292 
293      return hWnd;
294 
295 }
296 
297  
298 
299 // 文本框消息的處理過程
300 
301 LRESULT CALLBACK _TextBoxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
302 
303 {
304 
305      switch (message)
306 
307      {
308 
309      case WM_PAINT: {  // 繪制這里之所以加一對大括號,是為了讓之下定義的變量局部化
310 
311  
312 
313          static PAINTSTRUCT ps;
314 
315          static RECT rect;
316 
317          HDC hDC = ::BeginPaint(hWnd, &ps);  // 開始繪制操作
318 
319  
320 
321          ::GetClientRect(hWnd, &rect);        // 獲取客戶區的尺寸
322 
323          ::DrawEdge(hDC, &rect, EDGE_SUNKEN, BF_RECT);  // 繪制邊框,EDGE_SUNKEN表示繪制樣式為內嵌樣式,BF_RECT表示繪制矩形邊框
324 
325          _DrawText(hDC);                      // 繪制文本
326 
327          ::EndPaint(hWnd, &ps);               // 結束繪制操作
328 
329  
330 
331          } break;
332 
333  
334 
335      case WM_SETFOCUS: {    // 獲得焦點
336 
337          ::CreateCaret(hWnd, (HBITMAP)NULL, 1, TEXTBOX_HEIGHT-5);     // 創建光標
338 
339          _SetCaretPos(hWnd);                            // 設置光標位置
340 
341          ::ShowCaret(hWnd);                   // 顯示光標
342 
343          } break;
344 
345  
346 
347      case WM_KILLFOCUS: // 失去焦點
348 
349          ::HideCaret(hWnd);                   // 隱藏光標
350 
351          ::DestroyCaret();                    // 銷毀光標
352 
353          break;
354 
355  
356 
357      case WM_SETCURSOR: {  // 設置光標形狀
358 
359          static HCURSOR hCursor = ::LoadCursor(NULL, IDC_IBEAM);
360 
361          ::SetCursor(hCursor);
362 
363          } break;
364 
365  
366 
367      case WM_CHAR: {    // 字符消息
368 
369          TCHAR code = (TCHAR)wParam;
370 
371          int len = ::_tcslen(_String);
372 
373          if(code < (TCHAR)' ' || len >= TEXTBOX_MAXLENGTH)
374 
375               return 0;
376 
377  
378 
379          ::MoveMemory(_String + _StringPosition + 1, _String + _StringPosition, (len - _StringPosition + 1* sizeof(TCHAR));
380 
381          _String[_StringPosition ++= code;
382 
383  
384 
385          _UpdateWindow(hWnd);
386 
387          _SetCaretPos(hWnd);
388 
389  
390 
391          } break;
392 
393  
394 
395      case WM_KEYDOWN: {  // 鍵按下消息
396 
397          TCHAR code = (TCHAR)wParam;
398 
399  
400 
401          switch (code)
402 
403          {
404 
405          case VK_LEFT: // 左光標鍵
406 
407               if(_StringPosition > 0)
408 
409                    _StringPosition --;
410 
411               break;
412 
413  
414 
415          case VK_RIGHT:     // 右光標鍵
416 
417               if(_StringPosition < (int)::_tcslen(_String))
418 
419                    _StringPosition ++;
420 
421               break;
422 
423  
424 
425          case VK_HOME: // HOME 鍵
426 
427               _StringPosition = 0;
428 
429               break;
430 
431  
432 
433          case VK_END:  // END 鍵
434 
435               _StringPosition = ::_tcslen(_String);
436 
437               break;
438 
439  
440 
441          case VK_BACK: // 退格鍵
442 
443               if(_StringPosition > 0)
444 
445               {
446 
447                    ::MoveMemory(_String + _StringPosition - 1, _String + _StringPosition, (::_tcslen(_String)-_StringPosition + 1* sizeof(TCHAR));
448 
449                    _StringPosition --;
450 
451                    _UpdateWindow(hWnd);
452 
453               }
454 
455               break;
456 
457  
458 
459          case VK_DELETE: {  // 刪除鍵
460 
461               int len = ::_tcslen(_String);
462 
463               if(_StringPosition < len)
464 
465               {
466 
467                    ::MoveMemory(_String + _StringPosition, _String + _StringPosition + 1, (::_tcslen(_String) - _StringPosition + 1* sizeof(TCHAR));
468 
469                    _UpdateWindow(hWnd);
470 
471               }
472 
473  
474 
475               } break;
476 
477  
478 
479          }
480 
481  
482 
483          _SetCaretPos(hWnd);
484 
485  
486 
487          } break;
488 
489  
490 
491      case WM_LBUTTONDOWN: {  // 鼠標單擊,設置光標位置
492 
493          int x = LOWORD(lParam);
494 
495          HDC hDc = ::GetDC(hWnd);
496 
497  
498 
499          int strLen = ::_tcslen(_String), strPos = 0;
500 
501          SIZE size;
502 
503  
504 
505          for (strPos=0; strPos<strLen; strPos++)
506 
507          {
508 
509               ::GetTextExtentPoint(hDc, _String, strPos, &size);
510 
511  
512 
513               if(size.cx + 4 >= x)
514 
515                    break;
516 
517          }
518 
519  
520 
521          _StringPosition = strPos;
522 
523          ::GetTextExtentPoint(hDc, _String, strPos, &size);
524 
525          ::SetCaretPos(size.cx + 43);
526 
527  
528 
529          ::ReleaseDC(hWnd, hDc);
530 
531  
532 
533          } break;
534 
535  
536 
537      default:
538 
539          return ::DefWindowProc(hWnd, message, wParam, lParam);
540 
541      }
542 
543  
544 
545      return (LRESULT)0;
546 
547 }
548 
549  
550 
551 // 更新窗口
552 
553 void _UpdateWindow(HWND hWnd)
554 
555 {
556 
557      RECT rect;
558 
559      ::GetClientRect(hWnd, &rect);
560 
561      ::InvalidateRect(hWnd, &rect, TRUE);
562 
563      ::UpdateWindow(hWnd);
564 
565 }
566 
567  
568 
569 // 繪制文本
570 
571 void _DrawText(HDC hDC)
572 
573 {
574 
575      int len = ::_tcslen(_String);
576 
577      ::TextOut(hDC, 42, _String, len);
578 
579 }
580 
581  
582 
583 // 設置光標位置
584 
585 void _SetCaretPos(HWND hWnd)
586 
587 {
588 
589      HDC hDC = ::GetDC(hWnd);
590 
591  
592 
593      SIZE size;
594 
595      ::GetTextExtentPoint(hDC, _String, _StringPosition, &size);
596 
597      ::SetCaretPos(4 + size.cx, 3);
598 
599  
600 
601      ::ReleaseDC(hWnd, hDC);
602 
603  
604 
605 }
606 
607 
posted on 2010-02-16 12:07 會飛的兔子 閱讀(10763) 評論(0)  編輯 收藏 引用 所屬分類: 系統API,底層技術
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            国内外成人在线视频| 欧美一区二区成人| 久久久精品免费视频| 韩国成人福利片在线播放| 欧美在线欧美在线| 久久九九久精品国产免费直播| 一区二区三区日韩在线观看| 国产一区二区三区高清播放| 欧美视频第二页| 久久综合中文色婷婷| 一本大道久久精品懂色aⅴ| 亚洲精品日韩一| 一区二区欧美亚洲| 一区二区免费在线观看| 亚洲精品小视频| 欧美 日韩 国产 一区| 亚洲视频在线播放| 亚洲小视频在线| 欧美一区国产在线| 亚洲天堂av电影| 亚洲乱码久久| 亚洲日本电影| 欧美在线一级视频| 欧美+亚洲+精品+三区| 欧美一区二区三区视频| 另类成人小视频在线| 久久精品网址| 亚洲国产成人av在线| 亚洲精品乱码久久久久久蜜桃91| 日韩亚洲欧美成人一区| 午夜精品在线视频| 久久xxxx| 欧美成人免费va影院高清| 亚洲精品一级| 久久裸体艺术| 欧美网站大全在线观看| 国产精品丝袜白浆摸在线| 国产精品久久久久久av福利软件| 在线观看日韩av先锋影音电影院| 在线观看亚洲精品视频| 亚洲自拍另类| 狠狠色狠狠色综合日日五| 在线亚洲国产精品网站| 久久久久国产精品www| 亚洲欧洲在线一区| 亚洲国产婷婷综合在线精品| 久久久久久有精品国产| 欧美人与禽性xxxxx杂性| 国产毛片一区| 欧美一区2区三区4区公司二百| 亚洲精品日韩在线观看| 欧美日本在线播放| 亚洲福利在线观看| 久久免费少妇高潮久久精品99| 亚洲国产另类久久久精品极度 | 美脚丝袜一区二区三区在线观看| 国产农村妇女精品一区二区| 99亚洲一区二区| 亚洲精品乱码久久久久久| 欧美日本免费一区二区三区| 亚洲午夜国产一区99re久久| 亚洲免费成人| 国产一区二区三区高清播放| 亚洲成在线观看| 免费成人网www| 亚洲午夜一区二区| 99国产精品国产精品久久| 日韩一级不卡| 樱花yy私人影院亚洲| 欧美成人69av| 欧美福利视频在线观看| 久久久噜噜噜久久中文字免| 免费在线观看一区二区| 亚洲精品乱码久久久久久按摩观| 亚洲靠逼com| 欧美激情 亚洲a∨综合| 香蕉国产精品偷在线观看不卡 | 欧美日韩一区二区在线| 欧美剧在线免费观看网站| 亚洲欧美在线免费| 欧美日本在线一区| 久久人人97超碰人人澡爱香蕉| 国产精品久久久久久久久久妞妞| 久久蜜臀精品av| 国产欧美精品一区aⅴ影院| 久久精品欧美| 国产亚洲一区在线播放| 亚洲精品网站在线播放gif| 亚洲电影网站| 欧美日韩在线播放| 一区二区高清视频在线观看| 亚洲三级免费电影| 欧美国产免费| 男女激情视频一区| 在线一区观看| 亚洲一区三区视频在线观看| 国产日韩欧美综合在线| 最新69国产成人精品视频免费| 亚洲一级黄色片| 国产精品视频1区| 午夜精品免费视频| 欧美大片在线影院| 午夜国产一区| 亚洲国产精品成人精品 | 午夜免费在线观看精品视频| 国产精品中文字幕欧美| 麻豆91精品| 午夜综合激情| 亚洲精品欧美日韩专区| 老司机免费视频久久| 欧美一区二区三区久久精品茉莉花| 一区二区视频免费在线观看| 国产精品二区二区三区| 欧美国内亚洲| 久久天天躁夜夜躁狠狠躁2022| 亚洲一区二区日本| 夜夜爽av福利精品导航 | 欧美一区不卡| 午夜老司机精品| 亚洲午夜精品久久久久久app| 亚洲国产精品久久久久婷婷老年| 国产日韩欧美精品综合| 欧美亚一区二区| 国产精品久久久久久久久久免费 | 亚洲精品国产精品久久清纯直播| 99国产精品99久久久久久粉嫩 | 久久久久免费观看| 亚洲国产一区二区三区a毛片| 亚洲精品视频在线| 久久精品在这里| 欧美一区二区女人| 国产精品成人av性教育| 久久婷婷综合激情| 美脚丝袜一区二区三区在线观看| 久久中文在线| 亚洲一二三四区| 欧美精彩视频一区二区三区| 国产伦精品一区二区三区免费迷| 亚洲黄一区二区三区| 99re热这里只有精品视频| 久久超碰97人人做人人爱| 欧美激情第一页xxx| 亚洲欧美中文在线视频| 欧美日韩亚洲一区二区| 国产综合激情| 久久国产88| 亚洲一区二区免费视频| 欧美精品性视频| 日韩一区二区精品视频| 久久午夜影视| 久久不射电影网| 国产色综合网| 久久精品国产亚洲一区二区三区| av成人免费| 国产精品久久九九| 亚洲尤物在线| 午夜精品亚洲| 国内外成人免费视频| 久久国产精品久久国产精品| 欧美一区二区三区精品| 国内精品久久久久久久影视麻豆| 久久久精品欧美丰满| 久久精品在线| 亚洲一区二区网站| 久久免费精品视频| 亚洲欧美高清| 欧美成人a视频| 国产区二精品视| 欧美无砖砖区免费| 一区二区三区在线观看国产| 欧美三区在线| 性久久久久久| 亚洲日本免费| 亚洲综合精品| 欧美国产精品日韩| 国产九区一区在线| aa级大片欧美| 性色一区二区三区| 99国产麻豆精品| 欧美日韩中文字幕精品| 精品999在线播放| 午夜老司机精品| 开心色5月久久精品| 亚洲婷婷免费| 久久亚洲精品欧美| 久久激情综合网| 国产精品成人在线| 欧美二区在线播放| 国际精品欧美精品| 一区二区av在线| 亚洲视频一二区| 欧美二区视频| 亚洲第一搞黄网站| 国内免费精品永久在线视频| 亚洲一区免费| 午夜精品在线看| 国产日韩欧美亚洲一区| 午夜视频在线观看一区二区| 亚洲欧美日韩另类精品一区二区三区 | 亚洲高清视频在线|