User Tools

Site Tools


using_20a_20pager_20control

This is an old revision of the document!


Using a pager control

by Richard Russell, July 2010

A pager control is useful if you have a child window which is too big to be displayed in its entirety. The pager control allows you to scroll into view the part of the child control in which you are interested.

A typical use of a pager control is to allow you to scroll through a toolbar which is too wide to fit across your main window. Another use, and the one I will take as an example, is to allow you to scroll through a dialogue box which would otherwise be too big.

In order to use a pager control the first step is to perform some initialisation, as follows:

      INSTALL @lib$+"WINLIB2"
      INSTALL @lib$+"WINLIB5A"
      ON CLOSE PROCcleanup : QUIT
      ON ERROR SYS "MessageBox", @hwnd%, REPORT$, 0, 48 : PROCcleanup : QUIT
      REM!WC Windows Constants:
      CCS_NORESIZE = 4
      GWL_WNDPROC = -4
      ICC_PAGESCROLLER_CLASS = &1000
      PGM_SETCHILD = &1401
      PGN_CALCSIZE = &FFFFFC7A
      PGS_HORZ = 1
      PGS_VERT = 0
      WC_PAGESCROLLER$ = "SysPager"
      WM_NOTIFY = &4E
      WS_DLGFRAME = &400000
      WS_BORDER = &800000
      WS_CHILD = &40000000
      WS_POPUP = &80000000
      REM Enable the use of pager controls:
      DIM iccx{dwSize%, dwICC%}
      iccx.dwSize% = DIM(iccx{})
      iccx.dwICC% = ICC_PAGESCROLLER_CLASS
      SYS "InitCommonControlsEx", iccx{}

Note that WINLIB2 is installed for the purpose of creating the dialogue box; it is not required for the pager control itself. The ON CLOSE and ON ERROR statements ensure that the dialogue box is closed when the program is terminated. The PROCcleanup routine is listed below.

The next step is to create the pager control:

      x% = 100
      y% = 100
      dx% = 200
      dy% = 200
      hPager% = FN_createwindow(@hwnd%, WC_PAGESCROLLER$, "", x%, y%, dx%, dy%, \
      \                         0, PGS_VERT OR WS_BORDER, 0)
      IF hPager% = 0 ERROR 100, "Cannot create pager control"

The position and size have been set to arbitrary values for the purpose of the demonstration. The PGS_VERT style signifies that the pager control allows vertical scrolling; if you want to enable horizontal scrolling specify the PGS_HORZ style (you cannot enable both at the same time).

The appearance of the pager control and its scroll buttons can be changed by sending various messages; see this MSDN page for details.

Now we create the child window that we wish to scroll. In this case, purely for the purposes of the example, it is a dialogue box containing a grid of 160 pushbuttons:

      Dialog% = FN_newdialog("Pager test", 0, 0, 120, 1000, 8, 10000)
      id% = 100
      FOR y% = 5 TO 980 STEP 25
        FOR x% = 10 TO 100 STEP 30
          PROC_pushbutton(Dialog%, STR$(id%), id%, x%, y%, 20, 18, 0)
          id% += 1
        NEXT x%
      NEXT y%

Before we display the dialogue box we need to perform a little magic on its template:

      Dialog%!16 = (Dialog%!16 AND NOT (WS_POPUP OR WS_DLGFRAME)) OR \
      \            WS_CHILD OR CCS_NORESIZE
      !(Dialog%!4+8) = hPager% : REM Set parent
      PROC_showdialog(Dialog%)

The first line modifies the dialogue box's style; in particular the title bar is removed and it is made a child window. The second line sets the dialogue box's parent to be the pager control we created earlier.

We have to tell the pager control the dimensions of the child window it contains, so it can calculate when to display the scroll buttons. This is done as follows:

      DIM rc{l%,t%,r%,b%}
      SYS "GetWindowRect", !Dialog%, rc{}
      PROCsetnotify(rc.r%-rc.l%, rc.b%-rc.t%)

The PROCsetnotify routine is listed below.

There is just one more step, which is to 'assign' the dialogue box to the pager control:

      SYS "SendMessage", hPager%, PGM_SETCHILD, 0, !Dialog%

Now the pager control, containing the scrollable dialogue box, should be displayed. The rest of the program is simulated by this simple loop:

      REPEAT
        WAIT 0
      UNTIL FALSE
      END

In practice you will want to do something rather more useful!

Here are the listings of the PROCsetnotify and PROCcleanup routines:

      DEF PROCsetnotify(iWidth%, iHeight%)
      LOCAL L%, P%, oldwndproc, newwndproc, exit, notify
      DIM P% 50, L% -1
      SYS "GetWindowLong", @hwnd%, GWL_WNDPROC TO oldwndproc
      [OPT 10
      .exit
      pop eax
      push oldwndproc
      push eax
      jmp "CallWindowProc"
      ;
      .newwndproc
      cmp dword [esp+8],WM_NOTIFY
      jnz exit
      .notify
      mov edx,[esp+16] ; lParam
      cmp dword [edx+8],PGN_CALCSIZE
      jnz exit
      mov dword [edx+16],iWidth%
      mov dword [edx+20],iHeight%
      ret 16
      ]
      SYS "SetWindowLong", @hwnd%, GWL_WNDPROC, newwndproc
      ENDPROC
      DEF PROCcleanup
      Dialog% += 0 : IF Dialog% PROC_closedialog(Dialog%)
      hPager% += 0 : IF hPager% PROC_closewindow(hPager%)
      ENDPROC

Needless to say, you should incorporate in the PROCcleanup routine any cleanup operations needed by the rest of your program.

This website uses cookies. By using the website, you agree with storing cookies on your computer. Also you acknowledge that you have read and understand our Privacy Policy. If you do not agree leave the website.More information about cookies
using_20a_20pager_20control.1522502388.txt.gz · Last modified: 2024/01/05 00:16 (external edit)