0%

wxWidgets入门教程之九 :组件专题2

在这一章中,我们会继续介绍一些组件的知识,我们会提到wxListBox,wxNotebool和wxScrolledWindow。

wxListBox

一个wxListBox组件被用来显示一些元素,它是一个有一系列字符串的矩形。我们可以使用它来显示一个MP3文件的列表,一些书名,或者是一个大工程的模块名。一个wxListBox可以以两种不同的状态被创建。一个单一选择的状态或者一个多重选择的状态。单一状态是默认的状态,在wxListBox里面有两个事件类型,第一个是wxEVT_COMMAND_LISTBOX_SELECTED,当我们选择wxListBox里面的一个元素时这个事件产生;第二个是wxEVT_COMMAND_LISTBOX_DOUBLE_CLICKED,当我们双击wxListBox里面的一个元素时这个事件产生。在wxListBox内部的元素在GTK的平台上有限制,大概不能超过2000个左右的元素。元素的ID从0开始计算,滚动条会在需要的时候自动生成。
listbox.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <wx/wx.h>
#include <wx/listbox.h>

class MyPanel : public wxPanel
{
public:
MyPanel(wxPanel * parent);

void OnNew(wxCommandEvent & event);
void OnRename(wxCommandEvent & event);
void OnClear(wxCommandEvent & event);
void OnDelete(wxCommandEvent & event);

wxListBox * m_lb;

wxButton * m_newb;
wxButton * m_renameb;
wxButton * m_clearb;
wxButton * m_deleteb;
};

class Listbox : public wxFrame
{
public:
Listbox(const wxString & title);

void OnDbClick(wxCommandEvent & event);

wxListBox * listbox;
MyPanel * btnPanel;
};

enum{ID_RENAME, ID_LISTBOX};

listbox.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include "listbox.h"
#include <wx/textdlg.h>

Listbox::Listbox(const wxString & title)
: wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(270, 200))
{
wxPanel * panel = new wxPanel(this, wxID_ANY);

wxBoxSizer * hbox = new wxBoxSizer(wxHORIZONTAL);

listbox = new wxListBox(panel, ID_LISTBOX, wxDefaultPosition, wxDefaultSize);

btnPanel = new MyPanel(panel);

hbox->Add(listbox, 3, wxEXPAND | wxALL, 20);


hbox->Add(btnPanel, 2, wxEXPAND | wxRIGHT, 10);

Connect(wxEVT_COMMAND_LISTBOX_DOUBLECLICKED,
wxCommandEventHandler(Listbox::OnDbClick));

panel->SetSizer(hbox);

Centre();
}

MyPanel::MyPanel(wxPanel * parent)
: wxPanel(parent, wxID_ANY)
{
wxBoxSizer * vbox = new wxBoxSizer(wxVERTICAL);

// GetParent()方法获得了panel的父组件的地址
Listbox * lb = (Listbox*)parent->GetParent();

m_lb = lb->listbox;

m_newb = new wxButton(this, wxID_NEW, _T("New"));
m_renameb = new wxButton(this, ID_RENAME, _T("Rename"));
m_deleteb = new wxButton(this, wxID_DELETE, _T("Delete"));
m_clearb = new wxButton(this, wxID_CLEAR, _T("Clear"));

Connect(wxID_NEW, wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(MyPanel::OnNew) );
Connect(ID_RENAME, wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(MyPanel::OnRename) );
Connect(wxID_CLEAR, wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(MyPanel::OnClear) );
Connect(wxID_DELETE, wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(MyPanel::OnDelete) );

vbox->Add(-1, 20);
vbox->Add(m_newb);
vbox->Add(m_renameb, 0, wxTOP, 5);
vbox->Add(m_deleteb, 0, wxTOP, 5);
vbox->Add(m_clearb, 0, wxTOP, 5);

SetSizer(vbox);
}

void MyPanel::OnNew(wxCommandEvent & event)
{
wxString str = wxGetTextFromUser(_T("Add new item"));
if(str.Len() > 0)
{
m_lb->Append(str);
}
}

void MyPanel::OnClear(wxCommandEvent & event)
{
m_lb->Clear();
}

void MyPanel::OnRename(wxCommandEvent & event)
{
wxString text;
wxString renamed;

int sel = m_lb->GetSelection();
if(sel != -1)
{
text = m_lb->GetString(sel);
renamed = wxGetTextFromUser(_T("Rename item"), _T("Rename dialog"), text);
}
if(!renamed.IsEmpty())
{
m_lb->Delete(sel);
m_lb->Insert(renamed, sel);
}
}

void MyPanel::OnDelete(wxCommandEvent & event)
{
int sel = m_lb->GetSelection();
if(sel != -1)
{
m_lb->Delete(sel);
}
}

void Listbox::OnDbClick(wxCommandEvent & event)
{
wxString text;
wxString renamed;

int sel = listbox->GetSelection();
if(sel != -1)
{
text = listbox->GetString(sel);
renamed = wxGetTextFromUser(_T("Rename item"), _T("Rename dialog"), text);
}
if(!renamed.IsEmpty())
{
listbox->Delete(sel);
listbox->Insert(renamed, sel);
}
}

listbox = new wxListBox(panel, ID_LISTBOX, wxDEFAULT_POSITION, wxDEFAULT_SIZE);

这个是listbox组件的构造器.

在我们的例子中,我们有一列四个按钮,这些按钮用来在listbox内添加、修改、删除、清空元素。

wxString str = wxGetTextFromUser(_T(“Add new item”));

if(str.Len() > 0)
{

m_lb->Append(str);

}

我们使用上面的代码显示一个wxGetTextFromUser对话框接收用户输入,然后调用Append()函数添加到listbox内。

m_lb->Clear();

清空listbox只需要简单的调用一个Clear()方法。

int sel = m_lb->GetSelection();

if(sel != -1)
{

m_lb->Delete(sel);

}

我们调用GetSelection()方法计算出当前选中的是第几项,然后我们调用Delete()方法删除元素。

修改一个元素需要以下几个步骤:

wxString text;

wxString renamed;

我们定义了两个字符串对象。

int sel = listbox->GetSelection();

if(sel != -1)

{
text = listbox->GetString(sel);

Renamed = wxGetTextFromUser(_T(“Rename item”), _T(“Rename dialog”), text);

}

我们获取了当前选中的的字符串,并保存起来,然后请求用户的输入。

if(!renamed.IsEmpty())
{
m_lb->Delete(sel);
m_lb->Insert(renamed, sel);
}

我们检查了renamed字符串是否为空,避免了插入空字符串,然后我们删除了旧的元素,插入新的元素。

wxNotebook

wxNotebook可以在一个窗体上通过标签列举多个窗口。可以通过下面四个标识符指定标签的位置:

  • wxNB_LEFT
  • wxNB_RIGHT
  • wxNB_TOP
  • wxNB_BOTTOM
    默认的是wxNB_TOP

notebook.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <wx/wx.h>
#include <wx/notebook.h>
#include <wx/grid.h>

class Notebook : public wxFrame
{
public:
Notebook(const wxString & title);

void OnQuit(wxCommandEvent & event);
};

class MyGrid : public wxGrid
{
public:
MyGrid(wxNotebook * parent);
};

notebook.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include "notebook.h"

Notebook::Notebook(const wxString & title)
: wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(400, 350))
{
wxNotebook * nb = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_BOTTOM);

wxMenuBar * menubar = new wxMenuBar();
wxMenu * file = new wxMenu();
file->Append(wxID_EXIT, _T("Quit"), _T(""));
menubar->Append(file, _T("&File"));
SetMenuBar(menubar);

Connect(wxEVT_COMMAND_MENU_SELECTED,
wxCommandEventHandler(Notebook::OnQuit));
MyGrid * grid1 = new MyGrid(nb);
MyGrid * grid2 = new MyGrid(nb);
MyGrid * grid3 = new MyGrid(nb);

nb->AddPage(grid1, _T("Sheet1"));
nb->AddPage(grid2, _T("Sheet2"));
nb->AddPage(grid3, _T("Sheet3"));

CreateStatusBar();
Centre();
}

void Notebook::OnQuit(wxCommandEvent & event)
{
Close(true);
}

MyGrid::MyGrid(wxNotebook * parent)
: wxGrid(parent, wxID_ANY)
{
CreateGrid(30, 30);
SetRowLabelSize(50);
SetColLabelSize(25);
SetRowLabelAlignment(wxALIGN_RIGHT, wxALIGN_CENTER);
SetLabelFont(wxFont(9, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD));

for(int i = 0; i < 30; i++)
{
this->SetRowSize(i, 25);
}
}

在这个例子中,我们创建了一个包含三个表格控件的notebook组件,notebook的标签被放置在窗体底部。

wxNotebook * nb = new wxNotebook(this, wxID_ANY, wxDEFAULTPOSITION, wxDEFAULTSIZE, wxNB_BOTTOM);

这里我们创建了一个notebook组件。

nb->AddPage(grid1, _T(“Sheet1”));

nb->AddPage(grid2, _T(“Sheet2”));

nb->AddPage(grid3, _T(“Sheet3”));

我们添加了三个表格控件到notebook组件中。

wxScrolledWindow

这是容器组件中的其中一个。当我们有一个比屏幕还要大的区域需要显示时,这个组件很有用。在我们的例子中,我们示范了它的用法,我们在窗口中放置了一个巨大的图片。当窗口比我们的图片小的时候,滚动条会自动显示。

scrolledwindow.h

1
2
3
4
5
6
7
#include <wx/wx.h>

class ScrolledWindow : public wxFrame
{
public:
ScrolledWindow(const wxString & title);
};

scrolledwindow.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include "scrolledwindow.h"

ScrolledWindow::ScrolledWindow(const wxString & title)
: wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(300, 200))
{
wxImage::AddHandler(new wxJPEGHandler);

wxScrolledWindow * sw = new wxScrolledWindow(this);

wxBitmap bmp(_T("test.jpg"), wxBITMAP_TYPE_JPEG);
wxStaticBitmap * sb = new wxStaticBitmap(sw, -1, bmp);

int width = bmp.GetWidth();
int height = bmp.GetHeight();

sw->SetScrollbars(10, 10, width / 10, height / 10);
sw->Scroll(50, 10);

Centre();
}

在我们的例子中,我们显示了一张海贼王的图片。

wxImage::AddHandler(new wxJPEGHandler);

我们必须初始化wxJPEGHandler,才能处理jpg图像。

wxScrolledWindow * sw = new wxScrolledWindow(this);

wxBitmap bmp(_T(“test.jpg”), wxBITMAP_TYPE_JPEG);

wxStaticBitmap * sb = new wxStaticBitmap(sw, -1, bmp);

我们创建了一个滚动窗口,并放置了一张静态图。

sw->SetScrollbars(10, 10, width / 10, height / 10);

我们设置了滚动条。

sw->Scroll(50, 10);

滚动到初始位置。

在这一章中,我们继续介绍了wxWidgets库中的组件。