[GTK+] Button z obrazkiem


(Manonim93) #1

Cześć,

Stworzyłem sobie program który wyświetla główne okno GtkWindow w nim tablicę GtkTable następnie w tablicy wyświetlane są buttony GtkButton. I teraz chciałbym uzyskać efekt polegający na tym, że po kliknięciu w przycisk staje się on nieaktywny i wyświetla obrazek.

Tak wygląda moja funkcja zwrotna na sygnał clicked:

void clicked(GtkWidget* widget, gpointer image)

{

	GtkWidget* hbox;

	hbox = gtk_hbox_new(TRUE, 0);

	gtk_container_add(GTK_CONTAINER(widget), GTK_WIDGET(hbox));

	gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(image), TRUE, TRUE, 0);

	gtk_widget_set_sensitive(GTK_WIDGET(widget), FALSE);

}

Jednak po skompilowaniu i uruchomieniu w konsoli pojawia się błąd:

(main:7568): Gtk-CRITICAL **: gtk_box_pack: assertion `child->parent == NULL' failed

Czy zna ktoś poprawny i skuteczny sposób na umieszczenie obrazka w przycisku? I czy mój sposób na dezaktywowanie przycisku (czyli funkcja gtk_widget_set_sensitive) jest dobry?

Pozdrawiam.


(etam) #2

Do ustawiania obrazków na GtkButton jest gtk_button_set_image. gtk_widget_set_sensitive spowoduje wyłączenie i wyszarzenie przycisku (i zawartego w nim obrazka).


(Manonim93) #3

Aha dzięki właśnie wcześniej używałem gtk_button set_image, ale obrazek był wyszarzony i myślałem że to ta funkcja to robi. Czy jest więc sposób na dezaktywowanie przycisku bez wyszarzenia obrazka?


(etam) #4

Doprowadzenie do wyłączenia przycisku bez wyszarzenia, to by była jakaś straszna walka z systemem (chyba, że się da, ale ja nie znalazłem). Pozostają opcje:

1) po wciśnięciu przycisku, jest on usuwany i na jego miejsce wstawiany obrazek

2) po wciśnięciu przycisku, jest ustawiany w nim obrazek, a następne wciśnięcia są w obsłudze przycisku ignorowane. (animacja wciskania przycisku nadal będzie działać)


(Manonim93) #5

OK, jeszcze jedna rzecz nie daje mi spokoju, mam tabelę załóżmy 4 * 4 i w każdym polu przycisk razem 16 przycisków.

Za pomocą pętli for tworze sobie przyciski, ale po uruchomieniu programu, obrazek widoczny jest tylko w ostatnim z nich (tym utworzonym jako ostatni - prawy dolny róg), a nie tak jak chce czyli w każdym buttonie. Dodam że obrazek to GtkWidget *image przechowywany jako zmienna globalna

GtkButton* button**** ; ---- zmienna globalna.

GtkWidget *image ----- zmiennna globalna

int create_buttons(void)

{

	int i, j;

	for(i=0; i
	{	

		for(j=0; j
		{		

				button[i][j] = gtk_button_new();	//utworzenie nowego przycisku

				gtk_widget_set_size_request(GTK_WIDGET(button[i][j]), 50, 50); //ustawienie rozmiaru

				gtk_button_set_image(GTK_BUTTON(button[i][j]), GTK_WIDGET(cross_image)); <-- PROBLEM

					gtk_signal_connect(GTK_OBJECT(button[i][j]), "clicked", GTK_SIGNAL_FUNC(clicked), image);

					//obsługa sygnału kliknięcia - zmiana na nieaktywny i wstawienie obrazka

				gtk_table_attach_defaults(GTK_TABLE(table), button[i][j], j, j+1, i ,i+1); //wepchanie przycisku do tabeli

		}	

	}	


	return 0;

}

(Sawyer47) #6

Z tego co kojarzę jak działa GTK, obiekt może naraz znajdować się tylko w jednym kontenerze, w przypadku dodania do innego jest automatycznie usuwany ze starego (z pamięci, nie musi być to prawdą, ale coś takiego kojarzę oraz pasuje do opisu problemu). Musiałbyś mieć GtkImage dla każdego GtkButton.


(etam) #7

Dokładnie tak. Dla każdego GtkButton musisz stworzyć osobny GtkImage, nawet jeżeli zawiera ten sam obrazek.


(Manonim93) #8

Ok, a teraz mam problem taki:

W tabeli umieszczam GtkEventBoxy a w każdym z nich GtkImage. Chcę by po kliknięciu w EventBox została wywołana funkcja która zmieni obrazek za pomocą funkcji gtk_image_set_from_file(); Ale wyskakuje mi segmantation fault po kliknięciu.

image_[j] = gtk_image_new_from_file("border.png");_

int create_images(void)

{

	int i, j;

	for(i=0; i
		for(j=0; j
		{

			image[i][j] = gtk_image_new_from_file("border.png"); //utworzenie obrazka - pobranie z pliku


			event_box[i][j] = gtk_event_box_new(); //utworzenie Event Boxu dla obrazka by można go było kliknąć

			gtk_container_add(GTK_CONTAINER(event_box[i][j]), image[i][j]);	//umiesczenie obrazka w Event Boxie

			gtk_table_attach_defaults(GTK_TABLE(table), GTK_WIDGET(event_box[i][j]), j, j+1, i, i+1); //wepchanie eventboxa do tabeli

				//kliknięcie w EventBox zmienia jego obrazek (przekazanie obrazka jako dodatkowy parametr)

				gtk_signal_connect(GTK_OBJECT(event_box[i][j]), "button_press_event", GTK_SIGNAL_FUNC(clicked), image[i][j]);

		}


	return 0;

}

void clicked(GtkWidget* widget, gpointer dane)	//dane to obrazek z EventBoxa

{


	gtk_image_set_from_file(GTK_IMAGE(dane) ,"cross.png");


}

Oczywiście image[][] i event_box[][] to tablice globalne.


(etam) #9

Znalezione w dokumentacji: "Warning gtk_signal_connect is deprecated and should not be used in newly-written code. Use g_signal_connect() instead."

http://developer.gnome.org/gtk3/stable/ ... ress-event - obsługa button_press_event musi zwracać bool, a u ciebie jest void.

Przy okazji naskrobałem coś takiego w gtkmm:

#include 


class MyEventImage : public Gtk::EventBox {

private:

    Gtk::Image image;


    bool on_clicked(GdkEventButton* event) {

        image.set("g.png");

        return true;

    }


public:

    MyEventImage() : Gtk::EventBox(), image("r.png") {

        add(image);

        set_events(Gdk::BUTTON_PRESS_MASK);

        signal_button_press_event().connect(sigc::mem_fun(*this, &MyEventImage::on_clicked));

    }

};


int main(int argc, char *argv[]) {

    Gtk::Main kit(argc, argv);


    Gtk::Window window;


    Gtk::Table table(3, 3);


    for (int y=0; y<3; ++y)

        for (int x=0; x<3; ++x)

            table.attach(*Gtk::manage(new MyEventImage()), x, x+1, y, y+1);


    window.add(table);

    table.show_all();


    kit.run(window);

    return 0;

}

Gtkmm ma tą miłą cechę, że jeżeli podany callback nie pasuje, to jest błąd kompilacji.