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.
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.
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();
}
here is my problem: I just put a gtk_text_view_new() in a gtk_scrolled_window_new(). Now when I write in the textField, at the end of the gtk_widget_set_size_request->high the text is hidden and the whole text does not scroll upwards as I want.
-> The textfield should automatically scroll upwards and show its last line.
#include <gtk/gtk.h>
int main(int argc, char **argv) {
gtk_init(&argc, &argv);
GtkWidget *window;
GtkWidget *myGrid;
GtkWidget *scollwindow;
GtkWidget *textField;
GtkTextBuffer *buffer;
GtkWidget *quitbutton;
//---------------------widgets-------------------------------
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
quitbutton = gtk_button_new_with_label("QUIT");
myGrid = gtk_grid_new ();
//---------------------textField-------------------------------
textField = gtk_text_view_new ();
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (textField));
gtk_text_buffer_set_text (buffer, "Hello, this is some text, ", -1);
//---------------------insert textField in scrollwindow-------------------------------
scollwindow = gtk_scrolled_window_new (NULL,NULL);
gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scollwindow), textField);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scollwindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
//---------------------widgets size-------------------------------
gtk_widget_set_size_request (scollwindow, 200, 200);
gtk_widget_set_size_request (window, 200, 200);
//---------------------grid attache-------------------------------
gtk_grid_attach(GTK_GRID(myGrid), scollwindow, 0, 0, 1, 1);
gtk_grid_attach(GTK_GRID(myGrid), quitbutton, 0, 1, 1, 1);
//---------------------add to grid-------------------------------
gtk_container_add(GTK_CONTAINER(window), myGrid);
//---------------------signals-------------------------------
g_signal_connect(quitbutton, "clicked", G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(window, "destroy", gtk_main_quit, NULL);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
Got it, just change line " gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scollwindow), textField);" to "gtk_container_add (GTK_CONTAINER(scollwindow), textField);"
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
i´m trying to fix it out that when i click on "button1" the "on_draw_event"-funcion is called (that works) and a line is shown in my "darea"-drawing_area (that does not work).
Here is my code:
#include <gtk/gtk.h>
static gboolean on_draw_event(GtkWidget *button, cairo_t *darea)
{
printf ("function: on_draw_event\n");
cairo_set_source_rgb(darea, 0, 255, 0);
cairo_set_line_width(darea, 0.5);
cairo_move_to(darea, 0, 100);
cairo_line_to(darea, 400, 100);
cairo_stroke(darea);
return FALSE;
}
int main (int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *darea;
GtkWidget *myGrid;
GtkWidget *button1;
GtkWidget *button2;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_POPUP);
myGrid = gtk_grid_new ();
darea = gtk_drawing_area_new();
gtk_widget_set_size_request(darea, 400, 400);
button1 = gtk_button_new_with_label ("BUTTON 1");
button2 = gtk_button_new_with_label ("QUIT");
gtk_grid_attach(GTK_GRID(myGrid), button1, 0, 0, 1, 1);
gtk_grid_attach(GTK_GRID(myGrid), darea, 0, 1, 1, 1);
gtk_grid_attach(GTK_GRID(myGrid), button2, 0, 2, 1, 1);
gtk_container_add(GTK_CONTAINER(window), myGrid);
g_signal_connect(G_OBJECT(button2), "clicked", G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(button1, "clicked", G_CALLBACK(on_draw_event), darea);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
If i cange
"g_signal_connect(button1, "clicked", G_CALLBACK(on_draw_event), darea);"
to
"g_signal_connect(G_OBJECT(darea), "draw", G_CALLBACK(on_draw_event), NULL);"
the line will be drawn, but i want that it waits for my button click. Hope someone can halp me, cant be a big problem.
Thank you.
As posted, your example crashes because you are connecting a drawing callback to the clicked signal. When called, the callback gets nonsensical arguments and dies.
To "wait for the button click", introduce a flag that tells you whether the button has been clicked. Consult that flag in on_draw_event and set it in the button's clicked callback.
Your example modified to implement the above would look like this:
#include <gtk/gtk.h>
static gboolean on_draw_event(GtkWidget *darea, cairo_t *cr,
gboolean *draw_line)
{
if (!*draw_line)
return FALSE;
printf ("function: on_draw_event\n");
cairo_set_source_rgb(cr, 0, 255, 0);
cairo_set_line_width(cr, 0.5);
cairo_move_to(cr, 0, 100);
cairo_line_to(cr, 400, 100);
cairo_stroke(cr);
return FALSE;
}
static void on_button1_clicked(GtkWidget *button, gboolean *draw_line)
{
*draw_line = TRUE;
/* Make sure the widget is repainted after the click.
gtk_widget_queue_draw() should better be invoked with just the
drawing area, but this code accesses the common parent for
simplicity. Passing darea in a struct whose address is provided as
user_data (along with gboolean *draw_line) is left as exercise. */
gtk_widget_queue_draw(gtk_widget_get_parent(button));
}
int main (int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *darea;
GtkWidget *myGrid;
GtkWidget *button1;
GtkWidget *button2;
gboolean draw_line = FALSE;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_POPUP);
myGrid = gtk_grid_new ();
darea = gtk_drawing_area_new();
gtk_widget_set_size_request(darea, 400, 400);
button1 = gtk_button_new_with_label ("BUTTON 1");
button2 = gtk_button_new_with_label ("QUIT");
gtk_grid_attach(GTK_GRID(myGrid), button1, 0, 0, 1, 1);
gtk_grid_attach(GTK_GRID(myGrid), darea, 0, 1, 1, 1);
gtk_grid_attach(GTK_GRID(myGrid), button2, 0, 2, 1, 1);
gtk_container_add(GTK_CONTAINER(window), myGrid);
g_signal_connect(G_OBJECT(button2), "clicked", G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(button1, "clicked", G_CALLBACK(on_button1_clicked), &draw_line);
g_signal_connect(G_OBJECT(darea), "draw", G_CALLBACK(on_draw_event), &draw_line);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
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!