Clarisse 5.0 SP8 SDK  5.0.5.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
Introduction to GUI library

Table of Contents

This is a brief introduction to the GUI library that comes with Clarisse SDK. All the following examples are in Python. There's very little difference between programming the GUI library in C++ or Python. Please refer to Differences between C++ and Python

Creating a simple window

In the following example we will create and display a simple window.

1 window = ix.api.GuiWindow(ix.application, 0, 0, 640, 480)
2 window.show()
3 while window.is_shown():
4  ix.application.check_for_events()

As you can see, it's really easy to create and display a window. Executing this script will result to display a floating window. Let's go over each piece of code.

1 window = ix.api.GuiWindow(ix.application, 0, 0, 640, 480)

Here we create a simple window of class GuiWindow. We specify its location at (0, 0) in screen coordinates and its size to 640 pixels in width and 480 pixels in height. The first argument ix.application that is passed on to the window is the application that inherits from GuiApp. When passing an application as first argument, a window, becomes a top level window in the hierarchy of windows. In other words, the window has no parent.

1 window.show()

In order to actually display our window on the screen, we must call GuiWindow::show method.

The application main loop

1 while window.is_shown():
2  ix.application.check_for_events()

This last part enters a sub main loop in an cycle ending as soon as our window is closed. This sub main loop makes sure all events and pending redraw are properly passed and dispatched. If that line is missing the script would end and the window would be automatically destroyed.

Hello world

In this slightly more elaborate example, we will create a GuiWindow displaying Hello World using a GuiLabel.

1 class HelloWorldWindow(ix.api.GuiWindow):
2  def __init__(self, x, y, w, h):
3  super(HelloWorldWindow, self).__init__(ix.application.get_event_window(), x, y, w, h)
4  self.label = ix.api.GuiLabel(self, 0, 0, 640, 480, "Hello World")
5  self.label.set_justification(ix.api.GuiWidget.JUSTIFY_CENTER)
6 
7 window = HelloWorldWindow(0, 0, 640, 480)
8 window.show()
9 while window.is_shown():
10  ix.application.check_for_events()

Ok let's go over the first part of the example:

1 class HelloWorldWindow(ix.api.GuiWindow):
2  def __init__(self, x, y, w, h):
3  super(HelloWorldWindow, self).__init__(ix.application.get_event_window(), x, y, w, h)

This will define a new class named HelloWorldWindow that inherits from GuiWindow and we added a 'constructor' (the __init__ method) which will simply call the GuiWindow one, and pass the position and size to it.

Now, to display a static text, you need to use a GuiLabel. Please note GuiLabel also supports text editing. So now that we have a class, we can use the __init__ method to create and setup its content:

1 self.label = ix.api.GuiLabel(self, 0, 0, 640, 480, "Hello World")

Here we create a simple label located at (0, 0) in window coordinates while having the same size of our window. A quick word on the coordinate system:

The last argument is the text that is displayed by our label.

Interestingly, in this example the label is parented to our window. This means our label gets destroyed when the window is.

1 self.label.set_justification(ix.api.GuiWidget.JUSTIFY_CENTER)

We set the justification to center as by default it is set to right. The enum is defined in GuiWidget::Justify

Now that our window is fully defined, we can create it

1 window = HelloWorldWindow(0, 0, 640, 480)

And show it like in the first example:

1 while window.is_shown():
2  ix.application.check_for_events()

Note we don't need to call explicitely label.show() as it is implicitely called by its parent. By default children are automatically shown when their parent are.

Setting widget constraints

If you tried to resize our window in the last example, you should have seen Hello World didn't stay at the center of the window. This is due to the fact that our label size is independant from our window. The GUI library provides a constraint system allowing you constraint a widget to its parent. By default, the 4 borders (left, top, right, bottom borders) of widgets are constrained to left, top, left, top. Here is an example setting constraints to our label so it gets autmatically resized when the window is resized.

1 class HelloWorldWindow(ix.api.GuiWindow):
2  def __init__(self, x, y, w, h):
3  super(HelloWorldWindow, self).__init__(ix.application.get_event_window(), x, y, w, h)
4  self.label = ix.api.GuiLabel(self, 0, 0, 640, 480, "Hello World")
5  self.label.set_justification(ix.api.GuiWidget.JUSTIFY_CENTER)
6  self.label.set_constraints(ix.api.GuiWidget.CONSTRAINT_LEFT,
7  ix.api.GuiWidget.CONSTRAINT_TOP,
8  ix.api.GuiWidget.CONSTRAINT_RIGHT,
9  ix.api.GuiWidget.CONSTRAINT_BOTTOM)
10 
11 window = HelloWorldWindow(0, 0, 640, 480)
12 window.show()
13 while window.is_shown():
14  ix.application.check_for_events()

As you can see we've just added a new line calling the method GuiWidget::set_constraints. The enum Constraint is defined in GuiWidget::Constraint

Here we set our constraints to left, top, right and bottom. So basically each of our widget egde will stick to the edges our parent, here, the window.

Now if you resize the window, the label will stay centered.

gui_hello_world.png

Working with events

Most widgets provides events on which you can connect. Connecting to an event is fairly simple. You just need a method callback that will be called when the specified event is raised. In the following example, we will create a simple button and connect to its click event:

1 class ExampleWindow(ix.api.GuiWindow):
2  def __init__(self, x, y, w, h):
3  super(ExampleWindow, self).__init__(ix.application.get_event_window(), x, y, w, h)
4  self.button = ix.api.GuiPushButton(self, (w - 100) / 2, (h - 24) / 2, 100, 24, "Press Me!")
5  self.connect(self.button, "EVT_ID_PUSH_BUTTON_CLICK", self.on_click)
6 
7  def on_click(self, sender, evt_id):
8  self.button.set_label("Pressed")
9 
10 window = ExampleWindow(0, 0, 640, 480)
11 window.show()
12 while window.is_shown():
13  ix.application.check_for_events()

Ok, as with the previous examples, let's go through the code:

1 class ExampleWindow(ix.api.GuiWindow):
2  def __init__(self, x, y, w, h):
3  super(ExampleWindow, self).__init__(ix.application.get_event_window(), x, y, w, h)

Same as before, just the name of the class that changed.

1 self.button = ix.api.GuiPushButton(self, (w - 100) / 2, (h - 24) / 2, 100, 24, "Press Me!")

Like with the label, we created a GuiPushButton. Here we manually place it at the center of the window, but you could use constraints, etc. Now the interesting part:

1  self.connect(self.button, "EVT_ID_PUSH_BUTTON_CLICK", self.on_click)
2 
3 def on_click(self, sender, evt_id):
4  self.button.set_label("Pressed")

The first line (well, the last of the constructor) will connect the event named "EVT_ID_PUSH_BUTTON_CLICK" which is sent by the button to the window's method named on_click. And in the on_click method defined just after, we can change the label of the button.

The list of events can be found here Events but note that all events are not sent by all widgets. Usually the event names are composed by the EVT_ID_ prefix, followed by the name of the class that send them, and finally the event name itself.

Note that you can connect more than 1 method to the same event, and you can also connect the same method to many events. In the previous example, the on_click method will receive the event name as the evt_id parameter, so if you connected a single method to many event, you can use it to check which event you're processing.

Finally, the last part didn't change much; just create the window and start the event loop:

1 window = ExampleWindow(0, 0, 640, 480)
2 window.show()
3 while window.is_shown():
4  ix.application.check_for_events()

Drawing things using the GUI library

In order to draw something in a widget you must access to a valid device context (Dc). Now if you look carefully to GuiWidget::draw method prototype you can notice there is a GuiDc as input parameter. Currently, you can't create your own device context, this input dc is the only valid GuiDc handle you can get.

In GuiWidget, there are a few methods that are directly related to drawing things. Following are the two major ones:

Differences between C++ and Python

The major differences between C++ and Python are:

Following you can compare differences between C++ and Python. In python you have:

1 window = ix.api.GuiWindow(application, 0, 0, 640, 480)
2 window.show()
3 while window.is_shown():
4  application.check_for_events()

Here is the same code in C++:

#include <gui_window.h>
...
GuiWindow *window = new GuiWindow(*application, 0, 0, 640, 480);
window->show();
while (window->is_shown()) {
application->check_for_events();
}