GTK Flowbox中Button保持正圆形的实现方案问询
GTK FlowBox中按钮保持正圆形的解决方案
问题描述
在GTK FlowBox中放置若干GTK按钮,通过CSS的border-radius: 50%设置为圆形,同时用background-image设置背景后,按钮却显示为椭圆形。需要让按钮始终保持宽高相等,呈现完美正圆形。以下是可复现示例(MRE):
C文件
#include <gtk/gtk.h> #define WINDOW_HEIGHT 600 GtkWidget * stop; int num_stops; static void stop_toggle (GtkToggleButton *source, gpointer user_data) { if (gtk_toggle_button_get_active(source)) { gtk_widget_set_name(GTK_WIDGET(source), "stop_button_pressed"); } else { gtk_widget_set_name(GTK_WIDGET(source), "stop_button"); } } static void make_toggles (GtkWidget * window) { GtkWidget * stop_flow; short i; stop_flow = gtk_flow_box_new(); char label[7]; label[0] = '\0'; for (i = 0; i < num_stops; i++) { sprintf(label, "%d", i); stop = gtk_toggle_button_new_with_label(label); gtk_widget_set_name(stop, "stop_button"); gtk_flow_box_append(GTK_FLOW_BOX(stop_flow), stop); g_signal_connect(stop, "toggled", G_CALLBACK(stop_toggle), NULL); } gtk_flow_box_set_column_spacing(GTK_FLOW_BOX(stop_flow), 15); gtk_flow_box_set_row_spacing(GTK_FLOW_BOX(stop_flow), 10); gtk_flow_box_set_selection_mode(GTK_FLOW_BOX(stop_flow), GTK_SELECTION_NONE); gtk_widget_set_name(stop_flow, "window_main"); gtk_window_set_child (GTK_WINDOW (window), stop_flow); } static void app_startup(GtkApplication* app) { num_stops = 16; } static void activate (GtkApplication* app, gpointer user_data) { GtkWidget *window; window = gtk_application_window_new (app); gtk_window_set_title (GTK_WINDOW (window), "Left Panel"); gtk_window_set_default_size (GTK_WINDOW (window), 800, WINDOW_HEIGHT); make_toggles(window); GtkCssProvider * cssProvider = gtk_css_provider_new(); gtk_css_provider_load_from_path(cssProvider, "/your_location/GTK/styling2.css"); gtk_style_context_add_provider_for_display(gtk_widget_get_display(window), GTK_STYLE_PROVIDER(cssProvider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); gtk_widget_show (window); } int main(int argc, char **argv) { GtkApplication *app; int status; app = gtk_application_new("lcs.console", G_APPLICATION_DEFAULT_FLAGS); g_signal_connect(app, "startup", G_CALLBACK(app_startup), NULL); g_signal_connect (app, "activate", G_CALLBACK(activate), NULL); status = g_application_run (G_APPLICATION (app), argc, argv); g_object_unref (app); return status; }
CSS文件
#window_main { background-color: grey; } #stop_button { background-color: white; background-size: 100% 100%; background-position: center center; border-radius: 50%; color: black; font-weight: bold; font-size: xx-large; } #stop_button_pressed { background-color: yellow; background-size: 100% 100%; background-position: center center; border-radius: 50%; color: black; font-weight: bold; font-size: xx-large; }
(注:原CSS中w_main为错误选择器,已修正为#window_main,否则FlowBox背景样式不生效)
编译命令(Linux环境)
gcc -Wall `pkg-config --cflags gtk4` file.c `pkg-config --libs gtk4`
解决方法
按钮显示为椭圆形的核心原因是FlowBox会自动拉伸按钮宽度填充可用空间,但高度未同步匹配。以下两种方式可实现按钮宽高始终相等:
方法1:CSS强制固定尺寸
直接在CSS中给按钮设置固定宽高,同时禁止按钮被FlowBox拉伸:
#stop_button, #stop_button_pressed { /* 固定宽高,可根据需求调整数值 */ width: 60px; height: 60px; min-width: 60px; min-height: 60px; /* 禁止按钮被拉伸或压缩 */ flex-grow: 0; flex-shrink: 0; /* 保留原有样式 */ background-size: 100% 100%; background-position: center center; border-radius: 50%; color: black; font-weight: bold; font-size: xx-large; } #stop_button { background-color: white; } #stop_button_pressed { background-color: yellow; }
方法2:代码层面实现自适应尺寸
若需要按钮尺寸随窗口大小自动调整,可监听FlowBox的尺寸变化,动态计算并设置按钮宽高:
- 在创建按钮时禁止自动拉伸:
// 在make_toggles函数的循环内添加 gtk_widget_set_hexpand(stop, FALSE); gtk_widget_set_vexpand(stop, FALSE);
- 给FlowBox添加尺寸变化回调:
// 定义回调函数 static void on_flowbox_resize(GtkWidget *widget, GdkRectangle *allocation, gpointer user_data) { GtkFlowBox *flowbox = GTK_FLOW_BOX(widget); int num_cols = gtk_flow_box_get_n_columns(flowbox); if (num_cols == 0) return; // 计算单个按钮的可用尺寸(减去列间距) int btn_size = (allocation->width - (num_cols - 1) * 15) / num_cols; // 遍历所有按钮设置宽高 GListModel *model = gtk_flow_box_get_model(flowbox); for (int i = 0; i < g_list_model_get_n_items(model); i++) { GtkWidget *btn = GTK_WIDGET(g_list_model_get_item(model, i)); gtk_widget_set_size_request(btn, btn_size, btn_size); } } // 在make_toggles函数末尾添加信号连接 g_signal_connect(stop_flow, "size-allocate", G_CALLBACK(on_flowbox_resize), NULL);
关键注意点
- 确保CSS选择器正确,原示例中
w_main无法匹配到名称为window_main的FlowBox,需修正为#window_main; - 使用
flex-grow: 0和flex-shrink: 0可彻底避免按钮被FlowBox的布局逻辑拉伸变形; - 自适应方案中,需保证FlowBox的列数计算准确,否则按钮尺寸会出现偏差。
内容的提问来源于stack exchange,提问作者Cheetaiean
相关产品推荐
相关产品推荐

