Jump to content


GUI message handling


12 replies to this topic

#1 Stainless

    Member

  • Members
  • PipPipPipPip
  • 578 posts
  • LocationSouthampton

Posted 03 November 2012 - 03:35 PM

I have to write yet another gui. Probably my 100'th or something.

Anyway, normally I use a signal class and each widget defines a signal handler per event.

So you end up something like this.

class Button : public Widget
{
private:
    signal1<Button*> OnClicked;
public:
    signal1<Button*> *get_clicked_signal();
}

The trouble with this approach is you end up creating a lot of signals on some widgets, and creating a widget is a bit messy.
By the time you have called the gets on the each event you may have a dozen lines of code.

So I'm thinking of other approaches. I don't like the old win32 idea of having a single message pump, you end up with a huge switch statement with rubbish like this

switch (message)
{
     case BACKBUTTON_PRESSED:
       break;
     case FORWARDBUTTON_PRESSED:
       break;
      ........................................................
     case LITTLE_WIDGET_IN_THE_TOP_LEFT_CORNER_MOUSE_OVER:
      break;
     case OH_MY_GOD_IF_I_ADD_ONE_MORE_CASE_TO_THIS_SWITCH_I_WILL_KILL_MYSELF:
      break;
}

So I'm wondering if anyone has come up with a different approach.

It's more from boredom of having to create yet another gui than anything else

#2 TheNut

    Senior Member

  • Moderators
  • 1696 posts
  • LocationThornhill, ON

Posted 04 November 2012 - 04:37 AM

I follow the same design as WPF, which is essentially an events and delegate approach, data binding, and behaviours. One difference from your code is that I don't bother with a getter, I just make the events public. It keeps the code succinct and it's handy for writing UI test stubs since I could execute the click event from an external class. Data binding and behaviours are also great to work with as they decouple business logic from my UI controls and allows me greater level of customization. There's a lot more to it then what I can really write about here, but I loved it enough to spend the time to port it.

I've used a few other UI systems such as Win32, MFC, .NET forms, ClanLib's UI, Qt, WxWidgets, and briefly took a look at CEGUI. From my experience, none come close to the design of WPF. I won't say it will cut your coding down, it may increase it when you consider the grand design, but it most certainly keeps true to MVC design principles and really organizes your code.
http://www.nutty.ca - Being a nut has its advantages.

#3 fireside

    Senior Member

  • Members
  • PipPipPipPip
  • 1586 posts

Posted 04 November 2012 - 08:25 AM

I happen to like switch/case. I like everything grouped together and call a function of like name. When using Java, I always use one listener. Seems like a waste to have more. Games are not productivity software and I think some coders get carried away with the whole thing. Scroll bars come in handy, but that's about as far as I go, and a lot of the time, they make more work for the gamer. I'd also much rather use someone else's because I hate doing it. I suppose that's why there are so many around. I do like a nice background texture so at least it doesn't look like productivity software.
Currently using Blender and Unity.

#4 Stainless

    Member

  • Members
  • PipPipPipPip
  • 578 posts
  • LocationSouthampton

Posted 04 November 2012 - 04:53 PM

I love doing the pretty bits of guis, coming up with nice animation effects, etc.

The nuts and bolts of a gui are the boring bits I have done so many times before I can do it in my sleep. Literally.

For me it's getting the balance right between versatility, and coding speed.

Say you want to add a button, you create an instance of a button, maybe set the position, set the text, maybe set the sound effect, possibly set up different graphics for each button state, etc.etc. etc.

So adding a single button to a container could quite easily require 30-40 lines of code.

So you setup default values for everything, start coding the game and find that now you want ANOTHER optional variable on the button..... :blink:

Linking a widget into the game logic is one of those points that can easily lead to huge code bloat.

In my existing GUI, you can put widgets into a container which automatically figures out the best way to display them all in the available screen space. This is fine and not that complex code, but in some circumstances one of the widgets can trigger a re-arrangement of all the widgets. Doesn't sound complex, until you start thinking about which classes can see other classes etc.

I'm just trying to think of a new way of handling all this that can keep the code from inflating like a man stepping out of an airlock into the vacuum of space.

#5 fireside

    Senior Member

  • Members
  • PipPipPipPip
  • 1586 posts

Posted 04 November 2012 - 05:36 PM

Quote

So you setup default values for everything, start coding the game and find that now you want ANOTHER optional variable on the button..... :blink:

That's why I like object oriented code. You can add a variable to the base class and it affects everything, or add a derived class if it's only a certain button that needs different characteristics.
Currently using Blender and Unity.

#6 TheNut

    Senior Member

  • Moderators
  • 1696 posts
  • LocationThornhill, ON

Posted 04 November 2012 - 11:46 PM

That is one of the perks with WPF. If you want to extend logic for a control, for example adding sound playback on button clicks, you would add that as a behaviour. Behaviours themselves are classes, but designed in a way to abstract the details. When a behaviour is added to a control, its "Attached" method is called and it contains a pointer to the control. Likewise, when removed the behaviour's "Detached" method is called. Thus, you can hook into whatever events are available in the control and act on them.

For dealing with new property types, WPF addresses this using what they call dependency objects and properties. It's basically a dictionary object with an key and value type object. By it's nature it is bound to the data binding engine, so any updates to a dependency object automatically notify listeners. If I wanted to render a button in a particular row and column in a grid control, I'm not going to create a new button class or extend the existing one. I'll just define the grid row and column dependency properties for the button. If I change these values, the grid will automatically pick these up and refresh the layout.

For designing UIs, I use a similar XAML (XML) file format. The default loader handles the commonly supported controls, but it offers the ability to add extensions, so I can load any new custom control I create. By nature of dependency properties, I can define any property in XAML and have them auto loaded into my control.

Stainless said:

from inflating like a man stepping out of an airlock into the vacuum of space.
Or like in Total Recall where the eyes bulge out and the body explodes violently. Alas, reality is not that exciting :)
http://www.nutty.ca - Being a nut has its advantages.

#7 Vilem Otte

    Valued Member

  • Members
  • PipPipPipPip
  • 345 posts

Posted 05 November 2012 - 01:21 AM

Am I really the only guy here (don't call me masochist again, please :D ), who uses GUI system created in native C with function pointers (e.g. no derived classes (actually no classes at all), etc.)?

Basically this GUI originated a long time ago (and it was used in quite a lot of applications), the thing is that I've never used it actually in game, only inside database apps. :)
On my defence, the code isn't a unusable and unmaintable bloat (which OOP codes often becomes), and imo it's even a bit easier to use than to work with OOP model - you got just structures containing other structures (like every structure in GUI contains widget_t structure) and function pointers (standard onMouseOver, onClick, etc. etc. - you know it), invoked when needed. I think OOP here would bring (and brings) some complications that would made it harder to use.
My blog about game development (and not just game development) - http://gameprogramme...y.blogspot.com/

If you don't know how to speed up application, go "roarrrrrr!", hit the compiler with the club and use -O3 :D

#8 Stainless

    Member

  • Members
  • PipPipPipPip
  • 578 posts
  • LocationSouthampton

Posted 05 November 2012 - 09:51 AM

ermmmmmm YES! :D

I really do think you are the only one. :P

I had to port a browser a year or so ago that used a similar system. The structures used unions to emulate a class like structure. Porting it was an absolute nightmare. Alignment issues caused crashes and subtle bugs all over the place. In the end I had to go to Germany (in November.... COLD...) and explain the problem then parse the entire source code tree adding macros to the end of every structure.

I like the idea of behaviours being attached... hmmm got me thinking at last.

#9 alphadog

    DevMaster Staff

  • Moderators
  • 1716 posts

Posted 07 November 2012 - 04:25 PM

What you are looking for is an event bus which decouples all your widgets. Widgets publish (events (basically a pile of data) into the bus. Other code blocks subscribe to some or all events. Nice thing is, done right, this can be altered dynamically at run-time if needed.

There are tons out there of various levels of complexity, but basically it boils down to two classes/interfaces/thingee, depending on language used:
  • Some thingee to abstractly represent the event/data. It is a wrapper for arbitrary data related to the event.
  • A thingee to represent the bus. Usually a singleton. It manages the pub-sub linkages.
Google is your friend at this point. If you need any keyword help, just holla...
Hyperbole is, like, the absolute best, most wonderful thing ever! However, you'd be an idiot to not think dogmatism is always bad.

#10 Stainless

    Member

  • Members
  • PipPipPipPip
  • 578 posts
  • LocationSouthampton

Posted 07 November 2012 - 07:09 PM

Yes, you really have me thinking now. Thanks.

What I want to be able to do is global animation effects. So you have a display with a bunch of widgets all in view and live, you do something to one of them and all the widgets animate. Some kill themselves, some move..... whatever I can think of.

So attaching a behavior to a widget and link the behavior to an event ........ yes starting to look cool.

#11 Vilem Otte

    Valued Member

  • Members
  • PipPipPipPip
  • 345 posts

Posted 07 November 2012 - 07:31 PM

Basically this gets me to something maybe not directly related, but interesting. I've not tried it (yet), but it might worth try:

You have a widget object/struct that has function pointers (virtual methods, etc.) for events (like onClick, onMouseOver, etc. - like i described), and it points to some renderable (even 3D) object - basically this object will inform widget object about events (e.g. whether it has to call some function/method, along with arguments for these functions).

The renderable object can then be any 2D/3D object in the scene, that can be F.e. animated (it will have controller attached - so you can define it's behaviour in a script) - that way you could achieve a lot of very fancy stuff with gui - from basic moving of buttons, to even some hardcore effects (defragmenting buttons to parts and let them burn, on closing the window containing them - for example - hope you get what i mean), etc.
My blog about game development (and not just game development) - http://gameprogramme...y.blogspot.com/

If you don't know how to speed up application, go "roarrrrrr!", hit the compiler with the club and use -O3 :D

#12 Stainless

    Member

  • Members
  • PipPipPipPip
  • 578 posts
  • LocationSouthampton

Posted 07 November 2012 - 07:47 PM

Villem, your now seeing what I want to be able to do ;) , I'm just thinking about the best way to do it.

I personally don't like having named event handlers, you would need an OnEvent handler for every event you want to react to, and the code will bloat.

Having behaviors that can be attached to any widget means that in each widget you just need a vector containing all the handlers. No code bloat as you just need a single class for each behavior and a singleton to invoke them.

Still thinking about the design...

#13 alphadog

    DevMaster Staff

  • Moderators
  • 1716 posts

Posted 07 November 2012 - 10:06 PM

It's just some sort of pub-sub/observer pattern. In Qt it's signals and slots. You can have a more coupled pub-sub, or use a bus to decouple it.

http://www.cs.ru.nl/...s/manyfaces.pdf
http://www.comicfanboy.net/node/90
etc...
Hyperbole is, like, the absolute best, most wonderful thing ever! However, you'd be an idiot to not think dogmatism is always bad.





1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users