You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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的尺寸变化,动态计算并设置按钮宽高:

  1. 在创建按钮时禁止自动拉伸:
// 在make_toggles函数的循环内添加
gtk_widget_set_hexpand(stop, FALSE);
gtk_widget_set_vexpand(stop, FALSE);
  1. 给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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 22:29:59