more adventures in WX

BlitzMax Forums/Brucey's Modules/more adventures in WX

Wiebo(Posted 2009) [#1]
ok, stumbled upon this: i want to use right click to open a pop-up menu on a wxtreectrl item. I get the event because wxcodegen has created all that code for me automaticalyl, but now I have to find the object I right-clicked on... I don't understand a bit of this event stuff this module uses... I skimmed docs, and nothing really EXPLAINS how it works. All I see is coder comments and lot of type extensions, and i'm at a loss.

Can someone help me out to to understand the events in wxMax? plz? pretty plz?


Brucey(Posted 2009) [#2]
Hallo :-)

Not sure if this will help you any?


Brucey(Posted 2009) [#3]
Assuming you connect to wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, you will receive a wxTreeEvent passed into your callback function.

This event object has a GetItem() method with which you can get the wxTreeItemId object - ie. the item you clicked on.
With the itemId, you can query the treelist for things such as GetItemText().


DavidDC(Posted 2009) [#4]
Try "Cross-Platform GUI Programming with wxWidgets" Chapter 3, Event Handling. There is a free pdf version online if you google it.

Also, don't be afraid to head straight to the source in the wxmod folder. The event code is generally at the bottom of each source file - which is a quick way of finding the event name you are looking for.

e.g. For wxTreeCtrl, wxtreectrl.mod/wxTreeCtrl.bmx has this method at the bottom of the code page:




Wiebo(Posted 2009) [#5]
Brucey: your 2nd post was spot on, that's what I needed. I need to know more about how to get information out of the event.

davidDC: well, I headed into the source before I posted and yes, I found the events at the end of each source. But you know, looking at that doesn't tell me anything about HOW it works, but only which events get caught. It's not worth anything without know how to get the information you need out of the event.

Understand my dilemma? I'm getting there though! Thanks y'all.

Which additional methods does the event type contain? Where is the base type contained in the source code? Does anyone know that?


Brucey(Posted 2009) [#6]
wx.mod/events.bmx

These are the docs from 2.9.0 (which has not been released yet, but it's built with Doxygen, so you get pretty class hierarchies) : http://docs.wxwidgets.org/trunk/classwx_tree_event.html
It should be mostly relevant...


Wiebo(Posted 2009) [#7]
Yes, that's a good one. Thanks!


Wiebo(Posted 2009) [#8]
Alright. getID() doesn't seem to be the right method for me. I cannot get the wxtreeitemId from the wxTreeCtrl using the ID only. How weird is that. There is no mention in the docs of something like wxTreeCtrl.GetItem( id ). All the methods in wxTreeCtrl assume I have the wxTreeItemID already. which I don't. I only have its id. Any ideas?

If this doesn't work , I want to use HitTest, but that needs a wxPoint. I can get that from the mouse event (need to switch over to mouse events for that, instead of tree rightclick events), but wxPoint is not recognised. I cannot do something like: pos:wxPoint = Event.GetLogicalPosition()

Which mod do I need to Import to get it to work? It should be in the core module, but why can't I create my own?

baby steps, I know.


Brucey(Posted 2009) [#9]
If you have a wxTreeEvent object, you can use GetItem() to refer to the wxTreeItemId.

the ID you mention is the unique identifier for a control.

Are you still attempting this? : "i want to use right click to open a pop-up menu on a wxtreectrl item."
If yes, I can knock out a quick demo if you want?


Wiebo(Posted 2009) [#10]
I had it working with a wxTreeEvent... I got the item, I opened a popup menu, but only at mousepos 0,0... That's why I wanted to go to mouse events, but then I realized (while looking at the form editor) that I had attached the Mousemove event to the main window, and not the tree item. So I added it there, and now it all works...

Big discovery for me, that you can add events on widgets level, and not just on window level. But it's working now and it's awesome.

/me happy

thanks for the guidance folks. I'll ask more questions here when I'm stuck :)


Brucey(Posted 2009) [#11]
Glad you got it sorted!

Yes, the event handling in wxWidgets is exceptional.
You can subclass most widgets too, and basically override much of the functionality - as well as how it handles all of its events. Very useful.


Wiebo(Posted 2009) [#12]
Yes, but with lots of 'cotcha' moments :)


Brucey(Posted 2009) [#13]
Well, the documentation could be a little "more full", and I have gone through some of it - but there is a lot of it.

As David mentioned, that book is excellent. The C++ examples transfer almost exactly across to BlitzMax (since I've tried my best to match the original API).


Wiebo(Posted 2009) [#14]
It gets even better! I just found out that when I don't specify coordinated with PopupMenu() , the current mouse position is needed, so I don't need MouseEvents on the wxTreeCtrl at all.

I'll just file this under 'educational' and 'rtfm'


DavidDC(Posted 2009) [#15]
Well actually with wxMax and wxWidgets generally - "rtfm" isn't always as simple as it sounds. It sometimes takes a fair amount of googling and sifting through C++ or Python examples to find that key missing piece of info.

Downloading the actual C++ source helps - as does checking the sample code, and sometimes even the C++ sample code, as I'm not sure all the samples have been ported yet.

I also make the occassional search on the wxWidgets C++ forum.

Plain guess work has also been my friend on a few occassions!

That's not to say that Brucey hasn't done a great job with what he has been given to work with. It's just that wxWidgets is such a huge beast, and the emphasis has been on development over documentation in the wxWidgets team generally - at least according to my experience.

But at the end of the day it's well worth it. Once you get the feel of it, you tend to make the right guesses sooner rather than later - and there's no questioning the range and power of tools this exploration opens up for you.

[edit] OK, the above sounded a little heavier than intended. In the main, working with the different widgets has been a breeze and a pleasure. But the odd undocumented sections do exist where you need to be much more proactive to find the info you need - hence the above.


Brucey(Posted 2009) [#16]
But the odd undocumented sections do exist where you need to be much more proactive to find the info you need

Fair enough... :-)

If you feel a section/specific module is lacking in some way or other, you may wish to log an "issue" : http://code.google.com/p/wxmax/issues/list
That way, I can focus on improving the bits you all want improving.
A concept getting you down? Well, maybe we need some more examples...


DavidDC(Posted 2009) [#17]
Yes, I need to be less slack and post/document the tricky bits as I come across them as well :-)


Wiebo(Posted 2009) [#18]
Well I'll keep posting my 'cotchas' in this thread so you may have an idea of where there are holes in the docs. It will also be helpful for those who attempt to use this mod as well. But you're right, it's awesome and waaay more functional than the BRL mod, which I decided to un-install completely (for now)


Wiebo(Posted 2009) [#19]
I have a question about setting up events.

I have propertygrid and as you know, it's not supported by wxCodeGen so I do my setup in the extended frame, not the base frame. After the setup I call
Connect(PROPERTY_GRID.Getid(), wxEVT_PG_CHANGED, OnPropertyGridChange)
to catch the changing of fields.

I get this error while compiling: Unable to convert from 'Int(wx.wx.wxEvent)' to 'Int(wxEvent)'

If I add the setup and connect code into the base frame type, it works...

Which dependency am I missing?


Brucey(Posted 2009) [#20]
OnPropertyGridChange needs to be a Function with the parameter wxEvent.
eg.
Function OnPropertyGridChange(event:wxEvent)
...

(assuming this is the issue of course...)

What I've tended to do, to make my life a little easier (and is how the generated code works, is something like this :
Function _OnPropertyGridChange(event:wxEvent)
    BASETYPE(event.parent).OnPropertyGridChange(wxPropertyGridEvent(event))
End Function

Method OnPropertyGridChange(event:wxPropertyGridEvent)
 ....
End Method

Sometimes you need to swap event.parent for event.sink - depending how you are using Connect.

Anyway, that's just an assumption based on the supplied information.
Never be afraid to post code snippets ;-)


Wiebo(Posted 2009) [#21]
Is there a 'Brucey customer department' or something with several Bruceys monitoring the threads? :)

Adding that code sure did the trick. Your assumptions were correct!
Can you tell me why adding that extra function makes your life easier, because using just the function (I was using a method, duh) works as well.


Brucey(Posted 2009) [#22]
Can you tell me why adding that extra function makes your life easier

If you have a lot of code which refers to different objects that belong to the "parent", then you kind of need to do this :
Function.......
    Local frame:MyFrame = MyFrame(event.parent)

    frame.myobject.doSomething(....)

   ....
End Function

Or this...
Function.......

    MyFrame(event.parent).myobject.doSomething(....)

   ....
End Function


Whereas, from a Method, you can simply have this :
Method .........

    myobject.doSomething(....)

    ....
End Method


I'm all for number 3.
If you have a look at some of the samples, you'll see various uses of 1 and 2, but I think 3 is cleaner, although you do have that extra "pass-through" function.


Wiebo(Posted 2009) [#23]
Oh I answered my own question ust yet. If the connected code is in a Function you cannot access the internal fields in the 'live' type! Makes sense.


Wiebo(Posted 2009) [#24]
Like you mention in your post while I was busy typing mine.


Wiebo(Posted 2009) [#25]
[edit]never mind this post, I mixed up some docs and was qeuering the wrong fields and stuff.[/edit]


Wiebo(Posted 2009) [#26]
Hi Brucey,
I'm working on the property grid again. Is wxPGChoices.Clear() implemented? I cannot use it. I get an error at compile time: Indentifier 'clear' not found. Is there another way to clear a choices list?


Brucey(Posted 2009) [#27]
Oops. The one that got away?

Should be there now. Sorry.


Wiebo(Posted 2009) [#28]
Ah cool! Well, you know there is nothing better to test a module for completeness than building an application with it :) I assume you updated the version in SVN and not the compiled version?

Will you also be able to add the float property to the propertygrid? I'm using strings now to store them.


Brucey(Posted 2009) [#29]
you know there is nothing better to test a module for completeness than building an application with it

Absolutely!! Which is why I find writing things such as that radio player so useful. Helped me sort some issues with wxWidgets and the BASS module - just little things which you don't really notice until you start to use them.

Will you also be able to add the float property to the propertygrid?

Should be in there already. (Internally uses the Double property, but is exposed as Float through the API). If you can't see it, perhaps you are using it in a different place.

I assume you updated the version in SVN and not the compiled version?

Yeah. I'm saving up for the next full release. ;-)


Wiebo(Posted 2009) [#30]
Got an SVN update.... It broke a lot of code in my propertygrid stuff, thanks :)

Local col:wxcolour = PROPERTY_GRID.GetPropertyColourByName("particle_end_color")

Doesn't work anymore. How do you suggest I get to the property now?


Wiebo(Posted 2009) [#31]
I'm doing this now:
Local property:wxpgproperty = PROPERTY_GRID.GetPropertyByName("particle_start_color")
Local col:wxcolour = PROPERTY_GRID.getpropertycolour(property)

Is that the prefered method?


Wiebo(Posted 2009) [#32]
Also , wxFloatProperty is still not available to create. I also cannot add it to the grid example provided.


Wiebo(Posted 2009) [#33]
another question: I have this code:
ParticleBlendChoice = New wxPGChoices.Create()
ParticleBlendChoice.Add("Light blend", LIGHTBLEND)
ParticleBlendChoice.Add("Alpha blend", ALPHABLEND)
ParticleBlendChoice.Add("Shade blend", SHADEBLEND)

pg.AppendIn( particles, New wxEnumProperty.CreateWithChoices("Blend", "particle_blend", ParticleBlendChoice,LIGHTBLEND) )

Choice is now default at the option LIGHTBLEND. Now I want to set the choice selection to another entry, how do I do that? I can't find a Set method which is valid. But there must be one, right?


Brucey(Posted 2009) [#34]
Doesn't work anymore. How do you suggest I get to the property now?

Remember I said I was removing the ...ByName() methods?

Just remove "ByName" from the method name and it will work. It halves the number of exposed methods - less for me to deal with.

so...
Local col:wxcolour = PROPERTY_GRID.GetPropertyColour("particle_end_color")



Brucey(Posted 2009) [#35]
Now I want to set the choice selection to another entry, how do I do that?

I'm trying to work it out... please hold the line... :-p


Brucey(Posted 2009) [#36]
Righty... after some tinkering with the propgrid sample...

You can do this, using a reference to the enum property :
  enum_prop.SetValueInt(LIGHTBLEND)


it's magic ;-)


Wiebo(Posted 2009) [#37]
Hey thanks for those tips, I'm making progress again. It would be cool if you could do something about wxFloatProperty, which is not present at the moment as far as I can see.


Brucey(Posted 2009) [#38]
It should be there now.


Wiebo(Posted 2009) [#39]
Indeed it is! Thanks very much.

There is one more thing I really need to know, but I cannot find out how to do it. I've created a wxMultiChoiceProperty and added a list of choices to it. How can I read and set which of the choices are selected?


Brucey(Posted 2009) [#40]
Try calling property.GetValueAsArrayInt:Int[]().


Wiebo(Posted 2009) [#41]
That seems to be it, but I cannot create a wxArray... nor wxArrayInt or wxArrayString... Is it implemented? I cannot find it in the source :/
I can use Event.GetpropertyValueAsString() as well, which gets me a ; delimited string which contains the labels, but not the indexes. Not really what I need.


Brucey(Posted 2009) [#42]
Is it implemented? I cannot find it in the source

No... you'll get an Int[] back from the method.


Wiebo(Posted 2009) [#43]
Yes, I noticed that :/ A workaround for me is to split the returned string, search through the list of selectable items and get their indexes... Messy but works. Might was well do that as arrays are out of the question for now.

Makes me wonder if I actually be able to SET the multiselections.. I cannot find in the references a way on how to do that.


Brucey(Posted 2009) [#44]
What's the Int array return? I though it would simply be the list of selected indexes?


Wiebo(Posted 2009) [#45]
well, if I do this
Local ch:wxMultiChoiceProperty = wxMultiChoiceProperty(PROPERTY_GRID.GetPropertyByName("emitter_spawners"))
Local arr:Int[] = ch.GetValueAsArrayInt()

then my app crashes :)


Brucey(Posted 2009) [#46]
Ah... probably not the desire result ;-)


Brucey(Posted 2009) [#47]
Okay, it shouldn't crash now...


Wiebo(Posted 2009) [#48]
Awesome. I'm updating SVN after I have taken a shower :) Will report back here


Brucey(Posted 2009) [#49]
I just tried it in the sample... and that seems to work - the array contains the *values* of each of the selected items.

So, if I had two checked, the returned Int array was length of 2.


Wiebo(Posted 2009) [#50]
yes, it works now! I do this...
Local ch:wxMultiChoiceProperty = wxMultiChoiceProperty(PROPERTY_GRID.GetPropertyByName("emitter_spawners"))
Local arr:Int[] = ch.GetValueAsArrayInt()

If arr = Null Then DebugLog "nothing"	; Return
For Local a:Int = 0 To arr.length -1
     DebugLog arr[a]
Next

..and I get the index values of the selected choices. So that's mission accomplished. Now, to set the selections :) BTW : this is the last of the property challenges I'm having so there is light at the end of the tunnel :)


Wiebo(Posted 2009) [#51]
Brucey,

I notice that ChangePropertyValueIntArray in wxPropertyGrid is marked as TODO. I think that one is needed to select items in multichoice properties. Am I right?


Brucey(Posted 2009) [#52]
Having had a rummage in the actual source of wxPropGrid, it looks like that method will do the job. Watch this space...


Wiebo(Posted 2009) [#53]
That would be awesome and it would allow me to add the final touch to my editor... Thanks for your support through these days, Brucey...


Brucey(Posted 2009) [#54]
Thanks for your support through these days

No worries :-)
Sorry you have been the guinea pig for much of this...


Anyway... it all seems to compile (at least), so see if that method does what we think it does.


Wiebo(Posted 2009) [#55]
Thanks for the update! Looking at the size of this mod I'm not suprised that stuff is missing or not working. Luckily, I'm not working with deadlines =]

Nothing happens though when I use this:
PROPERTY_GRID.ChangePropertyValueIntArray(ch, array)

where ch is the multichoiceproperty. I get no error, no crashes, just nothing. I can see in the mod source that I have the new version, there is code at the method declaration, so I'm sure I have the latest version compiled.

I also doing a PROPERTY_GRID.refresh() but nothing shows up.


Wiebo(Posted 2009) [#56]
Back with a vengeance. =] wxTreeCtrl event (wxEVT_COMMAND_TREE_END_DRAG) is not raised when I release the mouse button after a drag... The start of the drag (wxEVT_COMMAND_TREE_BEGIN_DRAG) works fine though. All seems fine in the export from wxCodeGen.

Any ideas, Brucey?


Wiebo(Posted 2009) [#57]
Hi Brucey,

Could you take a look at the probs with multichoice and mousedrag end? I'd love to get these working now.


Wiebo(Posted 2009) [#58]
oh and one more question. How do I make a wxGLCanvas size with the sizer it's placed on?


Wiebo(Posted 2009) [#59]
Succes in plugging the engine into the editor! Maybe you're interested in what I've been up to with wxMax, so here are some screenshots:

http://wiebo.wordpress.com/2009/02/10/particle-engine-up-and-running-in-the-editor/


Brucey(Posted 2009) [#60]
Funnily enough, I missed posts 55 & 56... I'll have a look into it this evening.
Sorry for the delay...
(having too much fun with Raknet I suppose... :-p )


Wiebo(Posted 2009) [#61]
No problem Brucey... I've been busy being sick and plugging holes in my code =]


Brucey(Posted 2009) [#62]
For the dragging... try calling event.Allow() against the wxEVT_COMMAND_TREE_BEGIN_DRAG.
Apparently, by default the drag event is vetoed, so you must specifically allow it.

Google cache of some mention of it, and lack of docs mentioning it :

http://74.125.77.132/search?q=cache:lbdlVojpTqIJ:trac.wxwidgets.org/ticket/3915+wxtreectrl+drag&hl=en&strip=1


Of course, if that doesn't help you, be sure and let me know :-)


Brucey(Posted 2009) [#63]
I seem to have the selection thing working, although it appears to be a bit backwards...
pg.ChangePropertyValueStringArray(mc, ["Cabbage"])

(taken from the sample)

Would be nice to be able to set it via either by index, or the values...


Wiebo(Posted 2009) [#64]
OK, allowing the drag event works! That is cool. Now I can let the user drag and drop image to particle, particle to spawner, spawners to emitter.. This saves a lot on selecting and typing from the user.

Yes, my idea about the multi selection is to get it working with the index. In fact, labels could be (in theory) be identical... I'll see what happens if I use a string... I would definitly prefer index., through
PROPERTY_GRID.ChangePropertyValueIntArray(ch, array)



Brucey(Posted 2009) [#65]
I would definitly prefer index., through

So would I. I'll have a look and see if there is a way to hack around it and provide that functionality.

btw, I've just updated to the latest wxPropGrid source - various bug fixes and such like.


Wiebo(Posted 2009) [#66]
I just tested with strings (works fine) and with identical labels and the grid doesn't give a damn, it works like a charm. I never expected that!

Did you update SVN? is it safe? =]


Brucey(Posted 2009) [#67]
is it safe?

Well, I've only tried it on Mac so far, and it seems to work ok.
Although one bug fix means that if you create a grid with wxPG_AUTO_SORT, it does actually sort it now... (the sample uses this flag, and now everything appears in a different order - I hadn't noticed that it didn't work til now).


Wiebo(Posted 2009) [#68]
I take that last statement back Brucey. Having and selecting two identical labels selects the same item twice... It looks like the property enumnerates the strings and selects the first one it encounters.... Like I expected it to. So selection by index seems to be very important to avoid this.


Brucey(Posted 2009) [#69]
Are you likely to have two identical labels?


Brucey(Posted 2009) [#70]
Righty... I've added a new method for wxMultiChoiceProperty :

SetValueIntArray(value:Int[])

Pass in an array of values. These are the same values as you would get from a call to GetValueAsArrayInt().
Note that these arrays are not indexes. Yes, if you happen to number your values as 0, 1, 2, ....10, they will appear that way, but they are "values". For example, in the sample :
	Local tchoices:wxPGChoices = New wxPGChoices.Create()
	tchoices.Add("Cabbage",10)
	tchoices.Add("Carrot",15)
	tchoices.Add("Onion",20)
	tchoices.Add("Potato",25)
	tchoices.Add("Strawberry",30)

Those values are what would be returned from a call to GetValueAsArrayInt().

Anyhoo... calling this seems to work in the sample :
mc.SetValueIntArray([10, 11, 30])


I've based the code on how it sets the property after the choice dialog has been displayed and you've selected your choices.

wxPGProperty already has a SetValueIntArray() method, so I'm really just overriding its use here, although in reality the multichoice property doesn't support this functionality. No harm in extending it though :-)


See if that does what you need.


Wiebo(Posted 2009) [#71]
Are you likely to have two identical labels?

I can work around it, but it's nice to know that internally things work ok :)

Note that these arrays are not indexes

Oh but that's exactly what I need. Each item in my particle library has a unique ID and that is what I'm going for here.

I'll let you know how it's going.


Brucey(Posted 2009) [#72]
"Note that these arrays are not indexes"
Oh but that's exactly what I need. Each item in my particle library has a unique ID and that is what I'm going for here.


I guess it works how you want then.

When you've previously used the word "index" I thought you meant index in the sense of the value zero being the first item in the list (ie. index 0).
The "values" stored in a multichoice (or any choice) property can be any value, in any order.

:-)


Wiebo(Posted 2009) [#73]
Ok, works as intended, as far as I can see! The new propertygrid source is working as well, as I re-compiled it just now of course.


Brucey(Posted 2009) [#74]
Hey ho... seeing as you've still not got your resizing working.. here's an example of the glmax2d sample with support for resize :

Note the call to SetViewport() when required.

:o)


Wiebo(Posted 2009) [#75]
Ahh =] I'll implement that right now! thanks m8


[some time later] Works like a charm. Thanks! [/some time later]


DavidDC(Posted 2009) [#76]
Shouldn't you be skip()'ing the size event Brucey?

From wxEvent docs:

In general, it is recommended to skip all non-command events to allow the default handling to take place



Brucey(Posted 2009) [#77]
Probably :-)
I just hacked the example together... (as one does!)


Wiebo(Posted 2009) [#78]
BACK!!

I'm doing some more GUI things for my editor, and guess what happens when I try to raise an event when moving splitter sashes?
This is the generated code from CodeGen at the event setup part:
left_splitter.ConnectAny(EVENT_OnSplitterSashPosChanged_NOT_AVAILABLE, 
_OnLeftSplitterChange, Null, Self)

Ofcourse, the same event is added in the methods part of the code:
	Function _OnLeftSplitterChange(Event:wxEvent)
		MAIN_FRAMEBase(Event.sink).OnLeftSplitterChange(EVENT_OnSplitterSashPosChanged_NOT_AVAILABLE(Event))
	End Function

	Method OnLeftSplitterChange(Event:EVENT_OnSplitterSashPosChanged_NOT_AVAILABLE)
		DebugLog "Please override MAIN_FRAME.OnLeftSplitterChange()"
		Event.Skip()
	End Method

So, I'm not saying this is a wxMAX problem, but more a codegen problem.. According to the wx docs, the splitter should create a wxSplitterEvent.
wxFormBuilder 3.0 supports this event, calls it a OnSplitterSashPosChanged.
Any ideas on how to fix this , Brucey?


Brucey(Posted 2009) [#79]
Oops. Thought I had them all !

I've committed the changes, which you can get either by updating all of wxMax, or just the tools (if you aren't yet using the latest breakable code).

Or you can add this :
	AddEvent(TEventType.Set("OnSplitterSashPosChanged", "wxSplitterEvent", "wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGED"))
	AddEvent(TEventType.Set("OnSplitterSashPosChanging", "wxSplitterEvent", "wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGING"))
	AddEvent(TEventType.Set("OnSplitterDClick", "wxSplitterEvent", "wxEVT_COMMAND_SPLITTER_DOUBLECLICKED"))
	AddEvent(TEventType.Set("OnSplitterUnsplit", "wxSplitterEvent", "wxEVT_COMMAND_SPLITTER_UNSPLIT"))

to the InitEvents() function in code_gen.bmx.

HTH.


Wiebo(Posted 2009) [#80]
Ah, that's super! I havent updated wxMAX in a while so I will just get the new tools. Thanks Brucey.