1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxListBox sample
4 // Author: Vadim Zeitlin
6 // Copyright: (c) 2000 Vadim Zeitlin
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
13 +1. horz scrollbar doesn't appear in listbox
14 +2. truncating text ctrl doesn't update display
15 +3. deleting last listbox item doesn't update display
16 4. text ctrl background corrupted after resize
19 // ============================================================================
21 // ============================================================================
23 // ----------------------------------------------------------------------------
25 // ----------------------------------------------------------------------------
27 // for compilers that support precompilation, includes "wx/wx.h".
28 #include "wx/wxprec.h"
34 // for all others, include the necessary headers
39 #include "wx/dcclient.h"
41 #include "wx/button.h"
42 #include "wx/checkbox.h"
43 #include "wx/checklst.h"
44 #include "wx/listbox.h"
45 #include "wx/radiobox.h"
46 #include "wx/radiobut.h"
47 #include "wx/statbox.h"
48 #include "wx/stattext.h"
49 #include "wx/textctrl.h"
54 #ifdef __WXUNIVERSAL__
55 #include "wx/univ/theme.h"
56 #endif // __WXUNIVERSAL__
58 // ----------------------------------------------------------------------------
60 // ----------------------------------------------------------------------------
85 // ----------------------------------------------------------------------------
87 // ----------------------------------------------------------------------------
89 // Define a new application type, each program should derive a class from wxApp
90 class LboxTestApp
: public wxApp
93 // override base class virtuals
94 // ----------------------------
96 // this one is called on application startup and is a good place for the app
97 // initialization (doing it here and not in the ctor allows to have an error
98 // return: if OnInit() returns false, the application terminates)
99 virtual bool OnInit();
102 // Define a new frame type: this is going to be our main frame
103 class LboxTestFrame
: public wxFrame
107 LboxTestFrame(const wxString
& title
);
108 virtual ~LboxTestFrame();
112 void OnButtonReset(wxCommandEvent
& event
);
113 void OnButtonCreate(wxCommandEvent
& event
);
114 void OnButtonChange(wxCommandEvent
& event
);
115 void OnButtonDelete(wxCommandEvent
& event
);
116 void OnButtonDeleteSel(wxCommandEvent
& event
);
117 void OnButtonDeselectAll(wxCommandEvent
& event
);
118 void OnButtonClear(wxCommandEvent
& event
);
121 void OnButtonClearLog(wxCommandEvent
& event
);
123 void OnButtonAdd(wxCommandEvent
& event
);
124 void OnButtonAddSeveral(wxCommandEvent
& event
);
125 void OnButtonAddMany(wxCommandEvent
& event
);
126 void OnButtonQuit(wxCommandEvent
& event
);
128 void OnListbox(wxCommandEvent
& event
);
129 void OnListboxDClick(wxCommandEvent
& event
);
130 void OnListboxRDown(wxMouseEvent
& event
);
132 void OnCheckOrRadioBox(wxCommandEvent
& event
);
134 void OnUpdateUIAddSeveral(wxUpdateUIEvent
& event
);
135 void OnUpdateUICreateButton(wxUpdateUIEvent
& event
);
136 void OnUpdateUIClearButton(wxUpdateUIEvent
& event
);
137 void OnUpdateUIDeleteButton(wxUpdateUIEvent
& event
);
138 void OnUpdateUIDeleteSelButton(wxUpdateUIEvent
& event
);
139 void OnUpdateUIDeselectAllButton(wxUpdateUIEvent
& event
);
141 // reset the listbox parameters
144 // (re)create the listbox
147 // listbox parameters
148 // ------------------
150 // the selection mode
158 // should it be sorted?
161 // should it have horz scroll/vert scrollbar permanently shown?
165 // should the recreate button be enabled?
171 // the sel mode radiobox
172 wxRadioBox
*m_radioSelMode
;
175 wxCheckBox
*m_chkSort
,
179 // the listbox itself and the sizer it is in
181 wxSizer
*m_sizerLbox
;
183 // panel the controls such as the listbox are in
187 // the listbox for logging messages
188 wxListBox
*m_lboxLog
;
191 // the text entries for "Add/change string" and "Delete" buttons
192 wxTextCtrl
*m_textAdd
,
198 // the log target we use to redirect messages to the listbox
202 // any class wishing to process wxWidgets events must use this macro
203 DECLARE_EVENT_TABLE()
207 // A log target which just redirects the messages to a listbox
208 class LboxLogger
: public wxLog
211 LboxLogger(wxListBox
*lbox
, wxLog
*logOld
)
214 //m_lbox->Disable(); -- looks ugly under MSW
218 virtual ~LboxLogger()
220 wxLog::SetActiveTarget(m_logOld
);
224 // implement sink functions
225 virtual void DoLog(wxLogLevel level
, const wxChar
*szString
, time_t t
)
227 // don't put trace messages into listbox or we can get into infinite
229 if ( level
== wxLOG_Trace
)
233 // cast is needed to call protected method
234 ((LboxLogger
*)m_logOld
)->DoLog(level
, szString
, t
);
239 wxLog::DoLog(level
, szString
, t
);
243 virtual void DoLogString(const wxChar
*szString
, time_t WXUNUSED(t
))
248 #ifdef __WXUNIVERSAL__
249 m_lbox
->AppendAndEnsureVisible(msg
);
250 #else // other ports don't have this method yet
253 // SetFirstItem() isn't implemented in wxGTK
255 m_lbox
->SetFirstItem(m_lbox
->GetCount() - 1);
260 // the control we use
263 // the old log target
268 // ----------------------------------------------------------------------------
270 // ----------------------------------------------------------------------------
272 IMPLEMENT_APP(LboxTestApp
)
274 // ----------------------------------------------------------------------------
276 // ----------------------------------------------------------------------------
278 BEGIN_EVENT_TABLE(LboxTestFrame
, wxFrame
)
279 EVT_BUTTON(LboxTest_Reset
, LboxTestFrame::OnButtonReset
)
280 EVT_BUTTON(LboxTest_Create
, LboxTestFrame::OnButtonCreate
)
281 EVT_BUTTON(LboxTest_Change
, LboxTestFrame::OnButtonChange
)
282 EVT_BUTTON(LboxTest_Delete
, LboxTestFrame::OnButtonDelete
)
283 EVT_BUTTON(LboxTest_DeleteSel
, LboxTestFrame::OnButtonDeleteSel
)
284 EVT_BUTTON(LboxTest_DeselectAll
, LboxTestFrame::OnButtonDeselectAll
)
285 EVT_BUTTON(LboxTest_Clear
, LboxTestFrame::OnButtonClear
)
287 EVT_BUTTON(LboxTest_ClearLog
, LboxTestFrame::OnButtonClearLog
)
289 EVT_BUTTON(LboxTest_Add
, LboxTestFrame::OnButtonAdd
)
290 EVT_BUTTON(LboxTest_AddSeveral
, LboxTestFrame::OnButtonAddSeveral
)
291 EVT_BUTTON(LboxTest_AddMany
, LboxTestFrame::OnButtonAddMany
)
292 EVT_BUTTON(LboxTest_Quit
, LboxTestFrame::OnButtonQuit
)
294 EVT_TEXT_ENTER(LboxTest_AddText
, LboxTestFrame::OnButtonAdd
)
295 EVT_TEXT_ENTER(LboxTest_DeleteText
, LboxTestFrame::OnButtonDelete
)
297 EVT_UPDATE_UI_RANGE(LboxTest_Reset
, LboxTest_Create
,
298 LboxTestFrame::OnUpdateUICreateButton
)
300 EVT_UPDATE_UI(LboxTest_AddSeveral
, LboxTestFrame::OnUpdateUIAddSeveral
)
301 EVT_UPDATE_UI(LboxTest_Clear
, LboxTestFrame::OnUpdateUIClearButton
)
302 EVT_UPDATE_UI(LboxTest_DeleteText
, LboxTestFrame::OnUpdateUIClearButton
)
303 EVT_UPDATE_UI(LboxTest_Delete
, LboxTestFrame::OnUpdateUIDeleteButton
)
304 EVT_UPDATE_UI(LboxTest_Change
, LboxTestFrame::OnUpdateUIDeleteSelButton
)
305 EVT_UPDATE_UI(LboxTest_ChangeText
, LboxTestFrame::OnUpdateUIDeleteSelButton
)
306 EVT_UPDATE_UI(LboxTest_DeleteSel
, LboxTestFrame::OnUpdateUIDeleteSelButton
)
307 EVT_UPDATE_UI(LboxTest_DeselectAll
, LboxTestFrame::OnUpdateUIDeselectAllButton
)
309 EVT_LISTBOX(LboxTest_Listbox
, LboxTestFrame::OnListbox
)
310 EVT_LISTBOX_DCLICK(wxID_ANY
, LboxTestFrame::OnListboxDClick
)
311 EVT_CHECKBOX(wxID_ANY
, LboxTestFrame::OnCheckOrRadioBox
)
312 EVT_RADIOBOX(wxID_ANY
, LboxTestFrame::OnCheckOrRadioBox
)
315 // ============================================================================
317 // ============================================================================
319 // ----------------------------------------------------------------------------
321 // ----------------------------------------------------------------------------
323 bool LboxTestApp::OnInit()
325 wxFrame
*frame
= new LboxTestFrame(_T("wxListBox sample"));
329 //wxLog::AddTraceMask(_T("listbox"));
330 wxLog::AddTraceMask(_T("scrollbar"));
336 // ----------------------------------------------------------------------------
337 // top level frame class
338 // ----------------------------------------------------------------------------
340 LboxTestFrame::LboxTestFrame(const wxString
& title
)
341 : wxFrame(NULL
, wxID_ANY
, title
, wxPoint(100, 100))
345 m_radioSelMode
= (wxRadioBox
*)NULL
;
349 m_chkSort
= (wxCheckBox
*)NULL
;
351 m_lbox
= (wxListBox
*)NULL
;
353 m_lboxLog
= (wxListBox
*)NULL
;
355 m_sizerLbox
= (wxSizer
*)NULL
;
358 m_logTarget
= (wxLog
*)NULL
;
361 m_panel
= new wxPanel(this, wxID_ANY
);
364 What we create here is a frame having 3 panes: the explanatory pane to
365 the left allowing to set the listbox styles and recreate the control,
366 the pane containing the listbox itself and the lower pane containing
367 the buttons which allow to add/change/delete strings to/from it.
369 wxSizer
*sizerTop
= new wxBoxSizer(wxVERTICAL
),
370 *sizerUp
= new wxBoxSizer(wxHORIZONTAL
),
372 *sizerRight
= new wxBoxSizer(wxVERTICAL
);
375 static const wxString modes
[] =
382 wxStaticBox
*box
= new wxStaticBox(m_panel
, wxID_ANY
, _T("&Set listbox parameters"));
383 m_radioSelMode
= new wxRadioBox(m_panel
, wxID_ANY
, _T("Selection &mode:"),
384 wxDefaultPosition
, wxDefaultSize
,
385 WXSIZEOF(modes
), modes
,
386 1, wxRA_SPECIFY_COLS
);
388 m_chkVScroll
= new wxCheckBox(m_panel
, wxID_ANY
, _T("Always show &vertical scrollbar"));
389 m_chkHScroll
= new wxCheckBox(m_panel
, wxID_ANY
, _T("Show &horizontal scrollbar"));
390 m_chkSort
= new wxCheckBox(m_panel
, wxID_ANY
, _T("&Sort items"));
392 sizerLeft
= new wxStaticBoxSizer(box
, wxVERTICAL
);
394 sizerLeft
->Add(m_chkVScroll
, 0, wxLEFT
| wxRIGHT
, 5);
395 sizerLeft
->Add(m_chkHScroll
, 0, wxLEFT
| wxRIGHT
, 5);
396 sizerLeft
->Add(m_chkSort
, 0, wxLEFT
| wxRIGHT
, 5);
397 sizerLeft
->Add(5, 5, 0, wxGROW
| wxALL
, 5); // spacer
398 sizerLeft
->Add(m_radioSelMode
, 0, wxGROW
| wxALL
, 5);
400 wxSizer
*sizerBtn
= new wxBoxSizer(wxHORIZONTAL
);
401 wxButton
*btn
= new wxButton(m_panel
, LboxTest_Reset
, _T("&Reset"));
402 sizerBtn
->Add(btn
, 0, wxLEFT
| wxRIGHT
, 5);
403 btn
= new wxButton(m_panel
, LboxTest_Create
, _T("&Create"));
404 sizerBtn
->Add(btn
, 0, wxLEFT
| wxRIGHT
, 5);
405 sizerLeft
->Add(sizerBtn
, 0, wxALIGN_CENTRE_HORIZONTAL
| wxALL
, 15);
408 wxStaticBox
*box2
= new wxStaticBox(m_panel
, wxID_ANY
, _T("&Change listbox contents"));
409 wxSizer
*sizerMiddle
= new wxStaticBoxSizer(box2
, wxVERTICAL
);
411 wxSizer
*sizerRow
= new wxBoxSizer(wxHORIZONTAL
);
412 btn
= new wxButton(m_panel
, LboxTest_Add
, _T("&Add this string"));
413 m_textAdd
= new wxTextCtrl(m_panel
, LboxTest_AddText
, _T("test item 0"));
414 sizerRow
->Add(btn
, 0, wxRIGHT
, 5);
415 sizerRow
->Add(m_textAdd
, 1, wxLEFT
, 5);
416 sizerMiddle
->Add(sizerRow
, 0, wxALL
| wxGROW
, 5);
418 btn
= new wxButton(m_panel
, LboxTest_AddSeveral
, _T("&Insert a few strings"));
419 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
421 btn
= new wxButton(m_panel
, LboxTest_AddMany
, _T("Add &many strings"));
422 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
424 sizerRow
= new wxBoxSizer(wxHORIZONTAL
);
425 btn
= new wxButton(m_panel
, LboxTest_Change
, _T("C&hange current"));
426 m_textChange
= new wxTextCtrl(m_panel
, LboxTest_ChangeText
, wxEmptyString
);
427 sizerRow
->Add(btn
, 0, wxRIGHT
, 5);
428 sizerRow
->Add(m_textChange
, 1, wxLEFT
, 5);
429 sizerMiddle
->Add(sizerRow
, 0, wxALL
| wxGROW
, 5);
431 sizerRow
= new wxBoxSizer(wxHORIZONTAL
);
432 btn
= new wxButton(m_panel
, LboxTest_Delete
, _T("&Delete this item"));
433 m_textDelete
= new wxTextCtrl(m_panel
, LboxTest_DeleteText
, wxEmptyString
);
434 sizerRow
->Add(btn
, 0, wxRIGHT
, 5);
435 sizerRow
->Add(m_textDelete
, 1, wxLEFT
, 5);
436 sizerMiddle
->Add(sizerRow
, 0, wxALL
| wxGROW
, 5);
438 btn
= new wxButton(m_panel
, LboxTest_DeleteSel
, _T("Delete &selection"));
439 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
441 btn
= new wxButton(m_panel
, LboxTest_DeselectAll
, _T("Deselect All"));
442 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
444 btn
= new wxButton(m_panel
, LboxTest_Clear
, _T("&Clear"));
445 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
448 sizerRight
->SetMinSize(250, 0);
449 m_sizerLbox
= sizerRight
; // save it to modify it later
451 // the 3 panes panes compose the upper part of the window
452 sizerUp
->Add(sizerLeft
, 0, wxGROW
| (wxALL
& ~wxLEFT
), 10);
453 sizerUp
->Add(sizerMiddle
, 1, wxGROW
| wxALL
, 10);
454 sizerUp
->Add(sizerRight
, 1, wxGROW
| (wxALL
& ~wxRIGHT
), 10);
456 // the lower one only has the log listbox and a button to clear it
458 wxSizer
*sizerDown
= new wxStaticBoxSizer
460 new wxStaticBox(m_panel
, wxID_ANY
, _T("&Log window")),
463 m_lboxLog
= new wxListBox(m_panel
, wxID_ANY
);
464 sizerDown
->Add(m_lboxLog
, 1, wxGROW
| wxALL
, 5);
466 wxSizer
*sizerDown
= new wxBoxSizer(wxVERTICAL
);
468 wxBoxSizer
*sizerBtns
= new wxBoxSizer(wxHORIZONTAL
);
470 btn
= new wxButton(m_panel
, LboxTest_ClearLog
, _T("Clear &log"));
472 sizerBtns
->Add(10, 0); // spacer
474 btn
= new wxButton(m_panel
, LboxTest_Quit
, _T("E&xit"));
476 sizerDown
->Add(sizerBtns
, 0, wxALL
| wxALIGN_RIGHT
, 5);
478 // put everything together
479 sizerTop
->Add(sizerUp
, 1, wxGROW
| (wxALL
& ~wxBOTTOM
), 10);
480 sizerTop
->Add(0, 5, 0, wxGROW
); // spacer in between
481 sizerTop
->Add(sizerDown
, 0, wxGROW
| (wxALL
& ~wxTOP
), 10);
483 // final initialization and create the listbox
487 m_panel
->SetSizer(sizerTop
);
490 sizerTop
->SetSizeHints(this);
493 // now that everything is created we can redirect the log messages to the
495 m_logTarget
= new LboxLogger(m_lboxLog
, wxLog::GetActiveTarget());
496 wxLog::SetActiveTarget(m_logTarget
);
500 LboxTestFrame::~LboxTestFrame()
507 // ----------------------------------------------------------------------------
509 // ----------------------------------------------------------------------------
511 void LboxTestFrame::Reset()
513 if ( m_radioSelMode
->GetSelection() == LboxSel_Single
&&
514 !m_chkSort
->GetValue() &&
515 m_chkHScroll
->GetValue() &&
516 !m_chkVScroll
->GetValue() )
522 m_radioSelMode
->SetSelection(LboxSel_Single
);
523 m_chkSort
->SetValue(false);
524 m_chkHScroll
->SetValue(true);
525 m_chkVScroll
->SetValue(false);
530 void LboxTestFrame::CreateLbox()
533 switch ( m_radioSelMode
->GetSelection() )
536 wxFAIL_MSG( _T("unexpected radio box selection") );
538 case LboxSel_Single
: flags
|= wxLB_SINGLE
; break;
539 case LboxSel_Extended
: flags
|= wxLB_EXTENDED
; break;
540 case LboxSel_Multiple
: flags
|= wxLB_MULTIPLE
; break;
543 if ( m_chkVScroll
->GetValue() )
544 flags
|= wxLB_ALWAYS_SB
;
545 if ( m_chkHScroll
->GetValue() )
546 flags
|= wxLB_HSCROLL
;
547 if ( m_chkSort
->GetValue() )
552 if ( m_lbox
) // cache old items to restore later if listbox existed
554 int count
= m_lbox
->GetCount();
555 for ( int n
= 0; n
< count
; n
++ )
557 items
.Add(m_lbox
->GetString(n
));
560 m_sizerLbox
->Detach(m_lbox
);
564 m_lbox
= new wxListBox(m_panel
, LboxTest_Listbox
,
565 wxDefaultPosition
, wxDefaultSize
,
570 m_sizerLbox
->Add(m_lbox
, 1, wxGROW
| wxALL
, 5);
571 m_sizerLbox
->Layout();
575 m_lbox
->Connect(wxEVT_RIGHT_DOWN
,
576 wxMouseEventHandler(LboxTestFrame::OnListboxRDown
), NULL
, this);
579 // ----------------------------------------------------------------------------
581 // ----------------------------------------------------------------------------
583 void LboxTestFrame::OnButtonQuit(wxCommandEvent
& WXUNUSED(event
))
588 void LboxTestFrame::OnButtonReset(wxCommandEvent
& WXUNUSED(event
))
593 void LboxTestFrame::OnButtonCreate(wxCommandEvent
& WXUNUSED(event
))
598 void LboxTestFrame::OnButtonChange(wxCommandEvent
& WXUNUSED(event
))
600 wxArrayInt selections
;
601 int count
= m_lbox
->GetSelections(selections
);
602 wxString s
= m_textChange
->GetValue();
603 for ( int n
= 0; n
< count
; n
++ )
605 m_lbox
->SetString(selections
[n
], s
);
609 void LboxTestFrame::OnButtonDelete(wxCommandEvent
& WXUNUSED(event
))
612 if ( !m_textDelete
->GetValue().ToULong(&n
) ||
613 (n
>= (unsigned)m_lbox
->GetCount()) )
621 void LboxTestFrame::OnButtonDeleteSel(wxCommandEvent
& WXUNUSED(event
))
623 wxArrayInt selections
;
624 int n
= m_lbox
->GetSelections(selections
);
627 m_lbox
->Delete(selections
[--n
]);
631 void LboxTestFrame::OnButtonDeselectAll(wxCommandEvent
& WXUNUSED(event
))
633 m_lbox
->SetSelection(-1);
636 void LboxTestFrame::OnButtonClear(wxCommandEvent
& WXUNUSED(event
))
642 void LboxTestFrame::OnButtonClearLog(wxCommandEvent
& WXUNUSED(event
))
648 void LboxTestFrame::OnButtonAdd(wxCommandEvent
& WXUNUSED(event
))
650 static size_t s_item
= 0;
652 wxString s
= m_textAdd
->GetValue();
653 if ( !m_textAdd
->IsModified() )
655 // update the default string
656 m_textAdd
->SetValue(wxString::Format(_T("test item %u"), ++s_item
));
662 void LboxTestFrame::OnButtonAddMany(wxCommandEvent
& WXUNUSED(event
))
664 // "many" means 1000 here
665 for ( size_t n
= 0; n
< 1000; n
++ )
667 m_lbox
->Append(wxString::Format(_T("item #%u"), n
));
671 void LboxTestFrame::OnButtonAddSeveral(wxCommandEvent
& WXUNUSED(event
))
674 items
.Add(_T("First"));
675 items
.Add(_T("another one"));
676 items
.Add(_T("and the last (very very very very very very very very very very long) one"));
677 m_lbox
->InsertItems(items
, 0);
680 void LboxTestFrame::OnUpdateUICreateButton(wxUpdateUIEvent
& event
)
682 event
.Enable(m_dirty
);
685 void LboxTestFrame::OnUpdateUIDeleteButton(wxUpdateUIEvent
& event
)
688 event
.Enable(m_textDelete
->GetValue().ToULong(&n
) &&
689 (n
< (unsigned)m_lbox
->GetCount()));
692 void LboxTestFrame::OnUpdateUIDeleteSelButton(wxUpdateUIEvent
& event
)
694 wxArrayInt selections
;
695 event
.Enable(m_lbox
->GetSelections(selections
) != 0);
698 void LboxTestFrame::OnUpdateUIDeselectAllButton(wxUpdateUIEvent
& event
)
700 wxArrayInt selections
;
701 event
.Enable(m_lbox
->GetSelections(selections
) != 0);
704 void LboxTestFrame::OnUpdateUIClearButton(wxUpdateUIEvent
& event
)
706 event
.Enable(m_lbox
->GetCount() != 0);
709 void LboxTestFrame::OnUpdateUIAddSeveral(wxUpdateUIEvent
& event
)
711 event
.Enable(!(m_lbox
->GetWindowStyle() & wxLB_SORT
));
714 void LboxTestFrame::OnListbox(wxCommandEvent
& event
)
716 int sel
= event
.GetInt();
717 m_textDelete
->SetValue(wxString::Format(_T("%d"), sel
));
719 wxLogMessage(_T("Listbox item %d selected"), sel
);
722 void LboxTestFrame::OnListboxDClick(wxCommandEvent
& event
)
724 int sel
= event
.GetInt();
725 wxLogMessage(_T("Listbox item %d double clicked"), sel
);
728 void LboxTestFrame::OnListboxRDown(wxMouseEvent
& event
)
730 int item
= m_lbox
->HitTest(event
.GetPosition());
732 if ( item
!= wxNOT_FOUND
)
733 wxLogMessage(_T("Listbox item %d right clicked"), item
);
735 wxLogMessage(_T("Listbox right clicked but no item clicked upon"));
740 void LboxTestFrame::OnCheckOrRadioBox(wxCommandEvent
& WXUNUSED(event
))