news 2026/11/6 12:35:38

【wxWidgets教程】界面布局:wxSizer调整器使用详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【wxWidgets教程】界面布局:wxSizer调整器使用详解

继上一篇【wxWidgest教程】界面布局:自动布局之后,本篇将进入介绍界面布局器wxSizer的使用方法。wxWidgets教程完整目录

调整器使用的布局算法与其他GUI工具包(如Java的AWT、GTK工具包或Qt工具包)中的布局系统几乎相同。它基于单个子窗口报告其最小所需大小以及在父窗口大小发生更改时拉伸。这通常意味着您不设置对话框的启动大小,而是为对话框分配一个调整器,并询问这个调整器的建议大小,调整器将依次查询其子级(可以是普通窗体、空白区域或其他调整器),以便可以构造调整器的层次结构。

使调整器非常适合在wxWidgets中使用的原因是,每个控件都报告自己的最小大小,并且算法可以处理不同平台上字体大小或不同窗口(对话框项)大小的差异,而不会出现问题。例如,如果标准字体以及Linux/GTK小部件的总体设计需要比Windows上更多的空间,那么Linux/GTK上的初始对话框大小将自动比Windows上的大。

调整器同时也是一类容器,用于布局并包含子控件。使用wxWindow::Show()方法,可以像隐藏任何控件一样隐藏大小调整器中包含的控件。不过,wxSizer还提供了一个单独的方法,可以告诉调整器在其大小计算中不要考虑该控件。调用boolShow(wxWindow*window,boolshow=true,boolrecursive=false ),然后必须调用调整器上的void wxSizer::Layout()来强制更新。这在隐藏部分窗口时很有用,因为您可以避免从调整器中删除控件,以后再添加它们,仅wxBoxSizer和wxFlexGridSizer支持该功能。

一、一维布局

(一)wxBoxSizer

wxBoxSizer基于这样一个认识,即窗口通常以非常简单的基本几何形式布局,通常是一行或一列。

wxBoxSizer可以垂直或水平布局其子项,具体取决于其构造函数wxBoxSizer(intorient)中使用的标志是。orient为wxVERTICAL,使用垂直方向排列,每个子项都可以居中、右对齐或左对齐。相应地,orient为wxHORIZONTAL,水平方向排列,每个子项都可以居中、在底部对齐或在顶部对齐。拉伸因子用于主方向,确定子项水平或垂拉伸的程度。

下面的示例演示wxBoxSizer的使用,例子同时使用了两种标志设置方式。

MyFrame::MyFrame(wxWindowID id,const wxString& title,const wxPoint& pos, const wxSize& size ,long style , const wxString& name):wxFrame(NULL,id,title,pos,size,style,name){ //ctor wxSizerFlags sizerFlag; sizerFlag.Border(wxALL,1).Proportion(1).Expand(); wxBoxSizer* outBox=new wxBoxSizer(wxVERTICAL); wxBoxSizer* hBox1=new wxBoxSizer(wxHORIZONTAL); hBox1->Add(new wxButton(this,wxID_ANY,"Test Button 1"),sizerFlag); hBox1->Add(new wxButton(this,wxID_ANY,"Test Button 2"),1,wxEXPAND|wxALL); wxBoxSizer* hBox2=new wxBoxSizer(wxHORIZONTAL); hBox2->Add(new wxTextCtrl(this,wxID_ANY,"hbox2 text box1", wxDefaultPosition,wxDefaultSize, wxTE_MULTILINE),sizerFlag); hBox2->Add(new wxTextCtrl(this,wxID_ANY,"hbox2 text box2", wxDefaultPosition,wxDefaultSize, wxTE_MULTILINE),2,wxEXPAND|wxALL); hBox2->Add(new wxTextCtrl(this,wxID_ANY,"hbox2 text box3", wxDefaultPosition,wxDefaultSize, wxTE_MULTILINE),1,wxEXPAND|wxALL); outBox->Add(hBox1,sizerFlag); outBox->Add(hBox2,wxSizerFlags(1).Expand().Border(wxALL)); SetSizerAndFit(outBox); }

(二)wxStaticBoxSizer

wxStaticBoxSizer与wxBoxSizer相同,但由一个静态框包围。下面是一个示例:

MyFrame::MyFrame(wxWindowID id,const wxString& title):wxFrame(NULL,id,title){ //ctor wxBoxSizer *topSizer=new wxBoxSizer(wxVERTICAL); wxStaticBoxSizer* sizer1=new wxStaticBoxSizer(wxHORIZONTAL,this,"wxStaticBoxSizer"); sizer1->Add(new wxCheckBox(this,wxID_ANY,"option 1"),wxALL|wxEXPAND); sizer1->Add(new wxCheckBox(this,wxID_ANY,"option 2"),wxALL|wxEXPAND); sizer1->Add(new wxCheckBox(this,wxID_ANY,"option 3"),wxALL|wxEXPAND); sizer1->Add(new wxCheckBox(this,wxID_ANY,"option 4"),wxALL|wxEXPAND); wxStaticBoxSizer* sizer2=new wxStaticBoxSizer(wxHORIZONTAL,this,"wxStaticBoxSizer"); sizer2->Add(new wxCheckBox(this,wxID_ANY,"option 1"),wxALL|wxEXPAND); sizer2->Add(new wxCheckBox(this,wxID_ANY,"option 2"),wxALL|wxEXPAND); sizer2->Add(new wxCheckBox(this,wxID_ANY,"option 3"),wxALL|wxEXPAND); sizer2->Add(new wxCheckBox(this,wxID_ANY,"option 4"),wxALL|wxEXPAND); topSizer->Add(sizer1,wxSizerFlags(1).Expand().Border(wxALL)); topSizer->Add(sizer2,wxSizerFlags(1).Expand().Border(wxALL)); SetSizerAndFit(topSizer); }

(三)wxWrapSizer

一个wxWrapSizer将它的子项排成一行,就像wxBoxSizer一样,只要在主方向有可用的空间,不同的是,当空间占满后,wxWrapSizer将在次方向上添加新行或列。

二、二维布局

(一)wxGridSizer

wxGridSizer是一个二维的调整器。所有子项都被赋予相同的大小,其大小与最大子项所需的最小大小相同。在本例中是左下边框中的文本控件。列数或行数都是固定的,如果添加了新的子项,则网格大小调整器将按各自的其他方向增长:

MyFrame::MyFrame(wxWindowID id , const wxString& title) : wxFrame( nullptr, id, title){ //ctor wxGridSizer *sizer=new wxGridSizer(4,3,wxSize(1,1)); wxString btnNames[]={"0","1","2","3","4","5","6","7","8","9","+","-"}; for(wxString bn:btnNames){ sizer->Add(new wxButton(this,wxWindow::NewControlId(),bn), wxSizerFlags(1).Expand().Border(wxALL,1)); } SetSizerAndFit(sizer); }

在wxSizer的基础上,wxGridSizer增加了如下函数,用于设置网络的行列数及行列之间的间隔:voidSetRows(introws);voidSetCols(introws);voidSetVGap(intgap);voidSetHGap(intgap);

(二)wxFlexGridSizer

从wxGridSizer派生的另一个二维调整器。每一列的宽度和每一行的高度是根据各自最大的子级的最小要求分别计算的。此外,如果为调整器分配的大小不同于它所请求的大小,则可以将列和行声明为可扩展的。下面的示例显示的对话框与上面的示例相同,但使用的是wxFlexGridSizer:

MyFrame::MyFrame(wxWindowID id ,const wxString& title) : wxFrame( nullptr, id, title) { //ctor wxFlexGridSizer *sizer=new wxFlexGridSizer(4,3,wxSize(1,1)); wxString btnNames[]={"0","1","2","3","4"," 5+3=5; 2*222=444 \r\nf(n)=100*n", "6","7","8","9","+","-"}; for(wxString bn:btnNames){ sizer->Add(new wxButton(this,wxWindow::NewControlId(),bn),wxSizerFlags(1).Expand().Border(wxALL,1)); } SetSizerAndFit(sizer); }

在wxGridSizer的基础上,wxFlexGridSizer增加了以下操作:

设置行列拉伸因子

如同一维布局中子控件的proportion参数一样,在二维弹性布局中,行和列也具有拉伸因子,当调整器中有额外的空间时,该拉伸因子决定了行或列如何扩展以填充剩余空间。通过voidAddGrowableCol(size_tidx,intproportion=0)和voidAddGrowableRow(size_tidx,intproportion=0)函数可以设置行或列的拉伸因子。idx:从0开始计数,标识行号或列号;proportion:行或列的空间占比大小。

如果取消空间占比,则可调用voidRemoveGrowableCol(size_tidx)和voidRemoveGrowableRow(size_tidx)函数。boolIsRowGrowable(size_tidx)和boolIsColGrowable(size_tidx)可判断特定行列是否可拉伸。

设置拉伸方向

从wxWidgets 2.5.0开始,wxFlexGridSizer还可以在一个方向上等长调整控件大小,而在另一个方向则相对灵活,不要求长度相等。可以调用voidSetFlexibleDirection(intdirection)设置这个相对灵活的方向,参数direction可以是wxVERTICAL、wxHORIZONTAL或wxBOTH。而在另一个方向则需要调用voidSetNonFlexibleGrowMode(wxFlexSizerGrowModemode)设置子控件填充剩余空间的方式。mode可以设置为下面的值:

表 11wxFlexSizerGrowMode定义

wxFLEX_GROWMODE_NONE

Sizer不会在非弹性方向上拉伸其子控件

wxFLEX_GROWMODE_SPECIFIED

Sizer使用AddGrowtableCol()和AddGrowtableRow()设置的proportion来决定列或行的最小大小(这是默认值)

wxFLEX_GROWMODE_ALL

Sizer平等地拉伸所有列或行,与proportion参数无关

(三)wxGridBagSizer

wxGridBagSizer可以像wxFlexGridSizer一样在虚拟网格中布局控件。与之不同的是,该调整器还能够使用wxGBPosition显式地指定以(col、row)为坐标指定的网格位置,以及使用wxGBSpan指定子控件占用的行数、列数,类似于HTML<table>中的colspan和rowspan属性。该调整器的子项添加操作与其父类不同:

wxSizerItem*Add(wxWindow*window,const wxGBPosition&pos,
const wxGBSpan&span=wxDefaultSpan,
intflag=0,intborder=0,
wxObject*userData=NULL);

三、总结

本文介绍了wxWidgets中wxSizer布局器的使用方法。wxSizer采用基于控件最小大小和拉伸因子的布局算法,支持跨平台自适应。文章详细讲解了一维布局器(wxBoxSizer、wxStaticBoxSizer、wxWrapSizer)和二维布局器(wxGridSizer、wxFlexGridSizer、wxGridBagSizer)的特点及使用场景。重点说明了弹性布局中的行列拉伸因子设置、控件隐藏方法等实用功能,并通过代码示例展示了各类布局器的实际应用。

还有一些界面布局的高级用法,如标准布局、弹簧等,后续将进一步讨论。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/6 6:44:57

20、网站服务器安全防护全攻略

网站服务器安全防护全攻略 1. 网络访问控制 网络访问控制是保障服务器安全的基础。我们可以通过防火墙规则来限制对服务器特定端口的访问。以下是一个示例规则表: | To | Action | From | | — | — | — | | 80 | ALLOW | Anywhere | | 443 | ALLOW | Anywhere | | 22 …

作者头像 李华
网站建设 2026/11/5 22:34:13

时间过半,目标依然遥远?OKR如何让团队找回“冲刺感”

距离年中只剩不到两个月&#xff0c;会议室里的空气却已凝固。高管们对着一串飘红的数据沉默——新业务线进展滞后23%&#xff0c;客户满意度环比下降5.7%&#xff0c;三个关键产品迭代延期。更令人不安的是&#xff0c;当问到“我们现在最该聚焦什么”时&#xff0c;五个分管负…

作者头像 李华
网站建设 2026/11/5 10:14:26

【JavaSE】十一、Stack Queue Deque PriorityQueue Map Set

文章目录Ⅰ. Stack&#xff08;不推荐使用了☠&#xff09;Ⅱ. QueueⅢ. DequeⅣ. PriorityQueue堆排序Ⅴ. MapⅥ. SetⅠ. Stack&#xff08;不推荐使用了☠&#xff09; 常见方法如下所示&#xff1a; 其中 peek() 就相当于是 std::stack 中的 top()。 注意事项&#xff1a; 在…

作者头像 李华
网站建设 2026/11/6 3:57:22

蚌埠住了,Java面试居然卷到了JDK源码级别!

作为Java开发者&#xff0c;面试肯定被问过多线程。对于它&#xff0c;大多数好兄弟面试前都是看看八股文背背面试题以为就OK了&#xff1b;殊不知现在的面试官都是针对一个点往深了问&#xff0c;你要是不懂其中原理&#xff0c;面试就挂了。可能你知道什么是进程什么是线程&a…

作者头像 李华
网站建设 2026/11/5 11:10:34

别再白忙活!数电发票不能作废,红冲这些要点要注意!

自2024年12月1日数电发票在全国正式推广以来&#xff0c;这种“无需领用、智能赋额、全程电子化”的新型发票&#xff0c;已成为企业财务的日常工具。它不仅简化了开票流程&#xff0c;更通过税务数字账户实现了发票信息自动流转&#xff0c;但随之而来的“红冲操作”却让不少财…

作者头像 李华
网站建设 2026/11/5 19:01:00

ComfyUI-MultiGPU分布式显存优化实战指南

为什么你的AI项目总是卡在显存瓶颈&#xff1f; 【免费下载链接】ComfyUI-MultiGPU This custom_node for ComfyUI adds one-click "Virtual VRAM" for any GGUF UNet and CLIP loader, managing the offload of layers to DRAM or VRAM to maximize the latent spac…

作者头像 李华