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 // ============================================================================
24 #pragma implementation "lboxtest.cpp"
25 #pragma interface "lboxtest.cpp"
28 // ----------------------------------------------------------------------------
30 // ----------------------------------------------------------------------------
32 // for compilers that support precompilation, includes "wx/wx.h".
33 #include "wx/wxprec.h"
39 // for all others, include the necessary headers
44 #include "wx/dcclient.h"
46 #include "wx/button.h"
47 #include "wx/checkbox.h"
48 #include "wx/checklst.h"
49 #include "wx/listbox.h"
50 #include "wx/radiobox.h"
51 #include "wx/radiobut.h"
52 #include "wx/statbox.h"
53 #include "wx/stattext.h"
54 #include "wx/textctrl.h"
59 #ifdef __WXUNIVERSAL__
60 #include "wx/univ/theme.h"
61 #endif // __WXUNIVERSAL__
63 // ----------------------------------------------------------------------------
65 // ----------------------------------------------------------------------------
87 // ----------------------------------------------------------------------------
89 // ----------------------------------------------------------------------------
91 // Define a new application type, each program should derive a class from wxApp
92 class LboxTestApp
: public wxApp
95 // override base class virtuals
96 // ----------------------------
98 // this one is called on application startup and is a good place for the app
99 // initialization (doing it here and not in the ctor allows to have an error
100 // return: if OnInit() returns false, the application terminates)
101 virtual bool OnInit();
104 // Define a new frame type: this is going to be our main frame
105 class LboxTestFrame
: public wxFrame
109 LboxTestFrame(const wxString
& title
);
110 virtual ~LboxTestFrame();
114 void OnButtonReset(wxCommandEvent
& event
);
115 void OnButtonCreate(wxCommandEvent
& event
);
116 void OnButtonChange(wxCommandEvent
& event
);
117 void OnButtonDelete(wxCommandEvent
& event
);
118 void OnButtonDeleteSel(wxCommandEvent
& event
);
119 void OnButtonClear(wxCommandEvent
& event
);
120 void OnButtonClearLog(wxCommandEvent
& event
);
121 void OnButtonAdd(wxCommandEvent
& event
);
122 void OnButtonAddSeveral(wxCommandEvent
& event
);
123 void OnButtonAddMany(wxCommandEvent
& event
);
124 void OnButtonQuit(wxCommandEvent
& event
);
126 void OnListbox(wxCommandEvent
& event
);
127 void OnListboxDClick(wxCommandEvent
& event
);
129 void OnCheckOrRadioBox(wxCommandEvent
& event
);
131 void OnUpdateUIAddSeveral(wxUpdateUIEvent
& event
);
132 void OnUpdateUICreateButton(wxUpdateUIEvent
& event
);
133 void OnUpdateUIClearButton(wxUpdateUIEvent
& event
);
134 void OnUpdateUIDeleteButton(wxUpdateUIEvent
& event
);
135 void OnUpdateUIDeleteSelButton(wxUpdateUIEvent
& event
);
137 // reset the listbox parameters
140 // (re)create the listbox
143 // listbox parameters
144 // ------------------
146 // the selection mode
154 // should it be sorted?
157 // should it have horz scroll/vert scrollbar permanently shown?
161 // should the recreate button be enabled?
167 // the sel mode radiobox
168 wxRadioBox
*m_radioSelMode
;
171 wxCheckBox
*m_chkSort
,
175 // the listbox itself and the sizer it is in
177 wxSizer
*m_sizerLbox
;
179 // the listbox for logging messages
180 wxListBox
*m_lboxLog
;
182 // the text entries for "Add/change string" and "Delete" buttons
183 wxTextCtrl
*m_textAdd
,
188 // the log target we use to redirect messages to the listbox
191 // any class wishing to process wxWidgets events must use this macro
192 DECLARE_EVENT_TABLE()
195 // A log target which just redirects the messages to a listbox
196 class LboxLogger
: public wxLog
199 LboxLogger(wxListBox
*lbox
, wxLog
*logOld
)
202 //m_lbox->Disable(); -- looks ugly under MSW
206 virtual ~LboxLogger()
208 wxLog::SetActiveTarget(m_logOld
);
212 // implement sink functions
213 virtual void DoLog(wxLogLevel level
, const wxChar
*szString
, time_t t
)
215 // don't put trace messages into listbox or we can get into infinite
217 if ( level
== wxLOG_Trace
)
221 // cast is needed to call protected method
222 ((LboxLogger
*)m_logOld
)->DoLog(level
, szString
, t
);
227 wxLog::DoLog(level
, szString
, t
);
231 virtual void DoLogString(const wxChar
*szString
, time_t WXUNUSED(t
))
236 #ifdef __WXUNIVERSAL__
237 m_lbox
->AppendAndEnsureVisible(msg
);
238 #else // other ports don't have this method yet
241 // SetFirstItem() isn't implemented in wxGTK
243 m_lbox
->SetFirstItem(m_lbox
->GetCount() - 1);
248 // the control we use
251 // the old log target
255 // ----------------------------------------------------------------------------
257 // ----------------------------------------------------------------------------
259 IMPLEMENT_APP(LboxTestApp
)
261 // ----------------------------------------------------------------------------
263 // ----------------------------------------------------------------------------
265 BEGIN_EVENT_TABLE(LboxTestFrame
, wxFrame
)
266 EVT_BUTTON(LboxTest_Reset
, LboxTestFrame::OnButtonReset
)
267 EVT_BUTTON(LboxTest_Create
, LboxTestFrame::OnButtonCreate
)
268 EVT_BUTTON(LboxTest_Change
, LboxTestFrame::OnButtonChange
)
269 EVT_BUTTON(LboxTest_Delete
, LboxTestFrame::OnButtonDelete
)
270 EVT_BUTTON(LboxTest_DeleteSel
, LboxTestFrame::OnButtonDeleteSel
)
271 EVT_BUTTON(LboxTest_Clear
, LboxTestFrame::OnButtonClear
)
272 EVT_BUTTON(LboxTest_ClearLog
, LboxTestFrame::OnButtonClearLog
)
273 EVT_BUTTON(LboxTest_Add
, LboxTestFrame::OnButtonAdd
)
274 EVT_BUTTON(LboxTest_AddSeveral
, LboxTestFrame::OnButtonAddSeveral
)
275 EVT_BUTTON(LboxTest_AddMany
, LboxTestFrame::OnButtonAddMany
)
276 EVT_BUTTON(LboxTest_Quit
, LboxTestFrame::OnButtonQuit
)
278 EVT_TEXT_ENTER(LboxTest_AddText
, LboxTestFrame::OnButtonAdd
)
279 EVT_TEXT_ENTER(LboxTest_DeleteText
, LboxTestFrame::OnButtonDelete
)
281 EVT_UPDATE_UI_RANGE(LboxTest_Reset
, LboxTest_Create
,
282 LboxTestFrame::OnUpdateUICreateButton
)
284 EVT_UPDATE_UI(LboxTest_AddSeveral
, LboxTestFrame::OnUpdateUIAddSeveral
)
285 EVT_UPDATE_UI(LboxTest_Clear
, LboxTestFrame::OnUpdateUIClearButton
)
286 EVT_UPDATE_UI(LboxTest_DeleteText
, LboxTestFrame::OnUpdateUIClearButton
)
287 EVT_UPDATE_UI(LboxTest_Delete
, LboxTestFrame::OnUpdateUIDeleteButton
)
288 EVT_UPDATE_UI(LboxTest_Change
, LboxTestFrame::OnUpdateUIDeleteSelButton
)
289 EVT_UPDATE_UI(LboxTest_ChangeText
, LboxTestFrame::OnUpdateUIDeleteSelButton
)
290 EVT_UPDATE_UI(LboxTest_DeleteSel
, LboxTestFrame::OnUpdateUIDeleteSelButton
)
292 EVT_LISTBOX(LboxTest_Listbox
, LboxTestFrame::OnListbox
)
293 EVT_LISTBOX_DCLICK(wxID_ANY
, LboxTestFrame::OnListboxDClick
)
294 EVT_CHECKBOX(wxID_ANY
, LboxTestFrame::OnCheckOrRadioBox
)
295 EVT_RADIOBOX(wxID_ANY
, LboxTestFrame::OnCheckOrRadioBox
)
298 // ============================================================================
300 // ============================================================================
302 // ----------------------------------------------------------------------------
304 // ----------------------------------------------------------------------------
306 bool LboxTestApp::OnInit()
308 wxFrame
*frame
= new LboxTestFrame(_T("wxListBox sample"));
311 //wxLog::AddTraceMask(_T("listbox"));
312 wxLog::AddTraceMask(_T("scrollbar"));
317 // ----------------------------------------------------------------------------
318 // top level frame class
319 // ----------------------------------------------------------------------------
321 LboxTestFrame::LboxTestFrame(const wxString
& title
)
322 : wxFrame(NULL
, wxID_ANY
, title
, wxPoint(100, 100))
326 m_radioSelMode
= (wxRadioBox
*)NULL
;
330 m_chkSort
= (wxCheckBox
*)NULL
;
333 m_lboxLog
= (wxListBox
*)NULL
;
334 m_sizerLbox
= (wxSizer
*)NULL
;
336 m_logTarget
= (wxLog
*)NULL
;
338 wxPanel
*panel
= new wxPanel(this, wxID_ANY
);
341 What we create here is a frame having 3 panes: the explanatory pane to
342 the left allowing to set the listbox styles and recreate the control,
343 the pane containing the listbox itself and the lower pane containing
344 the buttons which allow to add/change/delete strings to/from it.
346 wxSizer
*sizerTop
= new wxBoxSizer(wxVERTICAL
),
347 *sizerUp
= new wxBoxSizer(wxHORIZONTAL
),
349 *sizerRight
= new wxBoxSizer(wxVERTICAL
);
352 static const wxString modes
[] =
359 wxStaticBox
*box
= new wxStaticBox(panel
, wxID_ANY
, _T("&Set listbox parameters"));
360 m_radioSelMode
= new wxRadioBox(panel
, wxID_ANY
, _T("Selection &mode:"),
361 wxDefaultPosition
, wxDefaultSize
,
362 WXSIZEOF(modes
), modes
,
363 1, wxRA_SPECIFY_COLS
);
365 m_chkVScroll
= new wxCheckBox(panel
, wxID_ANY
, _T("Always show &vertical scrollbar"));
366 m_chkHScroll
= new wxCheckBox(panel
, wxID_ANY
, _T("Show &horizontal scrollbar"));
367 m_chkSort
= new wxCheckBox(panel
, wxID_ANY
, _T("&Sort items"));
369 sizerLeft
= new wxStaticBoxSizer(box
, wxVERTICAL
);
371 sizerLeft
->Add(m_chkVScroll
, 0, wxLEFT
| wxRIGHT
, 5);
372 sizerLeft
->Add(m_chkHScroll
, 0, wxLEFT
| wxRIGHT
, 5);
373 sizerLeft
->Add(m_chkSort
, 0, wxLEFT
| wxRIGHT
, 5);
374 sizerLeft
->Add(5, 5, 0, wxGROW
| wxALL
, 5); // spacer
375 sizerLeft
->Add(m_radioSelMode
, 0, wxGROW
| wxALL
, 5);
377 wxSizer
*sizerBtn
= new wxBoxSizer(wxHORIZONTAL
);
378 wxButton
*btn
= new wxButton(panel
, LboxTest_Reset
, _T("&Reset"));
379 sizerBtn
->Add(btn
, 0, wxLEFT
| wxRIGHT
, 5);
380 btn
= new wxButton(panel
, LboxTest_Create
, _T("&Create"));
381 sizerBtn
->Add(btn
, 0, wxLEFT
| wxRIGHT
, 5);
382 sizerLeft
->Add(sizerBtn
, 0, wxALIGN_CENTRE_HORIZONTAL
| wxALL
, 15);
385 wxStaticBox
*box2
= new wxStaticBox(panel
, wxID_ANY
, _T("&Change listbox contents"));
386 wxSizer
*sizerMiddle
= new wxStaticBoxSizer(box2
, wxVERTICAL
);
388 wxSizer
*sizerRow
= new wxBoxSizer(wxHORIZONTAL
);
389 btn
= new wxButton(panel
, LboxTest_Add
, _T("&Add this string"));
390 m_textAdd
= new wxTextCtrl(panel
, LboxTest_AddText
, _T("test item 0"));
391 sizerRow
->Add(btn
, 0, wxRIGHT
, 5);
392 sizerRow
->Add(m_textAdd
, 1, wxLEFT
, 5);
393 sizerMiddle
->Add(sizerRow
, 0, wxALL
| wxGROW
, 5);
395 btn
= new wxButton(panel
, LboxTest_AddSeveral
, _T("&Insert a few strings"));
396 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
398 btn
= new wxButton(panel
, LboxTest_AddMany
, _T("Add &many strings"));
399 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
401 sizerRow
= new wxBoxSizer(wxHORIZONTAL
);
402 btn
= new wxButton(panel
, LboxTest_Change
, _T("C&hange current"));
403 m_textChange
= new wxTextCtrl(panel
, LboxTest_ChangeText
, wxEmptyString
);
404 sizerRow
->Add(btn
, 0, wxRIGHT
, 5);
405 sizerRow
->Add(m_textChange
, 1, wxLEFT
, 5);
406 sizerMiddle
->Add(sizerRow
, 0, wxALL
| wxGROW
, 5);
408 sizerRow
= new wxBoxSizer(wxHORIZONTAL
);
409 btn
= new wxButton(panel
, LboxTest_Delete
, _T("&Delete this item"));
410 m_textDelete
= new wxTextCtrl(panel
, LboxTest_DeleteText
, wxEmptyString
);
411 sizerRow
->Add(btn
, 0, wxRIGHT
, 5);
412 sizerRow
->Add(m_textDelete
, 1, wxLEFT
, 5);
413 sizerMiddle
->Add(sizerRow
, 0, wxALL
| wxGROW
, 5);
415 btn
= new wxButton(panel
, LboxTest_DeleteSel
, _T("Delete &selection"));
416 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
418 btn
= new wxButton(panel
, LboxTest_Clear
, _T("&Clear"));
419 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
422 m_lbox
= new wxListBox(panel
, LboxTest_Listbox
,
423 wxDefaultPosition
, wxDefaultSize
,
426 sizerRight
->Add(m_lbox
, 1, wxGROW
| wxALL
, 5);
427 sizerRight
->SetMinSize(250, 0);
428 m_sizerLbox
= sizerRight
; // save it to modify it later
430 // the 3 panes panes compose the upper part of the window
431 sizerUp
->Add(sizerLeft
, 0, wxGROW
| (wxALL
& ~wxLEFT
), 10);
432 sizerUp
->Add(sizerMiddle
, 1, wxGROW
| wxALL
, 10);
433 sizerUp
->Add(sizerRight
, 1, wxGROW
| (wxALL
& ~wxRIGHT
), 10);
435 // the lower one only has the log listbox and a button to clear it
436 wxSizer
*sizerDown
= new wxStaticBoxSizer
438 new wxStaticBox(panel
, wxID_ANY
, _T("&Log window")),
441 m_lboxLog
= new wxListBox(panel
, wxID_ANY
);
442 sizerDown
->Add(m_lboxLog
, 1, wxGROW
| wxALL
, 5);
443 wxBoxSizer
*sizerBtns
= new wxBoxSizer(wxHORIZONTAL
);
444 btn
= new wxButton(panel
, LboxTest_ClearLog
, _T("Clear &log"));
446 sizerBtns
->Add(10, 0); // spacer
447 btn
= new wxButton(panel
, LboxTest_Quit
, _T("E&xit"));
449 sizerDown
->Add(sizerBtns
, 0, wxALL
| wxALIGN_RIGHT
, 5);
451 // put everything together
452 sizerTop
->Add(sizerUp
, 1, wxGROW
| (wxALL
& ~wxBOTTOM
), 10);
453 sizerTop
->Add(0, 5, 0, wxGROW
); // spacer in between
454 sizerTop
->Add(sizerDown
, 0, wxGROW
| (wxALL
& ~wxTOP
), 10);
456 // final initialization
460 panel
->SetSizer(sizerTop
);
463 sizerTop
->SetSizeHints(this);
465 // now that everything is created we can redirect the log messages to the
467 m_logTarget
= new LboxLogger(m_lboxLog
, wxLog::GetActiveTarget());
468 wxLog::SetActiveTarget(m_logTarget
);
471 LboxTestFrame::~LboxTestFrame()
476 // ----------------------------------------------------------------------------
478 // ----------------------------------------------------------------------------
480 void LboxTestFrame::Reset()
482 if ( m_radioSelMode
->GetSelection() == LboxSel_Single
&&
483 !m_chkSort
->GetValue() &&
484 m_chkHScroll
->GetValue() &&
485 !m_chkVScroll
->GetValue() )
491 m_radioSelMode
->SetSelection(LboxSel_Single
);
492 m_chkSort
->SetValue(false);
493 m_chkHScroll
->SetValue(true);
494 m_chkVScroll
->SetValue(false);
499 void LboxTestFrame::CreateLbox()
502 switch ( m_radioSelMode
->GetSelection() )
505 wxFAIL_MSG( _T("unexpected radio box selection") );
507 case LboxSel_Single
: flags
|= wxLB_SINGLE
; break;
508 case LboxSel_Extended
: flags
|= wxLB_EXTENDED
; break;
509 case LboxSel_Multiple
: flags
|= wxLB_MULTIPLE
; break;
512 if ( m_chkVScroll
->GetValue() )
513 flags
|= wxLB_ALWAYS_SB
;
514 if ( m_chkHScroll
->GetValue() )
515 flags
|= wxLB_HSCROLL
;
516 if ( m_chkSort
->GetValue() )
522 int count
= m_lbox
->GetCount();
523 for ( int n
= 0; n
< count
; n
++ )
525 items
.Add(m_lbox
->GetString(n
));
528 m_sizerLbox
->Detach(m_lbox
);
532 m_lbox
= new wxListBox(this, wxID_ANY
,
533 wxDefaultPosition
, wxDefaultSize
,
537 m_sizerLbox
->Add(m_lbox
, 1, wxGROW
| wxALL
, 5);
538 m_sizerLbox
->Layout();
543 // ----------------------------------------------------------------------------
545 // ----------------------------------------------------------------------------
547 void LboxTestFrame::OnButtonQuit(wxCommandEvent
& WXUNUSED(event
))
552 void LboxTestFrame::OnButtonReset(wxCommandEvent
& WXUNUSED(event
))
557 void LboxTestFrame::OnButtonCreate(wxCommandEvent
& WXUNUSED(event
))
562 void LboxTestFrame::OnButtonChange(wxCommandEvent
& WXUNUSED(event
))
564 wxArrayInt selections
;
565 int count
= m_lbox
->GetSelections(selections
);
566 wxString s
= m_textChange
->GetValue();
567 for ( int n
= 0; n
< count
; n
++ )
569 m_lbox
->SetString(selections
[n
], s
);
573 void LboxTestFrame::OnButtonDelete(wxCommandEvent
& WXUNUSED(event
))
576 if ( !m_textDelete
->GetValue().ToULong(&n
) ||
577 (n
>= (unsigned)m_lbox
->GetCount()) )
585 void LboxTestFrame::OnButtonDeleteSel(wxCommandEvent
& WXUNUSED(event
))
587 wxArrayInt selections
;
588 int n
= m_lbox
->GetSelections(selections
);
591 m_lbox
->Delete(selections
[--n
]);
595 void LboxTestFrame::OnButtonClear(wxCommandEvent
& WXUNUSED(event
))
600 void LboxTestFrame::OnButtonClearLog(wxCommandEvent
& WXUNUSED(event
))
605 void LboxTestFrame::OnButtonAdd(wxCommandEvent
& WXUNUSED(event
))
607 static size_t s_item
= 0;
609 wxString s
= m_textAdd
->GetValue();
610 if ( !m_textAdd
->IsModified() )
612 // update the default string
613 m_textAdd
->SetValue(wxString::Format(_T("test item %u"), ++s_item
));
619 void LboxTestFrame::OnButtonAddMany(wxCommandEvent
& WXUNUSED(event
))
621 // "many" means 1000 here
622 for ( size_t n
= 0; n
< 1000; n
++ )
624 m_lbox
->Append(wxString::Format(_T("item #%u"), n
));
628 void LboxTestFrame::OnButtonAddSeveral(wxCommandEvent
& WXUNUSED(event
))
631 items
.Add(_T("First"));
632 items
.Add(_T("another one"));
633 items
.Add(_T("and the last (very very very very very very very very very very long) one"));
634 m_lbox
->InsertItems(items
, 0);
637 void LboxTestFrame::OnUpdateUICreateButton(wxUpdateUIEvent
& event
)
639 event
.Enable(m_dirty
);
642 void LboxTestFrame::OnUpdateUIDeleteButton(wxUpdateUIEvent
& event
)
645 event
.Enable(m_textDelete
->GetValue().ToULong(&n
) &&
646 (n
< (unsigned)m_lbox
->GetCount()));
649 void LboxTestFrame::OnUpdateUIDeleteSelButton(wxUpdateUIEvent
& event
)
651 wxArrayInt selections
;
652 event
.Enable(m_lbox
->GetSelections(selections
) != 0);
655 void LboxTestFrame::OnUpdateUIClearButton(wxUpdateUIEvent
& event
)
657 event
.Enable(m_lbox
->GetCount() != 0);
660 void LboxTestFrame::OnUpdateUIAddSeveral(wxUpdateUIEvent
& event
)
662 event
.Enable(!(m_lbox
->GetWindowStyle() & wxLB_SORT
));
665 void LboxTestFrame::OnListbox(wxCommandEvent
& event
)
667 int sel
= event
.GetInt();
668 m_textDelete
->SetValue(wxString::Format(_T("%d"), sel
));
670 wxLogMessage(_T("Listbox item %d selected"), sel
);
673 void LboxTestFrame::OnListboxDClick(wxCommandEvent
& event
)
675 int sel
= event
.GetInt();
676 wxLogMessage(_T("Listbox item %d double clicked"), sel
);
679 void LboxTestFrame::OnCheckOrRadioBox(wxCommandEvent
& WXUNUSED(event
))