API и FreeBasic. (дочерние окна-ScrollBar)

ScrollBar - контрол, необходимый для прокручивания определенной области, вмещающей данные большие по размеру, чем видимая область. Часть дочерних контролов имеют встроенные полосы прокрутки (EDIT, TREEVIEW, LISTVIEW...). Вызываются и прокручиваются они автоматически, когда область вмещенных данных вылезает за видимую часть. Но для обычных родительских окон автоматически работающих полос прокрутки не предусмотрено. В этом случае программист сам реализует данную возможность. Так же можно создать самостоятельный дочерний ScrollBar контрол , для которого так же нужно вручную реализовывать прокрутку. Надо сказать, что компания Майкрософт максимально облегчила задачу, поэтому реализация не сложна сама по себе.

Начнем с создания полос прокрутки для родительских окон. Различие таких полос от полос дочерних окон в том, что они не реагируют на действия клавиатуры, только на мышь. В первую очередь чтобы активировать данные полосы прокрутки для родительских окон, надо указать стили при создания окна WS_HSCROLL и\или WS_VSCROLL (горизонтальная и вертикальная соответственно). Можно использовать любую, можно использовать обе. По умолчанию диапазон прокрутки равен от 0 до 100, но его можно менять с помощью специальной функции SetScrollRange. Функция имеет пять параметров:

  • hWnd - хендл окна для которого выставлен ScrollBar или хендл контрола ScrollBar
  • nBar - флаг , определяющий прокрутку, может быть:
    • SB_HORZ - горизонтальная
    • SB_VERT - вертикальная
    • SB_CTL - определяет, что ScrollBar контрол дочернее окно, созданное программистом. В параметре Hwnd должен быть указан хендл этого контрола
  • nMinPos - минимальный диапазон прокрутки
  • nMaxPos - максимальный диапазон прокрутки
  • bRedraw - флаг перерисовки контрола ScrollBar

Как вы поняли данную функцию можно использовать как для родительского окна, так для вами созданного самостоятельного дочернего контрола ScrollBar.

Так же для получения диапазонов есть обратная функция GetScrollRange:

  • hWnd - хендл окна для которого выставлен ScrollBar или хендл контрола ScrollBar
  • nBar - флаг , определяющий прокрутку, может быть:
    • SB_HORZ - горизонтальная
    • SB_VERT - вертикальная
    • SB_CTL - определяет, что ScrollBar контрол дочернее окно, созданное программистом. В параметре Hwnd должен быть указан хендл этого контрола
  • nMinPos - адрес переменной для получения минимального диапазона прокрутки
  • nMaxPos - адрес переменной для получения максимального диапазона прокрутки

Сам по себе ползунок ScrollBar двигаться не будет, но при действиях произведенных на нем пользователем, в процедуру родительского окна посылаются сообщения WM_VSCROLL и WM_HSCROLL. Их и должен отловить программист. В первую очередь нужно принять во внимание уведомление в младшем слове(loword) параметра WPARAM. Список уведомлений:

  • SB_ENDSCROLL - конец скроллинга (отпущена кнопки мыши , удерживающая стрелку или полосу прокрутки контрола)
  • SB_LEFT - скроллинг в левом углу (только для дочерних контролов)
  • SB_RIGHT - скроллинг в правом углу (только для дочерних контролов)
  • SB_LINELEFT - сдвиг на одну колонку влево
  • SB_LINERIGHT - сдвиг на одну колонку вправо
  • SB_PAGELEFT - сдвиг на одну страницу влево
  • SB_PAGERIGHT - сдвиг на одну страницу вправо
  • SB_THUMBPOSITION - закончено передвижение бегунка, кнопка мыши отпущена
  • SB_THUMBTRACK - бегунок перемещается
  • SB_BOTTOM - Скроллинг в нижнем углу (только для дочерних контролов)
  • SB_TOP - скроллинг в верхнем углу (только для дочерних контролов)
  • SB_LINEDOWN - сдвиг на одну строчку вниз
  • SB_LINEUP - сдвиг на одну строчку вверх
  • SB_PAGEDOWN - сдвиг на одну страницу вниз
  • SB_PAGEUP - сдвиг на одну страницу вверх

Если уведомление будет равно SB_THUMBPOSITION или SB_THUMBTRACK, то в старшем слове (hiword) параметра WPARAM будет позиция ползунка, во всех остальных случаях hiword(wparam) не используется. Параметр LPARAM будет хранить хендл ScrollBar если конечно он реализован как дочернее окно.

Для того чтобы сместить ползунок существует функция SetScrollPos. Она имеет 4 параметра:

  • hWnd - хендл окна для которого выставлен ScrollBar или хендл контрола ScrollBar
  • nBar - флаг , определяющий прокрутку, может быть:
    • SB_HORZ - горизонтальная
    • SB_VERT - вертикальная
    • SB_CTL - определяет, что ScrollBar контрол дочернее окно, созданное программистом. В параметре Hwnd должен быть указан хендл этого контрола
  • nPos - новая позиция ползунка
  • bRedraw - флаг перерисовки контрола ScrollBar

Обратная функция , возвращающая расположения ползунка GetScrollPos имеет два параметра:

  • hWnd - хендл окна для которого выставлен ScrollBar или хендл контрола ScrollBar
  • nBar - флаг , определяющий прокрутку, может быть:
    • SB_HORZ - горизонтальная
    • SB_VERT - вертикальная
    • SB_CTL - определяет, что ScrollBar контрол дочернее окно, созданное программистом. В параметре Hwnd должен быть указан хендл этого контрола

Так же для установки и получения различных параметров (позиции ползунка, размеры страниц, диапазонов) ScrollBar есть функции GetScrollInfo и SetScrollInfo Использование их основывается на заполнении структуры SCROLLINFO . Так например для получения размера страницы нужно заполнить поля структуры: cbSize (размер структуры), fMask (указать маску SIF_PAGE), nPage (адрес переменной куда будет помещен размер страницы). Далее вызвать функцию GetScrollInfo и в 3 параметре функции передать указатель на структуру. Параметры функций GetScrollInfo и SetScrollInfo очень схожи с вышеописанными функциями, думаю сложностей быть не должно. Но если есть вопросы, задаем на форуме.

После того, как стало понятно как передвигать ползунок, становится наверно не очень понятно как же будет смещаться сама скроллируемая область. Тут важно понять принцип. Все движения скроллируемой области напрямую зависят от позиции ползунка. К примеру у нас рисунок до скроллинга находится в координатах 100х100 и мы сдвинули ползунок на 10 позиций вниз, то рисунок должен подняться на 10 пикселей вверх (то есть в координаты 100х90). Отсюда при получении сообщения WM_VSCROLL и соответствующих уведомлений нам нужно не только установить значение для ползунка с помощью SetScrollPos, но и установить новые координаты для рисунка и перерисовать видимую область.

Что касается самостоятельных дочерних контролов ScrollBar, то они как и все дочерние окна создаются с помощью функции CreateWindowEx, только с классом окна SCROLLBAR. Так же в стиле функции надо указать тип контрола (SB_HORZ - горизонтальный или SB_VERT - вертикальный). Для них можно строго определить нужный размер. Как я и писал выше они хорошо реагируют не только на мышь но и на клавиатуру, в том числе есть возможность переключаться между контролами по клавише TAB при установке стиля WS_TABSTOP.

А теперь пару примеров:

#INCLUDE "windows.bi"
Dim msg As MSG 
Dim As WNDCLASSEX wc
Dim As String NameClass="MyClass" 
Dim As HINSTANCE Hinst=GetModuleHandle(0) 

Function wndproc(hwnd As HWND, msg As Uinteger,_
    wparam As WPARAM, lparam As LPARAM) As Integer
    
    Static Button As HWND
    Static As Integer nPos, Ypos = 40
    
    Select Case msg
        Case WM_CREATE
            Button = CreateWindowEx(0,"button","Большая кнопка",WS_VISIBLE Or WS_CHILD,40,Ypos,200,400,hwnd,Cast(HMENU,1),0,0)
            SetScrollRange(hwnd,SB_VERT,0,400,TRUE)
        Case WM_VSCROLL
            If Loword(WPARAM) = SB_THUMBPOSITION Or Loword(WPARAM) = SB_THUMBTRACK Then
                nPos = Hiword(wParam)
                MoveWindow(Button,40,Ypos - nPos,200,400,TRUE)
                SetScrollPos(hwnd,SB_VERT,nPos,TRUE)                
            Endif
        Case WM_DESTROY
            PostQuitMessage(0)
    End Select
    Return DefWindowProc(hwnd,msg,wparam,lparam)
End Function

With wc
    .cbSize=SizeOf(WNDCLASSEX)
    .style=CS_HREDRAW Or CS_VREDRAW
    .lpfnWndProc=@wndproc
    .hInstance=Hinst
    .hIcon=LoadIcon(0,IDI_QUESTION)
    .hCursor=LoadCursor(0,IDC_ARROW)
    .hbrBackground=Cast(HBRUSH,COLOR_WINDOW)
    .lpszClassName=StrPtr(NameClass)
    .hIconSm=.hIcon
End With

If RegisterClassEx(@wc)=0 Then
    Print "Register error, press any key"
    Sleep
    End
Endif

CreateWindowEx(0,NameClass,"Окно со скроллингом",_
WS_VISIBLE Or WS_OVERLAPPEDWINDOW Or WS_VSCROLL,10,10,300,200,0,0,Hinst,0)

While GetMessage(@msg,0,0,0)
    TranslateMessage(@msg)
    DispatchMessage(@msg)
Wend

scrollbar.png

#INCLUDE "windows.bi"
Dim msg As MSG
Dim As WNDCLASSEX wc
Dim As String NameClass="MyClass"
Dim As HINSTANCE Hinst=GetModuleHandle(0)

Function wndproc(hwnd As HWND, msg As Uinteger,_
    wparam As WPARAM, lparam As LPARAM) As Integer

    Static As HWND Button, Scroll
    Static As Integer nPos, Ypos = 40

    Select Case msg
        Case WM_CREATE
            Button = CreateWindowEx(0,"button","Большая кнопка",WS_VISIBLE Or WS_CHILD,40,Ypos,200,400,hwnd,Cast(HMENU,1),0,0)
            Scroll = CreateWindowEx(0,"SCROLLBAR","",WS_VISIBLE Or WS_CHILD Or SB_VERT,10,10,20,100,hwnd,Cast(HMENU,2),0,0)
            SetScrollRange(Scroll,SB_CTL,0,400,TRUE)
        Case WM_VSCROLL
            Select Case Loword(WPARAM)
                Case SB_LINEUP
                    nPos = GetScrollPos(Scroll,SB_CTL)
                    nPos-=1
                    SetScrollPos(Scroll,SB_CTL,nPos,TRUE)
                Case SB_LINEDOWN
                    nPos = GetScrollPos(Scroll,SB_CTL)
                    nPos+=1
                    SetScrollPos(Scroll,SB_CTL,nPos,TRUE)
                Case SB_PAGEUP
                    nPos = GetScrollPos(Scroll,SB_CTL)
                    nPos-=10
                    SetScrollPos(Scroll,SB_CTL,nPos,TRUE)
                Case SB_PAGEDOWN
                    nPos = GetScrollPos(Scroll,SB_CTL)
                    nPos+=10
                    SetScrollPos(Scroll,SB_CTL,nPos,TRUE)
                Case SB_THUMBPOSITION,SB_THUMBTRACK
                    nPos = Hiword(wParam)
                    SetScrollPos(Scroll,SB_CTL,nPos,TRUE)
            End Select
            MoveWindow(Button,40,Ypos - nPos,200,400,TRUE)
        Case WM_DESTROY
            PostQuitMessage(0)
    End Select
    Return DefWindowProc(hwnd,msg,wparam,lparam)
End Function

With wc
.cbSize=SizeOf(WNDCLASSEX)
.style=CS_HREDRAW Or CS_VREDRAW
.lpfnWndProc=@wndproc
.hInstance=Hinst
.hIcon=LoadIcon(0,IDI_QUESTION)
.hCursor=LoadCursor(0,IDC_ARROW)
.hbrBackground=Cast(HBRUSH,COLOR_WINDOW)
.lpszClassName=StrPtr(NameClass)
.hIconSm=.hIcon
End With

If RegisterClassEx(@wc)=0 Then
    Print "Register error, press any key"
    Sleep
    End
Endif

CreateWindowEx(0,NameClass,"Окно со скроллингом",_
WS_VISIBLE Or WS_OVERLAPPEDWINDOW,10,10,300,200,0,0,Hinst,0)

While GetMessage(@msg,0,0,0)
    TranslateMessage(@msg)
    DispatchMessage(@msg)
Wend


scrollbar2.png

содержание | назад | вперед