Как сделать прокрутку текстового поля win32 как на iPhone - PullRequest
0 голосов
/ 01 марта 2010

Я делаю программу на win32 для платформы Windows Mobile (тестирование на WM6.1). Большая часть главного окна состоит из одного текстового поля, и я хотел бы использовать его для прокрутки, а не для выделения текста. Как бы я поступил так?

Ответы [ 2 ]

1 голос
/ 09 марта 2010

Я получил его на работу. Это было не так тривиально, как я надеялся. Кстати, это должно работать на обычных Windows, а не только Windows Mobile. Это произошло примерно так:

При создании окна (как дочернего окна главного окна)


HWND createCustomDrawArea(const LPCTSTR className, const HWND hWndParent) {
    WNDCLASS wndClass = {
        CS_HREDRAW | CS_VREDRAW,
        (WNDPROC)wndProc,
        0,
        0,
        hInstMain,
        NULL,
        0,
        (HBRUSH)GetStockObject(HOLLOW_BRUSH),
        0,
        className
    };

    RegisterClass(&wndClass);

    return CreateWindow(
        className,
        className,
        WS_CHILD | WS_TABSTOP,
        0, 0, 0, 0,
        hWndParent,
        NULL,
        hInstMain,
        NULL
    );
}

Затем в основной функции (основной цикл сообщений): <pre> while(GetMessage(&msg, NULL, 0, 0)) { if(!handleScrollingMessages(msg.hwnd, msg.message, msg.wParam, msg.lParam) && !TranslateAccelerator(msg.hwnd, NULL, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } }

Я сделал это так, чтобы после того, как палец (мышь) опустился, вы можете переместить палец в другое место (это все еще в той же программе, но может находиться за пределами окна прокрутки), и он будет продолжать прокручиваться, пока вы не отпустите (мышь вверх). Обработчик сообщений выглядит так:


inline BOOL handleScrollingMessages(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    static BOOL mouseIsDown = FALSE;
    static BOOL isScrolling;
    static POINT firstMousePos;
    static POINT lastMousePos;
    POINT currentMousePos;

    switch(message) {
        case WM_MOUSEMOVE:
            if(!mouseIsDown) {
                return FALSE;
            }
            GetCursorPos(&currentMousePos);

            scrollText(currentMousePos.y - lastMousePos.y);
            if(!isScrolling && (
                firstMousePos.x  currentMousePos.x + FINGER_SCROLL_SENSITIVITY ||
                firstMousePos.y  currentMousePos.y + FINGER_SCROLL_SENSITIVITY
            )) {
                isScrolling = TRUE;
            }
            lastMousePos = currentMousePos;
            return TRUE;

        case WM_LBUTTONDOWN:
            if(hWnd == whichPrimaryIsVisible) {
                if(!mouseIsDown) {
                    GetCursorPos(&firstMousePos);
                    lastMousePos = firstMousePos;
                    mouseIsDown = TRUE;
                    isScrolling = FALSE;
                }
                return TRUE;
            }
            return FALSE;

        case WM_LBUTTONUP:
            if(mouseIsDown) {
                mouseIsDown = FALSE;
                if(isScrolling) {
                    isScrolling = FALSE;
                } else {
                    if(hWnd == whichPrimaryIsVisible) {
                        jumpToSong(HIWORD(lParam));
                    }
                }
                return TRUE;
            }
            return FALSE;
    }

    return FALSE;
}

В обычном обработчике сообщений вы должны перехватывать сообщения WM_ERASEBKGND и WM_PAINT:


        case WM_ERASEBKGND:
            if(hWnd == whichPrimaryIsVisible) {
                drawBackground(hWnd, (HDC)wParam);
                return 1;
            }
            return DefWindowProc(hWnd, message, wParam, lParam);

        case WM_PAINT:
            if(hWnd != hWndMain && drawWindowSection(hWnd)) {
                return 0;
            }
            return DefWindowProc(hWnd, message, wParam, lParam);

Затем вы должны нарисовать фон и текст (передний план) отдельно. Функция прокрутки выглядит следующим образом:


inline void scrollText(const int mouseChange) {
    RECT wholeAreaRect;
    RECT invalidatedRect;

    scrollPos += mouseChange;

    GetClientRect(whichPrimaryIsVisible, &wholeAreaRect);
    ScrollWindowEx(whichPrimaryIsVisible, 0, mouseChange, NULL, &wholeAreaRect, NULL, &invalidatedRect, SW_ERASE | SW_INVALIDATE);
    UpdateWindow(whichPrimaryIsVisible);
}

Имейте в виду, что whichPrimaryIsVisible - это окно прокрутки (глобальная переменная), а scrollPos - глобальное целое.

Единственное, что осталось, это drawBackground () и drawWindowSection (). Они длинные и запутанные в моей программе, так как я заставляю их делать другие вещи (которые связаны с рисованием окна BTW). Если вы действительно хотите этот код, отправьте мне сообщение или что-то. Также дайте мне знать, правильно ли я разместил информацию, поскольку я новичок в публикации на форумах и т. Д.

1 голос
/ 01 марта 2010

Не вдаваясь в технические подробности, вы должны смотреть на разделение события «мыши» на события «мыши» вниз и «вверх» мыши.

Выполните выбор для события up, если местоположение указателя не изменилось с момента события down. Поэтому вам нужно будет сохранить местоположение указателя на событии down.

Затем вы можете обработать событие перемещения указателя для выполнения прокрутки.

...