"regain" interactivity in QuickWin

"regain" interactivity in QuickWin

Hi there,
I have a problem with my QuickWin App, but first I describe the circumstances:

In my App I use a Modeless Dialog, where the user can change the calculation parameters. After the DlgModeless command I use
Code:

	do while(GetMessage(mesg,NULL,0,0))
		if (DlgIsDlgMessage(mesg).eqv..false.) then
			lret = TranslateMessage( mesg )
			ret  = DispatchMessage( mesg )
		end if
	end do

to keep the App opened. To start the calculation, the user has to click on my own defined menu entry AppendMenuQQ(2,$MenuEnabled,'Calculation'C,start_calc). The calculationstarts and diagrams are painted etc.

The calculation hasa time limit, but the user should be able to change certain parameters while the calculation is made. But when I click on the dialog or press a button on the menu bar, the programm freezes, it seems that the diagrams wont paint any more. But when the time limit has been reached, everything is back to normal, the final diagram is shown and I can interact with the dialog.

I think that has something to do with the DlgModeless Message Loop and starting a new subroutine start_calc by a clicking the entry in the menu.

Do I have to use different threads for the main program and start_calc?

Kind regards
Markus

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

Well, yes, but you already have two threads in QuickWin -- you just have to use them in the right way:

* PROGRAM unit and its routines run in the "secondary" thread
* menu and mouse callbacks etc. run in the "primary" thread. The primary thread already has a message loop so it can run a modeless dialog without a message loop of your own.

Thus, I suggest the following:

* Put the calculation code in PROGRAM (or a routine called from it)
* Put the DlgModeless in a menu callback
* Communicate the "Start"/"Stop" events between PROGRAM and the dialog/callback via global (e.g. logical) variable(s). While the calculation is idle, let the PROGRAM "wait" for the start event and calling a short SLEEPQQ to reduce CPU utilization.

Jugoslav

Jugoslav
www.xeffort.com

Thanks for your help, your hint about the difference between menu callbacks and a call within a subroutine makes a lot of things clear. Maybe I should start to read a good book about Fortran to understand the essantials instead of trying by myself ;-)

But nowI have a minor problem:

The user has to start the modeless dialog from the menu, it will not be displayed from the start. Is it possible to cause an automatic start, like when the user clicksthe menu entry?

Maybe I should start to read a good book about Fortran to understand the essantials instead of trying by myself ;-)

I'm affraid you won't find that piece of info in any book :-). QuickWin is a Intel's (ex-Compaq's ex-Microsoft's) library but I don't recall seeing that particular information on a easily-reachable place.

Is it possible to cause an automatic start, like when the user clicks the menu entry?

You mean, something like ClickMenuQQ but which works ;-)? It's doable but by no means obvious. Generally, you should SendMessage to the frame window to activate the callback from the primary thread. One technique is to find out ID of the menu item using Spy++ (the ID is assigned by QuickWin and you don't have control over it) and:

integer, parameter:: ID_MYMENU = 
...
ret = SendMessage(GETHWNDQQ(QWIN$FRAMEWINDOW), &
WM_COMMAND, &
ID_MYMENU, &
0)

Another technique is to subclass the frame window and send your custom message to it. See QWToolbar sample on my home page.

Jugoslav

Jugoslav
www.xeffort.com

Thanks, everything works fine now. I hope that the ID of the menu item wont change often...

Youve saved my day!

I forgot, you can also retrieve it programmaticaly, which can be more bulletproof (untested):

subroutine GetMenuId(iMainMenu, iSubMenu, id)
use dfwin
implicit none

integer, intent(in):: iMainMenu, iSubMenu

integer, intent(out):: id


integer:: hMenu, iret

hMenu = GetMenu(GETHWNDQQ(QWIN$FRAMEWINDOW))
if (iSubMenu==0) then
id = GetMenuItemId(hMenu, iMainMenu-1)
else
hMenu = GetSubMenu(hMenu, iMainMenu-1)
id = GetMenuItemId(hMenu, iSubMenu-1)
end if

end subroutine

Jugoslav

Message Edited by JugoslavDujic on 11-03-2005 03:12 PM

Jugoslav
www.xeffort.com

The problem I found with QuickWin is the "$%^@!" doesn't stay around. Everytime you poke a button it goes away and comes back. To fix that I create a seperate thread that runs off of the main thread which is the application. Versis QuickWin's route having the main thread being the dialog box and your processing thread being the secondary thread.

Using the QuickWin method also has adverse interaction with ArrayVisualizer which assumes it is called from the main thread of the application. Andthe sameadverse interaction when using OpenMP.

Some wacked up code to launch a separate thread follows. You should be able to use this as a guideline to get you started. This is not hard once you get a simple dialog running (e.g. one button or check box). Once the simple dialog is running then you can expand on it to meet your needs.

module GlobalData
integer(INT_PTR_KIND()) :: ControlPanelHandle = 0
integer(INT_PTR_KIND()) :: ControlPanelSecurity = 0 ! inherit
integer(INT_PTR_KIND()) :: ControlPanelStack = 0 ! inherit
! use ControlPanel as thread_func
integer(INT_PTR_KIND()) :: ControlPanelArg = 0
integer(4) :: ControlPanelFlags = 0
integer(INT_PTR_KIND()) :: ControlPanelThread_ID = 0
...
! The volatile variables are tweeked in real time by the dialog callback
! It is good programming practice to copy the volatile variable into a
! secondary variable at one point in your main thread. The reason being
! that your application may have multiple tests of a particular contol
! and you may not want contradictory actions taken by the application.

LOGICAL, volatile :: vCheckAnneal = .false.! Checkbox set/cleared by Dlg
LOGICAL :: oCheckAnneal = .false. ! Copy set/cleared from vCheckAnneal
! from one point in the application

end module GlobalData

! A Callback subroutine used by the events activated by the dialog box

SUBROUTINE ControlPanelCallBack( dlg, id, callbacktype )
!DEC$ ATTRIBUTES DEFAULT :: ControlPanelCallBack
USE IFLOGM
INCLUDE 'DEC_AVFRT.FI' ! !dec$ define ...
use GlobalData
implicit none
INCLUDE 'RESOURCE.FD'
TYPE (dialog) dlg
INTEGER id, callbacktype, iStat
CHARACTER(256) text
LOGICAL retlog
INTEGER cel, far, retint
real(8) :: xyz(3)
text = 'undefined'
ControlPanelPauseRefresh = .true.
NextDisplayTime = 0 ! update now

SELECT CASE (id)
CASE (IDC_RADIO1)
! Radio button 1 selected by user so
! change display accordingly
vIavDisplayFrame = 0 ! vIavDisplayFrame = 0 Inertial Frame
! vIavDisplayFrame = 1 Orbital Frame
CASE (IDC_RADIO2)
...
end SUBROUTINE ControlPanelCallBack

...

! the control panel function that runs in a seperate thread
integer(4) FUNCTION ControlPanel(arg)
!DEC$ ATTRIBUTES STDCALL, ALIAS:"_controlpanel" :: ControlPanel
USE IFLOGM
use GlobalData
implicit none
INCLUDE 'RESOURCE.FD'
integer(4),POINTER :: arg
integer(4) returnVal, ms
CHARACTER(256) text
LOGICAL retlog
external ControlPanelCallBack
retlog = DLGINIT( IDD_DIALOG1, ControlPanelDlg )
call DlgSetTitle( ControlPanelDlg, ControlPanelTitle )
retlog = DlgSetSub( Cont
rolPanelDlg, IDC_RADIO1, ControlPanelCallBack )
...
retlog = DLGSETLOG (ControlPanelDlg, IDC_CHECK_FLIP_X, vCheckFlipX)
...
retlog = DLGSET( ControlPanelDlg, IDC_SPIN_INTEGRATION_STEPSIZE, 1, DLG_RANGEMIN)
retlog = DLGSET( ControlPanelDlg, IDC_SPIN_INTEGRATION_STEPSIZE, 1, DLG_SMALLSTEP)
retlog = DLGSET( ControlPanelDlg, IDC_SPIN_INTEGRATION_STEPSIZE, 10, DLG_BIGSTEP)
retlog = DLGSET( ControlPanelDlg, IDC_SPIN_INTEGRATION_STEPSIZE, 10000, DLG_RANGEMAX)
retlog = DlgSetSub( ControlPanelDlg, IDC_SPIN_INTEGRATION_STEPSIZE, ControlPanelCallBack )
...
! The following dialog box runs for the duration of the application
! i.e. it does not exit every time the user pokes a button (with accompaning screen flicker)
! The dialog activity data is place into shared memory (use GlobalData)

returnVal = DlgModal( ControlPanelDlg ) ! Doesn't return unless cancled (or IDC_event not specified)

! When the function returns the user application can detect this by examining the contents of
! returnVal
ControlPanel = returnVal
! The application can then perform any cleanup (save state)
! then exit or do something else
end FUNCTION ControlPanel

! in main program (typically a subroutine called from the main)
...
! Create seperate thread to run the Modal Dialog control pannel
ControlPanelHandle = CreateThread(&
& NULL, &
& ControlPanelStack, &
& loc(ControlPanel), &
& loc(ControlPanelArg), &
& ControlPanelFlags, &
& ControlPanelThread_ID)
...

This should get you started

JugoslavDujic wrote:
I forgot, you can also retrieve it programmaticaly, which can be more bulletproof (untested):

subroutine GetMenuId(iMainMenu, iSubMenu, id)
use dfwin
implicit none

integer, intent(in):: iMainMenu, iSubMenu

integer, intent(out):: id


integer:: hMenu, iret

hMenu = GetMenu(GETHWNDQQ(QWIN$FRAMEWINDOW))
if (iSubMenu==0) then
id = GetMenuItemId(hMenu, iMainMenu-1)
else
hMenu = GetSubMenu(hMenu, iMainMenu-1)
id = GetMenuItemId(hMenu, iSubMenu-1)
end if

end subroutine

Jugoslav

Message Edited by JugoslavDujic on 11-03-2005 03:12 PM

Hi Jugoslav,

that subroutine works fine, but not for one case: I have a Pause/Resume button on my dialog, that should click on State->Pause/Resume (iMenu=4, iSubMenu=1). But it works only for the first time to Pause the program. While debugging, I found out that Pause has the CrtlID 1008 and Resume has 1009. The problem is, that in runtime this CrtlID of 4,1 wont update, it is still 1008 after I paused the program.It will be updated to 1009, when I click on the State menu and the submenu with Resume is shown on the screen.

So I have to update that menu entry by myself. Using iSubMenu=0 doesnt do the trick (CtrlID is -1 in that case), neither UpdateWindow. Calling WM_COMMAND 1008 or 1009 works fine, but getting the CrtlID at runtime is the better solution.

Thanks in advance,

Markus

Leave a Comment

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