[C & Gtk+] Probleme mit TextWidget als Logfläche

  • Themenstarter Themenstarter rockin_santa
  • Beginndatum Beginndatum
R

rockin_santa

Guten Abend

Ich arbeite mich gerade in die GUI-Programmierung mit C & Gtk+ auf einem Linuxsystem ein.
Ich möchte u.a. ein nicht editierbares Textfeld haben, in dass ich mir Zeichenketten und Variablen ausgeben möchte, also eine Art Logger. Soll ein Steuerungsprogramm für ein mikrokontrollergestützten Roboter werden, der Daten liefert, die ausgegeben werden sollen.

Nun habe ich diverse deutsch- und englischsprachige Tutorials zu Gtk durchwühlt, und sehe bei allen, daß dort Textfelder zur Tastatureingabe verwendet werden, um dann diese Daten in Files zu speichern oder auf der Konsole auszugeben. Aber ich will es genau umgekehrt.
Das einzige, was ich fand, ist die Funktion gtk_text-insert(). Diese funktioniert auch, wenn ich sie in der main() aufrufe (einfrieren und auftauen wird entsprechend vor und danach auch gemacht).
Verwende ich diese Textausgabe allerdings in einer Unterfunktion, bekomme ich folgende Fehlermeldung auf der Konsole, wenn ich im laufenden Programm auf die Schaltfläche klicke (Kompiliert hat der gcc ohne zu Murren):

Gtk-Warning **: invalid cast from (NULL) pointer to `GtkText'

Gtk-CRITICAL **: file gtktext.c: 905 (gtk_text_freeze): assertion `text != NULL' failed.


Diese Fehlermeldung kommt auch für die Funktionsaufrufe:
gtk_text_insert und gtk_text_thaw

Ich kann mir nicht erklären, warum dieser Code in der main() funktioniert, aber in einer Unterfunktion nicht.

Generell stelle ich mir auch die Frage, ob dies überhaupt der richtige Ansatz ist, oder ob man nicht die Logfunktion über einen anderen Weg eleganter implementieren kann.

Könnt Ihr mir da vielleicht den einen oder anderen Tipp geben?
Falls Euch sonst noch etwas im unten gelisteten Programmcode auffällt, was ungünstig oder falsch ist, könnt Ihr gerne Kritik üben, ich bin ein Anfänger und über jeden Hinweis dankbar.

Grüße

rockin_santa

Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gtk/gtkwidget.h>
#include <gtk/gtk.h>
#include <gdk/gdk.h>

GtkItemFactory *items;
GtkAccelGroup *accl;

/* --- GUI-Funktionen ------------------------------------------------------- */

/* Menueeintragsfunktionen */
void neustart(GtkWidget *text_ausgabe)
{
/* --- Hier funktioniert die Textausgabe NICHT! ----------------------------- */
    gtk_text_freeze(GTK_TEXT(text_ausgabe));
    gtk_text_insert(GTK_TEXT(text_ausgabe), NULL, NULL, NULL, 
                    "Neustart wurde geklickt\n", -1);
    gtk_text_thaw(GTK_TEXT(text_ausgabe));
    g_print("Neustart\n");

}

void prog_schliessen()
{
    gtk_main_quit();
}
void daten()
{
    g_print("Daten aktualisieren\n");
}
void ort_bestimmen()
{
    g_print("Ort bestimmen\n");
}
void pos_anfahren()
{
    g_print("Position anfahren\n");
}
void akku()
{
    g_print("Akku laden\n");
}
void schlafen()
{
    g_print("Schlafen\n");
}
void info()
{
    g_print("Informationen\n");
}
/* Knopffunktionen */
void stop(GtkText *text_ausgabe)
{
    g_print("Stop\n");
}
void vorraus()
{
    g_print("Vorraus\n");
}
void achteraus()
{
    g_print("Achteraus\n");
}
void linksdrehen()
{
    g_print("Linksdrehen\n");
}
void rechtsdrehen()
{
    g_print("Rechtsdrehen\n");
}

/* Hier werden die Menueeintraege konfiguriert */
static GtkItemFactoryEntry menue[]={
    { "/_Programm", NULL, NULL, 0, "<Branch>" },
    { "/Programm/_Neustart", "<control>N", neustart, 0, NULL},
    { "/Programm/_Beenden", "<control>Q", gtk_main_quit, 0, NULL},

    { "/_Funktionen", NULL, NULL, 0, "<Branch>" },
    { "/Funktionen/_Daten aktualisieren", "<control>D", daten, 0, NULL},
    { "/Funktionen/_Ort bestimmen", "<control>O", ort_bestimmen, 0, NULL},
    { "/Funktionen/_Position anfahren", "<control>P", pos_anfahren, 0, NULL},
    { "/Funktionen/_Akkus laden", "<control>A", akku, 0, NULL},
    { "/Funktionen/_Schlafen", "<control>S", schlafen, 0, NULL},

    { "/_Info", NULL, NULL, 0, "<LastBranch>"},
    { "/Info/_Info", NULL, info, 0, NULL},
};

/* Beginn der Main-Funktion */
int main(int argc, char **argv)
{
    GtkWidget *fenster;
    GtkItemFactory *items;
    GtkAccelGroup *accl;
    GtkWidget *box_aussen;
    GtkWidget *box_mitte;
    GtkWidget *box_innen;
    GtkWidget *menue_leiste;
    GtkWidget *rahmen_steuerung;                                               
    GtkWidget *rahmen_status;                                                  
    GtkWidget *rahmen_karte;                                                   
    GtkWidget *rahmen_text;
    GtkWidget *tabelle;
    GtkWidget *knopf_stop;
    GtkWidget *knopf_vorraus;
    GtkWidget *knopf_achteraus;
    GtkWidget *knopf_linksdrehen;
    GtkWidget *knopf_rechtsdrehen;
    GtkWidget *text_ausgabe;
    GtkObject *adjtextscr;
    gint n_menue = sizeof(menue) /sizeof(menue[0]);

    /* Gtk initialisieren */
    gtk_init(&argc, &argv);
    /* Ein neues Fenster erstellen und anschliessend konfigurieren */
    fenster = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    /* Tastaturkuerzelstruktur erstellen */
    accl = gtk_accel_group_new();
    /* Fenstertitel */
    gtk_window_set_title(GTK_WINDOW(fenster),
                         "Robotersteuerprogramm fruehe Alphaversion");
    /* Fenstergroesse */
    gtk_window_set_default_size(GTK_WINDOW(fenster), 1280, 600);
    /* Fensterposition auf Desktop */
    gtk_window_set_position(GTK_WINDOW(fenster),GTK_WIN_POS_CENTER);

    /* Menueleiste erstellen */
    items = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<main>", accl);
    gtk_item_factory_create_items(items, n_menue, menue, NULL);
    /* Tastaturkuerzelstruktur dem Fenster zuordnen */
    gtk_accel_group_attach(accl, GTK_OBJECT(fenster));
    menue_leiste = gtk_item_factory_get_widget(items, "<main>");

    /* Knoepfe erstellen */
    knopf_stop = gtk_button_new_with_label("Stop");
    knopf_vorraus = gtk_button_new_with_label("Vorraus");
    knopf_achteraus = gtk_button_new_with_label("Achteraus");
    knopf_linksdrehen = gtk_button_new_with_label("Linksdrehen");
    knopf_rechtsdrehen = gtk_button_new_with_label("Rechtsdrehen");

    /* Rahmen erstellen */
    rahmen_steuerung = gtk_frame_new("Steuerung");                            
    rahmen_status = gtk_frame_new("Status");                                   
    rahmen_karte = gtk_frame_new("Karte");                                     
    rahmen_text = gtk_frame_new("Log");          

    /* 3x3-Tabelle erstellen und Knoepfe zuweisen */        
    tabelle = gtk_table_new(3, 3, TRUE);
    gtk_table_attach_defaults(GTK_TABLE(tabelle), knopf_stop, 1,2, 1,2);
    gtk_table_attach_defaults(GTK_TABLE(tabelle), knopf_vorraus, 1,2, 0,1);
    gtk_table_attach_defaults(GTK_TABLE(tabelle), knopf_achteraus, 1,2, 2,3);
    gtk_table_attach_defaults(GTK_TABLE(tabelle), knopf_linksdrehen, 0,1, 1,2);
    gtk_table_attach_defaults(GTK_TABLE(tabelle), knopf_rechtsdrehen, 2,3, 1,2);

    /* Textfeld fuer Datenausgabe erstellen und konfigurieren */

/* --- Hier funktioniert die Textausgabe ----------------------------- */
    text_ausgabe = gtk_text_new(NULL, NULL);
    gtk_text_set_editable(GTK_TEXT(text_ausgabe), FALSE);
    gtk_text_freeze(GTK_TEXT(text_ausgabe));
    gtk_text_insert(GTK_TEXT(text_ausgabe), NULL, NULL, NULL, 
                    "Hier funktioniert\ndie Textausgabe\n", -1);
    gtk_text_thaw(GTK_TEXT(text_ausgabe));

    /* Neue vertikale Box (aussen) erstellen */
    box_aussen = gtk_vbox_new(FALSE,0);
    /* Neue Horizontale dreiteilige Box (mitte) erstellen */
    box_mitte = gtk_hbox_new(FALSE,0);
    /* Neue vertikale Box (innen) erstellen */
    box_innen = gtk_vbox_new(FALSE,0);

    /* Signale registrieren */
    gtk_signal_connect(GTK_OBJECT(fenster), "destroy",
                       GTK_SIGNAL_FUNC(prog_schliessen), NULL);
    gtk_signal_connect_object(GTK_OBJECT(knopf_stop), "clicked",
                       GTK_SIGNAL_FUNC(stop), GTK_OBJECT(fenster));
    gtk_signal_connect_object(GTK_OBJECT(knopf_vorraus), "clicked",
                       GTK_SIGNAL_FUNC(vorraus), GTK_OBJECT(fenster));
    gtk_signal_connect_object(GTK_OBJECT(knopf_achteraus), "clicked",
                       GTK_SIGNAL_FUNC(achteraus), GTK_OBJECT(fenster));
    gtk_signal_connect_object(GTK_OBJECT(knopf_linksdrehen), "clicked",
                       GTK_SIGNAL_FUNC(linksdrehen), GTK_OBJECT(fenster));
    gtk_signal_connect_object(GTK_OBJECT(knopf_rechtsdrehen), "clicked",
                       GTK_SIGNAL_FUNC(rechtsdrehen), GTK_OBJECT(fenster));

    /* Statusfeld, Kartenfeld und Log den Rahmen zuordnen */
    gtk_container_add(GTK_CONTAINER(rahmen_steuerung),tabelle);                            
    gtk_container_add(GTK_CONTAINER(rahmen_text),text_ausgabe);                

    /* Menueleiste in die obere Haelfte der vertikalen Box plazieren, die  */
    /* untere Haelfte teilt sich in innere Box, Karte und Datenausgabe,    */
    /* die innere Box trennt das Steuerungsfeld vom Statusfeld.            */
    gtk_box_pack_start(GTK_BOX(box_aussen), menue_leiste, FALSE, TRUE, 0);
    gtk_box_pack_start(GTK_BOX(box_aussen), box_mitte, FALSE, TRUE, 0);
    gtk_box_pack_start(GTK_BOX(box_mitte), box_innen, FALSE, TRUE, 0);        
    gtk_box_pack_start(GTK_BOX(box_mitte), rahmen_karte, FALSE, TRUE, 20);     
    gtk_box_pack_start(GTK_BOX(box_mitte), rahmen_text, FALSE, TRUE, 20);      
    gtk_box_pack_start(GTK_BOX(box_innen), rahmen_steuerung , FALSE, TRUE, 20);
    gtk_box_pack_start(GTK_BOX(box_innen), rahmen_status, FALSE, TRUE, 0);
    /* Box in das Fenster plazieren */
    gtk_container_add(GTK_CONTAINER(fenster),box_aussen);
    /* Das Fenster sichtbar machen */
    gtk_widget_show_all(fenster);

/* --- Beginn der Steuerungsfunktionen -------------------------------------- */
    gtk_main();

 return 0;
}
 
Zurück