PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [C]/[Gtk+] for-Fehler in Callback und allgemeine Fragen



crocodilechris
11-09-2010, 12:00
Hallo Community,

ich wollte mal wieder Programmieren und dachte mir ich nehm meine alten Delphi-Beispiele aus der Schule und versuche mich mal in der GUI-Programmierung mit C.

Hab mir dazu Gtk+ ausgesucht - hat mir gefühlsmäßig besser gefallen...

Hab mir jetzt erst einmal mit Glade ne GUI gebaut und nach Tutorial das ganze zum laufen gebracht:
Bildschirmfoto-Schere-Stein-Papier.png (http://www.divshare.com/download/12523666-7e4)
Bekomme es auch schon hin, das Button-clicked-Signal zu nutzen und dort abzufragen, welcher RadioButton gedrückt wird:

void on_button1_clicked ( GtkButton *button1,
GSList *radio_list
) {
GtkWidget *radio;
int i;

for(i = 0; i < g_slist_length(radio_list); ++i) {
radio = g_slist_nth_data(radio_list, i);
/* radio != NULL check misses */
g_printf("%d. Durchlauf, ", i); /* Control of break */
if(gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(radio) )) {
g_printf("Button %d gedrueckt\n", 3-i);
break;
}
}
g_print("Kontrolle\n");
}Jetzt zu meinem Problem:
Wenn ich das so ausführe wird mir korrekt angezeigt, welcher RadioButton aktiv ist, allerdings wird die Kontrolausgabe nach der for-Schleife, sowohl vorher als auch hinterher ausgegeben:

chris@Terra-Lap:Schere_Stein_Papier$ gcc -o game_SSP game_SSP.c $(pkg-configflags --libs gtk+-2.0 gmodule-2.0)
chris@Terra-Lap:Schere_Stein_Papier$ ./game_SSP
Kontrolle
0. Durchlauf, 1. Durchlauf, 2. Durchlauf, Button 1 gedrueckt
Kontrolle
Kontrolle
0. Durchlauf, 1. Durchlauf, Button 2 gedrueckt
Kontrolle
Kontrolle
0. Durchlauf, Button 3 gedrueckt
Kontrolle
Wodurch tritt dieser Effekt auf? Ist das Normal?

Dann noch ne Frage zur Benutzung von Gtk+:
Wenn ich jetzt in dem Button-clicked callback
KI-Auswahl
Info-Ausgabe
Punkteveränderung
setzen will, muss ich dann die betroffenen Objekte mit übergeben, oder kann ich einfach darauf zugreifen?

THX 4 Help
PS: Quellcode im Anhang

John W
11-09-2010, 13:01
Falsches Forum, das gehört nach "Sparachen, Standard APIs".
Ich kann mir gut vorstellen, dass Kontrolle zweimal ausgegeben wird, weil der Handler zweimal aufgerufen wird, wobei einmal einfach kein Button aktiv ist oder die Liste leer ist - lass dir bei Kontrolle auch mal g_slist_length(radio_list) ausgeben.
Zudem würde ich int i in den for-Header packen, ist aber meist mehr eine Stilfrage:


for (int i = 0 ; ...)

sommerfee
11-09-2010, 14:59
Wodurch tritt dieser Effekt auf?

Bei GTK+ wird der Callback bei Radiobuttons (und Radio-Menüpunkten) auch dann aufgerufen, wenn der Knopf deselektiert wird, d.h. bei einer Änderung gibt es immer zwei Callbacks.


Ist das Normal?

Ja.

Liebe Grüße,
Axel

crocodilechris
11-09-2010, 17:13
Zudem würde ich int i in den for-Header packen, ist aber meist mehr eine Stilfrage:


for (int i = 0 ; ...)
Das wäre dann C99, versuche aber mich auf ANSI-C zu beschränken.

Bei GTK+ wird der Callback bei Radiobuttons (und Radio-Menüpunkten) auch dann aufgerufen, wenn der Knopf deselektiert wird, d.h. bei einer Änderung gibt es immer zwei Callbacks.

Ich weiß nicht obs was ändert, aber das ist nen Callback von nem GtkButton.
Hab zur Kontrolle mal wie folgt den Code geändert (Länge an 2 Stellen ausgeben):

void on_button1_clicked ( GtkButton *button1,
GSList *radio_list
) {
GtkWidget *radio;
unsigned int i;

for(i = 0; i < g_slist_length(radio_list); ++i) {
radio = g_slist_nth_data(radio_list, i);
/* radio != NULL check misses */
g_printf("Laenge: %d \n", g_slist_length(radio_list));
g_printf("%d. Durchlauf, ", i); /* Control of break */
if(gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(radio) )) {
g_printf("Button %d gedrueckt\n", 3-i);
break;
}
}
g_printf("Laenge2: %d \n", g_slist_length(radio_list));
g_print("Kontrolle\n");
}
Was mir dabei wieder auffällt:
Die Kontrollausgaben nach der for-Schleife wird doppelt ausgegeben, die in der for-Schleife nur einmal:

Laenge2: 0
Kontrolle
Laenge: 3
0. Durchlauf, Button 3 gedrueckt
Laenge2: 3
Kontrolle

Wenn der Callback zweimal aufgerufen würde, müsste doch auch die Schleife zweimal durchlaufen werden !?!?

sommerfee
11-09-2010, 18:23
Offensichtlich wird da auch on_button1_clicked() mit "radio_list" = NULL aufgerufen, wieso und warum kann ich ohne weiteren Quelltext auch nicht sagen.

crocodilechris
12-09-2010, 03:34
Hatte oben schon den Quelltext mit angehangen, aber hier nochmal im Anhang. ;)

Und danke für deine Mühen! :)

sommerfee
12-09-2010, 09:24
Hatte oben schon den Quelltext mit angehangen

Oh, sorry, das hatte ich gar nicht gesehen :o

Der Grund für das Verhalten ist in der Glade-Datei zu finden:
<signal name="clicked" handler="on_button1_clicked"/>
Hier wird "button1" schon mit dem Handler "on_button1_clicked" verknüpft und hieraus resultiert der zusätzliche Aufruf mit radio_list = NULL und damit g_slist_length(radio_list) = 0.

Wenn du also diese Verknüpfung aus der Glade-Datei herausnimmst, und nur diejenige im Quelltext game_SSP.c übrig läßt, sollte es besser funktionieren.

Liebe Grüße,
Axel

crocodilechris
14-09-2010, 10:18
Vielen Dank!
Das hat geholfen! :)

Ich hab ja jetzt noch beim window1 das "destroy"-Signal mit gtk_main_quit drin.
Würde es sich lohnen, dieses auch aus der Glade-Datei heraus zu nehmen und dafür dann folgenden Ausruf rauszuschmeißen?
/* Connect signals */
gtk_builder_connect_signals( builder, NULL );Bzw. wenn ich alle Signale in Glade Vordefinieren wollen würde, müsste ich dann ein Struct bauen, dass alle meine Objekte & Widges beinhalten müsste, denen ich ein Signal zugewiesen habe?
Wäre zwar "Arbeit", aber andererseits könnte ich eine Referenz davon immer jedem Callback mit Übergeben und könnte ohne Probleme auf meine Restlichen Widges zugreifen, oder?

John W
14-09-2010, 10:21
Ein Callback sollte eig. im Sourcecode definiert werden, nicht in der Glade-Datei - da kann sonst die Sicherheit drunter leiden, zudem ist Debuggen schwieriger, da man dann ja auch "Code" in der Glade-Datei hat. Man kann es machen, dann aber konsequent und sollte sich über sämtliche Folgen im Klaren sein.

crocodilechris
14-09-2010, 10:58
Falls ich mich wieder einmal unverständlich ausgedrückt habe (passiert mir öfter in Texten), dann nochmal klar:

Es war nicht die Frage, nach dem auslagern des Callbacks ins Glade-File, sondern ob es lohnt die Signale im Glade-File zu definieren.
Und ob ich in diesem Falle einen Struct definieren muss, in dem alle anzusprechenden Widges zusammengefasst werden.

John W
14-09-2010, 12:41
Eigentlich war ich da ungenau. :o
Signale würde ich im Sourcecode, nicht in der Glade-Datei verbinden.

crocodilechris
14-09-2010, 13:00
Signale würde ich im Sourcecode, nicht in der Glade-Datei verbinden.Okay, und dann kann ich auch die Argumente nachvollziehen:
da kann sonst die Sicherheit drunter leiden, zudem ist Debuggen schwieriger, da man dann ja auch "Code" in der Glade-Datei hat
So, dann werd ich mich mal ranwagen, mir überlegen, ob ich alle Objekte oder Widgets die ich bearbeiten will in nen Struct verlagere, oder ne GSList übergebe, die ich dann wieder zerpflücke...
Struct erscheint mir grad als sinnvollere Variante, wobei mir gerade auch union in den Kopf kommt, ... muss mir nochmal mein schlaues Buch vornehmen.:cool:

Ohman, das ganze war in Delphi früher einfacher, aber jetzt lern ich mehr. :D

John W
14-09-2010, 17:09
Das ist genau der Grund, warum ich meist Java nehm - da kommt man flott ans Ziel, und im Vergleich zu C und C++ ist die Performance auch ähnlich, wenn man in die Optimierungstrickkiste greift.
Für kleine Hacks zwischendurch nehm ich sonst aber auch Bash oder Python, hat bisher meist immer gepasst.

crocodilechris
14-09-2010, 17:42
Gut, aber als angehender Informatik-Lehrer sollte man schon mehr als eine Sprache und ein Konzept beherrschen. ;)
Ansonsten hab ich mir vorgenommen, das Projekt erst einmal in C zu realisieren, dann in Java und abschließend wollte ich mir noch Python beibringen und es damit dann auch noch realisieren.
Vielleicht auch noch in Delphi, aber dann müsste ich Windows booten und das ist immer son Akt:
Warten bis grub geladen ist und dann auch noch 2x Pfeiltaste-unten drücken, ... :p