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

Pager - это один из контролов, по которому оказалось трудно найти информацию на русском языке. По своей сути данный контрол является контейнером для других дочерних окон, не имеющих достаточного места. Pager позволяет делать скроллинг не умещающихся контролов. Чаще всего Pager применяют для скроллинга тулбара из-за того, что некоторым пользователям кнопок на тулбаре может не хватать. Но можно использовать для любого контрола. Как раз в нашем примере для простоты мы в контейнер поместим простую кнопку.

Иногда бывает, что в заголовках к компилятору FreeBasic содержатся ошибки или попросту не объявлены какие-то константы, декларации и пр. Я устал на оф. сайте доказывать их нужность или правильность... Так и в этот раз была найдена ошибка с помощью одного из пользователей форума SARG (создателя FbDebugger) в структуре NMPGSCROLL. Мы попросту в примере ниже объявим эту структуру правильно под другим именем. И конечно объявим нужные нам константы.

Pager контрол имеет свойство выставлять размер дочернего элемента автоматически по своему размеру. В результате чего отпадает надобность заботиться о размерах его дочернего элемента. Так например, если мы изменим размер Pager с помощью MoveWindow , то автоматически изменятся размеры его дочернего элемента.

Создается Pager как обычно функцией CreateWindowEx с классом окна SysPager. В его стиле должен быть указан один из стилей PGS_HORZ или PGS_VERT , которые означают горизонтальную или вертикальную прокрутку соответственно. Далее создается его дочерний элемент и ему в функции CreateWindowEx в девятом параметре указывается родительским окном хендл Pager. Следом должно быть послано сообщение PGM_SETCHILD контролу Pager с указанием хендла дочернего элемента в параметре LPARAM.

Для того чтобы появилась возможность скроллинга дочернего элемента Pager, нужно обработать сообщение WM_NOTIFY с его кодами извещения PGN_CALCSIZE и PGN_SCROLL. По первому коду извещения устанавливаются размеры рабочей поверхности скроллинга в пикселях. По второму извещению ставится шаг скроллинга в пикселях.

По получению извещения PGN_CALCSIZE , в параметре LPARAM будет предоставлен указатель на структуру NMPGCALCSIZE , в параметр iWidth или iHeight которой (в зависимости от прокрутки, которая указывается изначально при создании Pager), нужно указать величину размера прокручиваемой поверхности.

При получении извещения PGN_SCROLL, система передаст нам указатель на структуру NMPGSCROLL в параметре LPARAM. В один из параметров ( iScroll ) этой структуры (в нашем примере NMPGSCROLL2) , нужно указать смещение на сколько пикселей необходимо смещаться при нажатии на кнопку скроллинга.

И конечно пример для потверждения вышеописанного:

#INCLUDE "windows.bi"
#INCLUDE "win/commctrl.bi"

#IFNDEF PGN_SCROLL
#DEFINE PGN_SCROLL (PGN_FIRST-1)
#ENDIF
#IFNDEF PGN_CALCSIZE
#DEFINE PGN_CALCSIZE    (PGN_FIRST-2)
#ENDIF

Type NMPGSCROLL2 Field=1
    As NMHDR hdr
    As Short fwKeys
    As RECT  rcParent
    As Integer   iDir
    As Integer   iXpos
    As Integer   iYpos
    As  Integer   iScroll
End Type

Dim msg As MSG
Dim As WNDCLASSEX wc
Dim As String NameClass="MyClass"
Dim As HINSTANCE Hinst=GetModuleHandle(0)

' Для систем Windows XP 
' и может быть более ранних версий Windows
' нужен вызов функции InitCommonControlsEx
' для 100% загрузки comctl32.dll
' такой вот баг хрюши, 
' кстати сказать далеко не единственный
' спасибо пользователю miver, что напомнил и помог
' дополнить исходный код

Dim InitCtrlEx As InitCommonControlsEx
InitCtrlEx.dwSize = Sizeof(InitCommonControlsEx)
InitCtrlEx.dwICC  = ICC_STANDARD_CLASSES
InitCommonControlsEx(@InitCtrlEx)

Function wndproc(hwnd As HWND, msg As Uinteger,_
    wparam As WPARAM, lparam As LPARAM) As Integer
    Static As HWND hButton,hPager
    Select Case msg
        Case WM_CREATE
            hPager = CreateWindowEx( 0, "SysPager", 0,_
            WS_CHILD+PGS_HORZ+WS_VISIBLE,_
            10, 10, 100, 20, hwnd, Cast(HMENU,1000), 0, 0)
            hButton = CreateWindowEx(0,"Button",_
            "Это очень длинная кнопка",WS_VISIBLE Or WS_CHILD,_
            0,0,0,0,hPager,Cast(HMENU,1),0,0)
            SendMessage(hPager,PGM_SETCHILD,0,Cast(Lparam,hButton))
            SendMessage(hPager,PGM_SETBKCOLOR,0, &hFF00FF)
        Case WM_NOTIFY
            Dim As NMHDR Ptr nmhdr = Cast(NMHDR Ptr,lParam)
            If nmhdr->code = PGN_CALCSIZE Then
                Dim As NMPGCALCSIZE Ptr nmcal = Cast(NMPGCALCSIZE Ptr,lParam)
                If  nmcal->dwFlag = PGF_CALCWIDTH Then
                    nmcal->iWidth = 200
                Endif
            Elseif nmhdr->code = PGN_SCROLL Then
                Dim As NMPGSCROLL2 Ptr nmgs = Cast(NMPGSCROLL2 Ptr,lParam)
                nmgs->iScroll = 40
            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_WINLOGO)
    .hCursor=LoadCursor(0,IDC_ARROW)
    .hbrBackground=Cast(HBRUSH,COLOR_WINDOWFRAME)
    .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,100,100,150,100,0,0,Hinst,0)

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


pager.png

Дополнительно:

Стили Pager:

  1. PGS_AUTOSCROLL - Пейджер будет прокручиваться, когда пользователь наводит курсор мыши на одну из кнопок прокрутки.
  2. PGS_DRAGNDROP - The contained window can be a drag-and-drop target. The pager control will automatically scroll if an item is dragged from outside the pager over one of the scroll buttons.
  3. PGS_HORZ - Горизонтальный стиль прокрутки. Этот стиль не может быть совместим со стилем pgs_vert 
  4. PGS_VERT - Вертикальный стиль прокрутки. Этот стиль не может быть совместим со стилем pgs_horz

Сообщения Pager:

  1. PGM_FORWARDMOUSE - Включение или отключение переадресации сообщения WM_MOUSEMOVE в окно, которое содержится в текущем элементе Pager
  2. PGM_GETBKCOLOR - Возвращает текущий цвет фона Pager
  3. PGM_GETBORDER - Возвращает текущий размер границы Pager
  4. PGM_GETBUTTONSIZE - Возвращает текущий размер кнопки Pager
  5. PGM_GETBUTTONSTATE - Получает состояние кнопки Pager
  6. PGM_GETDROPTARGET - Получает указатель на IDropTarget интерфейс Pager
  7. PGM_GETPOS - Возвращает текущую позицию прокрутки Pager
  8. PGM_RECALCSIZE - Вызывается, когда нужно пересчитать размер содержимого окна
  9. PGM_SETBKCOLOR - Устанавливает текущий цвет фона Pager
  10. PGM_SETBORDER - Устанавливает текущий размер границы Pager
  11. PGM_SETBUTTONSIZE - Устанавливает текущий размер кнопки Pager
  12. PGM_SETCHILD - Устанавливает контролу Pager дочернее окно
  13. PGM_SETPOS - Устанавливает текущую позицию прокрутки Pager

Получить больше информации о сообщениях Pager можно ЗДЕСЬ

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