History: QuickGUI Basics
Source of version: 11 (current)
Copy to clipboard
!Introduction
This tutorial explains how to use QuickGUI to create a User Interface, and listen to events. It is already assumed QuickGUI is integrated into your application. If you have not completed the Integration tutorial, please finish that first.
((QuickGUI Integration Tutorial))
!Fonts
QuickGUI does not resize __Font__s when used in your application. __Font__s are provided to QuickGUI via the __FontManager__, and consist of an XML and image file. The XML file describes where font glyphs are in the image file, as well as each glyphs dimensions, and offsets, used when writing glyphs one after each other. By default I use [http://labs.delphituts.com/FontStudio421.zip|FontStudio] to create my __Font__s. Using FontStudio it is easy to create outlined and shadowed __Font__s.
!!FontManager
The following code is taken from the QuickGUIOgreDemo project, and registers __Font__s with QuickGUI:
{CODE(wrap="1", colors="c++")}
// Register all fonts we plan on using
QuickGUI::FontManager* fontMgr = QuickGUI::FontManager::getSingletonPtr();
fontMgr->createFont("ControlFreak.14",mGUIResourceManager->getImage("ControlFreak.14.png"),10,prefix+"/resources/fonts/ControlFreak.14.xml");
fontMgr->createFont("Cuckoo.14",mGUIResourceManager->getImage("Cuckoo.14.png"),10,prefix+"/resources/fonts/Cuckoo.14.xml");{CODE}
Explanation of parameters:
# The name of the __Font__, must be unique. I generally include the name and the size of the __Font__.
# The image file on disk that visually describes how the glyphs look.
# The baseline, or amount of pixels from the top of the glyphs to the imaginary line that all glyphs sit on when drawn. All glyphs in a particular __Font__ will have the same height. The baseline is useful for having multiple __Font__s on the same line. For example, imagine various __Font__s of various sizes next to each other, they will need to be aligned vertically to appear on the same line.
# The xml file describing the dimensions and offsets of each glyph in the __Font__. Imagine a pen drawng the glyphs one by one, from left to right. The offsets of each glyph tell us how far to move the pen before drawing the glyph, and after drawing the glyph, so that the text appears as you've come to expect. Each glyph has its own offsets, and offsets can be negative, positive, or zero.
!Skins
This section will only cover the very basics of __Skin__s. __Skin__s are very powerful, and will be covered more in depth in another tutorial.
__Skin__s describe the images that visually represent an object. A typical __Skin__ will consist of __SkinElement__ and __SkinReference__ objects. __Skin__s are registered with QuickGUI using the __SkinManager__.
!!SkinManager
The following code is taken from the QuickGUIOgreDemo, and shows how a Skin is registered:
{CODE(wrap="1", colors="c++")}
// Register all Skins we plan on using
QuickGUI::SkinManager* skinMgr = QuickGUI::SkinManager::getSingletonPtr();
skinMgr->loadSkins(prefix+"/resources/skins/Button.skin");
{CODE}
Skins are written in XML format, and will look like this:
{CODE(wrap="1", colors="c++")}
<Skin name="Button">
<Type type="string" value="Button" />
<TimelineLength type="float" value="0" />
<SkinElement name="default">
<TileBackground type="bool" value="false" />
<TileBorders type="bool" value="false" />
<Color type="ColorValue" value="1 1 1 1" />
<Rotation type="int" value="0" />
<Image type="string" value="qgui.button.png" />
<BottomBorderThickness type="unsigned int" value="3" />
<LeftBorderThickness type="unsigned int" value="3" />
<RightBorderThickness type="unsigned int" value="3" />
<TopBorderThickness type="unsigned int" value="3" />
</SkinElement>
<SkinElement name="over">
<TileBackground type="bool" value="false" />
<TileBorders type="bool" value="false" />
<Color type="ColorValue" value="1 1 1 1" />
<Rotation type="int" value="0" />
<Image type="string" value="qgui.button.over.png" />
<BottomBorderThickness type="unsigned int" value="3" />
<LeftBorderThickness type="unsigned int" value="3" />
<RightBorderThickness type="unsigned int" value="3" />
<TopBorderThickness type="unsigned int" value="3" />
</SkinElement>
<SkinElement name="down">
<TileBackground type="bool" value="false" />
<TileBorders type="bool" value="false" />
<Color type="ColorValue" value="1 1 1 1" />
<Rotation type="int" value="0" />
<Image type="string" value="qgui.button.down.png" />
<BottomBorderThickness type="unsigned int" value="3" />
<LeftBorderThickness type="unsigned int" value="3" />
<RightBorderThickness type="unsigned int" value="3" />
<TopBorderThickness type="unsigned int" value="3" />
</SkinElement>
</Skin>
{CODE}
Each class is represented by a tag, using the format <Skin name="''mySkinName''">
Properties are represented using the format <''PropertyName'' type="''data type''" value="''value''" />
You can see from the __Button__ __Skin__ provided, the Images used are "qgui.button.png", "qgui.button.down.png", and "qgui.button.over.png". If your resource manager does not have access to these images, the __Skin__ will throw an exception when trying to be drawn.
!Creating a Window
__Window__s are created from the __Interface__ class. All UI will appear in the form of __Window__s. __Window__s represent textures that are applied to __RenderTarget__s, which can be 2D (__Overlay__) or 3D (__UIPanel__). Creating a Window is very simple:
{CODE(wrap="1", colors="c++")}
QuickGUI::Window* newWin = mInterface->createWindow("Test");
{CODE}
By default this __Window__ will not have a __Skin__, and will not be visible in your application, even if attached to a __RenderTarget__. Here is how you would add a __Skin__ to the __Window__:
{CODE(wrap="1", colors="c++")}
newWin->setSkin(QuickGUI::SkinManager::getSingletonPtr()->getSkin("Window"));
{CODE}
NOTE: It is assumed that a __Skin__ of type __Window__ has already been registered with the __SkinManager__. If this has not been done, an exception will be thrown!
NOTE: There is nothing wrong with a __Widget__ not having a __Skin__. For example, if you wanted a 3D __ProgressBar__ or __Label__, you might want to create a __Window__ with no __Skin__, so that only its child __Widget__s will be visible.
Now that we've created a __Window__, how do we add child __Widget__s?
!Creating a Button
Aside from the __Window__, most __Widget__s can be created simply by supplying a name:
{CODE(wrap="1", colors="c++")}
QuickGUI::Button* newButton = new QuickGUI::Button("MyButton");
{CODE}
Once you've created the __Button__, it can be added to the __Window__ like this:
{CODE(wrap="1", colors="c++")}
newWin->addChild(newButton);
{CODE}
!Interacting with the GUI
Now that we're able to create a __Button__, how can we find out when it is clicked?
!!Message
QuickGUI relies heavily on the use of the __MessageManager__, which broadcasts __Message__s to __MessageHandler__s that are subscribed. __Message__s consist of 3 things:
# The type of the __Message__. A default list of __Message__s are supported, however this is just a string, and you can create any __Message__ type you like.
# The source of the __Message__. This is the string identifier representing the source of the __Message__. This will often be a __Widget__'s name, or an __Interface__'s name, or "Core", for example.
# The args associated with the __Message__. There are many types of args: __WidgetEventArgs__, __MouseEventArgs__, __TimeEventArgs__, etc. They all derive from __EventArgs__, and you will have to dynamically cast them to extract any data you need.
NOTE: Not only can you receive __Message__s, but you can use the __MessageManager__ to queue and broadcast __Message__s. You can modify __Message__s and re-send them out. Or create custom ones. The messaging system is very flexble!
!!MessageHandler
A __MessageHandler__ is any class that inherits from QuickGUI::__MessageHandler__. This class requires the API ''void handleMessage(Message m)'' to be implemented.
{CODE(wrap="1", colors="c++")}
class _QuickGUIExport MessageHandler
{
public:
virtual ~MessageHandler();
virtual void handleMessage(Message m) = 0;
protected:
};
{CODE}
!!MessageManager
Below are the main APIs of the __MessageManager__ class:
{CODE(wrap="1", colors="c++")}
/**
* Subscribes a MessageHandler instance to receive messages of a certain type.
*/
void subscribeToMessage(const std::string& messageType, MessageHandler* instance);
/**
* Subscribes a MessageHandler instance to receive messages of a certain type, from a specific source.
*/
void subscribeToMessage(const std::string& messageType, const std::string& source, MessageHandler* instance);
/**
* Unsubscribes a MessageHandler instance, preventing it from receiving messages of certain types.
*/
void unsubscribeFromMessage(const std::string& messageType, MessageHandler* instance);
/**
* Unsubscribes a MessageHandler instance, preventing it from receiving messages of certain types from a specific source.
*/
void unsubscribeFromMessage(const std::string& messageType, const std::string& source, MessageHandler* instance);
{CODE}
An important thing to note here is that you can subscribe generally to a __Message__ of a given type, or specifically to a __Message__ of a given type from a given source. For example, I could subscribe to a particular __Button__ being clicked, or subscribe to any click. This is useful in a variety of scenarios.
The following code shows how to subscribe to MouseButtonUp __Message__s, when sent from our __Button__ created earlier:
{CODE(wrap="1", colors="c++")}
QuickGUI::MessageManager::getSingletonPtr()->subscribeToMessage(QuickGUI::DefaultMessageType::MouseButtonUp,newButton->getName(),myMessageHandler);
{CODE}
''myMessageHandler'' refers to an instance of a class that inherits from QuickGUI::__MessageHandler__. This instance will receive a __Message__ whenever my __Button__ instance (newButton) broadcasts a __Message__ of type MouseButtonUp. The code to handle the __Message__ would look something like this:
{CODE(wrap="1", colors="c++")}
void MyClass::handleMessage(QuickGUI::Message m)
{
if(m.messageType == QuickGUI::DefaultMessageType::MouseButtonUp)
{
; // do something useful
}
}
{CODE}
!Conclusion
We covered __Font__s, __Skin__s, creation of __Widget__s, and message handling! If you are still having problems in any of these areas, please post on the __[http://www.ogre3d.org/addonforums/viewforum.php?f=13|QuickGUI Forums]__.