《使用wxWidgets进行跨平台程序开发》chap09——布局一个对话框

/////////////////////////////////////////////////////////////////////////////
// Name:        personalrecord.h
// Purpose:     Dialog to get name, age, sex, and voting preference
// Author:      Julian Smart
// Created:     02/28/04 06:52:49
// Copyright:   (c) 2004, Julian Smart
// Licence:     wxWindows license
/////////////////////////////////////////////////////////////////////////////

#ifndef _PERSONALRECORD_H_
#define _PERSONALRECORD_H_

#ifdef __GNUG__
#pragma interface "personalrecord.cpp"
#endif

/*!
 * Includes
 */

#include "wx/spinctrl.h"
#include "wx/statline.h"

/*!
 * Control identifiers
 */

/**< 事件标识符 */
enum{
        ID_PERSONAL_RECORD  = 10000,
        ID_NAME             = 10001,
        ID_AGE              = 10002,
        ID_SEX              = 10003,
        ID_VOTE             = 10006,
        ID_RESET            = 10004
    };

/*!
 * PersonalRecordDialog class declaration
 */

/**< 一个简单的对话框类 */
class PersonalRecordDialog: public wxDialog
{

private:

    DECLARE_CLASS( PersonalRecordDialog )   //提供运行期类型信息

    // This class handles events
    DECLARE_EVENT_TABLE()

public:

    // Constructors
    PersonalRecordDialog();

    /**< 一个标准的构造函数 */
    PersonalRecordDialog(
                            wxWindow* parent,                                       //父窗口
                            wxWindowID id              = ID_PERSONAL_RECORD,        //指定事件标志
                            const wxString& caption    = wxT("Personal Record"),    //标题
                            const wxPoint& pos         = wxDefaultPosition,         //默认的位置
                            const wxSize& size         = wxDefaultSize,             //默认的大小
                            long style                 = wxCAPTION|wxRESIZE_BORDER|wxSYSTEM_MENU    //对话框类型:显示标题、可变大小的边框、显示系统菜单
                        );

    /**<
    依照wxWidgets的惯例,我们同时支持了单步创建和两步窗口的方式,单步创建使用的是一个复杂
    的构造函数,而两步创建则使用的是一个简单的额构造函数和一个复杂的Create函数
    */

    /// Member initialisation
    void Init();

    /// Creation
    /**< 用于二步初始化的初始化函数 */
    bool Create(
                    wxWindow* parent,
                    wxWindowID id               = ID_PERSONAL_RECORD,
                    const wxString& caption     = wxT("Personal Record"),
                    const wxPoint& pos          = wxDefaultPosition,
                    const wxSize& size          = wxDefaultSize,
                    long style                  = wxCAPTION|wxRESIZE_BORDER|wxSYSTEM_MENU
               );

    /// Creates the controls and sizers
    /**< 组件这个对话框,被Create()函数调用 */
    /**< 在CreateControls函数中,我们使用了一个垂直盒子布局控件嵌套了另外一个垂直盒子布局控件
    以便使对话框产生边界.一个水平的盒子布局控件用来放置wxSpinCtrl, wxChoice和wxCheckBox,以
    及另外一个水平盒子布局控件来放置四个按钮 */
    void CreateControls();

    /// Sets the validators for the dialog controls
    /**< 有一个更容易的方法.wxWidgets支持验证器,所谓验证器是一个把数据变量和对应的控
    件联系起来的对象.虽然不总是可以使用,但是只要可以使用,总是可以节省你大量的时间和代码来进
    行数据的传输和验证 */
    void SetDialogValidators();

    /// Sets the help text for the dialog controls
    /**< 设置帮助文本 */
    void SetDialogHelp();

    /// Name accessors
    void SetName(const wxString& name)  { m_name = name; }
    wxString GetName() const            { return m_name; }

    /// Age accessors
    void SetAge(int age) { m_age = age; }
    int  GetAge() const   { return m_age; }

    /// Sex accessors (male = false, female = true)
    void SetSex(bool sex) { sex ? m_sex = 1 : m_sex = 0; }
    bool GetSex() const { return m_sex == 1; }

    /// Does the person vote?
    void SetVote(bool vote) { m_vote = vote; }
    bool GetVote() const { return m_vote; }

//// PersonalRecordDialog event handler declarations
/**< 事件响应函数 */

    /// wxEVT_UPDATE_UI event handler for ID_VOTE
    void OnVoteUpdate( wxUpdateUIEvent& event );

    /// wxEVT_COMMAND_BUTTON_CLICKED event handler for ID_RESET
    void OnResetClick( wxCommandEvent& event );

    /// wxEVT_COMMAND_BUTTON_CLICKED event handler for wxID_HELP
    void OnHelpClick( wxCommandEvent& event );

//// PersonalRecordDialog member variables

    /// Data members
    wxString    m_name;
    int         m_age;
    int         m_sex;
    bool        m_vote;
};

#endif  // _PERSONALRECORD_H_
/////////////////////////////////////////////////////////////////////////////
// Name:        personalrecord.cpp
// Purpose:     Dialog to get name, age, sex, and voting preference
// Author:      Julian Smart
// Created:     02/28/04 06:52:49
// Copyright:   (c) 2004, Julian Smart
// Licence:     wxWindows license
/////////////////////////////////////////////////////////////////////////////

#ifdef __GNUG__
#pragma implementation "personalrecord.h"
#endif

#include "wx/wx.h"

#include "wx/valtext.h"
#include "wx/valgen.h"
#include "wx/cshelp.h"

#include "personalrecord.h"

/*!
 * PersonalRecordDialog type definition
 */

IMPLEMENT_CLASS( PersonalRecordDialog, wxDialog )

/*!
 * PersonalRecordDialog event table definition
 */

BEGIN_EVENT_TABLE( PersonalRecordDialog, wxDialog )
    EVT_UPDATE_UI   ( ID_VOTE,      PersonalRecordDialog::OnVoteUpdate )
    EVT_BUTTON      ( ID_RESET,     PersonalRecordDialog::OnResetClick )
    EVT_BUTTON      ( wxID_HELP,    PersonalRecordDialog::OnHelpClick )
END_EVENT_TABLE()

/*!
 * PersonalRecordDialog constructors
 */

PersonalRecordDialog::PersonalRecordDialog()
{
    Init();
}

PersonalRecordDialog::PersonalRecordDialog( wxWindow* parent,
                                            wxWindowID id,
                                            const wxString& caption,
                                            const wxPoint& pos,
                                            const wxSize& size,
                                            long style )
{
    Init();

    Create(parent, id, caption, pos, size, style);
}

/// Initialisation
void PersonalRecordDialog::Init()
{
    m_name  = wxEmptyString;
    m_age   = 20;
    m_sex   = false;
    m_vote  = false;
}

/*!
 * PersonalRecord creator
 */

bool PersonalRecordDialog::Create( wxWindow* parent,
                                   wxWindowID id,
                                   const wxString& caption,
                                   const wxPoint& pos,
                                   const wxSize& size,
                                   long style )
{
    // We have to set extra styles before creating the
    // dialog

    /**< 在创建对话框之前设置一些属性值 */

    /**< wxWS_EX_BLOCK_EVENTS:
    wxCommandEvents事件将会在无法在当前事件表中找到匹配的时候在其父窗口中尝试匹配,
    设置这个扩展属性可以阻止这个行为。Dialog类型的窗口默认设置了这个类型,
    但是如果SetExtraStyle函数被应用程序类调用过的话,默认设置可能被覆盖. */

    /**< wxDIALOG_EX_CONTEXTHELP:
    在Windows平台上,这个扩展类型使得对话框增加一个查询按钮.如果这个按钮被按下,
    对话框将进入一种帮助模式,在这种模式下,无论用户点击哪个子窗口,都将发送一个
    wxEVT_HELP事件. 这个扩展类型不可以和wxMAXIMIZE BOX和wxMINIMIZE BOX类型混用 */
    SetExtraStyle(wxWS_EX_BLOCK_EVENTS|wxDIALOG_EX_CONTEXTHELP);

    /**< 调用wxDialog的Create函数初始化 */
    if (!wxDialog::Create( parent, id, caption, pos, size, style ))
    {
        return false;
    }

    /**< 把整个对话框窗口的组件布局好 */
    CreateControls();

    /**< 设置组件对应的帮助文本提示 */
    SetDialogHelp();

    /**< 把数据和对应控件联系起来 */
    SetDialogValidators();

    // This fits the dialog to the minimum size dictated by
    // the sizers

    GetSizer()->Fit(this);

    // This ensures that the dialog cannot be sized smaller
    // than the minimum size

    GetSizer()->SetSizeHints(this);

    // Centre the dialog on the parent or (if none) screen

    Centre();

    return true;
}

/*!
 * Control creation for PersonalRecordDialog
 */

void PersonalRecordDialog::CreateControls()
{
    // A top-level sizer
    /**< 一个顶层布局控件 */
    wxBoxSizer* topSizer = new wxBoxSizer(wxVERTICAL);
    /**< 设置为这个对话框的主布局控件 */
    this->SetSizer(topSizer);

    // A second box sizer to give more space around the controls
    /**< 第二个顶层布局控件来产生边界 */
    wxBoxSizer* boxSizer = new wxBoxSizer(wxVERTICAL);
    /**< 缩放因子为0、水平居中、四周都有空白边框、空白边框大小为5 */
    topSizer->Add(boxSizer, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5);

    // A friendly message
    /**< 一个静态文本控件 */
    wxStaticText* descr = new wxStaticText( this, wxID_STATIC,
        wxT("Please enter your name, age and sex, and specify whether you wish to\nvote in a general election."), wxDefaultPosition, wxDefaultSize, 0 );
    /**< 把这个静态文本控件添加到子布局控件中 */
    boxSizer->Add(descr, 0, wxALIGN_LEFT|wxALL, 5);

    // Spacer
    /**< 在子布局控件中添加一段空白:长、宽、缩放因子、水平居中、边界空白5像素 */
    boxSizer->Add(5, 5, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5);

    // Label for the name text control
    /**< 静态文本:Name */
    wxStaticText* nameLabel = new wxStaticText ( this, wxID_STATIC,
        wxT("&Name:"), wxDefaultPosition, wxDefaultSize, 0 );
    boxSizer->Add(nameLabel, 0, wxALIGN_LEFT|wxALL, 5); //左对齐

    // A text control for the user's name
    /**< 一个用于输入用户名的文本框 */
    wxTextCtrl* nameCtrl = new wxTextCtrl ( this, ID_NAME, wxT("Emma"), wxDefaultPosition, wxDefaultSize, 0 );
    boxSizer->Add(nameCtrl, 0, wxGROW|wxALL, 5);    //子元素随这布局控件一起改变大小

    // A horizontal box sizer to contain age, sex and vote
    /**< 一个水平布局控件用来放置年龄性别和是否投票 */
    wxBoxSizer* ageSexVoteBox = new wxBoxSizer(wxHORIZONTAL);
    boxSizer->Add(ageSexVoteBox, 0, wxGROW|wxALL, 5);   //子元素随这布局控件一起改变大小

    // Label for the age control
    /**< 静态文本:Age */
    wxStaticText* ageLabel = new wxStaticText ( this, wxID_STATIC,
        wxT("&Age:"), wxDefaultPosition, wxDefaultSize, 0 );
    ageSexVoteBox->Add(ageLabel, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);  //垂直对齐

    // A spin control for the user's age
    /**< 用于输入年龄的控件spin */
    wxSpinCtrl* ageSpin = new wxSpinCtrl ( this, ID_AGE,
        wxEmptyString, wxDefaultPosition, wxSize(60, -1),
        wxSP_ARROW_KEYS, 0, 120, 25 );  //用户可以通过方向键改变相关值、范围0 ~ 120、默认25
    ageSexVoteBox->Add(ageSpin, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);   //垂直对齐

    // Label for the sex control
    /**< 静态文本:Sex */
    wxStaticText* sexLabel = new wxStaticText ( this, wxID_STATIC,
        wxT("&Sex:"), wxDefaultPosition, wxDefaultSize, 0 );
    ageSexVoteBox->Add(sexLabel, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);  //垂直对齐

    // Create the sex choice control    /*
    /**< 性别选择框 */
    wxString sexStrings[] = {
        wxT("Male"),
        wxT("Female")
    };

    wxChoice* sexChoice = new wxChoice ( this, ID_SEX,
        wxDefaultPosition, wxSize(80, -1), WXSIZEOF(sexStrings),
            sexStrings, 0 );

    sexChoice->SetStringSelection(wxT("Female"));   //设置默认选项
    ageSexVoteBox->Add(sexChoice, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5); //垂直对齐

    // Add a spacer that stretches to push the Vote control
    // to the right
    /**< 在子布局中添加一段空白:长、宽、缩放因子1、垂直对齐 */
    /**< 增加一个可拉升的空白区域,以便让投票选项出现在右边 */
    ageSexVoteBox->Add(5, 5, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5);

    /**< 添加一个选择框 */
    wxCheckBox* voteCheckBox = new wxCheckBox( this, ID_VOTE,
       wxT("&Vote"), wxDefaultPosition, wxDefaultSize, 0 );
    voteCheckBox ->SetValue(true);  //默认为选中
    ageSexVoteBox->Add(voteCheckBox, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);  //垂直对齐


    // A dividing line before the OK and Cancel buttons
    /**< 创建一个静态分割条 */
    wxStaticLine* line = new wxStaticLine ( this, wxID_STATIC,
        wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
    boxSizer->Add(line, 0, wxGROW|wxALL, 5);

    // A horizontal box sizer to contain Reset, OK, Cancel and Help
    /**< 用来放置四个按钮的水平盒子布局控件 */
    wxBoxSizer* okCancelBox = new wxBoxSizer(wxHORIZONTAL);
    boxSizer->Add(okCancelBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5);

    // The Reset button
    /**< Reset按钮 */
    wxButton* reset = new wxButton( this, ID_RESET, wxT("&Reset"),
        wxDefaultPosition, wxDefaultSize, 0 );
    okCancelBox->Add(reset, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);

    // The OK button
    /**< OK按钮 */
    wxButton* ok = new wxButton ( this, wxID_OK, wxT("&OK"),
        wxDefaultPosition, wxDefaultSize, 0 );
    okCancelBox->Add(ok, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);

    // The Cancel button
    /**< Cancel按钮 */
    wxButton* cancel = new wxButton ( this, wxID_CANCEL,
        wxT("&Cancel"), wxDefaultPosition, wxDefaultSize, 0 );
    okCancelBox->Add(cancel, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);

    // The Help button
    /**< Help按钮 */
    wxButton* help = new wxButton( this, wxID_HELP,
        wxT("&Help"), wxDefaultPosition, wxDefaultSize, 0 );
    okCancelBox->Add(help, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
}

// Set the validators for the dialog controls
/**< 把数据和对应控件联系起来 */
void PersonalRecordDialog::SetDialogValidators()
{
    /**< wxGenericValidator是一个很简单的验证器,它只负责传输数据,不对数据进行校验,
    也正因为如此,它支持更多的基本控件 */

    /**< 别的验证器则象wxTextValidator一样,提供了各种的校验方法,比如wxTextValidator
    就可以阻止那些不合法的按键事件传入文本框控件.在这个例子中,我们只是使用了标准校验类型
    wxFILTER ALPHA,但是通过验证器的SetIncludes和SetExcludes函数,我们还可以指定具体哪些字符
    是允许的哪些是不允许的. */

    FindWindow(ID_NAME)->SetValidator(wxTextValidator(wxFILTER_ALPHA, & m_name));

    FindWindow(ID_AGE)->SetValidator(wxGenericValidator(& m_age));

    FindWindow(ID_SEX)->SetValidator(wxGenericValidator(& m_sex));

    FindWindow(ID_VOTE)->SetValidator(wxGenericValidator(& m_vote));
}

// Sets the help text for the dialog controls
/**< 设置对话框的帮助文本 */
void PersonalRecordDialog::SetDialogHelp()
{
    wxString nameHelp = wxT("Enter your full name.");
    wxString ageHelp = wxT("Specify your age.");
    wxString sexHelp = wxT("Specify your gender, male or female.");
    wxString voteHelp = wxT("Check this if you wish to vote.");

    FindWindow(ID_NAME)->SetHelpText(nameHelp);     //上下文敏感帮助
    FindWindow(ID_NAME)->SetToolTip(nameHelp);      //工具提示帮助

    FindWindow(ID_AGE)->SetHelpText(ageHelp);
    FindWindow(ID_AGE)->SetToolTip(ageHelp);

    FindWindow(ID_SEX)->SetHelpText(sexHelp);
    FindWindow(ID_SEX)->SetToolTip(sexHelp);

    FindWindow(ID_VOTE)->SetHelpText(voteHelp);
    FindWindow(ID_VOTE)->SetToolTip(voteHelp);

    //wxHelpProvider::Set(new wxSimpleHelpProvider);
}

/*
 * wxEVT_UPDATE_UI event handler for ID_CHECKBOX
 */

void PersonalRecordDialog::OnVoteUpdate( wxUpdateUIEvent& event )
{
    wxSpinCtrl* ageCtrl = (wxSpinCtrl*) FindWindow(ID_AGE);

    /**< 要注意在代码中我们不能直接判断m age成员,因为
    这个成员只有在用户点击了OK按钮以后才会将控件的数据传递过来 */
    if (ageCtrl->GetValue() < 18)
    {
        event.Enable(false);    //不能选中
        event.Check(false);     //选框灰色
    }
    else
        event.Enable(true);
}

/*!
 * wxEVT_COMMAND_BUTTON_CLICKED event handler for ID_RESET
 */
/**< 处理reset按钮事件 */
void PersonalRecordDialog::OnResetClick( wxCommandEvent& event )
{
    Init();                 //初始化
    TransferDataToWindow(); //将数据传输到控件
}

/*!
 * wxEVT_COMMAND_BUTTON_CLICKED event handler for wxID_HELP
 */
/**< 处理help按钮事件 */
void PersonalRecordDialog::OnHelpClick( wxCommandEvent& event )
{
    // Normally we would wish to display proper online help.
    // For this example, we're just using a message box.
    /*
    wxGetApp().GetHelpController().DisplaySection(wxT("Personal record dialog"));
     */

    wxString helpText =
      wxT("Please enter your full name, age and gender.\n")
      wxT("Also indicate your willingness to vote in general elections.\n\n")
      wxT("No non-alphabetical characters are allowed in the name field.\n")
      wxT("Try to be honest about your age.");


    wxMessageBox(helpText,
      wxT("Personal Record Dialog Help"),
      wxOK|wxICON_INFORMATION, this);
}
// Name:        demo.cpp
// Purpose:     Demo for PersonalRecordDialog
// Author:      Julian Smart
// License:     wxWindows License

#include "wx/wx.h"
#include "personalrecord.h"

// Declare the application class
class MyApp : public wxApp
{
public:
    // Called on application startup
    virtual bool OnInit();
};

// Declare our main frame class
class MyFrame : public wxFrame
{
public:
    // Constructor
    MyFrame(const wxString & title);

    // Event handlers
    void OnQuit         (wxCommandEvent & event);
    void OnAbout        (wxCommandEvent & event);
    void OnShowDialog   (wxCommandEvent & event);

    enum{
            ID_SHOW_DIALOG
        };

private:
    // This class handles events
    DECLARE_EVENT_TABLE()
};

// Implements MyApp & GetApp()
DECLARE_APP(MyApp)

// Give wxWidgets the means to create a MyApp object
IMPLEMENT_APP(MyApp)

// Initialize the application
bool MyApp::OnInit()
{
    // Create the main application window
    MyFrame * frame = new MyFrame(wxT("PersonalRecordDialog Demo"));

    // Show it
    frame->Show(true);

    // Start the event loop
    return true;
}

// Event table for MyFrame
BEGIN_EVENT_TABLE(MyFrame, wxFrame)
    EVT_MENU(wxID_ABOUT,        MyFrame::OnAbout)
    EVT_MENU(wxID_EXIT,         MyFrame::OnQuit)
    EVT_MENU(ID_SHOW_DIALOG,    MyFrame::OnShowDialog)
END_EVENT_TABLE()

void MyFrame::OnAbout(wxCommandEvent & event)
{
    wxString msg;
    msg.Printf(wxT("PersonalRecordDialog example, built with wxWidgets %s"),
               wxVERSION_STRING);

    wxMessageBox(msg, wxT("About this program"),
                 wxOK | wxICON_INFORMATION, this);
}

void MyFrame::OnQuit(wxCommandEvent & event)
{
    // Destroy the frame
    Close(true);
}

void MyFrame::OnShowDialog(wxCommandEvent & event)
{
    PersonalRecordDialog dialog(this, wxID_ANY, wxT("Personal Record"),
                                wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE);
    dialog.ShowModal();
}

#include "mondrian.xpm"

MyFrame::MyFrame(const wxString & title)
       : wxFrame(NULL, wxID_ANY, title)
{
    // Set the frame icon
    SetIcon(wxIcon(mondrian_xpm));

    // Create a menu bar
    wxMenu * fileMenu = new wxMenu;

    // The "About" item should be in the help menu
    wxMenu * helpMenu = new wxMenu;
    helpMenu->Append(wxID_ABOUT, wxT("&About...\tF1"),
                     wxT("Show about dialog"));

    fileMenu->Append(ID_SHOW_DIALOG, wxT("&Show Personal Record Dialog..."),
                     wxT("Show Personal Record Dialog"));
    fileMenu->Append(wxID_EXIT, wxT("E&xit\tAlt-X"),
                     wxT("Quit this program"));

    // Now append the freshly created menu to the menu bar...
    wxMenuBar *menuBar = new wxMenuBar();
    menuBar->Append(fileMenu, wxT("&File"));
    menuBar->Append(helpMenu, wxT("&Help"));

    // ... and attach this menu bar to the frame
    SetMenuBar(menuBar);

    CreateStatusBar(2);
    SetStatusText(wxT("welcome to wxWidgets!"), 1);
}

 

posted @ 2013-10-19 13:02  瓶哥  Views(1793)  Comments(0Edit  收藏  举报