4. Hello World
Germán Arias heeft deze pagina aangepast 5 jaren geleden

4 Hello World

4.1 Initialization

The code bellow will shows how to open an IUP environment and displays a simple message. Each line of code is explained after the code.

class HELLO_WORLD

inherit
   IUP_INTERFACE

create {ANY}
   make

feature {ANY}

   make
      local
            gui: IUP
            ms: IUP_MESSAGE
      do
            gui := iup_open

            create ms.message("Hello World 1", "Hello world from Eiffel-IUP.")

            gui.close
      end
      
end

Hello Wordl 1

Notice we inherit from class IUP_INTERFACE, this class allow us interact with the Eiffel-IUP toolkit. Next line is the standard creation feature declaration in Eiffel. And next lines define this feature. There are two local variables, gui of class IUP and ms of class IUP_MESSAGE. Before running any of the IUP's functions, the feature iup_open must be called to initialize the toolkit. This feature is defined at IUP_INTEFACE class, and return a shared object to interact with IUP. The returned object, of class IUP, is attached at gui variable. The next line creates and displays a message to the user using IUP_MESSAGE class. The create frature of this class, message, receives two parameters: title and message. The title will be displayed at the top of the message window and the message is a text message by itself that will be displayed to the user. Following, we have a close feature called at gui object. After running the last IUP function, close must be run so that the toolkit can free internal memory and close the interface system.

5.2 Creating a Dialog

Let's change the first example a little bit to add our own dialog.

class HELLO_WORLD_2

inherit
    IUP_INTERFACE

create {ANY}
   make

feature {ANY}

   make
      local
            s: STRING
            gui: IUP
            dlg: IUP_DIALOG
            label: IUP_LABEL
            vb: IUP_VBOX
      do
            gui := iup_open

            create label.label("Hello world from Eiffel-IUP.")
            create vb.vbox({ARRAY[IUP_WIDGET]} << label >>)

            create dlg.dialog(vb)
            dlg.set_title("Hello World 2")
            s := dlg.show_predefined_xy("IUP_CENTER", "IUP_CENTER")

            gui.main_loop
            gui.close
      end
      
end

Hello World 2

Now we have four different variables. One calle gui as before, other called dlg (class IUP_DIALOG) for our main dialog, other called vb (class IUP_VBOX) and another called label (class IUP_LABEL), which will hold a label with a hello message. Next, a new line creates a iup label control. Its only argument is the text that will be displayed inside the label. Next we create a IUP_VBOX control. This is a control that aligns all controls passed to it (as an array) vertically. In this example, we are passing just one control (our label). Notice the class IUP_WIDGET, all controls at Eiffel-IUP are descendants of this class (except IUP, which is just the interface). Then we reach the line in which we create our main dialog. The parameter passed to dialog feature is the control that will be placed into the dialog. In this case our IUP_VBOX control. Next line we are changing the main dialog's title to "Hello from IUP Tutorial" using the feature set_title. The next feature called is show_predefined_xy to configure the position where will be displayed the dialog at the screen using some predefined values. Here we passe the value "IUP_CENTER" (one of the various predefined values) to tell the dialog we want it displayed at the center of the screen horizontally and vertically. Check the documentation of this feature. The feature return the string "IUP_NOERROR" if successful, otherwise return "IUP_ERROR", Following comes one of the most important feature which is called at gui object: main_loop. This feature tells iup to wait for events. Otherwise, the program would go on, end and terminate without dealing with any event. Go on, comment this line, recompile your code and execute your program, and you will see the main dialog blink in the screen and the program ends just after it. It will be a valuable exercise.

From the most simple hello world to the most complex Eiffel-IUP application, all will have this same code structure.

5.3 Adding Interaction

In the previous section, we saw how to build a basic Eiffel-IUP application, but without any custom interaction with the dialog. In this section, we will add interaction to our application using a button.

class HELLO_WORLD_3

inherit
    IUP_INTERFACE

create {ANY}
   make

feature {ANY}

   make
      local
            s: STRING
            gui: IUP
            dlg: IUP_DIALOG
            btn: IUP_BUTTON
            vb: IUP_VBOX
      do
            gui := iup_open

            create btn.button("OK")
            btn.set_cb_action(agent click_btn)
            create vb.vbox({ARRAY[IUP_WIDGET]} << btn >>)

            create dlg.dialog(vb)
            dlg.set_title("Hello World 3")
            s := dlg.show_predefined_xy("IUP_CENTER", "IUP_CENTER")

            gui.main_loop
            gui.close
      end

    click_btn (button: IUP_BUTTON): STRING
        local
            ms: IUP_MESSAGE
        do
            create ms.message("Hello World Message", "Hello world from Eiffel-IUP.")

            Result := "IUP_CLOSE"
        end
      
end

Hello World 3

Note that we have added a variable btn of class IUP_BUTTON. Then we create this button with the title "OK". Next we set the feature click_btn (declared at the end) as the action callback, using the feature set_cb_action. Callbacks are special features defined by the programmer and called by IUP when an event needs to be handled. To create a callback, the programmer must declare a feature and put inside its body anything that he/she wants the application to do when the event occurs. After that, it is necessary to inform IUP that new function is, in fact, a callback. This was done here with the feature set_cb_action. The action event occurs when the user press the button. So, when the user press our button, the feature click_btn will be executed. Then we create our vb object with our button inside it. Next we create our dialog and display it as in the previous example.

Next lines contain the frature called click_btn that was registered as our button callback. This feature does nothing special, except showing the hello message that we saw in the first example and also closing the application returning code "IUP_CLOSE". This feature receive a paramater, button, of class IUP_BUTTON which is the button that generates the event. There are many events associated with each visible control and you can read about these, and the parameters they receive, at documentation. All callbacks receive at least the element which activated the action as a parameter.

Almost all callbacks implemented in the application must return one of the following values (a string):

  • "IUP_DEFAULT": Proceeds normally with user interaction. In case other return values do not apply, the callback should return this value.
  • "IUP_CLOSE": Call close (at IUP interface) after return. Depending on the state of the application it will close all windows and exit the application. Applies only to some actions.
  • "IUP_IGNORE": Makes the native system ignore that callback action. Applies only to some actions.
  • "IUP_CONTINUE": Makes the element to ignore the callback and pass the treatment of the execution to the parent element. Applies only to some actions.

Only some callbacks support the last 3 return values. Check each callback documentation. When nothing is documented then only "IUP_DEFAULT" is supported.

An important detail when using callbacks is that they are only called when the user actually executes an action over an element. A callback is not called when the programmer sets a value programmatically. For instance: when the programmer changes a selected item on a list, no callback is called.

The order of callback calling is system dependent. For instance, the resize and the show callbacks are called in different order in Win32 and in X-Windows when the dialog is shown for the first time.

When executed, the application's dialog box will show up, and when the user presses the button, it displays a hello message and will close the application. It seems not a big deal, but with this small sample of code, we have covered the process of creating an IUP application, declare elements and callbacks, and also handle an event.

5.4 Adding Layout Elements

Up until now we have just positioned our controls inside a IUP_VBOX object which, as told, aligns all controls inside it vertically. This is just a small sample of the Eiffel-IUP's layout concept. Eiffel-IUP implements an abstract layout, in which the positioning of controls is done relatively instead of absolutely. For such, composition elements are necessary for composing the interface elements. They are boxes and fills invisible to the user, but they play an important part. When a dialog size changes, these containers expand or retract to adjust the positioning of the controls to the new situation allowing the dialog to adapt even if the resolution of the screen changes. That would come in hand if you port your application to another system with a lower resolution, for example. Main composition elements are vertical boxes (IUP_VBOX), horizontal boxes (IUP_HBOX) and filling (IUP_FILL), among others. There is also a depth box (IUP_ZBOX), in which layers of elements can be created for the same dialog, and the elements in each layer are only visible when that given layer is active.

To clarify the way abstract layout works, lets modify our example adding a label to it.

class HELLO_WORLD_4

inherit
    IUP_INTERFACE

create {ANY}
   make

feature {ANY}

   make
      local
            s: STRING
            gui: IUP
            dlg: IUP_DIALOG
            l: IUP_LABEL
            btn: IUP_BUTTON
            vb: IUP_VBOX
      do
            gui := iup_open

            create l.label("Hello world from Eiffel-IUP.")

            create btn.button("OK")
            btn.set_cb_action(agent click_btn)
            create vb.vbox({ARRAY[IUP_WIDGET]} << l, btn >>)

            create dlg.dialog(vb)
            dlg.set_title("Hello World 4")
            s := dlg.show_predefined_xy("IUP_CENTER", "IUP_CENTER")

            gui.main_loop
            gui.close
      end

    click_btn (button: IUP_BUTTON): STRING
        local
            ms: IUP_MESSAGE
        do
            create ms.message("Hello World Message", "Hello world from Eiffel-IUP.")

            Result := "IUP_CLOSE"
        end
      
end

Hello World 4

Note that there is a new label declaration, variable l of class IUP_LABEL, and this new element appears inside our vb object as the top element. That means it will be displayed above the button, and that's all. Our example now has two different elements and is disposed vertically one above the other. An interesting exercise would be to change the code above and use an IUP_HBOX object to see what happens (the creation feature is hbox).

5.5 Improving the Layout

Now that you understand the basics of abstract layout, let us present three attributes available to both IUP_VBOX and IUP_HBOX. They are: alignment, gap and margin.

alignment defines the horizontal or vertical alignment of elements inside the box. If you are using a IUP_VBOX, it will be an horizontal alignment, or if you are using an IUP_HBOX, it will be a vertical alignment. Its values can be "ALEFT", "ACENTER" or "ARIGHT" for horizontal alignment, and "ATOP", "ACENTER" or "ABOTTOM" for vertical alignment. The default value is "ALEFT" and "ATOP".

gap defines a space in pixels between every element inside the box. If you are using a IUP_VBOX, it will be a vertical space, or if you are using a IUP_HBOX, it will be a horizontal space. The default value for gap is 0 (which means no space between elements).

margin defines a margin in pixels. The margin has two values width and height, in which width and height are integer values corresponding to the horizontal and vertical margins, respectively. Its default value is 0,0 (means no margin).

Let's see how our layout responds to these three attributes.

class HELLO_WORLD_5

inherit
    IUP_INTERFACE

create {ANY}
   make

feature {ANY}

   make
      local
            s: STRING
            gui: IUP
            dlg: IUP_DIALOG
            l: IUP_LABEL
            btn: IUP_BUTTON
            vb: IUP_VBOX
      do
            gui := iup_open

            create l.label("Hello world from Eiffel-IUP.")

            create btn.button("OK")
            btn.set_cb_action(agent click_btn)
            
            create vb.vbox({ARRAY[IUP_WIDGET]} << l, btn >>)
            vb.set_alignment("ACENTER")
            vb.set_gap(10)
            vb.set_margin(10, 10)

            create dlg.dialog(vb)
            dlg.set_title("Hello World 5")
            s := dlg.show_predefined_xy("IUP_CENTER", "IUP_CENTER")

            gui.main_loop
            gui.close
      end

    click_btn (button: IUP_BUTTON): STRING
        local
            ms: IUP_MESSAGE
        do
            create ms.message("Hello World Message", "Hello world from Eiffel-IUP.")

            Result := "IUP_CLOSE"
        end
      
end

Hello World 5

After creating the IUP_VBOX object, we have added three lines that set those attributes to values different than the default values. The result is much pleasanter to see. Although it is still not quite as the first example, which uses a pre-defined dialog. Can you figure out which attributes we need to set in order to obtain a more closer appearance?

Hello World 5a