| Subject |
Re: Form closing when idle |
| From |
Mervyn Bick <invalid@invalid.invalid> |
| Date |
Wed, 23 Jun 2021 14:14:36 +0200 |
| Newsgroups |
dbase.getting-started |
| Attachment(s) |
close_on_idle_main.wfm, close_on_idle_sub.wfm, close_on_idle.cfm |
On 2021/06/21 21:42, Mustansir Ghor wrote:
> Dear Mervyn Sir
>
> The findinstance() works well and did the job.
>
> But yet another issue came up. The readmodal form that was opened by menu, does not reset the time of mainform hence making it (mainform) to close even if one is working on the readmodal form.
>
> Is there anything that can be done.
You could base the readmodal form on close_on_idle.cfm. You will need
to stop the timer on the main form while the readmodal form is open.
When the readmodal form closes, either by time-out or user action, you
will need to null the instance of the readmodal form and restart the
timer for the main form.
In the attached example the time-out value has been set to 20 seconds
(life is too short to wait the default 2 minutes for testing. :-) ) so
the count-down is always visible instead of only appearing with a minute
to go.
Mervyn.
| ** END HEADER -- do not remove this line
//
// Generated on 2021-06-23
//
parameter bModal
local f
f = new close_on_idle_mainForm()
if (bModal)
f.mdi = false // ensure not MDI
f.readModal()
else
f.open()
endif
class close_on_idle_mainForm of CLOSE_ON_IDLE from "close_on_idle.cfm"
with (this)
onOpen = class::FORM_ONOPEN
height = 406.0
left = 190.0
top = 14.0
width = 437.0
topMost = true
endwith
this.PUSHBUTTON1 = new PUSHBUTTON(this)
with (this.PUSHBUTTON1)
onClick = class::PUSHBUTTON1_ONCLICK
height = 34.0
left = 168.0
top = 197.0
width = 107.0
text = "Open readmodal form"
endwith
function PUSHBUTTON1_onClick()
form.oSub = new close_on_idle_subForm()
form.oSub.mdi := false
form.timer.enabled = false
form.textlabel1.text = ''
form.oSub.readmodal()
form.oSub = null
form.timer.seconds = seconds()
form.timer.enabled = true
return
function form_onOpen()
close_on_idle::form_onOpen()
form.timer.allow_idle_time := 20
set procedure to close_on_idle_sub.wfm
return
endclass
| ** END HEADER -- do not remove this line
//
// Generated on 2021-06-23
//
parameter bModal
local f
f = new close_on_idle_subForm()
if (bModal)
f.mdi = false // ensure not MDI
f.readModal()
else
f.open()
endif
class close_on_idle_subForm of CLOSE_ON_IDLE from "close_on_idle.cfm"
with (this)
onOpen = class::FORM_ONOPEN
height = 406.0
left = 674.0
top = 21.0
width = 437.0
endwith
function form_onOpen()
close_on_idle::form_onOpen()
form.timer.allow_idle_time := 20
return
endclass
| /* *********************************************
File.......: Close_on_idle.cfm
Author ... : Mervyn Bick
Date.......: 2021-05-18
This custom form relies on the CALLBACK command and is, therefore,
only suitable for dBASE Plus 8 and later versions.
This custom form uses a keyboard hook and a mouse hook to monitor
instructions to the form. Any keystroke or mouse action resets a timer
which is used to close the form after a set period of inactivity. The default
is 2 minutes but this can be overridden for individual forms as required.
For the final 60 seconds of the allowable idle time a countdown is displayed.
The custom form metric is 6 i.e Pixels. Any form derived from this custom form will
also have its metric property set to 6. This can be changed in the form designer
if required.
The keyboard and mouse hooks are completely stable if they are correctly
attached when the form opens and detached when the form is closed.
Unfortunately there is an extremely annoying side effect when using keyboard
and mouse hooks. Any error, even though not associated with the hooks, causes
dBASE to close. Provision has, therefore, been made to disable the close_on_idle
feature while a form is being developed. Once the form is stable the close_on_idle
feature can be activated.
************IMPORTANT********
If this .cfm file is opened in the Custom Form designer the two lines immediately
below the class definition will be discarded. It will be necessary to replace them
manually.
class close_on_idle of FORM custom
#include winuser.h
#define wm_mousewheel 0x020A //not in winuser.h
********************************
To disable the close_on_idle feature a form_onOpen event handler is
required in any form derived from this custom form.
function form_onOpen()
form.close_on_idle = false //change to true when form is complete
//Execute the form_onOpen event handler in the .cfm file
//after setting the form's close_on idle property
close_on_idle::form_onOpen()
//If the default idle time is not appropriate assign a new value
//after the .cfm form_onOpen event handler has been executed.
form.timer.allow_idle_time := 60*2 //in seconds
// Any other code as required
return
If access is required to the number of seconds before the form closes
create function check_time_left(nSec) in a form derived from this
custom form.
function check_time_left(nSec)
//your code
return
*/ ********************************************
class close_on_idle of FORM custom
#include winuser.h // See note in comments above
#define wm_mousewheel 0x020A //not in winuser.h
with (this)
onMouseOver = class::FORM_ONMOUSEOVER
onMouseOut = class::FORM_ONMOUSEOUT
onOpen = class::FORM_ONOPEN
onClose = class::FORM_ONCLOSE
metric = 6 // Pixels
height = 406.0
left = 73.0
top = 5.0
width = 437.0
text = ""
endwith
this.TEXTLABEL1 = new TEXTLABEL(this)
with (this.TEXTLABEL1)
height = 22.0
left = 192.0
top = 18.0
width = 228.0
text = ""
endwith
function attach
if this.mhookProc == null
CALLBACK CLONG MouseHookWndProc(CINT, CUINT, CUINT) OBJECT this
this.mhookProc = GetCallAddress(class::MouseHookWndProc)
endif
mhInst = GetWindowLong(int(form.hwnd), WH_MOUSE)
this.mhook = SetWindowsHookEx(WH_MOUSE, this.mhookProc,mhInst, GetCurrentThreadId())
if this.khookProc == null
CALLBACK CLONG KeyHookWndProc(CINT, CUINT, CUINT) OBJECT this
this.khookProc = GetCallAddress(class::KeyHookWndProc)
endif
khInst = GetWindowLong(int(form.hwnd), WH_KEYBOARD)
this.khook = SetWindowsHookEx(WH_KEYBOARD, this.khookProc,khInst, GetCurrentThreadId())
return
function detach
UnhookWindowsHookEx(this.mhook)
UnhookWindowsHookEx(this.khook)
return
function form_onClose()
class::detach()
this.timer.enabled = false
return
function form_onMouseOut(flags, col, row)
form.mouseOver = false
return
function form_onMouseOver(flags, col, row)
form.mouseOver = true
return
function form_onOpen()
if type('form.close_on_idle') = 'U'
form.close_on_idle = true
endif
if type("GetCurrentThreadId") # "FP"
extern CULONG GetCurrentThreadId() kernel32 from "GetCurrentThreadId"
endif
if type("GetWindowLong") # "FP"
extern CLONG GetWindowLong(CHANDLE, CINT) user32 from "GetWindowLongA"
endif
if type("SetWindowsHookEx") # "FP"
extern CLONG SetWindowsHookEx(CINT, CPTR, CHANDLE, CULONG) user32 from "SetWindowsHookExA"
endif
if type("UnhookWindowsHookEx") # "FP"
extern CLOGICAL UnhookWindowsHookEx(CHANDLE) user32
endif
if type("CallNextHookEx") # "FP"
extern CLONG CallNextHookEx(CHANDLE, CINT, CUINT, CUINT) user32
endif
form.mouseOver = true
this.timer = new Timer( )
this.timer.parent = this
this.timer.seconds = seconds()
this.timer.allow_idle_time = 60 *2 // 2 minutes. value in sconds
this.timer.onTimer := this.check_action
this.timer.interval = 1
this.timer.parent.time_left = 0
this.mhook = null
this.khook = null
this.mhookProc = null
this.khookProc = null
if form.close_on_idle = false
this.timer.enabled = false
else
this.timer.enabled = true
class::attach()
endif
return
function check_action
this.parent.time_left = int(abs(seconds()-this.allow_idle_time-this.seconds)+1)
if int(abs(seconds()-this.allow_idle_time-this.seconds)+1) < 61
this.parent.textlabel1.text = 'This form will close in '+int(abs(seconds()-this.allow_idle_time-this.seconds)+1)+' second'+iif(int(abs(seconds()-this.allow_idle_time-this.seconds)+1) = 1,'', 's')
else
this.parent.textlabel1.text = ''
endif
if seconds()-this.allow_idle_time-this.seconds >1
this.parent.close()
endif
if type('this.parent.check_time_left') = 'FP'
this.parent.check_time_left(this.parent.time_left)
endif
return
function MouseHookWndProc(hCode, wParam, lParam)
if hCode = 0 and form.mouseOver = true
if wparam = wm_mousemove or ;
wparam = wm_nclbuttondown or ;
wparam = wm_lbuttondown or ;
wparam = wm_rbuttondown or ;
wparam = wm_mbuttondown or ;
wparam = wm_mousewheel
form.timer.seconds = seconds()
endif
endif
return CallNextHookEx(this.mhook, hCode, wParam, lParam)
function KeyHookWndproc(hCode, wParam, lParam)
t1 = wParam // virtual key code.
t2 = lParam // bit 31 = 0 keydown, bit 31 = 1 keyup
if bitset(lparam,31) = false and hCode = 0 and form.mouseOver = true
form.timer.seconds = seconds()
endif
return CallNextHookEx(this.khook, hCode, wParam, lParam)
endclass
|
|