目前共有16篇帖子。 內容轉換:不轉換▼
 
點擊 回復
508 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)
 

本帖信息

點擊數:508 回複數:15
評論數: ?
作者:巨大八爪鱼
最後回復:巨大八爪鱼
最後回復時間:2016-4-27 10:17
 
©2010-2024 Arslanbar Ver2.0
除非另有聲明,本站採用創用CC姓名標示-相同方式分享 3.0 Unported許可協議進行許可。