I have a scrolledwindow inside a main window. I want to when i click button refresh, content of scrolledwindow will refresh automatic.This is callback to button
vbox = gtk_vbox_new(TRUE, 5);
gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_window), vbox);
gtk_signal_connect(GTK_OBJECT(button_refresh), "clicked", GTK_SIGNAL_FUNC(button_re), NULL);
there is callback function:
void button_re(GtkWidget *window, gpointer data){
connectserver(myFile, numof);//connect to server and get information
if(numof > 0){
for(int i = 0; i< numof; i++){
hbox = gtk_hbox_new(TRUE, 0);
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 2);
sprintf(buffer, "%s", myFile[i].name);
label = gtk_label_new(buffer);
button_down = gtk_button_new_with_label("Download");
gtk_signal_connect(GTK_OBJECT(button_down), "clicked", GTK_SIGNAL_FUNC(button_download), (gpointer ) i);
gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), button_down, TRUE, FALSE, 0);
}
}else if(numof == 0){
label = gtk_label_new("Have nothing on server");
gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, FALSE, 2);
}
But when i click button, there are nothing happed. What should i do?
I'm so sorry because my english is not good.
Thanks !
In button_re you are creating new labels, buttons, etc. These won't show up until you call gtk_widget_show on them, somehow. Somewhere in the initialization of your program - main() perhaps - probably you call gtk_widget_show_all on your main window, which recursively "show"s everything within it. But these new objects won't be shown until you explicitly request that they are.
Related
edit: The problem described here seems to be theme related. I'm using Greybird from XUbuntu here.
The program
In my program you can click a button to create more buttons in a vertical GtkBox. If the buttons exceed the visible space a GtkScrollbar will be shown:
Problem
When the GtkScrollbar is shown for the first time, it dos not show on the side, as it should be; It's shown below the buttons:
This is weird, because the scrollbar is actually inside a horizontal GtkBox in a cell next to those buttons.
In this state, the buttons are not clickable anymore until either of of the following happens:
click the scroll bar
scroll via mouse wheel
click the window border
focus another application
UI Architecture
This is the architecture of my UI:
Whether the scrollbar is shown or not, is decided when the "page-size" property the GtkAdjustment is changed.
Code
#include <gtk/gtk.h>
gboolean
adj_page_sizechanged (GtkAdjustment *adjustment,
GdkEvent *unused,
GtkScrollbar *scrollbar)
{
gdouble maxValue = gtk_adjustment_get_upper (adjustment);
gdouble maxSize = gtk_adjustment_get_page_size (adjustment);
gboolean show = (maxValue - maxSize >= 0.000001);
g_object_set (scrollbar, "visible", show, NULL);
return FALSE;
}
/**
* Creates a `automatic` scollbar for `widget`, that will never
* overlay (hide) the content of `widget`.
**/
GtkWidget *
gtkx_scrollable_widget_vertical_new (GtkWidget *widget,
GtkAdjustment *adjustment_nullable)
{
GtkWidget *root = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
// setup adjustment
GtkAdjustment * adj_v = adjustment_nullable;
if (NULL == adj_v)
adj_v = gtk_adjustment_new (0,0,100,1,10,10);
// setup scrollbar
{
GtkWidget * scrollbar = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL, adj_v);
g_signal_connect(adj_v, "notify::page-size", G_CALLBACK (adj_page_sizechanged), scrollbar);
gtk_box_pack_end (GTK_BOX (root), scrollbar, FALSE, FALSE, 0);
}
// setup scrollable area
{
GtkWidget * scrolled_window = gtk_scrolled_window_new (NULL, adj_v);
gtk_container_add (GTK_CONTAINER (scrolled_window), widget);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
GTK_POLICY_NEVER, GTK_POLICY_EXTERNAL);
gtk_box_pack_start (GTK_BOX (root), scrolled_window, TRUE, TRUE, 0);
}
return root;
}
void
add_button (GtkButton *button,
GtkBox *box)
{
g_print("add button\n");
gtk_container_add (GTK_CONTAINER (box), gtk_button_new_with_label ("b 2"));
gtk_widget_show_all (GTK_WIDGET (box));
}
GtkWidget *
create_ui()
{
GtkWidget * action_button = NULL;
GtkWidget * box_outer = NULL;
GtkWidget * box_inner = NULL;
box_inner = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
action_button = gtk_button_new_with_label ("click me");
gtk_container_add (GTK_CONTAINER (box_inner), action_button);
g_signal_connect (action_button, "clicked", G_CALLBACK (add_button), box_inner);
box_outer = gtkx_scrollable_widget_vertical_new (box_inner, NULL);
return box_outer;
}
/**
* standard stuff. See `create_ui()`
**/
int main(int argc, char *argv[])
{
gtk_init (&argc, &argv);
GtkWidget *window;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size (GTK_WINDOW (window), -1, 60);
GtkWidget * ui = create_ui ();
gtk_container_add (GTK_CONTAINER (window), ui);
g_signal_connect (G_OBJECT (window), "destroy",
G_CALLBACK (gtk_main_quit), G_OBJECT (window));
gtk_widget_show_all(window);
gtk_main();
return 0;
}
Notes
I don't use GtkScrolledWindow's internal scrollbars, because they will overlay the content. I don't want that. Therefore I'm making this implementation.
I could imagine this to be a bug within GTK. Even if it is, is there a way to work around it?
I'm running Gtk3.24 under XOrg, XUb 21.04, Theme: Greybird.
edit
It looks like this behavior is triggered depending on the theme.
for some reason button expands fully from up to bottom, but fill and expand are set to false, so it shouldn't be the case, right?
this is how it looks
and code:
#include <gtk/gtk.h>
int main() {
GtkWidget* window;
GtkWidget* box;
GtkWidget* frame;
gtk_init(NULL, NULL);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size(GTK_WINDOW(window), 400, 400);
frame = gtk_frame_new("box");
gtk_container_add(GTK_CONTAINER(window), frame);
box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
gtk_container_add(GTK_CONTAINER(frame), box);
GtkWidget* button = gtk_button_new_with_mnemonic("test");
gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 0);
gtk_widget_set_hexpand(button, 0);
gtk_widget_set_vexpand(button, 0);
gtk_widget_show_all(window);
gtk_main();
}
forcing widget size with gtk_widget_set_size_request only affects the button's width.
I'm modifying an existing program wrote in C in which I added a GtkEntry.
When I try to write, for example, "qwerty" in the entry, it's filled only with "qwrty" because the character "e" is used as a shortcut (accelerator) to call another function, and that function is also activated when "e" is pressed.
Is there any way to avoid accelerator callbacks while we are writing in the entry?
Yes, you can disconnect your accelerator group in the focus-in-event callback of GtkEntry, and connect it again when you focus back out of the entry. Here's an example:
#include <stdio.h>
#include <gtk/gtk.h>
GtkAccelGroup *accel_group;
GClosure *closure;
void accelerator_pressed(void)
{
printf("Accelerator pressed!\n");
}
gboolean focus_in_callback(void)
{
gtk_accel_group_disconnect(accel_group, closure);
g_closure_unref(closure);
return GDK_EVENT_PROPAGATE;
}
gboolean focus_out_callback(void)
{
closure = g_cclosure_new(accelerator_pressed, 0, 0);
gtk_accel_group_connect(accel_group, GDK_KEY_e, (GdkModifierType)0, GTK_ACCEL_VISIBLE, closure);
return GDK_EVENT_PROPAGATE;
}
int main()
{
gtk_init(NULL, NULL);
GtkWidget *window, *box, *entry, *button;
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
entry = gtk_entry_new();
button = gtk_button_new_with_label("click me");
gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(entry), TRUE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(button), TRUE, TRUE, 0);
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(GTK_WIDGET(entry), "focus-in-event", G_CALLBACK(focus_in_callback), NULL);
g_signal_connect(GTK_WIDGET(entry), "focus-out-event", G_CALLBACK(focus_out_callback), accel_group);
accel_group = gtk_accel_group_new();
gtk_window_add_accel_group(GTK_WINDOW(window), accel_group);
gtk_container_add(GTK_CONTAINER(window), box);
gtk_widget_show_all(window);
gtk_main();
}
I was finding the way to limit of height of popup window for GtkComboBox and when that height is reached the control will get scrollbars. I cannot find wa way to do that. the list flows from top to bottom of window (try the attached code). I have checked API and I cannot find useful method. I'm new to GTK+ and I have searched google for days.
#include <gtk/gtk.h>
int main(int argc, char** argv) {
GtkWidget* frame;//main frame
GtkWidget* combobox;
GtkWidget* listbox;
GtkWidget* okbutton;
GtkWidget* cancelbutton;
GtkWidget* hbox_buttons;
GtkWidget* vbox;
gtk_init(&argc, &argv);
//create widgets
frame = gtk_window_new(GTK_WINDOW_TOPLEVEL);
/*Combobox issues*/
GtkListStore* list_store;
list_store = NULL;
GtkTreeIter iter;
list_store=gtk_list_store_new(1,G_TYPE_STRING);
int i;
for(i=0; i<100; i++) {
gtk_list_store_append(list_store, &iter);
gtk_list_store_set(list_store, &iter,0,"Residental", -1);
}
combobox = gtk_combo_box_new_with_model((GtkTreeModel *)list_store);
g_object_unref(G_OBJECT(list_store));
GtkCellRenderer* cell = gtk_cell_renderer_text_new();
gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combobox), cell, TRUE);
gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combobox), cell, "text", 0, NULL);
listbox = gtk_list_new();
okbutton = gtk_button_new_with_label("Ok");
cancelbutton = gtk_button_new_with_label("Cancel");
//create containers
hbox_buttons = gtk_hbox_new(FALSE, 5);
vbox = gtk_vbox_new(FALSE, 5);
//Pack things
gtk_container_add(GTK_CONTAINER(frame),vbox);
gtk_box_pack_start(GTK_BOX(vbox), combobox, FALSE, FALSE, 5);
gtk_box_pack_start(GTK_BOX(vbox), listbox, TRUE, TRUE, 5);
//pack buttons
gtk_box_pack_start(GTK_BOX(hbox_buttons), okbutton, TRUE, TRUE, 5);
gtk_box_pack_start(GTK_BOX(hbox_buttons), cancelbutton, TRUE, TRUE, 5);
gtk_box_pack_start(GTK_BOX(vbox), hbox_buttons, FALSE, TRUE, 5);
//gtk_box_pack_start(vbox, listbox, TRUE, TRUE, 5);
g_signal_connect_swapped(G_OBJECT(frame), "destroy",
G_CALLBACK(gtk_main_quit), G_OBJECT(frame));
gtk_widget_show_all(frame);
gtk_main();
return 0;
}
It is not possible so I ended up using wxComboCtrl which is very customizable!
I need to output the i progress bars and update them all. But only the last one updates i times. This is the code:
static void calculaPi (GtkButton * boton, Datos * dDatos){
const char * threads;
GtkWidget * barra, *bot2, *button, *progress, *vbox;
threads = gtk_entry_get_text(GTK_ENTRY(dDatos->dthreads ));
gint ithreads = 1;
ithreads = atoi(threads);
barra = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title((GtkWindow *) barra, "Loteria de Threads");
gtk_window_set_default_size(GTK_WINDOW(barra), 300, ithreads*30);
gtk_window_set_position(GTK_WINDOW(barra), GTK_WIN_POS_CENTER);
button = gtk_button_new_with_label ("Click me!");
vbox = gtk_vbox_new (FALSE, 5);
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 5);
gtk_container_add (GTK_CONTAINER (barra), vbox);
for (gint i = 1 ; i <= ithreads; i++) {
progress = gtk_progress_bar_new ();
gtk_box_pack_start (GTK_BOX (vbox), progress, FALSE, FALSE, 5);
g_object_set_data (G_OBJECT (barra), "pbar", (gpointer) progress);
g_signal_connect (G_OBJECT (button), "clicked",
G_CALLBACK (button_clicked), (gpointer) barra);
}
bot2 = gtk_button_new_with_label("Salir");
gtk_box_pack_start (GTK_BOX (vbox), bot2, FALSE, FALSE, 5);
gtk_widget_set_size_request(bot2, 100, 35);
g_signal_connect (G_OBJECT (bot2), "clicked",
G_CALLBACK (destroy),
G_OBJECT (barra));
gtk_widget_show_all(barra);
gtk_main();
}
static void
button_clicked (GtkButton *button,
GtkWidget *barra)
{
GtkProgressBar *progress;
gdouble percent = 0.0;
gtk_widget_set_sensitive (GTK_WIDGET (button), FALSE);
progress = GTK_PROGRESS_BAR (g_object_get_data (G_OBJECT (barra), "pbar"));
while (percent <= 100.0)
{
gchar *message = g_strdup_printf ("%.0f%% Complete", percent);
gtk_progress_bar_set_fraction (progress, percent / 100.0);
gtk_progress_bar_set_text (progress, message);
while (gtk_events_pending ())
gtk_main_iteration ();
g_usleep (500000);
percent += 5.0;
}
}
With this line:
g_object_set_data (G_OBJECT (barra), "pbar", (gpointer) progress);
you override previous value of "pbar" data entry on each loop iteration. When you later retrive it in button_clicked() you get the last set value, i.e. the last progress bar.
In this particular case you can just pass progress widget as user data (and drop g_object_[gs]et_data() calls) for button_clicked() callback: the function doesn't use current barra window for anything else anyway.
In a more general way, you should learn how to use your own structures for user data parameters. A common way is to declare and use one structure for given toplevel type and store pointers to widgets you need to access from callbacks in it.