GTK+ szignálküldés: delete-event

 ( nevergone | 2006. április 5., szerda - 14:37 )

Van egy programom, amelyben feldolgozom az alkalmazás főablakára irányuló delete_event szignált:

gboolean main_window_delete_event (GtkWidget * widget, GdkEvent * event, gpointer user_data) {
g_print ("delete-event\n");
return FALSE;
}

A szigálkezelő függvény a FALSE visszatérési értékkel jelzi, hogy az alkalmazás kiléphet, ha pedig a visszatérési érték TRUE, akkor az alkalmazás fut tovább.

Azt szerettem volna, hogy ha a program menűjéből kiválaszták a kilépés menűpontot, akkor egyszerűen küldje el a főablaknak a "delete-event" szignált, így az egész kilépési folyamatot csak egyszer kell megírnom, és a lehetőségekhez képest még szabályos is maradok:

void menuitem_quit_activate (GtkMenuItem * menuitem, gpointer user_data) {
/* a foablaknak kuldunk egy "delete_event" szignalt */
gboolean teszt;

g_signal_emit_by_name (G_OBJECT(main_window), "delete_event", G_TYPE_NONE, &teszt);
g_print ("eredmeny: %d\n", teszt);
}

Ha ez a szignálkezelő függvény végrehajtódik, akkor sikeresen elküldi a főablaknak a szignált (vagyis kiíródik a "delete-event" szöveg), a "teszt" változóban visszakapom annak a szignálkezelő függvénynek a visszatérési értékét, de a program nem lép ki, hanem továbbfut. Hiába játszadoztam a "delete-event" szignál visszatérési értékével, nem jutottam tovább.

Mi lehet a hiba, és a helyes megoldás?

Hozzászólás megjelenítési lehetőségek

A választott hozzászólás megjelenítési mód a „Beállítás” gombbal rögzíthető.

g_signal_emit_by_name

helyett ezzel?:

g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(main_window_delete_event), G_OBJECT(main_window));

Megnézem, bevallom, erre nem is gondoltam, pedig az általad írt függvényt régebben használtam már.
Bevallom, némelyik esetben annyira sokféle lehetőség van, hogy az már zavarbaejtő. :)

a main_window delete_event -jere van g_signal_connect?

gboolean main_window_delete_event (GtkWidget * widget, GdkEvent * event, gpointer user_data) {
g_print ("delete-event\n");
return FALSE;
}


g_signal_connect(G_OBJECT(main_window), "delete_event", G_CALLBACK(main_window_delete_event), NULL);

void menuitem_quit_activate (GtkMenuItem * menuitem, gpointer user_data) {
/* a foablaknak kuldunk egy "delete_event" szignalt */
gboolean teszt;

g_signal_emit_by_name (G_OBJECT(main_window), "delete_event", G_TYPE_NONE, &teszt);
g_print ("eredmeny: %d\n", teszt);
}

Igen, van rá szignál, vagyis ha be szeretném zárni az ablakot, minden tökéletesen és rendben fut le.
Gond csak akkor van, ha a kilépés menűpontot választva szeretném elküldeni az alkalmazás főablakának a "delete_event" szignált.

Ha csak ennyivel hívod? :

g_signal_emit_by_name (G_OBJECT(main_window), "delete_event");

Ha jól emlékszem, próbáltam, de a "&teszt" paraméter mindenképpen kell neki, hogy tudja hol eltárolni a szignálkezelő függvény visszatérési értékét.

gboolean ret;
g_signal_emit_by_name (G_OBJECT(main_window), "delete_event", main_window, &ret);

Bar ezt most csak emlekezetbol.
vagy ez nem jo?
gtk_widget_destroy (main_window);

Kipróbálom ezt is, holnap jelentkezem.
Köszönöm. :)

A gtk_widget_destroy (main_window) azért nem jó, mert ha a felhasználó nem mentette a munkáját, akkor lehetőséget szeretnék neki adni erre.
Bár, ha jobban belegondolok, akkor amikor az lefut, elméletileg meghívodna a "delete_event" is.

Mindenesetre, talán rosszul gondolom, de úgy lenne igazán szép a megoldás, ha küldenék a main_window -nak szignált, ahogy eredetileg terveztem.

Szep megoldas lenne, ha
GtkActionEntry - GtkActionGroup: igy helyesebb lenne a megoldas.
A GtkActionEntry-nek lehet callbacket allitani.
Megirod a callbacket (a menu nyomasakor meghivodik) itt lekezeled a mentes/valtozas kerdeset, utana mar mehet a destroy.

csinálsz egy cleanup függvényt amiben elvégzed a program kilépés előtti műveleteket, mondjuk így:

gboolean cleanup(GtkWidget *widget, GdkEvent *event, gpointer data)
{
  amit akarsz a kilépés előtt;
  gtk_widget_destroy(foablakod_neve);
  return FALSE;
}


Sima g_signal_connect-tel hozzácsatolod a főablakodhoz a "delete-event" signallal, majd csinálsz még egy csatolást a kilépéshez, pl.:

g_signal_connect(G_OBJECT(foablakod_neve), "destroy",
    G_CALLBACK(gtk_main_quit), NULL);


A menüből pedig a cleanup függvényt hívod.

Visszavonok szinte mindent. eleg a gtk_widget_destroy(window);
Ha a destroy signalhoz van callback fuggveny meghivodik. tehat akkor eleg lesz ott elvegezni a dolgokat.
Az menu action-jeben meg csak destroy();

Igen,attól függ mi is pontosan a cél.

A "destroy" mindenképp "kiléptet", de előbb lefuttatja a callback függvényét.

A "delete_event" a visszatérési értékétől függően:

FALSE esetén meghívódik a destroy,
TRUE esetén már nem kerül sor a destroy -ra, (nem záródik az alkalm.)

Tipikusan "Biztos kilépsz ebből a jó programból ?" jellegű dolgok esetén van értelme.

A kiinduló probléma esetében a legegyszerűbb a g_signal_connect_swapped(...)
lenne szerintem.

[...]

gboolean main_window_delete_event (GtkWidget * widget, GdkEvent * event, gpointer user_data) {
g_print ("delete-event\n");
return FALSE;
}

g_signal_connect(G_OBJECT(main_window), "delete_event", G_CALLBACK(main_window_delete_event), NULL);

g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(main_window_delete_event), G_OBJECT(main_window));

[...]

Ha olyan eseménykezelésre van szükség amit menüből és toolbarról is hívni kell, akkor inkább az "actionXXX" függvények, ill: libbonobo...

szerk: egy gtk_main_quit(); is jól jöhet

Kipróbáltam tegnap a három dolgot, amiket írtatok, az eredmények:

g_signal_emit_by_name (G_OBJECT(main_window), "delete_event", main_window, &ret);

Nem jó, ugyanazt a hibát produkálja, mint a nyitó hozzászólásban írt megoldásom.

g_signal_connect_swapped(G_OBJECT(menuitem), "activate", G_CALLBACK(main_window_delete_event), G_OBJECT(main_window));

Ha a menűben először kattintok a kilépésre, nem történik semmi, utána való kattintáskor lefut a "delete_event", de nem lép ki a program.

gtk_widget_destroy (main_window);

Nem fut le a "delete_event", hanem szó nélkül kilép a program.

A többi dolgot, amit írtatok, ma tudom kipróbálni.

Esetleg az én megoldásommal? Ott a delete signalt hívod meg és onnan a destroy-t.