news 2026/4/23 15:02:39

【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()来强制更新。这在隐藏部分窗口时很有用,因为您可以避免从调整器中删除控件,以后再添加它们,仅wxBoxSizerwxFlexGridSizer支持该功能。

一、一维布局

(一)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/4/23 14:12:23

构建本地化语音智能:Vosk离线识别技术深度解析

构建本地化语音智能&#xff1a;Vosk离线识别技术深度解析 【免费下载链接】vosk-api vosk-api: Vosk是一个开源的离线语音识别工具包&#xff0c;支持20多种语言和方言的语音识别&#xff0c;适用于各种编程语言&#xff0c;可以用于创建字幕、转录讲座和访谈等。 项目地址:…

作者头像 李华
网站建设 2026/4/22 21:34:07

33、Linux 系统中外设、内核参数与打印机管理全攻略

Linux 系统中外设、内核参数与打印机管理全攻略 1. Linux 内核模块管理外设 Linux 借助内核模块来管理硬件外设。运行中的 Linux 内核十分重要,它驱动着计算机的所有操作。为保证系统稳定,最好让内核在干扰最少的情况下工作。但如果每次对计算环境做小改动都要重启系统,插…

作者头像 李华
网站建设 2026/4/18 10:11:53

GameFramework框架实战指南:从入门到精通

GameFramework框架实战指南&#xff1a;从入门到精通 【免费下载链接】GameFramework This is literally a game framework, based on Unity game engine. It encapsulates commonly used game modules during development, and, to a large degree, standardises the process,…

作者头像 李华
网站建设 2026/4/16 12:36:18

24、构建抗入侵网络与系统监控指南

构建抗入侵网络与系统监控指南 1. 构建抗入侵网络 在网络安全领域,构建抗入侵网络是保障系统安全的重要一环。传统的 iptables 防火墙技术已不再处于前沿,若想了解使用 nftables 构建类似网络的官方指南,可访问 http://mng.bz/b0DM 。下面将重点介绍如何使用 Shorewall …

作者头像 李华
网站建设 2026/4/23 13:52:14

28、私有网络文件共享全攻略

私有网络文件共享全攻略 在当今数字化办公环境中,文件共享是一项至关重要的功能。无论是团队协作还是个人便捷访问文件,都需要高效且安全的文件共享方案。本文将详细介绍几种常见的文件共享方式,包括通过网络文件系统(NFS)、Samba与Windows用户共享文件,以及使用符号链接…

作者头像 李华