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

包含Gtk::DrawingArea的两个Gtk::Grid组件尺寸不一致问题

解决Gtk::Grid子控件Disc尺寸不一致的问题

嘿,我来帮你搞定这个两个Grid里Disc尺寸不一致的问题!你遇到的核心问题是布局管理器在分配空间时,因为两个Grid的行/列数量不同,加上Disc(继承自Gtk::DrawingArea)没有明确的尺寸约束,导致了控件大小差异。下面是具体的解决方案:

1. 给Disc类添加明确的尺寸约束

Gtk::DrawingArea默认没有最小尺寸,布局管理器会根据父容器的空间挤压它。我们需要给Disc设置最小尺寸,同时让它填充所在的Grid单元格:

修改Disc的构造函数:

Disc::Disc() {
    // 设置最小尺寸,确保每个Disc至少有这个大小
    set_size_request(50, 50);
    // 让Disc填充所在的Grid单元格空间
    set_hexpand(true);
    set_vexpand(true);
    set_halign(Gtk::ALIGN_FILL);
    set_valign(Gtk::ALIGN_FILL);
}

Disc::Disc(double p_red, double p_green, double p_blue, double p_alpha)
    : m_red(p_red), m_green(p_green), m_blue(p_blue), m_alpha(p_alpha) {
    set_size_request(50, 50);
    set_hexpand(true);
    set_vexpand(true);
    set_halign(Gtk::ALIGN_FILL);
    set_valign(Gtk::ALIGN_FILL);
}

同时,确保on_draw方法里的圆盘是自适应控件尺寸的(避免固定大小绘制导致的不协调):

bool Disc::on_draw(const Cairo::RefPtr<Cairo::Context>& p_context) {
    Gtk::Allocation allocation = get_allocation();
    const int width = allocation.get_width();
    const int height = allocation.get_height();

    // 以控件中心为圆心,取宽高中较小值的一半作为半径,保证圆盘是正圆
    double radius = std::min(width, height) / 2.0;
    p_context->arc(width/2.0, height/2.0, radius, 0, 2*M_PI);
    p_context->set_source_rgba(m_red, m_green, m_blue, m_alpha);
    p_context->fill();

    return true;
}

2. 调整两个Grid的布局属性

在GameBoard的构造函数里,给两个Grid设置统一的布局规则,确保它们的列宽一致,同时合理分配VBox的空间:

GameBoard::GameBoard() {
    const int nbRows{6};
    const int nbColumns{7};

    // 配置顶部的nextDiscArea
    m_nextDiscArea.set_row_homogeneous(true);
    m_nextDiscArea.set_column_homogeneous(true);
    m_nextDiscArea.set_hexpand(true); // 水平方向填充VBox宽度
    m_nextDiscArea.set_vexpand(false); // 垂直方向不扩展,只占自身需要的空间
    m_nextDiscArea.set_valign(Gtk::ALIGN_CENTER);
    m_nextDiscArea.set_column_spacing(0); // 去掉列间距,避免额外空间影响尺寸
    m_nextDiscArea.set_row_spacing(0);

    for(int col{0}; col < nbColumns; ++col) {
        Disc* noDisc{new Disc};
        m_nextDiscArea.attach(*noDisc, col, 0, 1, 1);
    }

    // 配置底部的gameBoardGrid
    m_gameBoardGrid.set_row_homogeneous(true);
    m_gameBoardGrid.set_column_homogeneous(true);
    m_gameBoardGrid.set_hexpand(true); // 水平方向填充VBox宽度
    m_gameBoardGrid.set_vexpand(true); // 垂直方向填充VBox剩余空间
    m_gameBoardGrid.set_valign(Gtk::ALIGN_FILL);
    m_gameBoardGrid.set_column_spacing(0);
    m_gameBoardGrid.set_row_spacing(0);

    for(int row{0}; row < nbRows; ++row) {
        for(int col{0}; col < nbColumns; ++col) {
            Disc* noDisc{new Disc};
            m_gameBoardGrid.attach(*noDisc, col, row, 1, 1);
        }
    }

    // 调整VBox的打包方式:nextDiscArea只占必要空间,gameBoardGrid填充剩余空间
    pack_start(m_nextDiscArea, Gtk::PACK_SHRINK, 0);
    pack_start(m_gameBoardGrid, Gtk::PACK_EXPAND_WIDGET, 0);
}

为什么这些修改有效?

  • set_size_request给Disc设置了最小尺寸,防止布局管理器把它压缩到过小;
  • set_hexpand/vexpand(true)让Disc完全填充所在的Grid单元格,确保单元格大小等于Disc的显示大小;
  • 两个Grid都开启了column_homogeneous(true),且水平方向都扩展填充VBox宽度,保证7列的宽度完全一致;
  • VBox的打包参数区分了两个Grid的垂直空间分配,避免nextDiscArea抢占gameBoardGrid的空间,同时保证两者水平尺寸对齐。

内容的提问来源于stack exchange,提问作者BobMorane

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:48:41