How build a large (and scrollable) Dialog Box?

How build a large (and scrollable) Dialog Box?

I'm trying to create one huge "window" or dialog box that has lots of questions (sort of like a questionnaire) where the user can answer the questions, scroll up, scroll down, go back and change answers, then hit an "ok" button when they're all done. I don't want a bunch of separate windows, I just want one huge window. When I create a dialog box, I haven't been able to dictate the size but I've been able to put vertical and horizontal scroll bars on my dialg box. When I run the application and make the dialog box very samll so you can't see all of the edit boxex, the scrolling does not work. Help. Thanks. Jill

11 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

It's not clear from your letter - which type of application you try to create - Dialog or Win32? For Win32 applications you must remember, that scrollbars are control elements only and no more... You must program the respective actions for these controls manually. From my side of view, your algorithm could be the next:
1.Create all necessary controls, using CreateWindow(Ex) function ( because, if your window is "huge", then you're not able to create them in Resource Editor).
2."Keep in mind" positions of all controls
3.Detect the visible group of controls
4.Programming the scrollbars actions/events, use MoveWindow function, to make the next group of controls visible/hidden.

Hope this helps,

Vladimir V.Vasilchenko

http://www.donpac.ru/usr/golub/fortran/

http://fortran-windows.tripod.com

I'd just add that you could consider using a tabbed dialog instead, since it should be simpler to program (and, IMHO, simpler to use). As you can see from Vladimir's post, using a huge window with scrollbar is far from trivial.

Jugoslav

I'm afraid I don't have the knowlege to program scroll bars in WIN32 yet. I'll probably have to take a class. So, is there a way to create a dialog box that is 2 to 4 screens long? and that automatically handles the scroll bars? Jill

A simpler idea than Vladimir's just struck my mind -- an approach similar to tabbed dialog boxes. I'll try to explain it in short notes.

First, create two dialogs: one "master" (Dlg), containing only a scrollbar, and one huge "child" (Child) containing everything else. Child should have style "child", no caption, no border. Also, variable Child should be global somehow:

 
MODULE Mod1 
USE DFLOGM 
TYPE(Dialog):: Child 
CONTAINS... 

In "main" routine initialize Dlg. Create an initialization callback for Dlg. Also, you can initialize and fill in controls in Child there:

 
SUBROUTINE MainDialog 
iSt = DlgInit(IDD_MASTER, Dlg) 
iSt = DlgInit(IDD_CHILD, Dlg) 
iSt = DlgSetSub(Dlg, IDD_MASTER, OnDlgInit) 
iSt = DlgSetSub(Dlg, IDD_SCROLLBAR, OnScroll) 
!Fill in child's contents here 

Then, in OnDlgInit, do DlgModeless for the child dialog:

 
SUBROUTINE OnDlgInit(Dlg, ID, iEvent) 
USE DFWIN 
TYPE (T_RECT):: Rect 
iSt = DlgModeless(Child, SW_SHOW, Dlg%hWnd) 
!Find height of child and adjust scrollbar's paramters 
iSt = GetWindowRect(Child%hWnd, Rect) 
iSt = DlgSet(Dlg, IDC_SCROLLBAR, Rect%Bottom-Rect%Top, DLG_RANGEMAX) 
END SUBROUTINE OnDlgInit 

and in OnScroll, just move the Child using MoveWindow:

 
SUBROUTINE OnScroll(Dlg, ID, iEvent) 
iSt = DlgGet(Dlg, IDC_SCROLLBAR, nPos, DLG_POSITION) 
iSt = GetWindowRect(Child%hWnd, Rect) 
iSt = MoveWindow(Child%hWnd, 0, -nPos, Rect%Right-Rect%Left, Rect%Bottom-Rect%Top) 

As you can see, only APIs needed are GetWindowRect and MoveWindow (see docs, they're rather simple). A variation of the theme (as in your second post) is possible -- create, say, four child dialogs, do a DlgModeless for each, set scrollbar range to 1-4 and in OnScroll do a ShowWindow(SW_SHOW) for the corresponding child.

HTH

Jugoslav

Small addendum:

- Of course, DlgModal has to be in MainDialog

- Er, I forgot that Dlg has to be closed somehow and it has to have some "OK" and/or "Cancel" button. For the start, you could place them on the right side of Dlg. If you want them at the bottom, you'd have to carefully calculate arguments to MoveWindow(Child...) to clip the child accordingly. You could also take a look at GetClientRect()

Jugoslav,
it seems to me, that "simpler" approach consists in using trivial scheme of any installations wizards. In practice it means - N dialog panels + using "Back","Next","Cancel" buttons + trivial external loop/block for the analysis of return code from each dialog panel... N-th panel will have "Back", "Finish", "Cancel" buttons...

Vladimir V.Vasilchenko

Fortran Programmers Club

http://www.donpac.ru/usr/golub/fortran/

http://fortran-windows.tripod.com

Sure it could; variations on the theme are indefinite. Personally, as a user, I dislike scrolling approach, since I get lost in a huge window. I'd prefer having information organized in groups somehow (tab control; a list control on the left or similar). Wizard-style you propose is also OK, but I prefer to keep it for tree-like data structures, where next screen depends on the choice in previous. I dislike wizards where info collected on each panel is totally unrelated with adjacent panels, since navigation with wizards is harder than with, say, tabs. But these are just my user's preferences.

Btw, I'd suggest a very funny but educating site related with GUI design -- Interface Hall of Shame

Thanks guys for your responses. I think I'll try the tab approach and see how that works. Jill.

Hello, i have the same problem as jschomaker. I have modified my program, but it works still not. What can I do? Thanks
integer*4 function WinMain( hInstance, hPrevInstance,
& lpszCmdLine, nCmdShow )
!DEC$ IF DEFINED(_X86_)
!DEC$ ATTRIBUTES STDCALL, ALIAS : '_WinMain@16' :: WinMain
!DEC$ ELSE
!DEC$ ATTRIBUTES STDCALL, ALIAS : 'WinMain' :: WinMain
!DEC$ ENDIF
!DEC$ ATTRIBUTES DLLEXPORT :: /X/
!COMMON /X/

use dfwin
use dflogm
use Mod1

implicit none

integer*4 hInstance
integer*4 hPrevInstance
integer*4 lpszCmdLine
integer*4 nCmdShow

include 'resource.fd'

external OnDialog
external OnScroll
type (T_MSG) mesg
type (T_RECT) :: Rect
type (dialog) modaldlg
type (dialog) dlg
integer*4 ret
integer*4 let
logical*4 llet

logical*4 lret
logical retlog

ghInstance = hInstance
ghModule = GetModuleHandle(NULL)
ghwndMain = NULL

llet = DlgInit (IDD_DIALOG1, modaldlg)
lret = DlgInit(IDC_MyDlg, dlg)
lret = DlgSetSub(dlg, IDC_MyDlg, OnDialog)
llet = DlgSetSub(modaldlg, IDD_DIALOG1, OnScroll)
if (lret == .FALSE.) goto 99999
do while( GetMessage (mesg, NULL, 0, 0) )
if ( DlgIsDlgMessage(mesg) .EQV. .FALSE. ) then
lret = TranslateMessage( mesg )
ret = DispatchMessage( mesg )
end if
end do

call DlgUninit(dlg)

WinMain = mesg.wParam
return

99999 ret = MessageBox(ghwndMain, "Error initializing application
+Eingabebutton"C,"Error"C, MB_OK)
WinMain = 0

end
SUBROUTINE OnDialog(dlg, id, callbacktype)

use dfwin
use dflogm
use Mod1

implicit none

include 'resource.fd'

type (T_RECT) :: Rect
type (dialog) dlg

integer id, callbacktype
logical lret

lret = DlgModeless (Child, SW_SHOW, Dlg%hWnd)
lret = GetWindowRect (Child%hWnd, Rect)
lret = DlgSet(Dlg, IDD_DIALOG1, Rect%Bottom-Rect%Top, DLG_RANGEMAX)
if (callbacktype == dlg_destroy) then
call PostQuitMessage(0)
endif

END SUBROUTINE OnDialog

SUBROUTINE OnScroll(Dlg, ID, iEvent)
use dfwin
use dflogm
use Mod1
type (dialog) modaldlg
type (T_RECT) :: Rect
logical llet
let = DlgModal(modaldlg, hwndParent = 0)
llet = DlgSet(modaldlg, IDD_SCROLLBAR, 212, DLG_RANGE)
llet = DlgGet(modaldlg, IDD_SCROLLBAR, nPos, DLG_POSITION)
llet = GetWindowRect(Child%hWnd, Rect)
llet = MoveWindow(Child%hWnd, 0, 0, -nPos, Rect%Right-Rect%Left,
+Rect%Bottom-Rect%Top)
call DlgUninit(modaldlg)
END SUBROUTINE OnScroll

Uh, your code is in quite a disorder. (Both display disorder and statements disorder). You need:

integer*4 function WinMain( hInstance, hPrevInstance,  
     & lpszCmdLine, nCmdShow )  
!DEC$ ATTRIBUTES STDCALL, ALIAS : '_WinMain@16' :: WinMain  
 
use dfwin  
use dflogm  
use Mod1  
 
implicit none  
 
integer*4 hInstance, hPrevInstance, lpszCmdLine, nCmdShow  
 
include 'resource.fd'  
 
external OnDialog  
 
type (T_RECT) :: Rect  
type (dialog) modaldlg  
!type (dialog) dlg This one goes to OnDialog 
integer*4 ret, let 
logical*4 llet, lret, retlog  
 
ghInstance = hInstance  
ghModule = hInstance 
ghwndMain = NULL  
 
llet = DlgInit (IDD_DIALOG1, modaldlg)  
lret = DlgSetSub(modaldlg, IDD_DIALOG1, OnDialog)  
lret = DlgSetSub(modaldlg, IDC_SCROLLBAR1, OnScroll)  
 
lret = DlgInit(IDC_MyDlg, dlg)  
if (lret == .FALSE.) goto 99999  
!You don't need this 
!do while( GetMessage (mesg, NULL, 0, 0) )  
!       if ( DlgIsDlgMessage(mesg) .EQV. .FALSE. ) then  
!           lret = TranslateMessage( mesg )  
!           ret = DispatchMessage( mesg )  
!       end if  
!      end do  
 
WinMain = DlgModal(dlgModal) 
 
return  
99999 ret = MessageBox(ghwndMain, "Error initializing application  
     +Eingabebutton"C,"Error"C, MB_OK)  
WinMain = 0 
end function WinMain 
!================================ 
SUBROUTINE OnDialog(modaldlg, id, callbacktype)  
 
use dfwin  
use dflogm  
use Mod1 
 
implicit none  
 
include 'resource.fd'  
 
type (T_RECT) :: Rect  
type (dialog) modaldlg  
 
integer id, callbacktype  
logical lret  
 
lret = DlgModeless (Child, SW_SHOW, ModalDlg%hWnd)  
lret = GetWindowRect (Child%hWnd, Rect)  
lret = DlgSet(ModalDlg, IDC_SCROLLBAR1, Rect%Bottom-Rect%Top, DLG_RANGEMAX)  
 
END SUBROUTINE OnDialog  
!================================ 
SUBROUTINE OnScroll(ModalDlg, ID, iEvent)  
use dfwin  
use dflogm  
use Mod1  
type (dialog) modaldlg  
type (T_RECT) :: Rect  
logical llet  
 
llet = DlgGet(modaldlg, IDD_SCROLLBAR, nPos, DLG_POSITION)  
llet = GetWindowRect(Child%hWnd, Rect)  
llet = MoveWindow(Child%hWnd, 0, 0, -nPos, Rect%Right-Rect%Left,  
     +Rect%Bottom-Rect%Top)  
 
END SUBROUTINE OnScroll 

I'm not sure whether it would work now (I used scissors extensively) but it's pretty close to it.

Few tips:

- In a Dialog-based application, when the main window is a modal dialog, you don't need message loop regardless of whether there are modeless children. You need message loop only when you have "standalone" modeless dialogs. In other words, having only DlgModal in WinMain is perfectly OK.

- For child dialog use "Child" and "Control" styles.

- Variable type(Dialog):: Child in the code above has to be global (say, defined in Mod1).

HTH

Jugoslav

Leave a Comment

Please sign in to add a comment. Not a member? Join today