This example is about a small GUI calculator. The UI is realized with GTK and has been designed with Glade3. That way the source code can be compiled and executed under windwos and LINUX.
The GUI design is created in Glade3 and saved as GUI-XML-file. This file gets loaded at runtime and the UI is generated regarding its content. For further improvement the file can be edited in Glade3 later on. For successful execution this code has to be saved as 'FB_Calc.ui' in the project folder
Code: Select all
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="2.22"/>
<object class="GtkWindow" id="winMain">
<property name="width_request">280</property>
<property name="height_request">310</property>
<property name="can_focus">False</property>
<property name="border_width">10</property>
<property name="title" translatable="yes">FB Calculator</property>
<signal name="delete-event" handler="gtk_main_quit" swapped="no"/>
<child>
<object class="GtkVBox" id="vbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">15</property>
<child>
<object class="GtkEntry" id="EntDisplay">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="editable">False</property>
<property name="invisible_char">●</property>
<property name="text">0</property>
<property name="xalign">0.94999998807907104</property>
<property name="truncate_multiline">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="padding">10</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkTable" id="table1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="n_rows">5</property>
<property name="n_columns">4</property>
<property name="column_spacing">10</property>
<property name="row_spacing">10</property>
<child>
<object class="GtkButton" id="but7">
<property name="label" translatable="yes">7</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<accelerator key="7" signal="clicked"/>
<accelerator key="KP_7" signal="clicked"/>
<signal name="clicked" handler="on_number_clicked" swapped="no"/>
</object>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="but4">
<property name="label" translatable="yes">4</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="focus_on_click">False</property>
<accelerator key="KP_4" signal="clicked"/>
<accelerator key="4" signal="clicked"/>
<signal name="clicked" handler="on_number_clicked" swapped="no"/>
</object>
<packing>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<object class="GtkButton" id="but1">
<property name="label" translatable="yes">1</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="focus_on_click">False</property>
<accelerator key="KP_1" signal="clicked"/>
<accelerator key="1" signal="clicked"/>
<signal name="clicked" handler="on_number_clicked" swapped="no"/>
</object>
<packing>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
</packing>
</child>
<child>
<object class="GtkButton" id="but0">
<property name="label" translatable="yes">0</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="focus_on_click">False</property>
<accelerator key="KP_0" signal="clicked"/>
<accelerator key="0" signal="clicked"/>
<signal name="clicked" handler="on_number_clicked" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
</packing>
</child>
<child>
<object class="GtkButton" id="but2">
<property name="label" translatable="yes">2</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="focus_on_click">False</property>
<accelerator key="KP_2" signal="clicked"/>
<accelerator key="2" signal="clicked"/>
<signal name="clicked" handler="on_number_clicked" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
</packing>
</child>
<child>
<object class="GtkButton" id="but5">
<property name="label" translatable="yes">5</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="focus_on_click">False</property>
<accelerator key="KP_5" signal="clicked"/>
<accelerator key="5" signal="clicked"/>
<signal name="clicked" handler="on_number_clicked" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<object class="GtkButton" id="but8">
<property name="label" translatable="yes">8</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<accelerator key="KP_8" signal="clicked"/>
<accelerator key="8" signal="clicked"/>
<signal name="clicked" handler="on_number_clicked" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="but9">
<property name="label" translatable="yes">9</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<accelerator key="KP_9" signal="clicked"/>
<accelerator key="9" signal="clicked"/>
<signal name="clicked" handler="on_number_clicked" swapped="no"/>
</object>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="but6">
<property name="label" translatable="yes">6</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="focus_on_click">False</property>
<accelerator key="KP_6" signal="clicked"/>
<accelerator key="6" signal="clicked"/>
<signal name="clicked" handler="on_number_clicked" swapped="no"/>
</object>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<object class="GtkButton" id="but3">
<property name="label" translatable="yes">3</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="focus_on_click">False</property>
<accelerator key="KP_3" signal="clicked"/>
<accelerator key="3" signal="clicked"/>
<signal name="clicked" handler="on_number_clicked" swapped="no"/>
</object>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
</packing>
</child>
<child>
<object class="GtkButton" id="but_plus">
<property name="label" translatable="yes">+</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="focus_on_click">False</property>
<accelerator key="plus" signal="clicked"/>
<accelerator key="KP_Add" signal="clicked"/>
<signal name="clicked" handler="on_operation_clicked" swapped="no"/>
</object>
<packing>
<property name="left_attach">3</property>
<property name="right_attach">4</property>
<property name="top_attach">1</property>
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<object class="GtkButton" id="but_gleich">
<property name="label" translatable="yes">=</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="has_focus">True</property>
<property name="is_focus">True</property>
<property name="can_default">True</property>
<property name="has_default">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<property name="focus_on_click">False</property>
<accelerator key="Return" signal="clicked"/>
<accelerator key="KP_Enter" signal="clicked"/>
<signal name="clicked" handler="on_operation_clicked" swapped="no"/>
</object>
<packing>
<property name="left_attach">3</property>
<property name="right_attach">4</property>
<property name="top_attach">3</property>
<property name="bottom_attach">5</property>
</packing>
</child>
<child>
<object class="GtkButton" id="but_minus">
<property name="label" translatable="yes">-</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="focus_on_click">False</property>
<accelerator key="minus" signal="clicked"/>
<accelerator key="KP_Subtract" signal="clicked"/>
<signal name="clicked" handler="on_operation_clicked" swapped="no"/>
</object>
<packing>
<property name="left_attach">3</property>
<property name="right_attach">4</property>
</packing>
</child>
<child>
<object class="GtkButton" id="but_mult">
<property name="label" translatable="yes">*</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="focus_on_click">False</property>
<accelerator key="asterisk" signal="clicked"/>
<accelerator key="KP_Multiply" signal="clicked"/>
<signal name="clicked" handler="on_operation_clicked" swapped="no"/>
</object>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
</packing>
</child>
<child>
<object class="GtkButton" id="but_div">
<property name="label" translatable="yes">÷</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="focus_on_click">False</property>
<accelerator key="slash" signal="clicked"/>
<accelerator key="KP_Divide" signal="clicked"/>
<signal name="clicked" handler="on_operation_clicked" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="but_clear">
<property name="label" translatable="yes">C</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="focus_on_click">False</property>
<accelerator key="Delete" signal="clicked"/>
<signal name="clicked" handler="on_operation_clicked" swapped="no"/>
</object>
</child>
<child>
<object class="GtkButton" id="butD">
<property name="label" translatable="yes">.</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<property name="focus_on_click">False</property>
<accelerator key="comma" signal="clicked"/>
<accelerator key="KP_Separator" signal="clicked"/>
<accelerator key="period" signal="clicked"/>
<signal name="clicked" handler="on_number_clicked" swapped="no"/>
</object>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
</packing>
</child>
<child>
<object class="GtkButton" id="butPM">
<property name="label" translatable="yes">±</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<property name="focus_on_click">False</property>
<signal name="clicked" handler="on_number_clicked" swapped="no"/>
</object>
<packing>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</interface>
When compiling this main file unchanged, some error messages will be shown. This is due to #ERROR lines in the code. The #ERROR lines are to mark the places to extend the code by your individual features.
In the following source code the #ERROR lines are replaced by the necessary FB statements and for easy handling all source files are bundled in one. Save this code as 'FB_Calc.bas' in to your project folder. For successful compiling the header from GladeToBac and a GTK installation >=2.16 is needed (due to GtkBuilder).
Code: Select all
' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
'< main program generated by utility GladeToBac V3.0.0.1 >
'< Hauptprogramm erzeugt von >
'< Generated at / Generierung am 2011-09-15, 12:27 >
' -----------------------------------------------------------------------------
'< Program info: >
CONST PROJ_NAME = "FB_Calc" ' >
CONST PROJ_DESC = "Taschenrechner" ' >
CONST PROJ_VERS = "0.0" ' >
CONST PROJ_YEAR = "2011" ' >
CONST PROJ_AUTH = "" ' >
CONST PROJ_MAIL = "Thomas{ dot ]Freiherr[ AT ]gmx[ dot }net" ' >
CONST PROJ_WEBS = "www.freebasic-portal.de" ' >
CONST PROJ_LICE = "GNU General Public License v3" ' >
'< >
'< Description / Beschreibung: >
'< >
'< >
'< License / Lizenz: >
'< >
'< This program is free software: you can redistribute it and/or modify >
'< it under the terms of the GNU General Public License as published by >
'< the Free Software Foundation, either version 3 of the License, or >
'< (at your option) any later version. >
'< >
'< This program is distributed in the hope that it will be useful, but >
'< WITHOUT ANY WARRANTY; without even the implied warranty of >
'< MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU >
'< General Public License for more details. >
'< >
'< You should have received a copy of the GNU General Public License along >
'< with this program. If not, see <http://www.gnu.org/licenses/>. >
'< >
' -----------------------------------------------------------------------------
'< Please prefer GNU GENERAL PUBLIC LICENSE to support open software. >
'< For more information please visit: http://www.fsf.org >
'< >
'< Bitte bevorzugen Sie die GNU GENERAL PUBLIC LICENSE und >
'< unterstuetzen Sie mit Ihrem Programm die freie Software >
'< Mehr Informationen finden Sie unter: http://www.fsf.org >
' -----------------------------------------------------------------------------
'< GTK+tobac: general init / Allgemeine Initialisierungen >
#DEFINE __TJF_GTK_OLD__ ' for old versions / alte GTK+ Version < 2.16 >
#INCLUDE "gtk/GTK-2.22.0_TJF.bi" ' GTK+library / GTK+ Bibliothek >
gtk_init(@__FB_ARGC__, @__FB_ARGV__) ' start GKT / GTK starten >
#INCLUDE "TJF/libintl.bi" ' load lib / Lib laden >
bindtextdomain(PROJ_NAME, EXEPATH & "/locale") ' path / Pfad >
bind_textdomain_codeset(PROJ_NAME, "UTF-8") ' set encoding / Zeichensatz >
textdomain(PROJ_NAME) ' Filename / Dateiname >
'< GTK+tobac: end block / Blockende >
' vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
#IFDEF __FB_WIN32__
#LIBPATH "C:\opt\GTK-2.22.1\lib"
#ENDIF
' place your source code here / eigenen Quelltext hier einfuegen
ENUM OP
Clear
Result
Plus
Minus
Multiplication
Division
END ENUM
DECLARE SUB Calc(BYVAL O AS OP)
DIM SHARED AS INTEGER CLEAR_DISPLAY = 1
DIM SHARED AS STRING D_SEP
IF VAL("0.1") <> 0.1 THEN D_SEP = "," ELSE D_SEP = "."
TYPE GUIData
AS GtkBuilder PTR XML
AS GObject PTR _
winMain, EntDisplay, but7, but4, but1, but0, but2, but5, but8, but9, _
but6, but3, but_plus, but_gleich, but_minus, but_mult, but_div, but_clear, _
butD, butPM
END TYPE
DIM SHARED AS GUIData GUI
GUI.XML = gtk_builder_new()
SCOPE
DIM AS GError PTR meld
IF 0 = gtk_builder_add_from_file(GUI.XML, "FB_Calc.ui", @meld) THEN
WITH *meld
?"Fehler/Error (GTK-Builder):"
?*.message
END WITH
END 2
END IF
END SCOPE
WITH GUI
.winMain = gtk_builder_get_object(.XML, "winMain")
.EntDisplay = gtk_builder_get_object(.XML, "EntDisplay")
.but7 = gtk_builder_get_object(.XML, "but7")
.but4 = gtk_builder_get_object(.XML, "but4")
.but1 = gtk_builder_get_object(.XML, "but1")
.but0 = gtk_builder_get_object(.XML, "but0")
.but2 = gtk_builder_get_object(.XML, "but2")
.but5 = gtk_builder_get_object(.XML, "but5")
.but8 = gtk_builder_get_object(.XML, "but8")
.but9 = gtk_builder_get_object(.XML, "but9")
.but6 = gtk_builder_get_object(.XML, "but6")
.but3 = gtk_builder_get_object(.XML, "but3")
.but_plus = gtk_builder_get_object(.XML, "but_plus")
.but_gleich = gtk_builder_get_object(.XML, "but_gleich")
.but_minus = gtk_builder_get_object(.XML, "but_minus")
.but_mult = gtk_builder_get_object(.XML, "but_mult")
.but_div = gtk_builder_get_object(.XML, "but_div")
.but_clear = gtk_builder_get_object(.XML, "but_clear")
.butD = gtk_builder_get_object(.XML, "butD")
.butPM = gtk_builder_get_object(.XML, "butPM")
END WITH
SUB on_number_clicked CDECL ALIAS "on_number_clicked" ( _
BYVAL button AS GtkButton PTR, _
BYVAL user_data AS gpointer) EXPORT
WITH GUI
VAR disp = GTK_ENTRY(.EntDisplay)
VAR t = *gtk_entry_get_text(disp)
IF t = "0" ORELSE CLEAR_DISPLAY THEN t = ""
SELECT CASE G_OBJECT(button)
CASE .but0 : t &= "0"
CASE .but1 : t &= "1"
CASE .but2 : t &= "2"
CASE .but3 : t &= "3"
CASE .but4 : t &= "4"
CASE .but5 : t &= "5"
CASE .but6 : t &= "6"
CASE .but7 : t &= "7"
CASE .but8 : t &= "8"
CASE .but9 : t &= "9"
CASE .butD
IF INSTR(t, D_SEP) = 0 THEN
IF t = "" THEN t = "0" & D_SEP ELSE t &= D_SEP
END IF
CASE .butPM
IF LEFT(t, 1) = "-" THEN
t = MID(t, 2)
ELSE
IF t = "" THEN t = "-0" ELSE t = "-" & t
END IF
END SELECT
END WITH
IF t = "" THEN t = "0"
gtk_entry_set_text(disp, t)
CLEAR_DISPLAY = 0
END SUB
SUB on_operation_clicked CDECL ALIAS "on_operation_clicked" ( _
BYVAL button AS GtkButton PTR, _
BYVAL user_data AS gpointer) EXPORT
WITH GUI
SELECT CASE G_OBJECT(button)
CASE .but_plus : Calc(Op.Plus)
CASE .but_minus : Calc(Op.Minus)
CASE .but_mult : Calc(Op.Multiplication)
CASE .but_div : Calc(Op.Division)
CASE .but_clear : Calc(Op.Clear)
CASE .but_gleich : Calc(Op.Result)
END SELECT
END WITH
END SUB
' here widgets are known, place your source code here
' hier sind die Widgets bekannt, eigenen Quelltext einfuegen
SUB Calc(BYVAL O AS OP)
STATIC AS STRING stack
VAR entry = GTK_ENTRY(GUI.EntDisplay)
VAR disp = VAL(*gtk_entry_get_text(entry))
IF O = Op.Clear THEN
stack = "" : disp = 0.0
ELSE
VAR p = LEN(stack) - 8
WHILE LEN(stack)
SELECT CASE AS CONST ASC(RIGHT(stack, 1))
CASE Op.Plus
IF O > Op.Minus THEN EXIT WHILE
disp += CVD(MID(stack, p, 8))
CASE Op.Minus
IF O > Op.Minus THEN EXIT WHILE
disp = CVD(MID(stack, p, 8)) - disp
CASE Op.Multiplication
disp *= CVD(MID(stack, p, 8))
CASE Op.Division
IF disp = 0.0 THEN
gtk_entry_set_text(entry, *__("Error"))
CLEAR_DISPLAY = 1
stack = ""
EXIT SUB
END IF
disp = CVD(MID(stack, p, 8)) / disp
END SELECT
stack = LEFT(stack, p - 1)
p -= 9
WEND
IF O <> Op.Result THEN stack &= MKD(disp) & CHR(O)
CLEAR_DISPLAY = 1
END IF
gtk_entry_set_text(entry, STR(disp))
END SUB
gtk_button_set_label(GTK_BUTTON(GUI.butD), D_SEP)
' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
'< GTK+tobac: run GTK main, then end / GTK Hauptschleife, dann Ende >
gtk_builder_connect_signals(GUI.XML, 0) ' Signale anbinden >
gtk_widget_show_all(GTK_WIDGET(GUI.winMain)) ' Hauptfenster darstellen >
gtk_main() ' main loop / Hauptschleife >
g_object_unref(GUI.XML) ' dereference / Referenz abbauen >
'< GTK+tobac: end block / Blockende >
' vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
' you may unref files here / ggf. Dateien hier schliessen
END 0 ' finish with return code 0 / Ende mit Returncode 0
And later on, have fun extending the calculator features. After changing the FB_Calc.ui file the FB source has to be updated with GladeToBac. (Therefor you need to separate the source in to the original files -- make a new code frame and copy the code from here.)
For updates see this link.