May 11, 2024, 09:52:36 PM

News:

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


EB window as child of custom control

Started by LarryMc, October 23, 2008, 03:19:46 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

LarryMc

I'm building another custom control that isn't based upon any existing windows control.

I want to have my custom control be the parent of an EBasic window so that I can do some things in that window using EBasic commands.

My custom control handler creates an instance unique UDT that contains configuration information for that particular custom control. 

Q1. How do I implement the child EBasic window inside the handler for the custom control?

Q2. How do I access that parent UDT in the message hander for the child EBasic window?

If the first 2 are doable:
  I would like to use the new modular OnMessage... functionality for the child window.

Q3. How would I pass elements from the UDT in the instance of the parent custom control into OnMessage.... subroutines for the associated child window?  It would appear the UDT would need to be global but there will be multiple instances of the custom control.

It might all be easy as pie but I'm just not seeing it right now.

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

sapero

Larry, read about the @HITWINDOW pointer. Before your handler gets called, this pointer is initiaized to the address of current WINDOW structure. You can use it instead global WINDOW variables.

TYPE WCONTROL
' WINDOW must be first
WINDOW win
' all control specific variables here
int control_color
int control_styles
string other_info
ENDTYPE


sub OpenNewWControl()
pointer ctrl

ctrl = new(WCONTROL, 1)
settype ctrl, WCONTROL

' initialize window data before creating it
*ctrl.control_color  = ?
*ctrl.control_styles = ?
*ctrl.other_info     = ?

openwindow(*ctrl.win, ..., &WControlHandler)

return
endsub


' use this handler only for windows created by OpenNewWindow()
sub WControlHandler
pointer pwwin

' this is the best place to save @HITWINDOW value
pwwin = @HITWINDOW
settype pwwin, WINDOW   /* always TRUE */
settype pwwin, WCONTROL /* only TRUE if our creator is OpenNewWindow */

select @MESSAGE
case @IDCREATE
' access variables private to this window
some_function1(*pwwin.control_color)
some_function2(*pwwin.control_styles)
some_function3(*pwwin.other_info)
some_function4(*pwwin.win.hwnd) /* access the current WINDOW udt */

case @IDDESTROY
' delete variables private to this window
delete pwwin

endselect
return
endsub


I think it was 1 and 2.
Q3 - you can share pointers between windows by "connecting" a pointer to window handle.
To 'connect' you can call SetProp(window.hwnd, "pointer to my udt", pointer or int) or SetWindowLong(window.hwnd, GWL_USERDATA, pointer or int).
To read back the pointer from window handle - use same functions with replaced Set with Get, without last parameter.

Lets say you have N child windows on main window. Every child is created by OpenNewWControl() to ensure that @HITWINDOW will point to same udt - extended version of WINDOW udt. Now if one child needs to access udt of another child - you need only the child handle, pass it to GetProp or GetWindowLong to receive the pointer to udt.
To do it in this way, you'll need to append one line to @IDCREATE handler in WControlHandler:
SetWindowLong(*pwwin.win.hwnd, GWL_USERDATA, pwwin)

Try it, it's really easy.

LarryMc

Sapero
QuoteTry it, it's really easy.
;)

For now let's forget about the "onevent " message handling that Paul recently added.

I want to create my on custon control using CONTROLEX with my own registered class.

The control's procedure gets hwnd, msg,hparam and lprarm as passed parameters.
The procedure has WM_create, destroy, buttondown, etc msg handling sections.

In the WM_PAINT message handling section I would like to do something like for example:

s.CreateWindowed(0,0,800,600,@noCAPTION,"",PARENT,true)
where PARENT is not a WINDOW OR DIALOG type UDT but is the hwnd of my custom control.

I guess I'm wanting (or think I'm wanting) to be able to plug a hwnd variable in where a WINDOW UDT normally goes.

Is there a way to accomplish that?  I'm wanting to use Paul's higher level functions in my custom control instead of having to use the api for everything.

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

sapero

Passing a parent handle mean you are creating a child window, so CONTROLEX still can be used:
WINDOW temp
temp.hwnd = PARENT
CONTROLEX temp, ...

LarryMc

Sapero,
I know you are telling me what to do and it seems so easy for you but I just can't understand due to my limited abilities.

I can't get from what you showed me above to something that looks like this psuedo code:
registermyclass()

openwindow(mainwin, ...parent(=0), &mainHandler)
controlex(mainwin,"myclass".....,id)

waituntil mainwin=0
end

sub mainHandler()

....normal stuff

endsub

sub myclassprocedure(whnd,msg,wparam,lparam)

select msg
case @wm_create
openwindow(thisinstanceclasswin, ...parent(=this controls id), &thischild windows handler)
case @wm_paint
s.CreateWindowed(0,0,800,600,@noCAPTION,"",PARENT(=thisclasswin),true)
case @wm_destroy
   closewindow thisinstanceclasswin
endsub


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

sapero

I think you want to create 3D window inside yor control. Am I right?
In attached example I've used a subclassed button to simulate your control.

LarryMc

Sapero

THANKS! ;D

Your example is in a format that even I can understand.

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

LarryMc

Besides fooling around with my custom control I've been looking at OOP classes.

So, here comes my next off-the-wall question.

Can I create a class that is instantiated in the "create" case of my custom control's message handler.

my class would have a method for each of the other messages that have to be handled + other supporting messages.
The class' member variables would be all that large amount of stuff I store in a udt pointed to by GWL_USERDATA.

That would allow me to use subroutines(methods) to make my code more modular.

I can't see any reason why it couldn't be done that way

Any Pros/Cons?

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

sapero

Sure, instantiate your class with NEW, and save the pointer in GWL_USERDATA. After this initialize the m_hwnd.
sub myclassprocedure(whnd,msg,wparam,lparam)

pointer pThis = GetWindowLong(hwnd, GWL_USERDATA)
settype pThis, CMyClass

select msg

case WM_NCCREATE:
' lParam = pointer to CREATESTRUCT*
' if you used CreateWindowEx, access your parameter in
' *<CREATESTRUCT>lParam.lpCreateParams
' TIP: You can move this to WM_CREATE
pThis = new(CMyClass, 1)
*pThis.m_hwnd = hwnd
SetWindowLong(hwnd, GWL_USERDATA, pThis)
return TRUE ' allow window creation

case WM_CREATE:
' lParam = pointer to CREATESTRUCT*
*pThis.OnCreate()

case xx:
*pThis.OnXX()

case WM_NCDESTROY: ' or WM_DESTROY
delete pThis


sub CMyClass::OnCreate()


Note to my previous answer: you can delete the new(WINDOW) right after using it, there is no need to hold it until your 3d screen is deleted.

LarryMc

November 21, 2008, 06:16:32 AM #9 Last Edit: November 21, 2008, 06:22:35 AM by Larry McCaughn
Sapero,
with your note about moving code to WM_CREATE are you saying this is valid?
sub myclassprocedure(whnd,msg,wparam,lparam)

  pointer pThis = GetWindowLong(hwnd, GWL_USERDATA)
  settype pThis, CMyClass

  select msg

    case WM_CREATE:
        pThis = new(CMyClass, 1)
       *pThis.m_hwnd = hwnd
       SetWindowLong(hwnd, GWL_USERDATA, pThis)
       *pThis.OnCreate()

    case xx:
        *pThis.OnXX()

    case WM_DESTROY
        delete pThis


sub CMyClass::OnCreate()

And I'm using CONTROLEX to create my control...so it uses CreateWindowEx if the parent is a window but it does something entirely different when the parent is a dialog.


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

sapero

Roger, you did it correct. The WM_NCCREATE message is sent prior to the WM_CREATE message when a window is first created. I posted this to let you choose one message. While processing WM_NCCREATE in a dialog, there is no single control yet, the window is 'empty'.

LarryMc

Thanks again Sapero!

As always, You're the Man!!

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

LarryMc

Sapero,
With the example you gave above I had no problem setting up my class inside a custom control.
I'm calling OnPaint as I would expect; etc.

I have succeeded in loading a bitmap background for my control or have it paint a color.

But I'm getting some strange results

I'm creating 3 controls for testing using a create function that calls CONTROLEX.
other than the size and title of each control being different all the other presets are initialized inthe constructor of the class which makes them all the same with the exception of size and title.
So I have all 3 loading the same bitmap bground.

If I create the 1st control with more than 2 characters all 3 controls are created with rows and rows of icon looking squares that have nothing in common with my bitmap.  Then I can put 2 characters in the 2nd control's title and put up to 6 characters in 1st title and it displays correctly.  Add a character in either title and I get the little icon looking squares.

I don't have a clue as to what is causing it. 

I was wondering if maybe there is some special way I need to address the member variables; since I have to use the *pThis.Onxx to address the methods.

I know I haven't given you much to work with but do you have any ideas at all?


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

sapero

Hard to answer not seeing your code. It may be a bug in global data sharing (eg. no reference counter).

LarryMc

My work around was to not send a window title in CONTROLEX.
My control requires the use of another config function to set things up so I just put the title in there.
No Fuss, No Muss.

Thanks for giving it some thought, though.

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