[solved] SetTimer to call a Method

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
Learning one
Posts: 173
Joined: 04 Oct 2013, 13:59
Location: Croatia
Contact:

[solved] SetTimer to call a Method

28 Apr 2014, 05:54

I can't figure out how to call a method via Timer. :oops: This is my (not working) test code, which will give you idea what I'm trying to do;

Code: Select all

Counter1 := new CounterClass()
Counter2 := new CounterClass()
return

F1::Counter1.Start()
F2::Counter1.Stop()

F3::Counter2.Start()
F4::Counter2.Stop()

Class CounterClass {
	static Counter := 0
	
	Start() {
		SetTimer, CounterClass_Count, 250
	}
	Stop() {
		SetTimer, CounterClass_Count, off
	}
	
	CounterClass_Count:
	Count() {
		this.Counter += 1
		ToolTip, % this.Counter
	}
	return
}
I want that:
- Start method periodically calls Count method (SetTimer On)
- Stop method stops calling Count method (SetTimer Off)

Thank you
Last edited by Learning one on 29 Apr 2014, 06:11, edited 1 time in total.
User avatar
uname
Posts: 23
Joined: 25 Oct 2013, 12:50

Re: SetTimer to call a Method

28 Apr 2014, 06:30

Code: Select all

Counter1 := new CounterClass()
Counter2 := new CounterClass()
return

F1::Counter1.Start()
F2::Counter1.Stop()

F3::Counter2.Start()
F4::Counter2.Stop()

Class CounterClass {
    static counter := 0

    __New() {
        static threadIndex := 0
        static maxThreads := 2
        static labelPrefix := "counter_class"

        if (++threadIndex <= maxThreads)
            this.Label := labelPrefix . threadIndex
        else
            throw Exception("we require more settimer labels")
    }

    Start() {
        this.SwitchTimerState(1)
    }

    Stop() {
        this.SwitchTimerState(0)
    }

    SwitchTimerState(state) {
        static timerList := {}

        if (state) {
            timerList[this.label] := this
            SetTimer, % this.label, 250
        }
        else {
            timerList[this.label] := ""
            SetTimer, % this.label, Off
        }
        return

counter_class1:
counter_class2:
         timerList[A_ThisLabel].counter++
        ToolTip % timerList[A_ThisLabel].counter
        return
    }
}
User avatar
Learning one
Posts: 173
Joined: 04 Oct 2013, 13:59
Location: Croatia
Contact:

Re: SetTimer to call a Method

28 Apr 2014, 12:34

Thank you for reply uname! :)

I respect your help and solution very much :) , but I can't resist to ask is there any better solution than this where we have to write labels like"counter_class1:, counter_class2: etc. ? I don't know how many objects will user derive from my class, and I don't prefer to write labels like that unless this is the only solution...

Any more ideas? Or is this the only solution?
HotKeyIt
Posts: 2364
Joined: 29 Sep 2013, 18:35
Contact:

Re: SetTimer to call a Method

28 Apr 2014, 14:20

Try this, it is a modifed version of SetTimerF().
Enjoy ;)

Code: Select all

Counter1 := new CounterClass()
Counter2 := new CounterClass()
return

F1::Counter1.Start()
F2::Counter1.Stop()

F3::Counter2.Start()
F4::Counter2.Stop()

Class CounterClass {
  static Counter := 0
  Count() {
    this.Counter += 1
    ToolTip, % this.Counter
  }
  Start() {
    this.SetTimer(this.base.count,250)
  }
  Stop() {
    this.SetTimer(this.base.count)
  }
  SetTimer( Function, Period=0, ParmObject=0, Priority=0 ) { 
    Static tmrs:=[] ; will hold timers that are currently running
    If IsFunc( Function ) {
      if IsObject(tmr:=tmrs[this]) ;destroy timer before creating a new one
        ret := DllCall( "KillTimer", "UInt",0, "UInt", tmr.tmr)
        , DllCall("GlobalFree", "UInt", tmr.CBA)
        , ObjRemove(tmrs,this)
      if (Period = 0 || Period = "off")
        return ret ;Return as we want to turn off timer
      ; create object that will hold information for timer, it will be passed trough A_EventInfo when Timer is launched
      tmr:=tmrs[this]:={func:Function,ref:this,Period:Period="on" ? 250 : Period,Priority:Priority
                        ,OneTime:Period<0,params:IsObject(ParmObject)?ParmObject:[],Tick:A_TickCount}
      ,tmr.CBA := RegisterCallback(this.base.SetTimer,"F",4,&tmr)
      return !!(tmr.tmr  := DllCall("SetTimer", "UInt",0, "UInt",0, "UInt"
            , (Period && Period!="On") ? Abs(Period) : (Period := 250)
            , "UInt",tmr.CBA)) ;Create Timer and return true if a timer was created
            , tmr.Tick:=A_TickCount
   }
  if IsObject(tmr := Object(A_EventInfo)) { ;A_Event holds object which contains timer information
    DllCall("KillTimer", "UInt",0, "UInt",tmr.tmr) ;deactivate timer so it does not run again while we are processing the function
    ,tmr.tick:= ErrorLevel := A_TickCount ;update tick to launch function on time
    ,func:=tmr.func,%func%(tmr.ref,tmr.params*) ; call function
    if (tmr.OneTime) ;One time timer, deactivate and delete it
      return DllCall("GlobalFree", "UInt",tmr.CBA)
            ,ObjRemove(tmrs,tmr.ref?tmr.ref:tmr.func)
   tmr.tmr := DllCall("SetTimer", "UInt",0, "UInt",0, "UInt" ;reset timer
            ,((A_TickCount-tmr.Tick) > tmr.Period) ? 0 : (tmr.Period-(A_TickCount-tmr.Tick)), "UInt",tmr.CBA)
  }
  }
}
EDIT:
Here is a Gui Example implementing 6 Timers.
I have also added __New to set timer period and control.
Note that each timer uses different settimer period.

Code: Select all

Gui,Add,Text,,Counter1 (Start=F1/Stop=F2):
Gui,Add,Edit,x+14 w40 ReadOnly,0
Counter1 := new CounterClass("Edit1")
Gui,Add,Text,xs,Counter2 (Start=F3/Stop=F4):
Gui,Add,Edit,x+14 w40 ReadOnly,0
Counter2 := new CounterClass("Edit2",150)
Gui,Add,Text,xs,Counter2 (Start=F5/Stop=F6):
Gui,Add,Edit,x+14 w40 ReadOnly,0
Counter3 := new CounterClass("Edit3",100)
Gui,Add,Text,xs,Counter2 (Start=F7/Stop=F8):
Gui,Add,Edit,x+14 w40 ReadOnly,0
Counter4 := new CounterClass("Edit4",50)
Gui,Add,Text,xs,Counter2 (Start=F9/Stop=F10):
Gui,Add,Edit,x+8 w40 ReadOnly,0
Counter5 := new CounterClass("Edit5",500)
Gui,Add,Text,xs,Counter2 (Start=F11/Stop=F12):
Gui,Add,Edit,x+2 w40 ReadOnly,0
Counter6 := new CounterClass("Edit6",1000)
Gui,Show
map:=[1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12]
return
GuiClose:
ExitApp


F1::
F2::
F3::
F4::
F5::
F6::
F7::
F8::
F9::
F10::
F11::
F12::
c:=map[SubStr(A_ThisHotkey,2)]
Counter%c%[Mod(SubStr(A_ThisHotkey,2),2)?"Start":"Stop"]()
Return

Class CounterClass {
  static Counter := 0, control := 0
  __New(control,timer:=250){
    this.control:=control
    ,this.timer := timer
  }
  Count() {
    this.Counter += 1
    GuiControl,,% this.control,% this.Counter
  }
  Start() {
    this.SetTimer(this.base.count,this.timer)
  }
  Stop() {
    this.SetTimer(this.base.count)
  }
  SetTimer( Function, Period=0, ParmObject=0, Priority=0 ) { 
    Static tmrs:=[] ; will hold timers that are currently running
    If IsFunc( Function ) {
      if IsObject(tmr:=tmrs[this]) ;destroy timer before creating a new one
        ret := DllCall( "KillTimer", "UInt",0, "UInt", tmr.tmr)
        , DllCall("GlobalFree", "UInt", tmr.CBA)
        , ObjRemove(tmrs,this)
      if (Period = 0 || Period = "off")
        return ret ;Return as we want to turn off timer
      ; create object that will hold information for timer, it will be passed trough A_EventInfo when Timer is launched
      tmr:=tmrs[this]:={func:Function,ref:this,Period:Period="on" ? 250 : Period,Priority:Priority
                        ,OneTime:Period<0,params:IsObject(ParmObject)?ParmObject:[],Tick:A_TickCount}
      ,tmr.CBA := RegisterCallback(this.base.SetTimer,"F",4,&tmr)
      return !!(tmr.tmr  := DllCall("SetTimer", "UInt",0, "UInt",0, "UInt"
            , (Period && Period!="On") ? Abs(Period) : (Period := 250)
            , "UInt",tmr.CBA)) ;Create Timer and return true if a timer was created
            , tmr.Tick:=A_TickCount
   }
  if IsObject(tmr := Object(A_EventInfo)) { ;A_Event holds object which contains timer information
    DllCall("KillTimer", "UInt",0, "UInt",tmr.tmr) ;deactivate timer so it does not run again while we are processing the function
    ,tmr.tick:= ErrorLevel := A_TickCount ;update tick to launch function on time
    ,func:=tmr.func,%func%(tmr.ref,tmr.params*) ; call function
    if (tmr.OneTime) ;One time timer, deactivate and delete it
      return DllCall("GlobalFree", "UInt",tmr.CBA)
            ,ObjRemove(tmrs,tmr.ref?tmr.ref:tmr.func)
   tmr.tmr := DllCall("SetTimer", "UInt",0, "UInt",0, "UInt" ;reset timer
            ,((A_TickCount-tmr.Tick) > tmr.Period) ? 0 : (tmr.Period-(A_TickCount-tmr.Tick)), "UInt",tmr.CBA)
  }
  }
}
User avatar
Learning one
Posts: 173
Joined: 04 Oct 2013, 13:59
Location: Croatia
Contact:

Re: SetTimer to call a Method

29 Apr 2014, 06:09

HotKeyIt, this is great :)
Thank you very much! :)
[Solved]

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: hiahkforum, NullRefEx, ShatterCoder and 95 guests