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!
Related
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 am trying to set a custom GtkAccelLabel to my GtkMenuItem, though I cant figure out how to use that widget ... for me just nothing is displayed.
Why are the following calls wrong / not sufficient ?
...
fileMi = gtk_menu_item_new_with_label("File");
label = gtk_accel_label_new ("Strg+X");
gtk_accel_label_set_accel_widget (label, quitMi);
...
Here a complete reproducer:
int main(int argc, char *argv[]) {
GtkWidget *window;
GtkWidget *vbox;
GtkWidget *menubar;
GtkWidget *fileMenu;
GtkWidget *fileMi;
GtkWidget *quitMi;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 300, 200);
gtk_window_set_title(GTK_WINDOW(window), "Simple menu");
vbox = gtk_vbox_new(FALSE, 0);
gtk_container_add(GTK_CONTAINER(window), vbox);
GtkAccelGroup *accel_group;
// Create a GtkAccelGroup and add it to the window.
accel_group = gtk_accel_group_new ();
gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
menubar = gtk_menu_bar_new();
fileMenu = gtk_menu_new();
fileMi = gtk_menu_item_new_with_label("File");
quitMi = gtk_menu_item_new_with_label("Quit");
gtk_menu_item_set_submenu(GTK_MENU_ITEM(fileMi), fileMenu);
gtk_menu_shell_append(GTK_MENU_SHELL(fileMenu), quitMi);
gtk_menu_shell_append(GTK_MENU_SHELL(menubar), fileMi);
gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
GtkWidget *label = gtk_accel_label_new ("Strg+X");
gtk_accel_label_set_accel_widget (label, quitMi);
gtk_accel_label_refetch (label);
g_signal_connect(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(G_OBJECT(quitMi), "activate",
G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
Hah, I found a solution .. though no idea if it actually should be done like that.
The key is, that there is already a gtk_accel_label on the MenuItem, and I can modify it:
for (GList* lp = gtk_container_get_children (quitMi); lp != NULL; lp = lp->next)
{
if (GTK_IS_ACCEL_LABEL (lp->data))
gtk_accel_label_set_accel (lp->data, GDK_KEY_0, GDK_MOD1_MASK);
}
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();
}
A program has a menu bar, which has a menu, which has a menu item. The menu item is enabled or disabled depending on some circumstances. Checking of circumstances and enabling/disabling of the menu item is done when a user clicks on the menu that holds that menu item.
But, there is also a shortcut associated with that menu item. The shortcut functions only when the menu item is enabled.
How can we set the state of a menu item without clicking on the menu that holds it, when we want to use a shortcut?
Here is an example program that will hopefully make my question more clear:
#include <gtk/gtk.h>
struct check_sensitivity
{
GtkWidget *menuitem;
GtkTextBuffer *buffer;
};
void sensitivity(GtkWidget *menu, struct check_sensitivity *sens)
{
if (gtk_text_buffer_get_modified(sens->buffer))
gtk_widget_set_sensitive(sens->menuitem, TRUE);
else
gtk_widget_set_sensitive(sens->menuitem, FALSE);
}
void menuitem_click(GtkWidget *menuitem, GtkTextBuffer *buffer)
{
gtk_text_buffer_set_text(buffer, "", -1);
gtk_text_buffer_set_modified(buffer, FALSE);
}
int main(int argc, char **argv)
{
gtk_init(&argc, &argv);
struct check_sensitivity sens;
GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(window, "delete-event", G_CALLBACK(gtk_main_quit), NULL);
GtkWidget *view = gtk_text_view_new();
sens.buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));
GtkWidget *menubar = gtk_menu_bar_new();
GtkWidget *menu = gtk_menu_new();
GtkAccelGroup *shortcuts = gtk_accel_group_new();
gtk_window_add_accel_group(GTK_WINDOW(window), shortcuts);
GtkWidget *menuitem = gtk_menu_item_new_with_label("Menu");
gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menu);
gtk_menu_shell_append(GTK_MENU_SHELL(menubar), menuitem);
g_signal_connect(menuitem, "activate", G_CALLBACK(sensitivity), &sens);
menuitem = gtk_menu_item_new_with_label("Clear");
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
gtk_widget_add_accelerator(menuitem, "activate", shortcuts, GDK_KEY_D, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
sens.menuitem = menuitem;
g_signal_connect(sens.menuitem, "activate", G_CALLBACK(menuitem_click), sens.buffer);
GtkWidget *box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
gtk_box_pack_start(GTK_BOX(box), menubar, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(box), view, TRUE, TRUE, 0);
gtk_container_add(GTK_CONTAINER(window), box);
gtk_widget_show_all(window);
gtk_main();
}
In this program, the state of menu item "Clear" depends on that whether the buffer is modified or not. The state is, of course, set when the user clicks on the menu "Menu".
There is also a shortcut Ctrl+D that does the same thing as clicking on "Clear". The shortcut works as it should depending on the state of the menu item, but what is wrong is the state of the menu item. Let me explain:
Since the menu item is (un)set when a user click on "Menu", to update the state of "Clear" before using a shortcut, a user must click on it. If the shortcut is used before updating of the state of the menu item, it may not be able to do its function when it should.
Here is what you can try: open the program and write something. Try clearing it with Ctrl+D. You'll see that nothing happens even though it should, because the state of the menu item is not updated. If you click on "Menu", then try using the shortcut again, the text buffer will clear.
I'm just asking for a why to update the state when the shortcut is pressed as well. I tried a few ways that base on setting the state when Ctrl is pressed (I can't check only for Ctrl+D, I may have another shortcuts in a program), but all of them failed or produced bugs. One of those ways you can see here.
If you want to update the menuitem sensitivity depending on if there is text in your textbuffer, connect to the textbuffer changed or modified-changed signal. Since I am not good at C, but normally use Python:
textbuffer.connect("changed", update_menuitem_sensitivity)
changed
modified-changed
Finally found a working method.
#include <gtk/gtk.h>
struct check_sensitivity
{
GtkWidget *menuitem;
GtkTextBuffer *buffer;
};
void sensitivity(GtkWidget *menu, struct check_sensitivity *sens);
void check_sensitivity_on_ctrl(GtkWidget *window, GdkEventKey *key, struct check_sensitivity *sens)
{
if(key->keyval == GDK_KEY_Control_L || key->keyval == GDK_KEY_Control_R)
{
sensitivity(NULL, sens);
}
}
void sensitivity(GtkWidget *menu, struct check_sensitivity *sens)
{
if (gtk_text_buffer_get_modified(sens->buffer))
gtk_widget_set_sensitive(sens->menuitem, TRUE);
else
gtk_widget_set_sensitive(sens->menuitem, FALSE);
}
void menuitem_click(GtkWidget *menuitem, GtkTextBuffer *buffer)
{
gtk_text_buffer_set_text(buffer, "", -1);
gtk_text_buffer_set_modified(buffer, FALSE);
}
int main(int argc, char **argv)
{
gtk_init(&argc, &argv);
struct check_sensitivity sens;
GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size(GTK_WINDOW(window), 400, 400);
g_signal_connect(window, "delete-event", G_CALLBACK(gtk_main_quit), NULL);
GtkWidget *view = gtk_text_view_new();
sens.buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));
gtk_text_buffer_set_modified(sens.buffer, FALSE);
GtkWidget *menubar = gtk_menu_bar_new();
GtkWidget *menu = gtk_menu_new();
GtkAccelGroup *shortcuts = gtk_accel_group_new();
gtk_window_add_accel_group(GTK_WINDOW(window), shortcuts);
GtkWidget *menuitem = gtk_menu_item_new_with_label("Menu");
gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menu);
gtk_menu_shell_append(GTK_MENU_SHELL(menubar), menuitem);
g_signal_connect(menuitem, "activate", G_CALLBACK(sensitivity), &sens);
menuitem = gtk_menu_item_new_with_label("Clear");
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
gtk_widget_add_accelerator(menuitem, "activate", shortcuts, GDK_KEY_D, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
sens.menuitem = menuitem;
g_signal_connect(sens.menuitem, "activate", G_CALLBACK(menuitem_click), sens.buffer);
g_signal_connect_after(window, "key-press-event", G_CALLBACK(check_sensitivity_on_ctrl), &sens);
GtkWidget *box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
gtk_box_pack_start(GTK_BOX(box), menubar, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(box), view, TRUE, TRUE, 0);
gtk_container_add(GTK_CONTAINER(window), box);
gtk_widget_show_all(window);
gtk_main();
}
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.