我使用 GTK+3 C API 编写了一个程序。它应该在左上角显示一个黑色绘图区域。如果窗口大于绘图区域,则窗口应具有“空填充”,否则允许在绘图区域内滚动。
但是,如果窗口最初大于绘图区域,它将不会显示绘图区域,直到窗口被调整为小于绘图区域的大小。
代码如下:
#include <gtk/gtk.h>
#include <assert.h>
int current_frame_x = 200;
int current_frame_y = 300;
gint max(gint a, gint b) {
return a > b ? a : b;
}
gint min(gint a, gint b) {
return a < b ? a : b;
}
static void on_size_allocate(GtkWidget *widget, GtkAllocation *allocation, gpointer /*user_data*/) {
// Get the new size of the window
gint parent_width = allocation->width;
gint parent_height = allocation->height;
int draw_x = min(current_frame_x, parent_width);
int draw_y = min(current_frame_y, parent_height);
int exceeding_x = max(parent_width - draw_x, 0);
int exceeding_y = max(parent_height - draw_y, 0);
// Get the child widgets of the grid
GtkWidget *upper_left = gtk_grid_get_child_at(GTK_GRID((widget)), 0, 0);
GtkWidget *upper_right = gtk_grid_get_child_at(GTK_GRID((widget)), 1, 0);
GtkWidget *lower_left = gtk_grid_get_child_at(GTK_GRID((widget)), 0, 1);
GtkWidget *lower_right = gtk_grid_get_child_at(GTK_GRID((widget)), 1, 1);
// Set the new sizes of the cells
assert(upper_left);
GtkAllocation upper_left_alloc;
upper_left_alloc.x = allocation->x;
upper_left_alloc.y = allocation->y;
upper_left_alloc.width = draw_x;
upper_left_alloc.height = draw_y;
gtk_widget_size_allocate(upper_left, &upper_left_alloc);
if (upper_right) {
GtkAllocation upper_right_alloc;
upper_right_alloc.x = allocation->x + draw_x;
upper_right_alloc.y = allocation->y;
upper_right_alloc.width = exceeding_x;
upper_right_alloc.height = draw_y;
gtk_widget_size_allocate(upper_right, &upper_right_alloc);
}
if (upper_left) {
GtkAllocation lower_left_alloc;
lower_left_alloc.x = allocation->x;
lower_left_alloc.y = allocation->y + draw_y;
lower_left_alloc.width = draw_x;
lower_left_alloc.height = exceeding_y;
gtk_widget_size_allocate(lower_left, &lower_left_alloc);
}
if (lower_right) {
GtkAllocation lower_right_alloc;
lower_right_alloc.x = allocation->x + draw_x;
lower_right_alloc.y = allocation->y + draw_y;
lower_right_alloc.width = exceeding_x;
lower_right_alloc.height = exceeding_y;
gtk_widget_size_allocate(lower_right, &lower_right_alloc);
}
}
int main(int argc, char *argv[]) {
gtk_init(&argc, &argv);
// Create the main window
GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "Hello Stack Overflow :)");
gtk_window_set_default_size(GTK_WINDOW(window), 800, 600);
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
// Create the drawing area
GtkWidget *drawing_area = gtk_drawing_area_new();
gtk_widget_set_size_request(drawing_area, current_frame_x, current_frame_y);
// Set the background color of the drawing area (for debugging)
GdkRGBA color;
color.red = 1;
color.green = 1;
color.blue = 1;
color.alpha = 1;
gtk_widget_override_background_color(drawing_area, GTK_STATE_FLAG_NORMAL, &color);
// Wrap the drawing area in a scroll window
GtkWidget *scroll_window = gtk_scrolled_window_new(NULL, NULL);
gtk_container_add(GTK_CONTAINER(scroll_window), drawing_area);
gtk_widget_show(scroll_window);
GtkWidget *tmp_h_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
GtkWidget *tmp_v_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
GtkWidget *other_tmp_v_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
// Wrap the scroll window in a grid for resizing
GtkWidget *draw_grid = gtk_grid_new();
gtk_grid_attach(GTK_GRID(draw_grid), scroll_window, 0, 0, 1, 1);
gtk_grid_attach(GTK_GRID(draw_grid), tmp_h_box, 0, 1, 1, 1);
gtk_grid_attach(GTK_GRID(draw_grid), tmp_v_box, 1, 0, 1, 1);
gtk_grid_attach(GTK_GRID(draw_grid), other_tmp_v_box, 1, 1, 1, 1);
gtk_grid_set_column_homogeneous(GTK_GRID(draw_grid), FALSE);
gtk_grid_set_row_homogeneous(GTK_GRID(draw_grid), FALSE);
gtk_widget_set_hexpand(draw_grid, TRUE);
gtk_widget_set_vexpand(draw_grid, TRUE);
g_signal_connect(draw_grid, "size-allocate", G_CALLBACK(on_size_allocate), NULL);
gtk_container_add(GTK_CONTAINER(window), draw_grid);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
想法是使用网格来处理这个。我让网格通过
hexpand
和 vexpand
扩展,并通过监听 size-allocate
的函数手动设置其子项的大小。从交互式调试器和一些调试打印来看,所有大小计算似乎都是正确的。框和绘图区域似乎放置在我想要的位置并且大小合适。当窗口变大时,绘图区域最初是不可见的。 (即使调试器显示空间已分配。)
也可能(和更好的解决方案)只使用一个容器并使用滚动窗口的对齐属性将其放在左上角。但我对此并不陌生,所以让我先了解这里出了什么问题。