Add support for using arbitrary windows as wxStaticBox labels

This commit implements the new feature in wxGTK and updates the sample
and the documentation.
This commit is contained in:
Vadim Zeitlin 2017-12-19 21:29:32 +01:00
parent 29bd25b757
commit 7c849276f8
6 changed files with 226 additions and 17 deletions

View File

@ -113,6 +113,7 @@ All (GUI):
- Allow wxWebView::RunScript() return values (Jose Lorenzo, GSoC 2017).
- Allow using fractional pen widths with wxGraphicsContext (Adrien Tétar).
- Add support for loading fonts from external files (Arthur Norman).
- Add support for using arbitrary windows as wxStaticBox labels.
- Improve wxSVGFileDC to support more of wxDC API (Maarten Bent).
- Add support for wxAuiManager and wxAuiPaneInfo to XRC (Andrea Zanellato).
- Add support for wxSL_MIN_MAX_LABELS and wxSL_VALUE_LABEL to XRC (ousnius).

View File

@ -194,6 +194,8 @@ Currently the following symbols exist:
@itemdef{wxHAS_RAW_KEY_CODES, Defined if raw key codes (see wxKeyEvent::GetRawKeyCode are supported.}
@itemdef{wxHAS_REGEX_ADVANCED, Defined if advanced syntax is available in wxRegEx.}
@itemdef{wxHAS_TASK_BAR_ICON, Defined if wxTaskBarIcon is available on the current platform.}
@itemdef{wxHAS_WINDOW_LABEL_IN_STATIC_BOX, Defined if wxStaticBox::Create()
overload taking @c wxWindow* instead of the text label is available on the current platform.}
@itemdef{wxHAS_MODE_T, Defined when wxWidgets defines @c mode_t typedef for the
compilers not providing it. If another library used in a wxWidgets
application, such as ACE (http://www.cs.wustl.edu/~schmidt/ACE.html), also

View File

@ -18,6 +18,7 @@ class WXDLLIMPEXP_CORE wxStaticBox : public wxStaticBoxBase
public:
wxStaticBox()
{
Init();
}
wxStaticBox( wxWindow *parent,
@ -28,6 +29,21 @@ public:
long style = 0,
const wxString &name = wxStaticBoxNameStr )
{
Init();
Create( parent, id, label, pos, size, style, name );
}
wxStaticBox( wxWindow *parent,
wxWindowID id,
wxWindow* label,
const wxPoint &pos = wxDefaultPosition,
const wxSize &size = wxDefaultSize,
long style = 0,
const wxString &name = wxStaticBoxNameStr )
{
Init();
Create( parent, id, label, pos, size, style, name );
}
@ -37,7 +53,21 @@ public:
const wxPoint &pos = wxDefaultPosition,
const wxSize &size = wxDefaultSize,
long style = 0,
const wxString &name = wxStaticBoxNameStr );
const wxString &name = wxStaticBoxNameStr )
{
return DoCreate( parent, id, &label, NULL, pos, size, style, name );
}
bool Create( wxWindow *parent,
wxWindowID id,
wxWindow* label,
const wxPoint &pos = wxDefaultPosition,
const wxSize &size = wxDefaultSize,
long style = 0,
const wxString &name = wxStaticBoxNameStr )
{
return DoCreate( parent, id, NULL, label, pos, size, style, name );
}
virtual void SetLabel( const wxString &label ) wxOVERRIDE;
@ -52,13 +82,39 @@ public:
virtual void AddChild( wxWindowBase *child ) wxOVERRIDE;
virtual void WXDestroyWithoutChildren() wxOVERRIDE;
protected:
// Common part of all ctors.
void Init()
{
m_labelWin = NULL;
}
// Common implementation of both Create() overloads: exactly one of
// labelStr and labelWin parameters must be non-null.
bool DoCreate(wxWindow *parent,
wxWindowID id,
const wxString* labelStr,
wxWindow* labelWin,
const wxPoint& pos,
const wxSize& size,
long style,
const wxString& name);
virtual bool GTKWidgetNeedsMnemonic() const wxOVERRIDE;
virtual void GTKWidgetDoSetMnemonic(GtkWidget* w) wxOVERRIDE;
void DoApplyWidgetStyle(GtkRcStyle *style) wxOVERRIDE;
// If non-null, the window used as our label. This window is owned by the
// static box and will be deleted when it is.
wxWindow* m_labelWin;
wxDECLARE_DYNAMIC_CLASS(wxStaticBox);
};
// Indicate that we have the ctor overload taking wxWindow as label.
#define wxHAS_WINDOW_LABEL_IN_STATIC_BOX
#endif // _WX_GTKSTATICBOX_H_

View File

@ -84,6 +84,42 @@ public:
long style = 0,
const wxString& name = wxStaticBoxNameStr);
/**
Constructor for a static box using the given window as label.
This constructor takes a pointer to an arbitrary window (although
usually a wxCheckBox or a wxRadioButton) instead of just the usual text
label and puts this window at the top of the box at the place where the
label would be shown.
The @a label window must be a non-null, fully created window and will
become a child of this wxStaticBox, i.e. it will be owned by this
control and will be deleted when the wxStaticBox itself is deleted.
An example of creating a wxStaticBox with window as a label:
@code
void MyFrame::CreateControls()
{
wxPanel* panel = new wxPanel(this);
wxCheckBox* checkbox = new wxCheckBox(panel, wxID_ANY, "Box checkbox");
wxStaticBox* box = new wxStaticBox(panel, wxID_ANY, checkbox);
...
}
@endcode
Currently this constructor is only available in wxGTK, use
@c wxHAS_WINDOW_LABEL_IN_STATIC_BOX to check whether it can be used at
compile-time.
@since 3.1.1
*/
wxStaticBox(wxWindow* parent, wxWindowID id,
wxWindow* label,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = 0,
const wxString& name = wxStaticBoxNameStr);
/**
Destructor, destroying the group box.
*/
@ -97,5 +133,25 @@ public:
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize, long style = 0,
const wxString& name = wxStaticBoxNameStr);
};
/**
Creates the static box with the window as a label.
This method can only be called for an object created using its default
constructor.
See the constructor documentation for more details.
Currently this overload is only available in wxGTK, use
@c wxHAS_WINDOW_LABEL_IN_STATIC_BOX to check whether it can be used at
compile-time.
@since 3.1.1
*/
wxStaticBox(wxWindow* parent, wxWindowID id,
wxWindow* label,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = 0,
const wxString& name = wxStaticBoxNameStr);
};

View File

@ -116,6 +116,9 @@ public:
protected:
// event handlers
void OnCheckOrRadioBox(wxCommandEvent& event);
#ifdef wxHAS_WINDOW_LABEL_IN_STATIC_BOX
void OnBoxCheckBox(wxCommandEvent& event);
#endif // wxHAS_WINDOW_LABEL_IN_STATIC_BOX
void OnButtonReset(wxCommandEvent& event);
void OnButtonBoxText(wxCommandEvent& event);
@ -137,6 +140,9 @@ protected:
// the check/radio boxes for styles
wxCheckBox *m_chkVert,
*m_chkGeneric,
#ifdef wxHAS_WINDOW_LABEL_IN_STATIC_BOX
*m_chkBoxWithCheck,
#endif // wxHAS_WINDOW_LABEL_IN_STATIC_BOX
*m_chkAutoResize,
*m_chkEllipsize;
@ -207,6 +213,9 @@ StaticWidgetsPage::StaticWidgetsPage(WidgetsBookCtrl *book,
m_chkVert =
m_chkAutoResize =
m_chkGeneric =
#ifdef wxHAS_WINDOW_LABEL_IN_STATIC_BOX
m_chkBoxWithCheck =
#endif // wxHAS_WINDOW_LABEL_IN_STATIC_BOX
#if wxUSE_MARKUP
m_chkGreen =
#endif // wxUSE_MARKUP
@ -243,6 +252,9 @@ void StaticWidgetsPage::CreateContent()
m_chkGeneric = CreateCheckBoxAndAddToSizer(sizerLeft,
"&Generic wxStaticText");
#ifdef wxHAS_WINDOW_LABEL_IN_STATIC_BOX
m_chkBoxWithCheck = CreateCheckBoxAndAddToSizer(sizerLeft, "Checkable &box");
#endif // wxHAS_WINDOW_LABEL_IN_STATIC_BOX
m_chkVert = CreateCheckBoxAndAddToSizer(sizerLeft, "&Vertical line");
m_chkAutoResize = CreateCheckBoxAndAddToSizer(sizerLeft, "&Fit to text");
sizerLeft->Add(5, 5, 0, wxGROW | wxALL, 5); // spacer
@ -367,6 +379,9 @@ void StaticWidgetsPage::CreateContent()
void StaticWidgetsPage::Reset()
{
m_chkGeneric->SetValue(false);
#ifdef wxHAS_WINDOW_LABEL_IN_STATIC_BOX
m_chkBoxWithCheck->SetValue(false);
#endif // wxHAS_WINDOW_LABEL_IN_STATIC_BOX
m_chkVert->SetValue(false);
m_chkAutoResize->SetValue(true);
m_chkEllipsize->SetValue(true);
@ -469,10 +484,28 @@ void StaticWidgetsPage::CreateStatic()
flagsText |= align;
flagsBox |= align;
wxStaticBox *staticBox = new wxStaticBox(this, wxID_ANY,
m_textBox->GetValue(),
wxDefaultPosition, wxDefaultSize,
flagsBox);
wxStaticBox *staticBox;
#ifdef wxHAS_WINDOW_LABEL_IN_STATIC_BOX
if ( m_chkBoxWithCheck->GetValue() )
{
wxCheckBox* const label = new wxCheckBox(this, wxID_ANY,
m_textBox->GetValue());
label->Bind(wxEVT_CHECKBOX, &StaticWidgetsPage::OnBoxCheckBox, this);
staticBox = new wxStaticBox(this, wxID_ANY,
label,
wxDefaultPosition, wxDefaultSize,
flagsBox);
}
else // normal static box
#endif // wxHAS_WINDOW_LABEL_IN_STATIC_BOX
{
staticBox = new wxStaticBox(this, wxID_ANY,
m_textBox->GetValue(),
wxDefaultPosition, wxDefaultSize,
flagsBox);
}
m_sizerStatBox = new wxStaticBoxSizer(staticBox, isVert ? wxHORIZONTAL
: wxVERTICAL);
@ -559,6 +592,14 @@ void StaticWidgetsPage::OnCheckOrRadioBox(wxCommandEvent& event)
CreateStatic();
}
#ifdef wxHAS_WINDOW_LABEL_IN_STATIC_BOX
void StaticWidgetsPage::OnBoxCheckBox(wxCommandEvent& event)
{
wxLogMessage("Box check box has been %schecked",
event.IsChecked() ? "": "un");
}
#endif // wxHAS_WINDOW_LABEL_IN_STATIC_BOX
void StaticWidgetsPage::OnButtonBoxText(wxCommandEvent& WXUNUSED(event))
{
m_sizerStatBox->GetStaticBox()->SetLabel(m_textBox->GetValue());

View File

@ -59,13 +59,14 @@ static gboolean expose_event(GtkWidget* widget, GdkEventExpose*, wxWindow*)
// wxStaticBox
//-----------------------------------------------------------------------------
bool wxStaticBox::Create( wxWindow *parent,
wxWindowID id,
const wxString& label,
const wxPoint& pos,
const wxSize& size,
long style,
const wxString& name )
bool wxStaticBox::DoCreate(wxWindow *parent,
wxWindowID id,
const wxString* labelStr,
wxWindow* labelWin,
const wxPoint& pos,
const wxSize& size,
long style,
const wxString& name)
{
if (!PreCreation( parent, pos, size ) ||
!CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
@ -74,11 +75,41 @@ bool wxStaticBox::Create( wxWindow *parent,
return false;
}
m_widget = GTKCreateFrame(label);
g_object_ref(m_widget);
if ( labelStr )
{
m_widget = GTKCreateFrame(*labelStr);
// only base SetLabel needs to be called after GTKCreateFrame
wxControl::SetLabel(label);
// only base SetLabel needs to be called after GTKCreateFrame
wxControl::SetLabel(*labelStr);
}
else // Use the given window as the label.
{
wxCHECK_MSG( labelWin, false, wxS("Label window can't be null") );
GtkWidget* const labelWidget = labelWin->m_widget;
wxCHECK_MSG( labelWidget, false, wxS("Label window must be created") );
// The widget must not have any parent at GTK+ level or setting it as
// label widget would fail.
GtkWidget* const oldParent = gtk_widget_get_parent(labelWidget);
gtk_container_remove(GTK_CONTAINER(oldParent), labelWidget);
gtk_widget_unparent(labelWidget);
// It also should be our child at wx API level, but without being our
// child in wxGTK, i.e. it must not be added to the GtkFrame container,
// so we can't call Reparent() here (not even wxWindowBase version, as
// it still would end up in our overridden AddChild()), nor the normal
// AddChild() for the same reason.
labelWin->GetParent()->RemoveChild(labelWin);
wxWindowBase::AddChild(labelWin);
m_labelWin = labelWin;
m_widget = gtk_frame_new(NULL);
gtk_frame_set_label_widget(GTK_FRAME(m_widget), labelWidget);
}
g_object_ref(m_widget);
m_parent->DoAddChild( this );
@ -121,16 +152,38 @@ void wxStaticBox::AddChild( wxWindowBase *child )
wxStaticBoxBase::AddChild(child);
}
void wxStaticBox::WXDestroyWithoutChildren()
{
// The label window doesn't count as our child, it's really a part of
// static box itself and it makes no sense to leave it alive when the box
// is destroyed, so do it even when it's supposed to be destroyed without
// destroying its children.
if ( m_labelWin )
{
// By deleting it here, we indirectly remove this window from the list
// of our children and hence prevent the base class version of this
// method from reparenting it and thus keeping it alive.
delete m_labelWin;
m_labelWin = NULL;
}
wxStaticBoxBase::WXDestroyWithoutChildren();
}
void wxStaticBox::SetLabel( const wxString& label )
{
wxCHECK_RET( m_widget != NULL, wxT("invalid staticbox") );
wxCHECK_RET( !m_labelWin, wxS("Doesn't make sense when using label window") );
GTKSetLabelForFrame(GTK_FRAME(m_widget), label);
}
void wxStaticBox::DoApplyWidgetStyle(GtkRcStyle *style)
{
GTKFrameApplyWidgetStyle(GTK_FRAME(m_widget), style);
if ( m_labelWin )
GTKDoApplyWidgetStyle(m_labelWin, style);
if (m_wxwindow)
GTKApplyStyle(m_wxwindow, style);