目前共有16篇帖子。 字体大小:较小 - 100% (默认)▼  内容转换:港澳繁體▼
 
点击 回复
1070 15
【API】ScrollWindow和ScrollWindowEx的用法
一派掌门 二十级
1楼 发表于:2016-4-26 21:10
ScrollWindow(hWnd, 水平滾動量, 垂直滾動量, NULL, NULL);
UpdateWindow(hWnd);

當水平滾動量為負時向左滾動,為正時向右滾動。
垂直滾動量為負時向上滾動,為正時向下滾動。
滾動後最好調用UpdateWindow函數立即執行WM_PAINT。雖然不調用這個函數最終WM_PAINT也會執行,但是系統會拖到所有其他消息都處理完畢了才執行,有時會影響用戶體驗。
第三、四個參數一般為NULL,即滾動整個窗口。

滾動後,系統會自動將暴露出來的空白部分交給WM_PAINT繪製。

如果使用Ex版本的話,一般使用:
ScrollWindowEx(hWnd, -40, 0, NULL, NULL, NULL, NULL, SW_INVALIDATE);
一派掌门 二十级
2楼 发表于:2016-4-26 21:10
【示例程序】
#include <tchar.h>
#include <Windows.h>

BITMAP bmp;
HBITMAP hbmp;

int nScrolled = 0;

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    HDC hdc, hdcMem;
    PAINTSTRUCT ps;

    switch (uMsg)
    {
    case WM_CHAR:
        if (wParam == '+')
        {
            nScrolled = 1;
            //ScrollWindowEx(hWnd, -40, 0, NULL, NULL, NULL, NULL, SW_INVALIDATE);
            ScrollWindow(hWnd, -40, 0, NULL, NULL);
            UpdateWindow(hWnd);
        }
        else if (wParam == '-')
        {
            nScrolled = 2;
            ScrollWindow(hWnd, +40, 0, NULL, NULL);
            UpdateWindow(hWnd);
        }
        break;
    case WM_CREATE:
        hbmp = (HBITMAP)LoadImage(NULL, TEXT("img21.bmp"), IMAGE_BITMAP, NULL, NULL, LR_LOADFROMFILE);
        GetObject(hbmp, sizeof(bmp), &bmp);
        break;
    case WM_DESTROY:
        DeleteObject(hbmp);
        PostQuitMessage(0);
        break;
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        if (nScrolled > 0)
        {
            HBRUSH hbr;
            RECT rcClient;
            GetClientRect(hWnd, &rcClient);
            if (nScrolled == 1)
                hbr = CreateSolidBrush(RGB(0, 0, 255));
            else
                hbr = CreateSolidBrush(RGB(0, 255, 0));
            FillRect(hdc, &rcClient, hbr);
            DeleteObject(hbr);
        }
        else
        {
            hdcMem = CreateCompatibleDC(hdc);
            SelectObject(hdcMem, hbmp);
            BitBlt(hdc, 0, 0, bmp.bmWidth, bmp.bmHeight, hdcMem, 0, 0, SRCCOPY);
            DeleteDC(hdcMem);
        }
        EndPaint(hWnd, &ps);
        break;
    default:
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    return FALSE;
}

int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
    WNDCLASSEX wcex;
    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.cbClsExtra = wcex.cbWndExtra = 0;
    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcex.hIcon = wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
    wcex.hInstance = hInstance;
    wcex.lpfnWndProc = WndProc;
    wcex.lpszClassName = TEXT("Scrolling Demo Window");
    wcex.lpszMenuName = NULL;
    wcex.style = NULL;
    RegisterClassEx(&wcex);

    HWND hWnd = CreateWindow(wcex.lpszClassName, TEXT("Scrolling Demo"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return 0;
}
 
一派掌门 二十级
3楼 发表于:2016-4-26 21:13
在上面的程序中,按下+鍵窗口向左滾動,並將nScrolled設為1。如果按下-鍵則向右滾動,並將nScrolled設為2。程序剛啟動時nScrolled值為0。
WM_PAINT的執行內容是:當nScrolled為0時繪製一張BMP圖片,為1時將整個屏幕刷成藍色,為2時刷成綠色。(這是為了方便觀察ScrollWindow將窗口哪些區域設為了無效區域)
 
一派掌门 二十级
4楼 发表于:2016-4-26 21:14
原窗口:

 
一派掌门 二十级
5楼 发表于:2016-4-26 21:14
按下+後:

藍色部分為ScrollWindow創建的無效區域。
 
一派掌门 二十级
6楼 发表于:2016-4-26 21:17
按下-後:

綠色部分為ScrollWindow創建的無效區域。

注意:如果在WM_PAINT中繪製時將圖像畫在了無效區域以外,那麼這部分圖像將不會顯示出來。因為Windows為了提高性能,更新窗口時只將無效區域中的像素傳送給顯示器顯示。
 
一派掌门 二十级
7楼 发表于:2016-4-26 21:34
當ScrollWindow的第四個參數不為NULL時,滾動區域僅為該參數指定的矩形區域,並重繪暴露出來的區域。
 
一派掌门 二十级
8楼 发表于:2016-4-26 22:00

圖中紅色矩形為滾動區域。
A的坐標為(50, 50)
B的坐標為(200, 150)
C區域的寬度為40
 
一派掌门 二十级
9楼 发表于:2016-4-26 22:05

當第三個參數不為NULL時,該函數直接把這塊矩形區域剪下來往指定方向移動,並重繪暴露出來的區域。
例如這裏把rect矩形剪下來直接往左平移到(10, 50)處,然後把暴露出來的區域交給WM_PAINT重繪。
 
一派掌门 二十级
10楼 发表于:2016-4-26 22:14
 
一派掌门 二十级
11楼 发表于:2016-4-26 22:18
樓上是第三、四個參數都不為NULL的例子。

總的來說,第三個參數決定要把哪塊區域剪下來平移(如果為NULL就把整個客戶區剪下來平移),第四個參數是決定平移之後哪塊區域需要反映到屏幕上(如果為NULL的話就把所作的改動全部反映到屏幕上)。
平移後暴露出來的區域都會自動交給WM_PAINT處理。
 
一派掌门 二十级
12楼 发表于:2016-4-26 22:27
至於ScrollWindowEx函數,前四個完全一樣。
第六個是輸出參數,表示滾動後哪個區域暴露出來了。
例如在上面的程序中(160,50)(200,70)這塊40x20的矩形就被暴露出來了。
 
一派掌门 二十级
13楼 发表于:2016-4-26 22:36
第五個參數和第六個參數作用一樣,只不過是HRGN類型的變量(存放任意形狀的區域)。
 
一派掌门 二十级
14楼 发表于:2016-4-26 22:38

當重繪區域是不規則圖形時,HRGN能精確地保存這個區域。
 
一派掌门 二十级
15楼 发表于:2016-4-26 22:40

但是RECT不能精確保存這個區域。它只能表示重繪區域所在的最小矩形區域。
 
一派掌门 二十级
16楼 发表于:2016-4-27 10:17
//  返回值表示操作是否成功
BOOL ScrollDC(HDC hDC, int dx, int dy, const RECT *lprcScroll,  const RECT *lprcClip, HRGN hrgnUpdate, LPRECT lprcUpdate);
BOOL ScrollWindow(HWND hWnd, int XAmount, int YAmount, const RECT *lpRect, const RECT *lpClipRect);

// 返回值: 暴露出據矩形區域SIMPLEREGION,非矩形區域COMPLEXREGION,無暴露區域NULLREGION;操作失敗ERROR
int ScrollWindowEx(HWND hWnd, int dx, int dy, const RECT *prcScroll, const RECT *prcClip, HRGN hrgnUpdate, LPRECT prcUpdate, UINT flags);
 

回复帖子

内容:
用户名: 您目前是匿名发表
验证码:
(快捷键:Ctrl+Enter)
 

本帖信息

点击数:1070 回复数:15
评论数: ?
作者:巨大八爪鱼
最后回复:巨大八爪鱼
最后回复时间:2016-4-27 10:17
 
©2010-2025 Purasbar Ver2.0
除非另有声明,本站采用知识共享署名-相同方式共享 3.0 Unported许可协议进行许可。