我們都知道在 console 版的 c++ 中,我們要將文字顯示在螢幕上
可以使用 cout << 將文字顯示在螢幕上,而進到視窗版的 c++ 又要如何處理呢?
今天就來聊聊兩個函式 DrawText() 和 TextOut()
int DrawText(
HDC hdc,
LPCTSTR lpchText,
int cchText,
LPRECT lprc,
UINT format
);
HDC hdc, 輸出標的指引碼
LPCTSTR lpchText, 字串,指標
int cchText, 字串的長度,如果字串是以零字碼結尾,此值必須為-1
LPRECT lprc, 要書寫文字所在的矩形範圍,指標
UINT format 排置方式旗標
這個 format 可選擇的選項太多了,請自行上微軟官網看一看
https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-drawtext
到目前為止,我比較不用 DrawText() 這個函式,個人喜歡 TextOut()
或許是...我也還是新手,還沒找到讓他發揮的空間吧
DrawText 還有一個擴充版函式 DrawTextEx 也請自行上微軟官網一趟,瞧個仔細
再來就是 TextOut()
BOOL TextOutA(
HDC hdc, 輸出標的指引碼
int x, 起始點之X座標
int y, 起始點之Y座標
LPCSTR lpString, 字串,指標
int c 字串長度(不接受零字碼結尾之字串)
);
想不到微軟官網稱為 TextOutA ,好吧!多個 A 就多個 A
TextOut也有一個擴充版函式 ExTextOut() 以及跳格輸出文字 TabbedTextOut()
好了,我們就稍微瞄一下程式碼,在一些程式碼要配合修改的地方就稍微修改一下,
在 LRESULT CALLBACK WndProc() 內增加一下宣告和字串
RECT rect;
RECT 是微軟設定好的矩形結構,我們就跟著宣告一個 rect 來給 DrawText() 函數中使用
TCHAR szstr[] = "最美麗的風景從這裡開始...DrawText( )";
TCHAR szstr2[] = "最堅定的美麗風景在這裡...TextOut( )";
static UINT dwformat = 0;
就是這個 dwformat 有一大堆選項,你可以在宣告這裡改變一下成非0數值看看他的變化,
在 case WM_PAINT: 內就套套函式 DrawText() TextOut()
記得 case IDM_Bottom: 也改一下
dwformat = DT_SINGLELINE | DT_BOTTOM; 這個參數是可以搭配使用的
InvalidateRect(hwnd, NULL, TRUE);
由於WM_PAINT訊息的優先權很低,而且我們無法預期視窗何時有空可以處理這個訊息,這種情況下,
如果有特定的需要,必須馬上更新顯示內容,而不想讓WM_PAINT訊息一直被動的留在訊息佇列裡等待處理,
可以透過 InvalidateRect()函式指定視窗的某個範圍為無效區域之後接著呼叫 UpdateWindow()函式,
強制更新視窗的畫面,這種情況系統會直接要求視窗程序立刻處理WM_PAINT訊息而不是僅放在訊息佇列裡排隊等待
。,、'﹕︰﹔﹖﹑•!?!﹪%*﹡﹢ 我是可愛的分隔線 〈〉『』〖〗[]《》〔〕 「」【】﹁﹃︻﹂﹄︼
resource.rc
#define IDM_Demo1 1001 // 設定選單識別碼
#define IDM_Bottom 1002 ///// 配合修改一下
DODO MENU
{
POPUP "檔案 "
{
MENUITEM "&開新檔案", IDM_Demo1
// 請自行增加其他功能 例如: MENUITEM "&開啟舊檔", IDM_Demo11
// 所有想歸類在 "檔案 " 底下的功能選項都寫在這邊
}
POPUP "編輯"
{
MENUITEM "&文字置底", IDM_Bottom ///// 配合修改一下
// 你還可以增加任何你要的功能..如:畫兩條線...
}
}
。,、'﹕︰﹔﹖﹑•!?!﹪%*﹡﹢ 我是可愛的分隔線 〈〉『』〖〗[]《》〔〕 「」【】﹁﹃︻﹂﹄︼
main.cpp
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define IDM_Demo1 1001
#define IDM_Bottom 1002 //
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
char szAppName[] = "HelloWin";
HWND hwnd ;
MSG msg ;
WNDCLASSEX wndclass ;
wndclass.cbSize = sizeof(WNDCLASSEX) ;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = GetSysColorBrush(COLOR_3DFACE); //3DFACE);
wndclass.lpszMenuName = "DODO";
wndclass.lpszClassName = szAppName ;
wndclass.hIconSm = 0 ;
RegisterClassEx (&wndclass);
hwnd = CreateWindowEx (
0,
szAppName,
"Graph 繪製圖形",
WS_OVERLAPPEDWINDOW,
0,0,800,500,
NULL,
NULL,
hInstance,
NULL) ;
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam,
LPARAM lParam)
{
PAINTSTRUCT ps; // 若改用這樣則不會閃爍 //*
RECT rect;
TCHAR szstr[] = "最美麗的風景從這裡開始...DrawText( )";
TCHAR szstr2[] = "最堅定的美麗風景在這裡...TextOut( )";
static UINT dwformat = 0;
switch (message)
{
HDC hdc;
case WM_PAINT:
// hdc = GetDC(hwnd);
hdc = BeginPaint(hwnd,&ps); // 若改用這樣則不會閃爍 //*
// SetRect(&rect, 32,32,280,64); // 選擇一 自己決定顯示位置
GetClientRect(hwnd, &rect); // 選擇二 dwformatd 控制顯示位置
// 二選一 看你要註標掉哪一個
DrawText(hdc, szstr, -1, &rect, dwformat); // 第三個參數 -1 你也可以試試直接給字數
TextOutA(hdc, 50, 50, szstr2, 36); // 可以直接計算字數...中文字要算2
TextOut(hdc, 80, 80, szstr2, sizeof(szstr2)-1); // 記得 sizeof(szstr2) 要 -1
// ReleaseDC(hwnd,hdc);
EndPaint(hwnd,&ps); // 若改用這樣則不會閃爍 //*
return 0;
case WM_CREATE:
return 0 ;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDM_Demo1:
break;
case IDM_Bottom: //
{
dwformat = DT_SINGLELINE | DT_BOTTOM;
InvalidateRect(hwnd, NULL, TRUE);
}
break;
}
return 0 ;
case WM_DESTROY:
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
延伸閱讀
.