使用滾動條
本節包含的示例代碼將引導您完成以下內容:
創建滾動條
滾動文字
滾動圖片
爲一個滾動條創建鍵盤接口
創建滾動條
無論創建一個重疊,彈出,或是子窗口時,您都可以在CreateWindowEx函數(第三個參數)中註明WS_HSCROLL, WS_VSCROLL(或者兩者一起)來創建一個水平或豎直滾動條(或兩者都有)。下面這個例子創建了一個包含了水平和豎直滾動條的窗口。
0L, // 無拓展樣式
"MyAppClass", // 窗口類別名
"Scroll Bar Application", // 窗口標題
WS_OVERLAPPEDWINDOW | // 窗口樣式
WS_HSCROLL |
WS_VSCROLL,
CW_USEDEFAULT, // 默認的水平位置
CW_USEDEFAULT, // 默認的豎直位置
CW_USEDEFAULT, // 默認寬度
CW_USEDEFAULT, // 默認高度
(HWND) NULL, // 沒有父窗口
(HMENU) NULL, // 窗口菜單
hinst, // 窗口所有者爲一個實例(猜的)
(LPVOID) NULL // 不需要指針(猜的)
);
爲了處理滾動條消息,必須在主窗口程序中加入正確的代碼。
當使用CreateWindowEx函數創建一個窗口的時候,你可以通過指定滾動條樣式來創建一個滾動條。而創建水平還是豎直滾動條由窗口樣式是由指定的是SBS_HORZ還是SBS_VERT決定(這裏不知道他爲什麼要寫成不同,事實證明用哪種定義方式看起來是完全相同的)。滾動條大小和相對於它的副窗口的位置關係也可以指定。下面這個例子創建了一個在左上方的水平滾動條。
0L, // 沒有拓展樣式(猜的)
"SCROLLBAR", // 滾動條控制類
(LPSTR) NULL, // 窗口標題
WS_CHILD | SBS_HORZ, // 滾動條樣式
0, // 水平位置
0, // 豎直文字
200, // 滾動條長度
CW_USEDEFAULT, // 默認高度
hwnd, // 主窗口句柄
(HMENU) NULL, // 滾動條沒有菜單
hinst, // 擁有此窗口的是一個實例
(LPVOID) NULL // 不需要指針
);
滾動文字
這一節介紹瞭如何改變窗口主程序使用戶可以滾動文字。在“滾動文字示例程序”將通過處理WM_HSCROLL和WM_VSCROLL消息來顯示超出範圍的文字,以實現滾動水平和豎直的文字。
滾動文字與WM_CREATE消息
滾動模塊一般在處理WM_CREATE消息時進行參數設定。滾動條可以非常方便的根據由設備句柄提供的字體的大小信息來進行設定,您可以使用GetTextMetrics函數和具體的設備句柄來取得需要的字體信息。
正如示例程序中所示範的,一個垂直滾動條與文字的高度加行間距的和有關。一個水平滾動條與文字的平均寬度有關。因此,水平滾動條的位置不應該完全對應於實際字符,除非顯示的字體的寬度是固定的。
滾動文字與WM_SIZE消息
當處理WM_SIZE消息時,可以很方便地調整滾動條的範圍和位置,這麼做可以根據用戶區域改變顯示出的文本行數。SetScrollInfo函數可以設定這些東東(包括最小範圍和最大範圍,頁面大小還有滾動條的位置等)。
滾動文字與WM_HSCROLL和WM_VSCROLL消息
無論是點擊還是釋放滾動條,都會受到一個WM_HSCROLL或者WM_VSCROLL消息。WM_HSCROLL和WM_VSCROLL返回值的低字組包含了一個消息代碼以表示對滾動條進行了何種動作。
當窗口被滾動的時候,窗口的一部分會被標示爲無效區域(更新區域),如果要更新這個區域可以調用UpdateWindow函數直接產生一個WM_PAINT消息。
滾動文字與WM_PAINT消息
當處理WM_PAINT消息的時候,你應該在繪製那些要在窗口上顯示的文字。下面的例子使用了當前滾動位置和無效區域大小確定顯示文字的範圍。
下面這個示例程序示範瞭如何調整文字來響應水平和垂直滾動條:
PAINTSTRUCT ps;
TEXTMETRIC tm;
SCROLLINFO si;
// 這些變量保存了現實文字需要的信息
static int xClient; // 客戶區域寬度
static int yClient; // 客戶區域高度
static int xClientMax; // 客戶區域最大寬度
static int xChar; // 水平滾動單位
static int yChar; // 豎直滾動單位
static int xUpper; // 大寫字母平均寬度
static int xPos; // 水平滾動條當前位置
static int yPos; // 豎直滾動條當前位置
int i; // 循環計數器
int x, y; // 水平和豎直的座標
int FirstLine; // 顯示區域的第一行
int LastLine; // 顯示區域的最後一行
HRESULT hr;
size_t * abcLength; // abc[] 的長度
// 創建一個數組儲存需要顯示的文字
#define LINES 28
static TCHAR *abc[] = {
TEXT("anteater"), TEXT("bear"), TEXT("cougar"),
TEXT("dingo"), TEXT("elephant"), TEXT("frog"),
TEXT("gazelle"), TEXT("hyena"), TEXT("iguana"),
TEXT("jackal"), TEXT("kangaroo"), TEXT("llama"),
TEXT("moose"), TEXT("newt"), TEXT("octopus"),
TEXT("penguin"), TEXT("quail"), TEXT("rat"),
TEXT("squid"), TEXT("tortoise"), TEXT("urus"),
TEXT("vole"), TEXT("walrus"), TEXT("xylophone"),
TEXT("yak"), TEXT("zebra"),
TEXT("This line contains words, but no character. Go figure."),
TEXT("")
};
switch (uMsg)
{
case WM_CREATE :
// 取得設備類型的句柄
hdc = GetDC (hwnd);
// 取得文字大小信息
GetTextMetrics (hdc, &tm);
xChar = tm.tmAveCharWidth;
xUpper = (tm.tmPitchAndFamily & 1 ? 3 : 2) * xChar/2;
yChar = tm.tmHeight + tm.tmExternalLeading;
// 釋放設備類型句柄
ReleaseDC (hwnd, hdc);
// 設置顯示的文字的最大寬度
// (其中包括個小寫字母和2個大寫字母)
xClientMax = 48 * xChar + 12 * xUpper;
return 0;
case WM_SIZE:
// 取得顯示區域的大小
yClient = HIWORD (lParam);
xClient = LOWORD (lParam);
// 設定豎直滾動條範圍和頁面大小
si.cbSize = sizeof(si);
si.fMask = SIF_RANGE | SIF_PAGE;
si.nMin = 0;
si.nMax = LINES - 1;
si.nPage = yClient / yChar;
SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
// 設置水平滾動條的範圍和頁面大小
si.cbSize = sizeof(si);
si.fMask = SIF_RANGE | SIF_PAGE;
si.nMin = 0;
si.nMax = 2 + xClientMax / xChar;
si.nPage = xClient / xChar;
SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);
return 0;
case WM_HSCROLL:
// 取得水平滾動條的信息
si.cbSize = sizeof (si);
si.fMask = SIF_ALL;
// 保存以便於等會進行比較
GetScrollInfo (hwnd, SB_HORZ, &si);
xPos = si.nPos;
switch (LOWORD (wParam))
{
// 用戶點擊了左箭頭
case SB_LINELEFT:
si.nPos -= 1;
break;
// 用戶點擊了右箭頭
case SB_LINERIGHT:
si.nPos += 1;
break;
// 用戶點擊連滾動條左邊的區域
case SB_PAGELEFT:
si.nPos -= si.nPage;
break;
// 用戶點擊連滾動條右邊的區域
case SB_PAGERIGHT:
si.nPos += si.nPage;
break;
// 用戶拖動了滾動條
case SB_THUMBTRACK:
si.nPos = si.nTrackPos;
break;
default :
break;
}
// 設定並儲存位置,如果超出範圍Window會自動處理的
si.fMask = SIF_POS;
SetScrollInfo (hwnd, SB_HORZ, &si, TRUE);
GetScrollInfo (hwnd, SB_HORZ, &si);
// 如果位置變了就滾動屏幕
if (si.nPos != xPos)
{
ScrollWindow(hwnd, xChar * (xPos - si.nPos), 0, NULL, NULL);
}
return 0;
case WM_VSCROLL:
// 取得豎直滾動條的信息
si.cbSize = sizeof (si);
si.fMask = SIF_ALL;
GetScrollInfo (hwnd, SB_VERT, &si);
// 保存以便於等會進行比較
yPos = si.nPos;
switch (LOWORD (wParam))
{
// 當用戶按了HOME按鈕
case SB_TOP:
si.nPos = si.nMin;
break;
// 當用戶按了 END 按鈕
case SB_BOTTOM:
si.nPos = si.nMax;
break;
// 用戶點擊了上箭頭
case SB_LINEUP:
si.nPos -= 1;
break;
// 用戶點擊了下箭頭
case SB_LINEDOWN:
si.nPos += 1;
break;
// 用戶點擊了滾動條下面的區域
case SB_PAGEUP:
si.nPos -= si.nPage;
break;
// 用戶點擊了滾動條上面的區域
case SB_PAGEDOWN:
si.nPos += si.nPage;
break;
// 用戶拖動了滾動條
case SB_THUMBTRACK:
si.nPos = si.nTrackPos;
break;
default:
break;
}
// 設定並儲存位置,如果超出範圍Window會自動處理的
si.fMask = SIF_POS;
SetScrollInfo (hwnd, SB_VERT, &si, TRUE);
GetScrollInfo (hwnd, SB_VERT, &si);
// 如果位置變了就滾動並更新屏幕
if (si.nPos != yPos)
{
ScrollWindow(hwnd, 0, yChar * (yPos - si.nPos), NULL, NULL);
UpdateWindow (hwnd);
}
return 0;
case WM_PAINT :
// 爲繪製窗口做準備
hdc = BeginPaint (hwnd, &ps);
// 取得豎直滾動條的位置
si.cbSize = sizeof (si);
si.fMask = SIF_POS;
GetScrollInfo (hwnd, SB_VERT, &si);
yPos = si.nPos;
// 取得水平滾動條的位置
GetScrollInfo (hwnd, SB_HORZ, &si);
xPos = si.nPos;
// 計算繪製的範圍
FirstLine = max (0, yPos + ps.rcPaint.top / yChar);
LastLine = min (LINES - 1, yPos + ps.rcPaint.bottom / yChar);
for (i = FirstLine; i <= LastLine; i++)
{
x = xChar * (1 - xPos);
y = yChar * (i - yPos);
// Note that "55" in the following depends on the
// maximum size of an abc[] item.
//
hr = StringCchLength(abc[i], 55, abcLength);
if ((FAILED(hr))|(abcLength == NULL))
{
//
// TODO: 加入出錯代碼
//
}
}
// 繪圖完畢
EndPaint (hwnd, &ps);
return 0;
case WM_DESTROY :
PostQuitMessage (0);
return 0;
}
return DefWindowProc (hwnd, uMsg, wParam, lParam);
}
滾動圖片
(無關就不翻譯了)
爲一個滾動條創建鍵盤接口
(還沒有學到,也不翻譯了)