GUI design help

Started by
7 comments, last by Telastyn 18 years, 8 months ago
I'm trying to design my gui so that it is flexible, and I've got a 'level' based system worked out:
  1. IWidget
  2. CText, CImage
  3. CProgressBar, CGroupBox, CButton
    • CCheckBox, CRadioButton
  4. CFader, CRoller
  5. CScrollBar
  6. CEditBox
    • CTextBox
  7. CListBox
  8. CDropDownList

class IDialog
{
    WidgetVector /*std::vector<IWidget*>*/ m_Widgets;
public:
    virtual void Initialize() = 0;
    virtual void Destroy() = 0;
    virtual void Draw(ID3DXSprite* pSprite, IDirect3DTexture9* pTexture) = 0;
    virtual void HandleMessage(IEvent* pEvent) = 0;
};
The user then derives a class from IDialog (I will provide sample classes), instances some widgets and viola, you've got a dialog. Or you can instance, and have them on the main screen (i.e. health bar, text box, etc.) Basically, each level depends on one or more of the items in the previous levels. For example: CScrollBar (level 5) requires a CFader and a CRoller from level 4. CButton (level 3) requires a CText etc I have a few questions: 1) Are there any widgets that I missed (other than tabs, I'm thinking about implementing them, but I'm not sure.) 2) Does my implementation seem logical? 3) Should I have my GUI enviroment class have a function like so: void HandleWndProc(UINT nMsg, WPARAM wParam, LPARAM lParam); And have the user call that in their wndproc, or is there a different way? Nothing has been coded yet, I'm still working on the design. Thanks! Also: Should I track how many widgets are in the dialog (actually, I should ask: does std::vector track it, or does it iterate through and count each node when size() is called)? Edit: I just noticed that I had missed CImage on level 2. Its been added Edit: I forgot to mention, I'm thinking of adding a layer system so that you could layer, say a CBitmap on top of a progress bar, for a nifty little health bar (ala Diablo). [Edited by - Programmer16 on August 3, 2005 2:40:59 PM]
Advertisement
Well, I can tell you std::vector tracks the size. Actually it works by doubling the buffer size whenever it gets filled for the sake of speed (that is it has two sizes - the number of elements in the vector and the size of the buffer).

One recommendation - PLEASE don't model any GUI on MFC (Not that I'm at all sure you are). I'm so fed up with the thing that I think next time I write a Windows app I'll just use the HWND functions.

Edit: clicked reply before I finished typing by accient
I'm not going to base it on MFC (I've never used MFC. Everytime I try to open one and read the source code, I get lost.)

So, no MFC for me :)

[Edited by - Programmer16 on August 3, 2005 2:27:08 PM]
Programmer16,

1. I think if you added a "group" widget, you won't need to worry about depths of widgets. As an example, for my tabs I have a tabs class, and a tabpanels class. The tabs class is the parent that handles the COMMAND messages (for switching through the tabs). The tabpanel is basically a group (well, thats kinda right and kinda not right. Check out the WS_GROUP style), but has the power to turn off and on the entire child structure from that point on.

Another reason for a group is to have a nice clean structure within a widget. If you have two sets of radio buttons, how will you differentiate between the two groups? The group widget wouldn't be a "rendered" widget, but it would still be a concrete object.

2. I think that once you figure out how YOU want to add a "group" type widget, then it will be logical system.

3. The easiest thing to do is have your own message system. If you create windows widgets along side of yours, then it would be worthwhile to have a "HandleWndProc", but you'll have to generate all the messages to those widgets (since you don't want them to appear above your main window, and you need them to be around).

Yeah, if stl::vector isn't using a constant access time to the size, than there is something wrong with the implementation IMO.

-brad
-brad
Quote:Original post by Galapaegos
Programmer16,

1. I think if you added a "group" widget, you won't need to worry about depths of widgets. As an example, for my tabs I have a tabs class, and a tabpanels class. The tabs class is the parent that handles the COMMAND messages (for switching through the tabs). The tabpanel is basically a group (well, thats kinda right and kinda not right. Check out the WS_GROUP style), but has the power to turn off and on the entire child structure from that point on.

Another reason for a group is to have a nice clean structure within a widget. If you have two sets of radio buttons, how will you differentiate between the two groups? The group widget wouldn't be a "rendered" widget, but it would still be a concrete object.

2. I think that once you figure out how YOU want to add a "group" type widget, then it will be logical system.

3. The easiest thing to do is have your own message system. If you create windows widgets along side of yours, then it would be worthwhile to have a "HandleWndProc", but you'll have to generate all the messages to those widgets (since you don't want them to appear above your main window, and you need them to be around).

Yeah, if stl::vector isn't using a constant access time to the size, than there is something wrong with the implementation IMO.

-brad


I had forgotten about the group problem (thank you). Before I tried doing a simple handle-based solution for groups, but that didn't work too well. I've never really used WS_GROUP, other than with radio buttons. I'll have to read up on it.

I was thinking of using window procedure for input, I'm not using windows at all other than that.

I also forgot my CGroupBox, which I'll add to level 3.

Thanks!

Edit: And I was just wondering if std::vector tracked its size, or did it some other way.

[Edited by - Programmer16 on August 3, 2005 2:40:18 PM]
Quote:Original post by Programmer16
I was thinking of using window procedure for input, I'm not using windows at all other than that.


Hmmm.. Something for you to think about here: Your main app will receive it (of course), but it will need to know to which widget to send the message. And then you'll have to toggle from normal game-running mode to the options mode, but that should be pretty easy.

Edit: Yeah, I was simply implying that the stl::vector should be tracking as it adds, and if it doesn't than there is something screwy!

-brad
-brad
With my current design:
The main app recieves the message
The user calls his GUI enviroment::HandleMessage(nMsg, wParam, lParam);
Which inturn iterates through the widgets and passes the messages to them.
The widget decides wether or not the message is for it. If so, it takes it, otherwise it returns it.

[Edited by - Programmer16 on August 3, 2005 2:59:27 PM]
Quote:Original post by Programmer16
Edit: And I was just wondering if std::vector tracked its size, or did it some other way.

You can get the size of an std::vector at any time by calling its size() function.
Hey; not an expert, so the standard caveats apply.

1. I'd tend to include other things [such as generify the ListBox into an 'arrangement', add non-rendered widgets like timed-triggers, a 'root' class for window/API info, and higher level things like chatboxes], but as long as everything derives from a base which goes to an Image and a Text, the rest should be fine.

2. I'm not sure the strict level system is such a logical way about things. It seems like it might restrict future design. In my experience, designing the Widget base to allow for a standard interface is better than making 'level' assumptions.

Also, an important thing I've found is how you design the positioning/orientation portion of the classes. More often than not you want to say 'place this widget next to widget B'. Intuitively, this is simple. In code, it tends to be far less simple, especially when you can't know what widget A or B are... It's something you might want to focus on with the design.

3. Whatever works for you. I'm still trying different things in this regard.

This topic is closed to new replies.

Advertisement