October 29, 2025, 03:33:15 PM

News:

Own IWBasic 2.x ? -----> Get your free upgrade to 3.x now.........


Subclassing

Started by Andy, July 22, 2015, 03:15:37 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Andy

Hi Everyone,

Been meaning to ask this question for some time now.

What does subclassing actually mean in programming? there have been a couple of instances when I've needed some help and the resulting explanation is to "sub class it".

So can anyone explain in English, and in simple terms (that matches my brain!) what it is and why you sometimes have to do it.

Looked around on the Internet but non the wiser.

Thanks,
Andy.
:)
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

Bill-Bo

July 22, 2015, 03:54:02 AM #1 Last Edit: July 22, 2015, 03:56:53 AM by Bill-Bo
andy,

This may be steep, but try https://en.wikipedia.org/wiki/Inheritance_(object-oriented_programming)#Subclasses_and_superclasses

But I'm sure the way LarryMc explains would be much better.

Bill

Andy

Thanks Bill,

Will have a look and try and get my head around it!

Andy.
:)
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

LarryMc

 :o :o, that wiki $#@t made my head spin   ???

I'm not feeling real good  and I fixin' to go back to bed so I'll give you my overview.

You've done enough programming with IWB now that you know that windows have message handlers and each message performs a specific function.

Controls, in reality, are nothing more than specialized windows with their own message handlers and their messages that perform specific functions written just for them. ( If you don't believe that read my tutorial on creating custom controls)

Why subclass?
Sometimes a control doesn't act quite like you want it to.
(but it is not limited to controls; it could be a window but for now a control example is easier to explain but it is all the same)
Let's say I'm building an application where I want an edit control and I want the user to enter hex characters and@#$.
I'm in trouble.
The User types in random characters.
I have to read it and scan for bad characters (while he's still typing by the way)
Strip out the bad characters and replace the contents in the edit control without loosing anything.
Good luck with that.

This is a prime example of when sub-classing is called for.
What do you do to sub-class?

You create a new message handler for the edit control.
The only message that this new handler handles is the one that accepts keyboard input.
You write code to pass keys that are acceptable thru to the original handler which will display them.
All other keys are ignored
All other messages are passed thru to the original handler

After setting up the above handler you initialize the subclass by
Using a special Windows command to swap and store the addresses of the message handlers

So now when a message is generated for our control it is first sent to our subclassed handler.  If it isn';t keybooard input it is passed on to the regular handler.  If it is keyboard input and it is one of our allowable characters it is sent to the regular handler for display otherwise it is discarded.

And before you destroy the the control there is a command to swap the addresses for the two handlers back (all part of memory cleanup)

I've used this to block keys as described above, to block right-click context popups, to block closing a window with the x in the upper right corner(at certain times) and all over my grid control and in my other libraries.

Internally the IWBasic @button is subclassed because the button is custom drawn.

Super-Classing
Although I have never used it it is my understanding that the only difference between sub-classing and super-classing is that in sub-classing you are intercepting and modifying the action of an existing message and in super-classing you are adding a completely new message.

I haven't looked to check but I don't think a button has a right click message.
You could go through the process above for subclassing but in this case you would want to create your own user defined messageID (so as not to interfere with any Windows message ID) and then write the code for what you want it to do when you right-click on the button

Hope all that makes a little sense.

Edited:Corrected some of my grammar.

LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

Andy

Hi Larry,

Thanks for the explanation, I get what you are saying and I think I understand it much better now, so thanks again for that!

I think you need to get to bed and rest - that's the most important thing!!

in my experience, people think that because you work with computers, that you are one as well (like the terminator - never stopping, or getting tired etc).

Rest, and get better soon!

Andy.
:)
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

LarryMc

Here's an example that I modified.  I think Brian had posted it.
It shows an old way to sub class.
It has the handler as I described and the name of the handler is of your choosing as long as it is unique for your program.

The 1st 2 edit controls allow alpha-numeric input.  The 3rd only allows numeric and . because it is subclassed.

In this old way  it uses a sub to subclass and a sub to unsubclass; again the names of the subs are the users choice.
In the subclass routine:
What is happening is we're getting the handle to the control with this line:
hEdit = GETCONTROLHANDLE(parent,id)
then with this line
lpFn = SetWindowLongA(hEdit,-4,&numEditHandler)
we're doing two things:
1)we're reading the address of our control's handler and putting it in lpFn
2)we're replacing the handler with our subclassing handler's address
with this line
SetPropA(hEdit,"edit_handler",lpFn)
we are storing the address of our original handler in a property that we named "edit_handler".  We can name it anything we want as long as it is unique to a given control.  A control can have as many properties as you want

We've got to do cleanup when we go to close the window.
So to the window handler I've added the WM_DESTROY message.
This is the proper place to call the unsubclass sub
Here we read the address saved in the property and restore the original message handler
   SetWindowLongA(hEdit,-4,GetPropA(hEdit,"edit_handler"))
and here we release the memory we used for storage.
   RemovePropA(hEdit,"edit_handler")

DECLARE IMPORT,CallWindowProcA(lpPrevWndFunc:INT,hWnd:INT,Msg:INT,wParam:INT,lParam:INT),INT
DECLARE IMPORT,SetWindowLongA(hWnd:INT,nIndex:INT,dwNewLong:INT),INT
DECLARE IMPORT,SetPropA(hWnd:UINT,lpString:STRING,hData:UINT),INT
DECLARE IMPORT,GetPropA(hWnd:UINT,lpString:STRING),UINT
DECLARE IMPORT,RemovePropA(hWnd:UINT,lpString:STRING),UINT
CONST WM_DESTROY = 2

enum cc
EDIT_1
EDIT_2
EDIT_3
BUTTON_11
BUTTON_12
endenum
WINDOW W1

OPENWINDOW W1,0,0,310,170,0,0,"Enter Tabbing",&W1_handler
   CONTROL W1,@EDIT,"Edit1",19,14,265,20,0x50810080,EDIT_1
   CONTROL W1,@EDIT,"Edit2",19,37,265,20,0x50810080,EDIT_2
   CONTROL W1,@EDIT,"Edit3",19,60,265,20,0x50810080,EDIT_3
   SubclassNumEdit(W1,EDIT_3)
   CONTROL W1,@SYSBUTTON,"Cancel",142,100,70,23,0x50010000,BUTTON_11
   CONTROL W1,@SYSBUTTON,"OK",216,100,70,23,0x50010000,BUTTON_12
FOR x = EDIT_1 TO EDIT_3
SETCONTROLNOTIFY(W1,x,1,1)
SETFONT W1,"MS Sans Serif",8,400,0,x
NEXT x
   SETFOCUS W1,EDIT_1

WAITUNTIL W1 = 0
   END

SUB W1_handler(),int
   SELECT @MESSAGE
CASE @IDCONTROL
select @CONTROLID
case EDIT_1
case& EDIT_2
case& EDIT_3
'Set the focus of the next control
select @NOTIFYCODE
case @ENENTERKEY
case& @ENTABKEY
SETFOCUS W1,@CONTROLID + 1
'Set the background color of the edit control
case  @ENKILLFOCUS
SETCONTROLCOLOR W1,@CONTROLID,0,0xFFFFFF
case  @ENSETFOCUS
SETCONTROLCOLOR W1,@CONTROLID,0,0xFFC94B
ENDselect
case BUTTON_12
CLOSEWINDOW W1
ENDselect
CASE @IDCREATE
CENTERWINDOW W1
CASE @IDCLOSEWINDOW
CLOSEWINDOW W1
case WM_DESTROY
UnSubclassNumEdit(W1,EDIT_3)
ENDSELECT
RETURN 0
ENDSUB

SUB SubclassNumEdit(parent:WINDOW,id:INT)
   hEdit = GETCONTROLHANDLE(parent,id)
   lpFn = SetWindowLongA(hEdit,-4,&numEditHandler)
'Save the old handler as a property in the edit control, this way we don't need any global variables
   SetPropA(hEdit,"edit_handler",lpFn)
RETURN:ENDSUB

SUB UnSubclassNumEdit(parent:WINDOW,id:INT)
'Restore the old handler and remove the property
   hEdit = GETCONTROLHANDLE(parent,id)
   SetWindowLongA(hEdit,-4,GetPropA(hEdit,"edit_handler"))
   RemovePropA(hEdit,"edit_handler")
RETURN:ENDSUB

SUB numEditHandler(hWnd:INT,uMsg:INT,wParam:INT,lParam:POINTER),INT
   SELECT uMsg
CASE @IDCHAR
IF ((wParam < 0x30) OR (wParam > 0x39)) AND (wParam <> ASC(".")) AND (wParam <> 0x08) THEN RETURN 1
ENDSELECT
RETURN CallWindowProcA(GetPropA(hWnd,"edit_handler"),hWnd,uMsg,wParam,lParam)
ENDSUB
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

Andy

Thanks Larry,

It's been a great help!!!

Andy.
:)
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.