more adventures in WX
BlitzMax Forums/Brucey's Modules/more adventures in WX
| ||
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? |
| ||
Hallo :-) Not sure if this will help you any? |
| ||
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(). |
| ||
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: |
| ||
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? |
| ||
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... |
| ||
Yes, that's a good one. Thanks! |
| ||
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. |
| ||
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? |
| ||
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 :) |
| ||
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. |
| ||
Yes, but with lots of 'cotcha' moments :) |
| ||
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). |
| ||
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' |
| ||
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. |
| ||
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... |
| ||
Yes, I need to be less slack and post/document the tricky bits as I come across them as well :-) |
| ||
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) |
| ||
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? |
| ||
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 ;-) |
| ||
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. |
| ||
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. |
| ||
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. |
| ||
Like you mention in your post while I was busy typing mine. |
| ||
[edit]never mind this post, I mixed up some docs and was qeuering the wrong fields and stuff.[/edit] |
| ||
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? |
| ||
Oops. The one that got away? Should be there now. Sorry. |
| ||
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. |
| ||
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. ;-) |
| ||
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? |
| ||
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? |
| ||
Also , wxFloatProperty is still not available to create. I also cannot add it to the grid example provided. |
| ||
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? |
| ||
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") |
| ||
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 |
| ||
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 ;-) |
| ||
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. |
| ||
It should be there now. |
| ||
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? |
| ||
Try calling property.GetValueAsArrayInt:Int[](). |
| ||
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. |
| ||
Is it implemented? I cannot find it in the source No... you'll get an Int[] back from the method. |
| ||
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. |
| ||
What's the Int array return? I though it would simply be the list of selected indexes? |
| ||
well, if I do this Local ch:wxMultiChoiceProperty = wxMultiChoiceProperty(PROPERTY_GRID.GetPropertyByName("emitter_spawners")) Local arr:Int[] = ch.GetValueAsArrayInt() then my app crashes :) |
| ||
Ah... probably not the desire result ;-) |
| ||
Okay, it shouldn't crash now... |
| ||
Awesome. I'm updating SVN after I have taken a shower :) Will report back here |
| ||
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. |
| ||
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 :) |
| ||
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? |
| ||
Having had a rummage in the actual source of wxPropGrid, it looks like that method will do the job. Watch this space... |
| ||
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... |
| ||
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. |
| ||
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. |
| ||
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? |
| ||
Hi Brucey, Could you take a look at the probs with multichoice and mousedrag end? I'd love to get these working now. |
| ||
oh and one more question. How do I make a wxGLCanvas size with the sizer it's placed on? |
| ||
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/ |
| ||
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 ) |
| ||
No problem Brucey... I've been busy being sick and plugging holes in my code =] |
| ||
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 :-) |
| ||
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... |
| ||
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) |
| ||
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. |
| ||
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? =] |
| ||
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). |
| ||
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. |
| ||
Are you likely to have two identical labels? |
| ||
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. |
| ||
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. |
| ||
"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. :-) |
| ||
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. |
| ||
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) |
| ||
Ahh =] I'll implement that right now! thanks m8 [some time later] Works like a charm. Thanks! [/some time later] |
| ||
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 |
| ||
Probably :-) I just hacked the example together... (as one does!) |
| ||
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? |
| ||
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. |
| ||
Ah, that's super! I havent updated wxMAX in a while so I will just get the new tools. Thanks Brucey. |