can you call a class method with OnMessage ?

Get help for the alpha version of AutoHotkey v2 here. Please state the v2 version you are working with in the title when making a new topic.
User avatar
evilC
Posts: 4792
Joined: 27 Feb 2014, 12:30

can you call a class method with OnMessage ?

02 Aug 2014, 08:22

Is there a way to encapsulate all of this within the class, or is the external function the only way to route these messages to the OnScroll() method in MyClass?

Code: Select all

OnMessage(0x115, "OnScroll") ; WM_VSCROLL
OnMessage(0x114, "OnScroll") ; WM_HSCROLL

scrollhandler := new MyClass()

OnScroll(wParam, lParam, msg, hwnd){
	global scrollhandler
	scrollhandler.OnScroll(wParam, lParam, msg, hwnd)
}

Class MyClass {
	__New(){
		[set up gui ...]
		; Could I not put the OnMessage commands in here somehow?
	}

	OnScroll(wParam, lParam, msg, hwnd){
		[...]
	}

}
Coco
Posts: 771
Joined: 29 Sep 2013, 20:37
GitHub: cocobelgica

Re: can you call a class method with OnMessage ?

02 Aug 2014, 08:52

The previous behavior in v1.1 which allows class methods as OnMessage handler(s) is no longer allowed in v2. I can't find the reference on this but I've read it somewhere, perhaps in one of the releases.
User avatar
evilC
Posts: 4792
Joined: 27 Feb 2014, 12:30

Re: can you call a class method with OnMessage ?

02 Aug 2014, 19:36

I think I found a reasonably good workaround.

if scroll handles are dragged with a mouse, the onscroll message includes the hwnd of the window you dragged the scrollbar in - all good there.

For hooking into the mousewheel, if you execute MouseGetPos(tmp,tmp,tmp,hwnd,2) you get the HWND of whatever the mouse is hovering over.
This could be a control, not a gui.
However, if you execute a GetParent DllCall, you can find that control's parent, then keep "walking" up the hierarchy until you find something with a scrollbar, then pass the parameters to that.

So I managed to rig something whereby the mouse wheel by default scrolls my "main" window, but if the mouse is over a navigation window when you scroll the wheel, it scrolls that window instead.

Video: http://screencast-o-matic.com/watch/c2jec3nK4Z

Code snippet (NOT WORKING CODE!):

Code: Select all

#IfWinActive ahk_group MyGui
~WheelUp::
~WheelDown::
~+WheelUp::
~+WheelDown::
    ; SB_LINEDOWN=1, SB_LINEUP=0, WM_HSCROLL=0x114, WM_VSCROLL=0x115
	; Pass 0 to Onscroll's hwnd param
    OnScroll(InStr(A_ThisHotkey,"Down") ? 1 : 0, 0, GetKeyState("Shift") ? 0x114 : 0x115, 0)
return
#IfWinActive

OnScroll(wParam, lParam, msg, hwnd := 0){
	global MainWindow
	if (!hwnd){
		; No Hwnd - Mouse wheel used. Find Hwnd of what is under the cursor
		MouseGetPos(tmp,tmp,tmp,hwnd,2)
	}
	MainWindow.OnScroll(wParam, lParam, msg, hwnd)
}

Class MainWindow{
	OnScroll(wParam, lParam, msg, hwnd){
		[...]
		h := hwnd
		Loop {
			h := this.GetParent(h)
			if (h == this.TaskBar.Hwnd){
				this.TaskBar.OnScroll(wParam, lParam, msg, this.TaskBar.Hwnd)
				return
			}
			if (!h){
				break
			}

		}
		; Default route for scroll is ChildCanvas
		this.ChildCanvas.OnScroll(wParam, lParam, msg, this.ChildCanvas.Hwnd)
	}
}

lexikos
Posts: 7309
Joined: 30 Sep 2013, 04:07
GitHub: Lexikos

Re: can you call a class method with OnMessage ?

03 Aug 2014, 03:32

Coco wrote:The previous behavior in v1.1 which allows class methods as OnMessage handler(s) is no longer allowed in v2.
It never actually worked in any useful way. In v1, some users wrote code like this:

Code: Select all

   OnMessage(0x114, "MyClass.OnScroll")  ; <= relies on undocumented behaviour.
   ...
   OnScroll(lParam, msg, hwnd){
      wParam := this
      [...]
   }
Please don't. OnMessage wants a function to call - so give it a function.

Many users, like evilC, don't think about the method's hidden this parameter and so would be confused by the results. v2 immediately alerts the user to the error.
just me
Posts: 7857
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: can you call a class method with OnMessage ?

03 Aug 2014, 04:41

If you need to access a class within the function, the hidden parameter This which has to be used instead of the wParam parameter is the only difference between a fundtion and a class method. But IMO, encapsulating a message handler within a class is more a "Look, I can!" feature (Yes, I did it, too!).
User avatar
evilC
Posts: 4792
Joined: 27 Feb 2014, 12:30

Re: can you call a class method with OnMessage ?

03 Aug 2014, 08:23

lexikos wrote:Many users, like evilC, don't think about the method's hidden this parameter and so would be confused by the results. v2 immediately alerts the user to the error.
What "hidden This parameter" ? Surely if it is "hidden", I cannot think about it?

IIRC you could do silly stuff like OnMessage(0x114, "MyClass.OnScroll") in V1, but when it got to the OnScroll method in MyClass, "this" was unset, and so it was useless.
lexikos
Posts: 7309
Joined: 30 Sep 2013, 04:07
GitHub: Lexikos

Re: can you call a class method with OnMessage ?

03 Aug 2014, 22:01

evilC wrote:What "hidden This parameter" ? Surely if it is "hidden", I cannot think about it?
Nonsense. Being hidden implies that it exists, and having read the documentation you would know it exists. It's also possible to think about nonexistent things. ;)
IIRC you could do silly stuff like OnMessage(0x114, "MyClass.OnScroll") in V1, but when it got to the OnScroll method in MyClass, "this" was unset, and so it was useless.
You are mistaken. My example code demonstrates that this is not the case, but your false assumption reaffirms my point about user confusion.
User avatar
evilC
Posts: 4792
Joined: 27 Feb 2014, 12:30

Re: can you call a class method with OnMessage ?

04 Aug 2014, 09:51

lexikos wrote:
evilC wrote:What "hidden This parameter" ? Surely if it is "hidden", I cannot think about it?
Nonsense. Being hidden implies that it exists, and having read the documentation you would know it exists. It's also possible to think about nonexistent things. ;)
C'mon man, I read AHK docs on a regular basis but there is a LOT to take in. OK so I am no professional programmer, but I try really hard to learn and also try to do my bit for the community, yet I often feel a negative vibe towards me, and that makes me sad. I tried scouring the docs but could find no reference to a "hidden This parameter".

I have recently made excellent progress extending your Scrollbar Proof of Concept into a fully fledged windowed environment: http://screencast-o-matic.com/watch/c2jeYjnKgC
Whilst making this, it definitely seems to me that it would be nice to be able to route the WM_SCROLL messages without needing to pass everything through the main class. As it stands, I have to check the hwnd of the WM_SCROLL message and see if it matches any of the child windows, and if not, walk up the hierarchy of HWNDs until I find something I want to route to.
Being able to override OnMessage in a class-based GUI and have it automatically catch any messages that are destined for that GUI / control would be much nicer.
Coco
Posts: 771
Joined: 29 Sep 2013, 20:37
GitHub: cocobelgica

Re: can you call a class method with OnMessage ?

04 Aug 2014, 10:22

@evilC: What lexikos meant is the hidden this parameter in class methods w/c contains the reference to the object that invoked the method call. Now, if one were to use class methods as OnMessage handler(s), this becomes wParam which some OR most users might totally forget about (if careless). You must've thought that he was referring to another/different undocumented this parameter, hence, the confusion/misunderstanding in both of your exchanges... Don't worry there is no negative vibe towards you :-). Most discussions are for the improvement of the individual as an AHK user, the improvement of the language and the community. Thank you for your eagerness to learn and your contributions.
User avatar
evilC
Posts: 4792
Joined: 27 Feb 2014, 12:30

Re: can you call a class method with OnMessage ?

04 Aug 2014, 10:48

Coco wrote:@evilC: What lexikos meant is the hidden this parameter in class methods w/c contains the reference to the object that invoked the method call. Now, if one were to use class methods as OnMessage handler(s), this becomes wParam which some OR most users might totally forget about (if careless).
Thanks for that explanation, I think it may take a bit of work for me to digest it.
I am not sure I get what you mean - as far as I was concerned, in a class method, this always refers to the class instance, like so:

Code: Select all

Class MyClass {
   myMethod(blah){
      this.foo := "blah"  ; "this" points to this instance of MyClass
   }
}
I was under the assumption that if you were to make the OnMessage handler a class method, it could work something like this:

Code: Select all

Class MyClass {
   __New(){
      myGui := GuiCreate("Hello World", "x100 y100")
      [Here, maybe merge myGui and the class into one, like Fincs does with AFC]
      OnMessage(0x115, "OnScroll") ; Route WM_SCROLL messages for this GUI item to the OnScroll method of this class
      ; myGui.OnMessage([...]) or even maybe something like this?
   }

   OnScroll(wParam, lParam, msg, hwnd){
      ; The hwnd parameter is kind of superfluous as it will be the hwnd of myGui.
      ; Maybe allow it to trap messages from child controls?
      this.foo := "blah" ; "this" still points to class.
      bar := msg - 0x114 ; SB_HORZ=0, SB_VERT=1
      [ ... ]
      DllCall("SetScrollInfo", "uint", hwnd, "int", bar, "uint", &si, "int", 1)
   }
}
I understand that this would make no sense in vanilla AHK v2 as it stands, but with Fincs rewriting the GUI to be OOP, I thought something like this may be of value?
Coco
Posts: 771
Joined: 29 Sep 2013, 20:37
GitHub: cocobelgica

Re: can you call a class method with OnMessage ?

04 Aug 2014, 11:00

evilC wrote:as far as I was concerned, in a class method, this always refers to the class instance
this can be any object -> an instance of the class, the class object, an object that extends the class or another unrelated object(passed via something likefunc_ref := Class.method, %func_ref%(some_object, args*)
evilC wrote:I was under the assumption that if you were to make the OnMessage handler a class method, it could work something like this..
It should be something like this:

Code: Select all

class Test
{
	OnScroll(lParam, msg, hWnd) { ;// 'this' (first, hidden parameter) becomes 'wParam'
		;// code here
	}
}
A class method if written as a normal function definition would look something like (note: dot is for demonstration purposes/for clarity only; pseudo-code only):

Code: Select all

Class.Method(this, params*) {
	;// code here
}
User avatar
evilC
Posts: 4792
Joined: 27 Feb 2014, 12:30

Re: can you call a class method with OnMessage ?

04 Aug 2014, 11:26

OK, penny is maybe starting to drop here...

The first param for a class method is "this"?

I thought class methods did not have any parameters by default...
So in order to preserve it, when calling a class method you would have to pass nothing to the first param?

I finally found a reference to the "hidden this param" in the docs...

Its going to take some time for me to fully digest everything being said here, but thanks to all for helping me down that road.
just me
Posts: 7857
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: can you call a class method with OnMessage ?

04 Aug 2014, 11:30

The problem here is, that the object reference won't be added internally as the first (hidden) parameter if the method is called as a plain function by the message handler. However, AHK detects the method call, removes the first parameter (wParam in this case) and puts it into the method variable This. The second parameter will be stored in the first parameter of the method, and so on.
Coco
Posts: 771
Joined: 29 Sep 2013, 20:37
GitHub: cocobelgica

Re: can you call a class method with OnMessage ?

04 Aug 2014, 11:36

evilC wrote:The first param for a class method is "this"?
Yes, it's hidden.
evilC wrote:I finally found a reference to the "hidden this param" in the docs...
I thought that you were already aware of this, my bad.
evilC wrote:I thought class methods did not have any parameters by default...
Here's a test using IsFunc, IsFunc returns one plus the minimum number parameters.

Code: Select all

class Test
{
	Method() { ;// no parameter(s) explicitly defined

	}
}
MsgBox % IsFunc(Test.Method) ;// returns 2 -> 1+(this)
lexikos
Posts: 7309
Joined: 30 Sep 2013, 04:07
GitHub: Lexikos

Re: can you call a class method with OnMessage ?

04 Aug 2014, 21:08

just me wrote:AHK detects the method call, removes the first parameter (wParam in this case) and puts it into the method variable This.
Not really. It just passes four parameters.

Declaring X(Y) in a class is the same as declaring X(this, Y) outside the class and then assigning Class.X := Func("X"), except that the function name "X" is not reserved. Either way, this is just parameter #1.
just me
Posts: 7857
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: can you call a class method with OnMessage ?

05 Aug 2014, 01:48

Too simple for me. :lol:

It's added internally to the parameter list of the method, not to the parameters of the method call. Thanks!

Return to “AutoHotkey v2 Help”

Who is online

Users browsing this forum: No registered users and 2 guests