Buchempfehlung
Mikrocomputertechnik mit Controllern der Atmel AVR-RISC-Familie
Mikrocomputertechnik mit Controllern der Atmel AVR-RISC-Familie
Umfassend, aber leicht verständlich führt dieses Buch in die Programmierung von ATMEL AVR Mikrocontrollern ein. [Mehr Infos...]
FreeBASIC-Chat
Es sind Benutzer im FreeBASIC-Chat online.
(Stand:  )
FreeBASIC bei Twitter
Twitter FreeBASIC-Nachrichten jetzt auch über Twitter erhalten. Follow us!

Code-Beispiel

Code-Beispiele » GTK, WxWidgets etc.

GTK-Fenster mit GLib-Thread kombinieren

Lizenz:Erster Autor:Letzte Bearbeitung:
GPLv3MitgliedTJF 24.05.2012
Bildschirmausgabe g_thread Beispiel
Vergrößern
Bildschirmausgabe g_thread Beispiel

Diese kleine Beispiel betrifft die Anwendung von Threads in Kombination mit einem Ausgabefenster. Ein Thread ist ein Unterprogramm, welches selbstständig (quasi) zeitgleich mit dem Hauptprogramm ausgeführt wird.

Im Beispiel werden in zwei Threads Zähler in unterschiedlicher Geschwindigkeit heraufgezählt und das Ergebnis wird in einem GTK Fenster angezeigt. Gleichzeitig wird im Hauptprogramm die Betätigung der Buttons bearbeitet.

Threads können die Ausgabe in Fenstern des Hauptprogrammes stören, was durch Kapselung mit gdk_thread_enter() und gdk_thread_leave() verhindert wird. Diese Kapselung ist unter X11 (LINUX) nicht notwendig. Leider gibt es große Unterschiede zwischen den verschiedenen windows Versionen. Das Beispiel ist für XP und höher einzusetzen. Die GLib Dokumentation weist jedoch darauf hin, dass bei manchen XP Versionen Probleme mit dem Mutex-Lock auftreten können (bitte ggf. rückmelden). Alternativ kann auch die Verwendung von gdk_threads (timeout / idle) erwogen werden.

Das GUI wird mit dem Designer Glade3 erstellt und als GUI-XML-Datei gespeichert. Aus dieser Datei werden mit GladeToBac Vorlagen für den FB Quelltext erstellt und diese durch individuelle Funktionalität ergänzt. GladeToBac erzeugt dabei Quelltext, der in mehrere Dateien aufgeteilt ist, damit eine nachträgliche Ergänzung bzw. Veränderung ohne manuelle Nacharbeiten möglich wird. In diesem Beispiel wird der "tobac"-Ordner verwendet. Voraussetzung für das erfolgreiche Kompilieren ist die Verwendung von Externer Link!aktualisierten GLib / GTK+ Headern und folgende Dateistruktur:

Projekt -+- tobac -+- wwt_tobac.bas
         |         +- on_ButL_clicked.bas
         |         +- on_ButR_clicked.bas
         |
         +- wwt.bas
         +- wwt.ui

tobac Ordner

wwt_tobac.bas (GladeToBac Steuerdatei. Wird automatisch erzeugt bzw. verändert.)

' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
'< _tobac.bas modul generated by utility                     GladeToBac V3.0.3 >
'< Modul _tobac.bas erzeugt von                                                >
'< Generated at / Generierung am                             2012-05-23, 08:29 >
' -----------------------------------------------------------------------------
'< Main/Haupt Program name: wwt.bas                                            >
'<  Email:  Thomas[ dot ]Freiherr[ at ]gmx[ dot ]net                           >
' -----------------------------------------------------------------------------
'< declare names, signal handlers, load GUI-XML                   do not edit! >
'< deklariert Namen, Signale, laedt GUI-XML                  nicht veraendern! >
' vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv

TYPE GUIData
  AS GtkBuilder PTR XML
  AS GObject PTR _
  window1, LabOL, LabOR, LabUL, LabUR
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, "wwt.ui", @meld) THEN
  WITH *meld
    ?"Fehler/Error (GTK-Builder):"
    ?*.message
  END WITH
  g_error_free(meld)
  END 2
END IF
END SCOPE

WITH GUI
  .window1 = gtk_builder_get_object(.XML, "window1")
  .LabOL = gtk_builder_get_object(.XML, "LabOL")
  .LabOR = gtk_builder_get_object(.XML, "LabOR")
  .LabUL = gtk_builder_get_object(.XML, "LabUL")
  .LabUR = gtk_builder_get_object(.XML, "LabUR")
END WITH

#INCLUDE "on_ButL_clicked.bas"
#INCLUDE "on_ButR_clicked.bas"

on_ButL_clicked.bas (Signal Handler für linken Button. Vorlage automatisch erzeugt, Quelltext individuell)

' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
'< Signal handler generated by utility                       GladeToBac V3.0.3 >
'< Signal-Modul erzeugt von                                                    >
'< Generated at / Generierung am                             2012-05-22, 19:37 >
' -----------------------------------------------------------------------------
'< Main/Haupt Program name: wwt.bas                                            >
'<  Email:  Thomas[ dot ]Freiherr[ at ]gmx[ dot ]net                           >
' -----------------------------------------------------------------------------
'< callback SUB/FUNCTION                                          insert code! >
'< Ereignis Unterprogramm/Funktion                        Quelltext einfuegen! >
' vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
SUB on_ButL_clicked CDECL ALIAS "on_ButL_clicked" ( _
  BYVAL button AS GtkButton PTR, _
  BYVAL user_data AS gpointer) EXPORT

  STATIC AS BYTE flag = 0
  STATIC AS INTEGER zaehler = 0

  zaehler += 1
  IF flag THEN
    gtk_label_set_text(GTK_LABEL(GUI.LabUL), *__("Button 1 jetzt ") & zaehler & *__(" mal geklickt"))
    flag = 0
  ELSE
    gtk_label_set_text(GTK_LABEL(GUI.LabUL), *__("Button 1 nun ") & zaehler & *__(" mal geklickt"))
    flag = 1
  END IF

END SUB

on_ButR_clicked.bas (Signal Handler für rechten Button)

' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
'< Signal handler generated by utility                       GladeToBac V3.0.3 >
'< Signal-Modul erzeugt von                                                    >
'< Generated at / Generierung am                             2012-05-22, 19:37 >
' -----------------------------------------------------------------------------
'< Main/Haupt Program name: wwt.bas                                            >
'<  Email:  Thomas[ dot ]Freiherr[ at ]gmx[ dot ]net                           >
' -----------------------------------------------------------------------------
'< callback SUB/FUNCTION                                          insert code! >
'< Ereignis Unterprogramm/Funktion                        Quelltext einfuegen! >
' vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
SUB on_ButR_clicked CDECL ALIAS "on_ButR_clicked" ( _
  BYVAL button AS GtkButton PTR, _
  BYVAL user_data AS gpointer) EXPORT

  STATIC AS BYTE flag = 0
  STATIC AS INTEGER zaehler = 0

  zaehler += 1
  IF flag THEN
    gtk_label_set_text(GTK_LABEL(GUI.LabUR), *__("Button 2 jetzt ") & zaehler & *__(" mal geklickt"))
    flag = 0
  ELSE
    gtk_label_set_text(GTK_LABEL(GUI.LabUR), *__("Button 2 nun ") & zaehler & *__(" mal geklickt"))
    flag = 1
  END IF

END SUB

Projekt Ordner

wwt.bas (Hauptdatei, diese wird kompiliert. Vorlage automatisch erzeugt, Quelltext individuell.)

' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
'< main program generated by utility                         GladeToBac V3.0.3 >
'< Hauptprogramm erzeugt von                                                   >
'< Generated at / Generierung am                             2012-05-22, 19:37 >
' -----------------------------------------------------------------------------
'< Program info:                                                               >
CONST PROJ_NAME = "wwt" '                                                      >
CONST PROJ_DESC = "g_threads" '                                                >
CONST PROJ_VERS = "0.0" '                                                      >
CONST PROJ_YEAR = "2012" '                                                     >
CONST PROJ_AUTH = "" '                                                         >
CONST PROJ_MAIL = "Thomas[ dot ]Freiherr[ at ]gmx[ dot ]net" '                 >
CONST PROJ_WEBS = "" '                                                         >
CONST PROJ_LICE = "" '                                                         >
'<                                                                             >
'< Description / Beschreibung:                                                 >
'<                                                                             >
'<   Example for GTK and GLib thread / Beispiel GTK Fenster und GLib Thread    >
'<                                                                             >
'< License / Lizenz:                                                           >
'<                                                                             >
'<   GPLv3                                                                     >
'<                                                                             >
' -----------------------------------------------------------------------------
'< 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 >
' -----------------------------------------------------------------------------
'<  GladeToBac:                    general init / Allgemeine Initialisierungen >
'    #DEFINE __USE_GTK_3__ '         for new versions / new GTK+ Version >= 3.0 >
    #INCLUDE "gtk/gtk.bi" '                      GTK+library / GTK+ Bibliothek >
    gtk_init(@__FB_ARGC__, @__FB_ARGV__) '             start GKT / GTK starten >
    #INCLUDE "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 >
'<  GladeToBac:                                          end block / Blockende >
' vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv


g_thread_init(NULL)
gdk_threads_init()

#IFNDEF __FB_UNIX__
#LIBPATH "C:\opt\gtk\lib"
' under X11 we don't need this / Nicht benoetigt unter X11
gdk_threads_enter()
#ENDIF


' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
'<  GladeToBac:                                 load GTK stuff / GTK Anbindung >
    #INCLUDE "tobac/wwt_tobac.bas" '                         Signale & GUI-XML >
'<  GladeToBac:                                          end block / Blockende >
' vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv


FUNCTION Timer1 CDECL(BYVAL Ud AS gpointer) AS gpointer
  STATIC AS INTEGER ende = 200
  FOR i AS INTEGER = 0 TO ende
    gdk_threads_enter()
    gtk_label_set_text(GTK_LABEL(GUI.LabOL), *__("Thread 1, Durchlauf ") & i & " (" & ende & ")")
    gdk_threads_leave()
    SLEEP 50
  NEXT : RETURN NULL
END FUNCTION

FUNCTION Timer2 CDECL(BYVAL Ud AS gpointer) AS gpointer
  STATIC AS INTEGER ende = 100
  FOR i AS INTEGER = 0 TO ende
    gdk_threads_enter()
    gtk_label_set_text(GTK_LABEL(GUI.LabOR), *__("Thread 2, Durchlauf ") & i & " (" & ende & ")")
    gdk_threads_leave()
    SLEEP 70
  NEXT : RETURN NULL
END FUNCTION

DIM AS GError PTR meld
VAR Thread1 = g_thread_create(@TIMER1, NULL, FALSE, @meld)
IF 0 = Thread1 THEN ? meld->message : g_error_free(meld)
VAR Thread2 = g_thread_create(@Timer2, NULL, FALSE, @meld)
IF 0 = Thread2 THEN ? meld->message : g_error_free(meld)


' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
'<  GladeToBac:          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.window1)) '     Hauptfenster darstellen >
    gtk_main() '                                     main loop / Hauptschleife >
    g_object_unref(GUI.XML) '                   dereference / Referenz abbauen >
'<  GladeToBac:                                          end block / Blockende >
' vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv

#IFNDEF __FB_UNIX__
' under X11 we don't need this / Nicht benoetigt unter X11
gdk_threads_leave()
#ENDIF

END 0 ' finish with return code 0 / Ende mit Returncode 0

wwt.ui (GUI-XML-Datei, erstellt mit Glade3.)

<?xml version="1.0" encoding="UTF-8"?>
<interface>
  <requires lib="gtk+" version="2.24"/>
  <object class="GtkWindow" id="window1">
    <property name="can_focus">False</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="border_width">5</property>
        <property name="spacing">5</property>
        <child>
          <object class="GtkTable" id="table1">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="n_rows">2</property>
            <property name="n_columns">2</property>
            <property name="column_spacing">10</property>
            <property name="row_spacing">10</property>
            <property name="homogeneous">True</property>
            <child>
              <object class="GtkLabel" id="LabOL">
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <property name="label" translatable="yes">label</property>
              </object>
            </child>
            <child>
              <object class="GtkLabel" id="LabOR">
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <property name="label" translatable="yes">label</property>
              </object>
              <packing>
                <property name="left_attach">1</property>
              </packing>
            </child>
            <child>
              <object class="GtkLabel" id="LabUL">
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <property name="label" translatable="yes">Button 1 noch nicht geklickt</property>
              </object>
              <packing>
                <property name="top_attach">1</property>
              </packing>
            </child>
            <child>
              <object class="GtkLabel" id="LabUR">
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <property name="label" translatable="yes">Button 2 noch nicht geklickt</property>
              </object>
              <packing>
                <property name="left_attach">1</property>
                <property name="top_attach">1</property>
              </packing>
            </child>
          </object>
          <packing>
            <property name="expand">True</property>
            <property name="fill">True</property>
            <property name="padding">10</property>
            <property name="position">0</property>
          </packing>
        </child>
        <child>
          <object class="GtkHBox" id="hbox1">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="spacing">5</property>
            <property name="homogeneous">True</property>
            <child>
              <object class="GtkButton" id="button1">
                <property name="label" translatable="yes">Button 1</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>
                <signal name="clicked" handler="on_ButL_clicked" swapped="no"/>
              </object>
              <packing>
                <property name="expand">True</property>
                <property name="fill">True</property>
                <property name="position">0</property>
              </packing>
            </child>
            <child>
              <object class="GtkButton" id="button2">
                <property name="label" translatable="yes">Button 2</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>
                <signal name="clicked" handler="on_ButR_clicked" swapped="no"/>
              </object>
              <packing>
                <property name="expand">True</property>
                <property name="fill">True</property>
                <property name="position">1</property>
              </packing>
            </child>
          </object>
          <packing>
            <property name="expand">True</property>
            <property name="fill">True</property>
            <property name="padding">10</property>
            <property name="position">1</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>

English

See Externer Link!english forum thread.


Zusätzliche Informationen und Funktionen
  • Das Code-Beispiel wurde am 22.05.2012 von MitgliedTJF angelegt.
  • Die aktuellste Version wurde am 24.05.2012 von MitgliedTJF gespeichert.
  Bearbeiten Bearbeiten  

  Versionen Versionen