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 // ----------------------------------------------------------------------------
84 // ----------------------------------------------------------------------------
86 // ----------------------------------------------------------------------------
88 // Define a new application type, each program should derive a class from wxApp
89 class LboxTestApp
: public wxApp
92 // override base class virtuals
93 // ----------------------------
95 // this one is called on application startup and is a good place for the app
96 // initialization (doing it here and not in the ctor allows to have an error
97 // return: if OnInit() returns false, the application terminates)
98 virtual bool OnInit();
101 // Define a new frame type: this is going to be our main frame
102 class LboxTestFrame
: public wxFrame
106 LboxTestFrame(const wxString
& title
);
107 virtual ~LboxTestFrame();
111 void OnButtonReset(wxCommandEvent
& event
);
112 void OnButtonCreate(wxCommandEvent
& event
);
113 void OnButtonChange(wxCommandEvent
& event
);
114 void OnButtonDelete(wxCommandEvent
& event
);
115 void OnButtonDeleteSel(wxCommandEvent
& event
);
116 void OnButtonClear(wxCommandEvent
& event
);
118 void OnButtonClearLog(wxCommandEvent
& event
);
120 void OnButtonAdd(wxCommandEvent
& event
);
121 void OnButtonAddSeveral(wxCommandEvent
& event
);
122 void OnButtonAddMany(wxCommandEvent
& event
);
123 void OnButtonQuit(wxCommandEvent
& event
);
125 void OnListbox(wxCommandEvent
& event
);
126 void OnListboxDClick(wxCommandEvent
& event
);
128 void OnCheckOrRadioBox(wxCommandEvent
& event
);
130 void OnUpdateUIAddSeveral(wxUpdateUIEvent
& event
);
131 void OnUpdateUICreateButton(wxUpdateUIEvent
& event
);
132 void OnUpdateUIClearButton(wxUpdateUIEvent
& event
);
133 void OnUpdateUIDeleteButton(wxUpdateUIEvent
& event
);
134 void OnUpdateUIDeleteSelButton(wxUpdateUIEvent
& event
);
136 // reset the listbox parameters
139 // (re)create the listbox
142 // listbox parameters
143 // ------------------
145 // the selection mode
153 // should it be sorted?
156 // should it have horz scroll/vert scrollbar permanently shown?
160 // should the recreate button be enabled?
166 // the sel mode radiobox
167 wxRadioBox
*m_radioSelMode
;
170 wxCheckBox
*m_chkSort
,
174 // the listbox itself and the sizer it is in
176 wxSizer
*m_sizerLbox
;
179 // the listbox for logging messages
180 wxListBox
*m_lboxLog
;
183 // the text entries for "Add/change string" and "Delete" buttons
184 wxTextCtrl
*m_textAdd
,
190 // the log target we use to redirect messages to the listbox
194 // any class wishing to process wxWidgets events must use this macro
195 DECLARE_EVENT_TABLE()
199 // A log target which just redirects the messages to a listbox
200 class LboxLogger
: public wxLog
203 LboxLogger(wxListBox
*lbox
, wxLog
*logOld
)
206 //m_lbox->Disable(); -- looks ugly under MSW
210 virtual ~LboxLogger()
212 wxLog::SetActiveTarget(m_logOld
);
216 // implement sink functions
217 virtual void DoLog(wxLogLevel level
, const wxChar
*szString
, time_t t
)
219 // don't put trace messages into listbox or we can get into infinite
221 if ( level
== wxLOG_Trace
)
225 // cast is needed to call protected method
226 ((LboxLogger
*)m_logOld
)->DoLog(level
, szString
, t
);
231 wxLog::DoLog(level
, szString
, t
);
235 virtual void DoLogString(const wxChar
*szString
, time_t WXUNUSED(t
))
240 #ifdef __WXUNIVERSAL__
241 m_lbox
->AppendAndEnsureVisible(msg
);
242 #else // other ports don't have this method yet
245 // SetFirstItem() isn't implemented in wxGTK
247 m_lbox
->SetFirstItem(m_lbox
->GetCount() - 1);
252 // the control we use
255 // the old log target
260 // ----------------------------------------------------------------------------
262 // ----------------------------------------------------------------------------
264 IMPLEMENT_APP(LboxTestApp
)
266 // ----------------------------------------------------------------------------
268 // ----------------------------------------------------------------------------
270 BEGIN_EVENT_TABLE(LboxTestFrame
, wxFrame
)
271 EVT_BUTTON(LboxTest_Reset
, LboxTestFrame::OnButtonReset
)
272 EVT_BUTTON(LboxTest_Create
, LboxTestFrame::OnButtonCreate
)
273 EVT_BUTTON(LboxTest_Change
, LboxTestFrame::OnButtonChange
)
274 EVT_BUTTON(LboxTest_Delete
, LboxTestFrame::OnButtonDelete
)
275 EVT_BUTTON(LboxTest_DeleteSel
, LboxTestFrame::OnButtonDeleteSel
)
276 EVT_BUTTON(LboxTest_Clear
, LboxTestFrame::OnButtonClear
)
278 EVT_BUTTON(LboxTest_ClearLog
, LboxTestFrame::OnButtonClearLog
)
280 EVT_BUTTON(LboxTest_Add
, LboxTestFrame::OnButtonAdd
)
281 EVT_BUTTON(LboxTest_AddSeveral
, LboxTestFrame::OnButtonAddSeveral
)
282 EVT_BUTTON(LboxTest_AddMany
, LboxTestFrame::OnButtonAddMany
)
283 EVT_BUTTON(LboxTest_Quit
, LboxTestFrame::OnButtonQuit
)
285 EVT_TEXT_ENTER(LboxTest_AddText
, LboxTestFrame::OnButtonAdd
)
286 EVT_TEXT_ENTER(LboxTest_DeleteText
, LboxTestFrame::OnButtonDelete
)
288 EVT_UPDATE_UI_RANGE(LboxTest_Reset
, LboxTest_Create
,
289 LboxTestFrame::OnUpdateUICreateButton
)
291 EVT_UPDATE_UI(LboxTest_AddSeveral
, LboxTestFrame::OnUpdateUIAddSeveral
)
292 EVT_UPDATE_UI(LboxTest_Clear
, LboxTestFrame::OnUpdateUIClearButton
)
293 EVT_UPDATE_UI(LboxTest_DeleteText
, LboxTestFrame::OnUpdateUIClearButton
)
294 EVT_UPDATE_UI(LboxTest_Delete
, LboxTestFrame::OnUpdateUIDeleteButton
)
295 EVT_UPDATE_UI(LboxTest_Change
, LboxTestFrame::OnUpdateUIDeleteSelButton
)
296 EVT_UPDATE_UI(LboxTest_ChangeText
, LboxTestFrame::OnUpdateUIDeleteSelButton
)
297 EVT_UPDATE_UI(LboxTest_DeleteSel
, LboxTestFrame::OnUpdateUIDeleteSelButton
)
299 EVT_LISTBOX(LboxTest_Listbox
, LboxTestFrame::OnListbox
)
300 EVT_LISTBOX_DCLICK(wxID_ANY
, LboxTestFrame::OnListboxDClick
)
301 EVT_CHECKBOX(wxID_ANY
, LboxTestFrame::OnCheckOrRadioBox
)
302 EVT_RADIOBOX(wxID_ANY
, LboxTestFrame::OnCheckOrRadioBox
)
305 // ============================================================================
307 // ============================================================================
309 // ----------------------------------------------------------------------------
311 // ----------------------------------------------------------------------------
313 bool LboxTestApp::OnInit()
315 wxFrame
*frame
= new LboxTestFrame(_T("wxListBox sample"));
319 //wxLog::AddTraceMask(_T("listbox"));
320 wxLog::AddTraceMask(_T("scrollbar"));
326 // ----------------------------------------------------------------------------
327 // top level frame class
328 // ----------------------------------------------------------------------------
330 LboxTestFrame::LboxTestFrame(const wxString
& title
)
331 : wxFrame(NULL
, wxID_ANY
, title
, wxPoint(100, 100))
335 m_radioSelMode
= (wxRadioBox
*)NULL
;
339 m_chkSort
= (wxCheckBox
*)NULL
;
341 m_lbox
= (wxListBox
*)NULL
;
343 m_lboxLog
= (wxListBox
*)NULL
;
345 m_sizerLbox
= (wxSizer
*)NULL
;
348 m_logTarget
= (wxLog
*)NULL
;
351 wxPanel
*panel
= new wxPanel(this, wxID_ANY
);
354 What we create here is a frame having 3 panes: the explanatory pane to
355 the left allowing to set the listbox styles and recreate the control,
356 the pane containing the listbox itself and the lower pane containing
357 the buttons which allow to add/change/delete strings to/from it.
359 wxSizer
*sizerTop
= new wxBoxSizer(wxVERTICAL
),
360 *sizerUp
= new wxBoxSizer(wxHORIZONTAL
),
362 *sizerRight
= new wxBoxSizer(wxVERTICAL
);
365 static const wxString modes
[] =
372 wxStaticBox
*box
= new wxStaticBox(panel
, wxID_ANY
, _T("&Set listbox parameters"));
373 m_radioSelMode
= new wxRadioBox(panel
, wxID_ANY
, _T("Selection &mode:"),
374 wxDefaultPosition
, wxDefaultSize
,
375 WXSIZEOF(modes
), modes
,
376 1, wxRA_SPECIFY_COLS
);
378 m_chkVScroll
= new wxCheckBox(panel
, wxID_ANY
, _T("Always show &vertical scrollbar"));
379 m_chkHScroll
= new wxCheckBox(panel
, wxID_ANY
, _T("Show &horizontal scrollbar"));
380 m_chkSort
= new wxCheckBox(panel
, wxID_ANY
, _T("&Sort items"));
382 sizerLeft
= new wxStaticBoxSizer(box
, wxVERTICAL
);
384 sizerLeft
->Add(m_chkVScroll
, 0, wxLEFT
| wxRIGHT
, 5);
385 sizerLeft
->Add(m_chkHScroll
, 0, wxLEFT
| wxRIGHT
, 5);
386 sizerLeft
->Add(m_chkSort
, 0, wxLEFT
| wxRIGHT
, 5);
387 sizerLeft
->Add(5, 5, 0, wxGROW
| wxALL
, 5); // spacer
388 sizerLeft
->Add(m_radioSelMode
, 0, wxGROW
| wxALL
, 5);
390 wxSizer
*sizerBtn
= new wxBoxSizer(wxHORIZONTAL
);
391 wxButton
*btn
= new wxButton(panel
, LboxTest_Reset
, _T("&Reset"));
392 sizerBtn
->Add(btn
, 0, wxLEFT
| wxRIGHT
, 5);
393 btn
= new wxButton(panel
, LboxTest_Create
, _T("&Create"));
394 sizerBtn
->Add(btn
, 0, wxLEFT
| wxRIGHT
, 5);
395 sizerLeft
->Add(sizerBtn
, 0, wxALIGN_CENTRE_HORIZONTAL
| wxALL
, 15);
398 wxStaticBox
*box2
= new wxStaticBox(panel
, wxID_ANY
, _T("&Change listbox contents"));
399 wxSizer
*sizerMiddle
= new wxStaticBoxSizer(box2
, wxVERTICAL
);
401 wxSizer
*sizerRow
= new wxBoxSizer(wxHORIZONTAL
);
402 btn
= new wxButton(panel
, LboxTest_Add
, _T("&Add this string"));
403 m_textAdd
= new wxTextCtrl(panel
, LboxTest_AddText
, _T("test item 0"));
404 sizerRow
->Add(btn
, 0, wxRIGHT
, 5);
405 sizerRow
->Add(m_textAdd
, 1, wxLEFT
, 5);
406 sizerMiddle
->Add(sizerRow
, 0, wxALL
| wxGROW
, 5);
408 btn
= new wxButton(panel
, LboxTest_AddSeveral
, _T("&Insert a few strings"));
409 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
411 btn
= new wxButton(panel
, LboxTest_AddMany
, _T("Add &many strings"));
412 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
414 sizerRow
= new wxBoxSizer(wxHORIZONTAL
);
415 btn
= new wxButton(panel
, LboxTest_Change
, _T("C&hange current"));
416 m_textChange
= new wxTextCtrl(panel
, LboxTest_ChangeText
, wxEmptyString
);
417 sizerRow
->Add(btn
, 0, wxRIGHT
, 5);
418 sizerRow
->Add(m_textChange
, 1, wxLEFT
, 5);
419 sizerMiddle
->Add(sizerRow
, 0, wxALL
| wxGROW
, 5);
421 sizerRow
= new wxBoxSizer(wxHORIZONTAL
);
422 btn
= new wxButton(panel
, LboxTest_Delete
, _T("&Delete this item"));
423 m_textDelete
= new wxTextCtrl(panel
, LboxTest_DeleteText
, wxEmptyString
);
424 sizerRow
->Add(btn
, 0, wxRIGHT
, 5);
425 sizerRow
->Add(m_textDelete
, 1, wxLEFT
, 5);
426 sizerMiddle
->Add(sizerRow
, 0, wxALL
| wxGROW
, 5);
428 btn
= new wxButton(panel
, LboxTest_DeleteSel
, _T("Delete &selection"));
429 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
431 btn
= new wxButton(panel
, LboxTest_Clear
, _T("&Clear"));
432 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
435 m_lbox
= new wxListBox(panel
, LboxTest_Listbox
,
436 wxDefaultPosition
, wxDefaultSize
,
439 sizerRight
->Add(m_lbox
, 1, wxGROW
| wxALL
, 5);
440 sizerRight
->SetMinSize(250, 0);
441 m_sizerLbox
= sizerRight
; // save it to modify it later
443 // the 3 panes panes compose the upper part of the window
444 sizerUp
->Add(sizerLeft
, 0, wxGROW
| (wxALL
& ~wxLEFT
), 10);
445 sizerUp
->Add(sizerMiddle
, 1, wxGROW
| wxALL
, 10);
446 sizerUp
->Add(sizerRight
, 1, wxGROW
| (wxALL
& ~wxRIGHT
), 10);
448 // the lower one only has the log listbox and a button to clear it
450 wxSizer
*sizerDown
= new wxStaticBoxSizer
452 new wxStaticBox(panel
, wxID_ANY
, _T("&Log window")),
455 m_lboxLog
= new wxListBox(panel
, wxID_ANY
);
456 sizerDown
->Add(m_lboxLog
, 1, wxGROW
| wxALL
, 5);
458 wxSizer
*sizerDown
= new wxBoxSizer(wxVERTICAL
);
460 wxBoxSizer
*sizerBtns
= new wxBoxSizer(wxHORIZONTAL
);
462 btn
= new wxButton(panel
, LboxTest_ClearLog
, _T("Clear &log"));
464 sizerBtns
->Add(10, 0); // spacer
466 btn
= new wxButton(panel
, LboxTest_Quit
, _T("E&xit"));
468 sizerDown
->Add(sizerBtns
, 0, wxALL
| wxALIGN_RIGHT
, 5);
470 // put everything together
471 sizerTop
->Add(sizerUp
, 1, wxGROW
| (wxALL
& ~wxBOTTOM
), 10);
472 sizerTop
->Add(0, 5, 0, wxGROW
); // spacer in between
473 sizerTop
->Add(sizerDown
, 0, wxGROW
| (wxALL
& ~wxTOP
), 10);
475 // final initialization
479 panel
->SetSizer(sizerTop
);
482 sizerTop
->SetSizeHints(this);
485 // now that everything is created we can redirect the log messages to the
487 m_logTarget
= new LboxLogger(m_lboxLog
, wxLog::GetActiveTarget());
488 wxLog::SetActiveTarget(m_logTarget
);
492 LboxTestFrame::~LboxTestFrame()
499 // ----------------------------------------------------------------------------
501 // ----------------------------------------------------------------------------
503 void LboxTestFrame::Reset()
505 if ( m_radioSelMode
->GetSelection() == LboxSel_Single
&&
506 !m_chkSort
->GetValue() &&
507 m_chkHScroll
->GetValue() &&
508 !m_chkVScroll
->GetValue() )
514 m_radioSelMode
->SetSelection(LboxSel_Single
);
515 m_chkSort
->SetValue(false);
516 m_chkHScroll
->SetValue(true);
517 m_chkVScroll
->SetValue(false);
522 void LboxTestFrame::CreateLbox()
524 wxWindow
*parent
= m_lbox
->GetParent();
526 switch ( m_radioSelMode
->GetSelection() )
529 wxFAIL_MSG( _T("unexpected radio box selection") );
531 case LboxSel_Single
: flags
|= wxLB_SINGLE
; break;
532 case LboxSel_Extended
: flags
|= wxLB_EXTENDED
; break;
533 case LboxSel_Multiple
: flags
|= wxLB_MULTIPLE
; break;
536 if ( m_chkVScroll
->GetValue() )
537 flags
|= wxLB_ALWAYS_SB
;
538 if ( m_chkHScroll
->GetValue() )
539 flags
|= wxLB_HSCROLL
;
540 if ( m_chkSort
->GetValue() )
544 int count
= m_lbox
->GetCount();
545 for ( int n
= 0; n
< count
; n
++ )
547 items
.Add(m_lbox
->GetString(n
));
550 m_sizerLbox
->Detach(m_lbox
);
553 m_lbox
= new wxListBox(parent
, LboxTest_Listbox
,
554 wxDefaultPosition
, wxDefaultSize
,
558 m_sizerLbox
->Add(m_lbox
, 1, wxGROW
| wxALL
, 5);
559 m_sizerLbox
->Layout();
564 // ----------------------------------------------------------------------------
566 // ----------------------------------------------------------------------------
568 void LboxTestFrame::OnButtonQuit(wxCommandEvent
& WXUNUSED(event
))
573 void LboxTestFrame::OnButtonReset(wxCommandEvent
& WXUNUSED(event
))
578 void LboxTestFrame::OnButtonCreate(wxCommandEvent
& WXUNUSED(event
))
583 void LboxTestFrame::OnButtonChange(wxCommandEvent
& WXUNUSED(event
))
585 wxArrayInt selections
;
586 int count
= m_lbox
->GetSelections(selections
);
587 wxString s
= m_textChange
->GetValue();
588 for ( int n
= 0; n
< count
; n
++ )
590 m_lbox
->SetString(selections
[n
], s
);
594 void LboxTestFrame::OnButtonDelete(wxCommandEvent
& WXUNUSED(event
))
597 if ( !m_textDelete
->GetValue().ToULong(&n
) ||
598 (n
>= (unsigned)m_lbox
->GetCount()) )
606 void LboxTestFrame::OnButtonDeleteSel(wxCommandEvent
& WXUNUSED(event
))
608 wxArrayInt selections
;
609 int n
= m_lbox
->GetSelections(selections
);
612 m_lbox
->Delete(selections
[--n
]);
616 void LboxTestFrame::OnButtonClear(wxCommandEvent
& WXUNUSED(event
))
622 void LboxTestFrame::OnButtonClearLog(wxCommandEvent
& WXUNUSED(event
))
628 void LboxTestFrame::OnButtonAdd(wxCommandEvent
& WXUNUSED(event
))
630 static size_t s_item
= 0;
632 wxString s
= m_textAdd
->GetValue();
633 if ( !m_textAdd
->IsModified() )
635 // update the default string
636 m_textAdd
->SetValue(wxString::Format(_T("test item %u"), ++s_item
));
642 void LboxTestFrame::OnButtonAddMany(wxCommandEvent
& WXUNUSED(event
))
644 // "many" means 1000 here
645 for ( size_t n
= 0; n
< 1000; n
++ )
647 m_lbox
->Append(wxString::Format(_T("item #%u"), n
));
651 void LboxTestFrame::OnButtonAddSeveral(wxCommandEvent
& WXUNUSED(event
))
654 items
.Add(_T("First"));
655 items
.Add(_T("another one"));
656 items
.Add(_T("and the last (very very very very very very very very very very long) one"));
657 m_lbox
->InsertItems(items
, 0);
660 void LboxTestFrame::OnUpdateUICreateButton(wxUpdateUIEvent
& event
)
662 event
.Enable(m_dirty
);
665 void LboxTestFrame::OnUpdateUIDeleteButton(wxUpdateUIEvent
& event
)
668 event
.Enable(m_textDelete
->GetValue().ToULong(&n
) &&
669 (n
< (unsigned)m_lbox
->GetCount()));
672 void LboxTestFrame::OnUpdateUIDeleteSelButton(wxUpdateUIEvent
& event
)
674 wxArrayInt selections
;
675 event
.Enable(m_lbox
->GetSelections(selections
) != 0);
678 void LboxTestFrame::OnUpdateUIClearButton(wxUpdateUIEvent
& event
)
680 event
.Enable(m_lbox
->GetCount() != 0);
683 void LboxTestFrame::OnUpdateUIAddSeveral(wxUpdateUIEvent
& event
)
685 event
.Enable(!(m_lbox
->GetWindowStyle() & wxLB_SORT
));
688 void LboxTestFrame::OnListbox(wxCommandEvent
& event
)
690 int sel
= event
.GetInt();
691 m_textDelete
->SetValue(wxString::Format(_T("%d"), sel
));
693 wxLogMessage(_T("Listbox item %d selected"), sel
);
696 void LboxTestFrame::OnListboxDClick(wxCommandEvent
& event
)
698 int sel
= event
.GetInt();
699 wxLogMessage(_T("Listbox item %d double clicked"), sel
);
702 void LboxTestFrame::OnCheckOrRadioBox(wxCommandEvent
& WXUNUSED(event
))