• 5、wxWidgets布局管理


    布局管理

    一个典型的应用程序由各种各样的组件组成,这些组件被放置在容器组件内。一个程序员必须要管理应用程序的界面布局,这不是一个简单的工作,在wxWidgets里面我们有两个选择:

      1.使用绝对位置放置组件

      2.使用布局控件

    绝对位置

    程序员以像素单位去指定一个组件的位置和大小,当你使用绝对位置时,你会明白以下几点:

      1.当你缩放主窗口时,组件的位置和大小不会改变。

      2.程序在不同的平台上看起来不同(蹩脚的)。

      3.在你的程序中更改字体也许会破坏布局。

      4.如果你决定改变你的布局,你必须要完全重做你的布局,这将是单调乏味且浪费时间的工作。

    【实例】

    下面是一个使用绝对位置布局的例子:

    main.h

     1 #include <wx/wx.h>
     2 //定义主框架类
     3 class MyFrame : public wxFrame
     4 {
     5 public:
     6     MyFrame(const wxString & title);
     7     //定义菜单条
     8     wxMenuBar * menubar;
     9     wxMenu * file;
    10     wxMenu * edit;
    11     wxMenu * help;
    12     //定义一个静态文本框
    13     wxTextCtrl * textctrl;
    14 };
    15 //定义应用程序类
    16 class MyApp : public wxApp
    17 {
    18 public:
    19     virtual bool OnInit();
    20 };

    main.cpp

     1 #include "main.h"
     2 //主框架类的实现
     3 MyFrame::MyFrame(const wxString & title)
     4         : wxFrame(NULL, -1, title, wxPoint(-1, -1), wxSize(250, 180))
     5 {
     6     //定义一个面板容器
     7     wxPanel * panel = new wxPanel(this, wxID_ANY);
     8     //添加菜单条
     9     menubar = new wxMenuBar;
    10     file = new wxMenu;
    11     edit = new wxMenu;
    12     help = new wxMenu;
    13 
    14     menubar->Append(file, _T("&File"));
    15     menubar->Append(edit, _T("&Edit"));
    16     menubar->Append(help, _T("&Help"));
    17 
    18     SetMenuBar(menubar);
    19     //向面板添加一个静态文本框,使用wxPoint(-1, -1)对静态文本框绝对位置布局
    20     textctrl = new wxTextCtrl(panel, -1, _T(""), wxPoint(-1, -1), wxSize(250, 150));
    21 
    22     Centre();
    23 }
    24 //声明应用程序
    25 IMPLEMENT_APP(MyApp)
    26 
    27 bool MyApp::OnInit()
    28 {
    29     MyFrame * myFrame = new MyFrame(_T("MyFrame"));
    30     myFrame->Show(true);
    31 
    32     return true;
    33 }

    展示效果:

    调整大小之前:

    调整大小之后:

     

    可以看出使用绝对位置布局的静态文本框,不会随着整体框架大小的改变而改变。

    使用布局控件

    wxWidgets里面的布局控件处理关于组件的位置的所有问题。

    我们能够在以下这些布局控件中选择:

    1.wxBoxSizer

    2.wxStaticBoxSizer

    3.wxGridSizer

    4.wxFlexGridSizer

    5.wxGridBagSizer

    【实例】

    下面是一个静态文本框会随着主框架的大小而改变大小的实例。

    main.h

     1 #include <wx/wx.h>
     2 /*
     3     使用绝对位置进行布局
     4 */
     5 //定义主框架类
     6 class MyFrame : public wxFrame
     7 {
     8 public:
     9     MyFrame(const wxString & title);
    10     //定义菜单条
    11     wxMenuBar * menubar;
    12     wxMenu * file;
    13     wxMenu * edit;
    14     wxMenu * help;
    15     //定义一个静态文本框
    16     wxTextCtrl * textctrl;
    17 };
    18 //定义应用程序类
    19 class MyApp : public wxApp
    20 {
    21 public:
    22     virtual bool OnInit();
    23 };

    main.cpp

     1 #include "main.h"
     2 //主框架类的实现
     3 MyFrame::MyFrame(const wxString & title)
     4         : wxFrame(NULL, -1, title, wxPoint(-1, -1), wxSize(250, 180))
     5 {
     6     //添加菜单条
     7     menubar = new wxMenuBar;
     8     file = new wxMenu;
     9     edit = new wxMenu;
    10     help = new wxMenu;
    11 
    12     menubar->Append(file, _T("&File"));
    13     menubar->Append(edit, _T("&Edit"));
    14     menubar->Append(help, _T("&Help"));
    15 
    16     SetMenuBar(menubar);
    17     //向面板添加一个静态文本框
    18     textctrl = new wxTextCtrl(this, -1, _T(""), wxPoint(-1, -1), wxSize(250, 150));
    19 
    20     Centre();
    21 }
    22 //声明应用程序
    23 IMPLEMENT_APP(MyApp)
    24 
    25 bool MyApp::OnInit()
    26 {
    27     MyFrame * myFrame = new MyFrame(_T("MyFrame"));
    28     myFrame->Show(true);
    29 
    30     return true;
    31 }

    效果展示

    调整大小之前:

     

    调整大小之后:

     

    wxBoxSizer

    这个布局控件允许我们把多个组件放在一行或者一列上,我们能在一个布局控件中放入另一个布局控件。这种设计使得我们能够设计非常复杂的布局。

    1 wxBoxSizer(int orient)
    2 wxSIzerItem * Add(wxWindow * window, int proportion = 0, int flag = 0, int border = 0)

      参数orient可以是wxVERTICAL或者wxHORIZONTAL。通过Add()方法添加组件到wxBoxSizer内,为了能够更好的理解它,我们需要看它的参数。

      参数proportion定义了组件在指定的排列方向内自由缩放的比例,让我们假定有三个按钮,它们的proportion分别是0、1、2它们被添加进一个水平布局控,proportion = 0的按钮始终都不会改变,proportion = 2的按钮会比proportion = 1的按钮在水平尺寸上多缩放一倍的尺寸。

      有了flag参数你能够进一步设置wxBoxSizer内的组件的行为,我们能够控制两个组件之间的边界距离,我们可以在两个组件之间填充一些空白像素。为了显示边框,我们需要定义哪个方向上的边框需要使用。我们能够使用|运算符把它们组合起来,例如wxLEFT | wxBOTTOM,我们能够下面这些标志中选择:

    1.wxLEFT
    2.wxRIGHT
    3.wxBOTTOM
    4.wxTOP
    5.wxALL
    

     【实例】一个wxPanel组件周围的边框

    main.h

     1 #include <wx/wx.h>
     2 /*
     3     使用wxBoxSizer进行布局
     4 */
     5 //定义主框架类
     6 class MyFrame : public wxFrame
     7 {
     8 public:
     9     MyFrame(const wxString & title);
    10 };
    11 //定义应用程序类
    12 class MyApp : public wxApp
    13 {
    14 public:
    15     virtual bool OnInit();
    16 };

    main.cpp

     1 #include "main.h"
     2 //主框架类的实现
     3 MyFrame::MyFrame(const wxString & title)
     4         : wxFrame(NULL, -1, title, wxPoint(-1, -1), wxSize(250, 180))
     5 {
     6     //颜色定义
     7     wxColor col1, col2;
     8     col1.Set(_T("#4F50F9"));
     9     col2.Set(_T("#EDEDED"));
    10     //定义底层面板,并为面板设置背景色
    11     wxPanel * panel = new wxPanel(this, -1);
    12     panel->SetBackgroundColour(col1);
    13     //定义顶层面板,并为面板设置背景色
    14     wxPanel * midPan = new wxPanel(panel, wxID_ANY);
    15     midPan->SetBackgroundColour(col2);
    16     //定义wxBoxSizer容器,布局方式为垂直布局
    17     wxBoxSizer * vbox = new wxBoxSizer(wxVERTICAL);
    18     //将midpan加载到vbox中
    19     vbox->Add(midPan, 1, wxEXPAND | wxALL, 30);
    20     //将wxBoxSizer容器放入Panel面板中
    21     panel->SetSizer(vbox);
    22 
    23     Centre();
    24 }
    25 //声明应用程序
    26 IMPLEMENT_APP(MyApp)
    27 
    28 bool MyApp::OnInit()
    29 {
    30     MyFrame * myFrame = new MyFrame(_T("MyFrame"));
    31     myFrame->Show(true);
    32 
    33     return true;
    34 }

      在这个例子中,我们创建了两个panels,第二个panel在其自身周围有一圈空白。

    Box->Add(midPan, 1, wxEXPAND | wxALL, 20);
    

      我们在midPan这个panel周围放置了宽度为20px的边框,wxALL表示边框适用于全部四个方向。如果我们使用wxEXPAND标识,这个组件会在允许的边框内扩展到最大。

    最后,我们也可以定义组件的对齐标识,我们使用以下标识去定义:

    1.wxALIGN_LEFT
    2.wxALIGN_RIGHT
    3.wxALIGN_TOP
    4.wxALIGN_BOTTOM
    5.wxALIGN_CENTER_VERTICAL
    6.wxALIGN_CENTER_HORIZONTAL
    7.wxALIGN_CENTER
    

    【实例】组件对齐

    main.h

     1 #include <wx/wx.h>
     2 /*
     3     使用wxBoxSizer进行布局,组件的对齐方式
     4 */
     5 //定义主框架类
     6 class MyFrame : public wxFrame
     7 {
     8 public:
     9     MyFrame(const wxString & title);
    10 };
    11 //定义应用程序类
    12 class MyApp : public wxApp
    13 {
    14 public:
    15     virtual bool OnInit();
    16 };

    main.cpp

     1 #include "main.h"
     2 //主框架类的实现
     3 MyFrame::MyFrame(const wxString & title)
     4         : wxFrame(NULL, -1, title, wxPoint(-1, -1), wxSize(250, 180))
     5 {
     6     //颜色定义
     7     wxColor col1;
     8     col1.Set(_T("#4F50F9"));
     9 
    10     //定义底层面板,并为面板设置背景色
    11     wxPanel * panel = new wxPanel(this, -1);
    12     panel->SetBackgroundColour(col1);
    13 
    14     //定义了一个垂直布局控件,两个水平布局控件
    15     wxBoxSizer * vbox = new wxBoxSizer(wxVERTICAL);
    16     wxBoxSizer * hbox1 = new wxBoxSizer(wxHORIZONTAL);
    17     wxBoxSizer * hbox2 = new wxBoxSizer(wxHORIZONTAL);
    18     //定义两个按钮
    19     wxButton * ok = new wxButton(panel, wxID_ANY, _T("OK"));
    20     wxButton * cancel = new wxButton(panel, wxID_ANY, _T("Cancel"));
    21     //在水平布局控件hbox1中,新建了一个空白面板
    22     hbox1->Add(new wxPanel(panel, wxID_ANY));
    23     //在水平布局控件hbox2中,加入了两个按钮
    24     hbox2->Add(ok);
    25     hbox2->Add(cancel);
    26     //将两个水平布局控件加载到垂直布局控件中
    27     vbox->Add(hbox1, 1, wxEXPAND);
    28     //水平布局控件hbox2右对齐,且与底部。右侧的间隔为10像素(注意这些单词的大小写,大小写敏感)
    29     vbox->Add(hbox2, 0, wxALIGN_RIGHT | wxRIGHT | wxBOTTOM, 10);
    30     //将垂直布局控件vbox加载到panel中
    31     panel->SetSizer(vbox);
    32 
    33     //将wxBoxSizer容器放入Panel面板中
    34     panel->SetSizer(vbox);
    35 
    36     Centre();
    37 }
    38 //声明应用程序
    39 IMPLEMENT_APP(MyApp)
    40 
    41 bool MyApp::OnInit()
    42 {
    43     MyFrame * myFrame = new MyFrame(_T("MyFrame"));
    44     myFrame->Show(true);
    45 
    46     return true;
    47 }

      在这个实例中,我们创建了三个布局控件,一个垂直控件和两个水平控件。我们把这两个水平布局控件放置到垂直布局控件中。

    1 Hbox->Add(new wxPanel(panel, wxID_ANY));
    2 Vbox->Add(hbox, 1, wxEXPAND);

      我们把一个wxPanel放置在第一个水平控件中,我们把缩放因子设置为1并且设置了wxEXPAND标识,这样做这个布局控件就会占据除了hbox2之外的所有空间。

    1 Vbox->Add(hbox2, 0, wxALIGN_RIGHT | wxRIGHT | wxBOTTOM, 10);

      我们把两个按钮放置在hbox2这个控件中,在hbox2中的控件是右对齐排列的,而且我们在这两个按钮的底部和右边放置了宽度为10px的空白元素。

    wxGridSizer

      wxGridSizer把控件布局在一个格子中,每一个格子都有相同的大小。

    1 wxGridSizer(int rows, int cols, int vgap, int hgap);

      在构造函数中我们指定网格的行数和列数和每个格子的垂直、水平间距。在我们的例子中我们建立了一个计算器的框架,这是一个介绍wxGridSizer的完美的例子。

    main.h

     1 #include <wx/wx.h>
     2 //定义主框架类
     3 class GridSizer : public wxFrame
     4 {
     5 public:
     6     GridSizer(const wxString & title);
     7 
     8     wxBoxSizer * sizer;
     9     wxGridSizer * gs;
    10     wxTextCtrl * display;
    11 };
    12 
    13 //定义应用程序类
    14 class MyApp : public wxApp
    15 {
    16 public:
    17     virtual bool OnInit();
    18 };

    main.cpp

     1 #include "main.h"
     2 
     3 //主框架类的实现
     4 GridSizer::GridSizer(const wxString & title)
     5          : wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(270, 220))
     6 {
     7     sizer = new wxBoxSizer(wxVERTICAL);//垂直布局控件wxBoxSizer
     8     //静态文本框,用于显示数据
     9     display = new wxTextCtrl(this, wxID_ANY, _T(""), wxDefaultPosition, wxDefaultSize, wxTE_RIGHT);
    10     //将静态文本框,加载到wxBoxSizer中
    11     sizer->Add(display, 0, wxEXPAND | wxTOP | wxBOTTOM, 4);
    12     //定义一个wxGridSizer控件,5行 4列  垂直间隔为3 水平间隔为3
    13     gs = new wxGridSizer(5, 4, 3, 3);
    14     //按照每行4个子组件,先wxGridSizer中添加内容
    15     gs->Add(new wxButton(this, -1, _T("Cls")), 0, wxEXPAND);
    16     gs->Add(new wxButton(this, -1, _T("Bck")), 0, wxEXPAND);
    17     gs->Add(new wxStaticText(this, -1, _T("")), 0, wxEXPAND);
    18     gs->Add(new wxButton(this, -1, _T("Close")), 0, wxEXPAND);
    19 
    20     gs->Add(new wxButton(this, -1, _T("7")), 0, wxEXPAND);
    21     gs->Add(new wxButton(this, -1, _T("8")), 0, wxEXPAND);
    22     gs->Add(new wxButton(this, -1, _T("9")), 0, wxEXPAND);
    23     gs->Add(new wxButton(this, -1, _T("/")), 0, wxEXPAND);
    24 
    25     gs->Add(new wxButton(this, -1, _T("4")), 0, wxEXPAND);
    26     gs->Add(new wxButton(this, -1, _T("5")), 0, wxEXPAND);
    27     gs->Add(new wxButton(this, -1, _T("6")), 0, wxEXPAND);
    28     gs->Add(new wxButton(this, -1, _T("*")), 0, wxEXPAND);
    29 
    30     gs->Add(new wxButton(this, -1, _T("1")), 0, wxEXPAND);
    31     gs->Add(new wxButton(this, -1, _T("2")), 0, wxEXPAND);
    32     gs->Add(new wxButton(this, -1, _T("3")), 0, wxEXPAND);
    33     gs->Add(new wxButton(this, -1, _T("-")), 0, wxEXPAND);
    34 
    35     gs->Add(new wxButton(this, -1, _T("0")), 0, wxEXPAND);
    36     gs->Add(new wxButton(this, -1, _T(".")), 0, wxEXPAND);
    37     gs->Add(new wxButton(this, -1, _T("=")), 0, wxEXPAND);
    38     gs->Add(new wxButton(this, -1, _T("+")), 0, wxEXPAND);
    39 
    40     //将wxGridSizer加载到wxBoxSizer中
    41     sizer->Add(gs, 1, wxEXPAND);
    42     //将wxBoxSizer加载到主框架中
    43     this->SetSizer(sizer);
    44     //设置主框架的最小尺寸
    45     this->SetMinSize(wxSize(270, 220));
    46 
    47     Centre();
    48 }
    49 //声明应用程序
    50 IMPLEMENT_APP(MyApp)
    51 //应用程序类初始化函数
    52 bool MyApp::OnInit()
    53 {
    54     GridSizer * gs = new GridSizer(_T("GridSizer"));
    55     gs->Show(true);
    56 
    57     return true;
    58 }

        在我们的例子中,我们为wxFrame建立一个垂直布局控件,我们把一个静态文本和一个网格布局控件放进垂直布局控件。注意我们是如何在Bck和Close按钮之间添加空白的,我们只是简单的添加了一个空的wxStaticText,这是一个很常用的技巧。

    gs->Add(new wxButton(this, -1, _T("Cls")), 0, wxEXPAND);
    

      我们调用Add()方法许多次,组件被顺序放置进网格布局控件,第一行被放满,第二行,第三行同样。

    效果展示:

    wxFlexGridSizer

      这个布局控件和wxGridSizer有点相似,它同样把组件布局到有两个尺寸的格子中,但是它添加了一些灵活性,wxGridSizer的格子都是相同大小的,在wxFlexSizer中所有的格子在一行上有相同的高度,一列上有相同的宽度,但是所有的行和列不一定有相同的高度和宽度。

    wxFlexGridSize(int rows, int cols, int vgap, int hgap);
    

      rows和cols指定了布局控件中的行数和列数。vgap和hgap在组件之间两个方向上添加了一些空白。

      许多时候程序员需要开发一个对话框用来进行数据录入或修改,wxFlexGridSIzer很适合这个任务,一个程序员可以使用这个布局控件轻松的创建一个对话框,使用wxGridSizer或许同样可以完成这个任务,但是这样会影响美观,因为每一个网格的大小都一样会显得很不自然。

     【实例】

    main.h

     1 #include <wx/wx.h>
     2 //定义主框架类
     3 class FlexGridSizer : public wxFrame
     4 {
     5 public:
     6     FlexGridSizer(const wxString & title);
     7 };
     8 
     9 //定义应用程序类
    10 class MyApp : public wxApp
    11 {
    12 public:
    13     virtual bool OnInit();
    14 };

    main.cpp

     1 #include "main.h"
     2 //主框架类的实现
     3 FlexGridSizer::FlexGridSizer(const wxString & title)
     4              : wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(270, 220))
     5 {
     6     //定义一个面板
     7     wxPanel * panel = new wxPanel(this, wxID_ANY);
     8     //定义一个wxBoxSizer水平布局控件
     9     wxBoxSizer * hbox = new wxBoxSizer(wxHORIZONTAL);
    10     //定义一个wxFlexGridSizer布局控件,行数为3, 列数为2, 垂直间隔为9, 水平间隔为25
    11     wxFlexGridSizer * fgs = new wxFlexGridSizer(3, 2, 9, 25);
    12 
    13     //定义三个静态文本
    14     wxStaticText * thetitle = new wxStaticText(panel, wxID_ANY, _T("Title :"));
    15     wxStaticText * author   = new wxStaticText(panel, wxID_ANY, _T("Author:"));
    16     wxStaticText * review   = new wxStaticText(panel, wxID_ANY, _T("Review:"));
    17     //定义三个文本框
    18     wxTextCtrl * tc1 = new wxTextCtrl(panel, wxID_ANY);
    19     wxTextCtrl * tc2 = new wxTextCtrl(panel, wxID_ANY);
    20     wxTextCtrl * tc3 = new wxTextCtrl(panel, wxID_ANY, _T(""),
    21                                       wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE);
    22 
    23     //将静态文版和文本框加载到wxFlexGridSizer布局控件中
    24     fgs->Add(thetitle);
    25     fgs->Add(tc1, 1, wxEXPAND);
    26     fgs->Add(author);
    27     fgs->Add(tc2, 1, wxEXPAND);
    28     fgs->Add(review, 1, wxEXPAND);
    29     fgs->Add(tc3, 1, wxEXPAND);
    30 
    31     //将第三行和第二列设置为可扩展的
    32     fgs->AddGrowableRow(2, 1);
    33     fgs->AddGrowableCol(1, 1);
    34 
    35     //将wxFlexGridSizer布局控件加载到wxBoxSizer水平布局控件中
    36     hbox->Add(fgs, 1, wxALL | wxEXPAND, 15);
    37     //将水平布局控件加载到Panel中
    38     panel->SetSizer(hbox);
    39     Centre();
    40 }
    41 
    42 IMPLEMENT_APP(MyApp)
    43 
    44 bool MyApp::OnInit()
    45 {
    46     FlexGridSizer * fgs = new FlexGridSizer(_T("FlexGridSizer"));
    47     fgs->Show(true);
    48 
    49     return true;
    50 }

    效果展示:

    1 wxBoxSizer * hbox = new wxBoxSizer(wxHORIZONTAL);
    2 Hbox->Add(fgs, 1, wxALL | wxEXPAND, 15);

      我们创建了一个水平布局控件,用来在组件的边界制造出15px的空白。

    fgs->Add(thetitle);

      我们像使用wxGridSizer一样把组件添加进布局控件。

    1 fgs->AddGrowableRow(2, 1);
    2 fgs->AddGrowableCol(1, 1);

      我们让第三行和第二列成为可扩展的,这样当主窗口缩放时,第三个多行文本控件就可以自动扩展。前两个文本控件会在水平方向自动扩展,第三个会在两个方向自动扩展,我们必须使用wxEXPAND确保它们正常工作。

     

  • 相关阅读:
    R语言 逐步回归分析
    R语言 一元线性回归
    基于Qt的信号分析简单应用软件的设计
    【图论 5】图的应用——拓扑排序和关键路径
    【图论 3】图的应用——最小生成树
    B+树
    大概是最简明的B树博客了
    KMP算法
    【内存管理篇】基本分页存储管理方式
    双向链表为何时间复杂度为O(1)?
  • 原文地址:https://www.cnblogs.com/Long-w/p/9591045.html
Copyright © 2020-2023  润新知