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
43 #include "wx/dcclient.h"
45 #include "wx/button.h"
46 #include "wx/checkbox.h"
47 #include "wx/checklst.h"
48 #include "wx/listbox.h"
49 #include "wx/radiobox.h"
50 #include "wx/radiobut.h"
51 #include "wx/statbox.h"
52 #include "wx/stattext.h"
53 #include "wx/textctrl.h"
58 #ifdef __WXUNIVERSAL__
59 #include "wx/univ/theme.h"
60 #endif // __WXUNIVERSAL__
62 // ----------------------------------------------------------------------------
64 // ----------------------------------------------------------------------------
86 // ----------------------------------------------------------------------------
88 // ----------------------------------------------------------------------------
90 // Define a new application type, each program should derive a class from wxApp
91 class LboxTestApp
: public wxApp
94 // override base class virtuals
95 // ----------------------------
97 // this one is called on application startup and is a good place for the app
98 // initialization (doing it here and not in the ctor allows to have an error
99 // return: if OnInit() returns false, the application terminates)
100 virtual bool OnInit();
103 // Define a new frame type: this is going to be our main frame
104 class LboxTestFrame
: public wxFrame
108 LboxTestFrame(const wxString
& title
);
109 virtual ~LboxTestFrame();
113 void OnButtonReset(wxCommandEvent
& event
);
114 void OnButtonCreate(wxCommandEvent
& event
);
115 void OnButtonChange(wxCommandEvent
& event
);
116 void OnButtonDelete(wxCommandEvent
& event
);
117 void OnButtonDeleteSel(wxCommandEvent
& event
);
118 void OnButtonClear(wxCommandEvent
& event
);
119 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
;
178 // the listbox for logging messages
179 wxListBox
*m_lboxLog
;
181 // the text entries for "Add/change string" and "Delete" buttons
182 wxTextCtrl
*m_textAdd
,
187 // the log target we use to redirect messages to the listbox
190 // any class wishing to process wxWindows events must use this macro
191 DECLARE_EVENT_TABLE()
194 // A log target which just redirects the messages to a listbox
195 class LboxLogger
: public wxLog
198 LboxLogger(wxListBox
*lbox
, wxLog
*logOld
)
201 //m_lbox->Disable(); -- looks ugly under MSW
205 virtual ~LboxLogger()
207 wxLog::SetActiveTarget(m_logOld
);
211 // implement sink functions
212 virtual void DoLog(wxLogLevel level
, const wxChar
*szString
, time_t t
)
214 // don't put trace messages into listbox or we can get into infinite
216 if ( level
== wxLOG_Trace
)
220 // cast is needed to call protected method
221 ((LboxLogger
*)m_logOld
)->DoLog(level
, szString
, t
);
226 wxLog::DoLog(level
, szString
, t
);
230 virtual void DoLogString(const wxChar
*szString
, time_t t
)
235 #ifdef __WXUNIVERSAL__
236 m_lbox
->AppendAndEnsureVisible(msg
);
237 #else // other ports don't have this method yet
240 // SetFirstItem() isn't implemented in wxGTK
242 m_lbox
->SetFirstItem(m_lbox
->GetCount() - 1);
247 // the control we use
250 // the old log target
254 // ----------------------------------------------------------------------------
256 // ----------------------------------------------------------------------------
258 IMPLEMENT_APP(LboxTestApp
)
260 #ifdef __WXUNIVERSAL__
263 #endif // __WXUNIVERSAL__
265 // ----------------------------------------------------------------------------
267 // ----------------------------------------------------------------------------
269 BEGIN_EVENT_TABLE(LboxTestFrame
, wxFrame
)
270 EVT_BUTTON(LboxTest_Reset
, LboxTestFrame::OnButtonReset
)
271 EVT_BUTTON(LboxTest_Create
, LboxTestFrame::OnButtonCreate
)
272 EVT_BUTTON(LboxTest_Change
, LboxTestFrame::OnButtonChange
)
273 EVT_BUTTON(LboxTest_Delete
, LboxTestFrame::OnButtonDelete
)
274 EVT_BUTTON(LboxTest_DeleteSel
, LboxTestFrame::OnButtonDeleteSel
)
275 EVT_BUTTON(LboxTest_Clear
, LboxTestFrame::OnButtonClear
)
276 EVT_BUTTON(LboxTest_ClearLog
, LboxTestFrame::OnButtonClearLog
)
277 EVT_BUTTON(LboxTest_Add
, LboxTestFrame::OnButtonAdd
)
278 EVT_BUTTON(LboxTest_AddSeveral
, LboxTestFrame::OnButtonAddSeveral
)
279 EVT_BUTTON(LboxTest_AddMany
, LboxTestFrame::OnButtonAddMany
)
280 EVT_BUTTON(LboxTest_Quit
, LboxTestFrame::OnButtonQuit
)
282 EVT_TEXT_ENTER(LboxTest_AddText
, LboxTestFrame::OnButtonAdd
)
283 EVT_TEXT_ENTER(LboxTest_DeleteText
, LboxTestFrame::OnButtonDelete
)
285 EVT_UPDATE_UI_RANGE(LboxTest_Reset
, LboxTest_Create
,
286 LboxTestFrame::OnUpdateUICreateButton
)
288 EVT_UPDATE_UI(LboxTest_AddSeveral
, LboxTestFrame::OnUpdateUIAddSeveral
)
289 EVT_UPDATE_UI(LboxTest_Clear
, LboxTestFrame::OnUpdateUIClearButton
)
290 EVT_UPDATE_UI(LboxTest_DeleteText
, LboxTestFrame::OnUpdateUIClearButton
)
291 EVT_UPDATE_UI(LboxTest_Delete
, LboxTestFrame::OnUpdateUIDeleteButton
)
292 EVT_UPDATE_UI(LboxTest_Change
, LboxTestFrame::OnUpdateUIDeleteSelButton
)
293 EVT_UPDATE_UI(LboxTest_ChangeText
, LboxTestFrame::OnUpdateUIDeleteSelButton
)
294 EVT_UPDATE_UI(LboxTest_DeleteSel
, LboxTestFrame::OnUpdateUIDeleteSelButton
)
296 EVT_LISTBOX(LboxTest_Listbox
, LboxTestFrame::OnListbox
)
297 EVT_LISTBOX_DCLICK(-1, LboxTestFrame::OnListboxDClick
)
298 EVT_CHECKBOX(-1, LboxTestFrame::OnCheckOrRadioBox
)
299 EVT_RADIOBOX(-1, LboxTestFrame::OnCheckOrRadioBox
)
302 // ============================================================================
304 // ============================================================================
306 // ----------------------------------------------------------------------------
308 // ----------------------------------------------------------------------------
310 bool LboxTestApp::OnInit()
312 wxFrame
*frame
= new LboxTestFrame(_T("wxListBox sample"));
315 //wxLog::AddTraceMask(_T("listbox"));
316 wxLog::AddTraceMask(_T("scrollbar"));
321 // ----------------------------------------------------------------------------
322 // top level frame class
323 // ----------------------------------------------------------------------------
325 LboxTestFrame::LboxTestFrame(const wxString
& title
)
326 : wxFrame(NULL
, -1, title
, wxPoint(100, 100))
330 m_radioSelMode
= (wxRadioBox
*)NULL
;
334 m_chkSort
= (wxCheckBox
*)NULL
;
337 m_lboxLog
= (wxListBox
*)NULL
;
338 m_sizerLbox
= (wxSizer
*)NULL
;
340 m_logTarget
= (wxLog
*)NULL
;
342 wxPanel
*panel
= new wxPanel(this, -1);
345 What we create here is a frame having 3 panes: the explanatory pane to
346 the left allowing to set the listbox styles and recreate the control,
347 the pane containing the listbox itself and the lower pane containing
348 the buttons which allow to add/change/delete strings to/from it.
350 wxSizer
*sizerTop
= new wxBoxSizer(wxVERTICAL
),
351 *sizerUp
= new wxBoxSizer(wxHORIZONTAL
),
353 *sizerRight
= new wxBoxSizer(wxVERTICAL
);
356 static const wxString modes
[] =
363 wxStaticBox
*box
= new wxStaticBox(panel
, -1, _T("&Set listbox parameters"));
364 m_radioSelMode
= new wxRadioBox(panel
, -1, _T("Selection &mode:"),
365 wxDefaultPosition
, wxDefaultSize
,
366 WXSIZEOF(modes
), modes
,
367 1, wxRA_SPECIFY_COLS
);
369 m_chkVScroll
= new wxCheckBox(panel
, -1, _T("Always show &vertical scrollbar"));
370 m_chkHScroll
= new wxCheckBox(panel
, -1, _T("Show &horizontal scrollbar"));
371 m_chkSort
= new wxCheckBox(panel
, -1, _T("&Sort items"));
373 sizerLeft
= new wxStaticBoxSizer(box
, wxVERTICAL
);
375 sizerLeft
->Add(m_chkVScroll
, 0, wxLEFT
| wxRIGHT
, 5);
376 sizerLeft
->Add(m_chkHScroll
, 0, wxLEFT
| wxRIGHT
, 5);
377 sizerLeft
->Add(m_chkSort
, 0, wxLEFT
| wxRIGHT
, 5);
378 sizerLeft
->Add(5, 5, 0, wxGROW
| wxALL
, 5); // spacer
379 sizerLeft
->Add(m_radioSelMode
, 0, wxGROW
| wxALL
, 5);
381 wxSizer
*sizerBtn
= new wxBoxSizer(wxHORIZONTAL
);
382 wxButton
*btn
= new wxButton(panel
, LboxTest_Reset
, _T("&Reset"));
383 sizerBtn
->Add(btn
, 0, wxLEFT
| wxRIGHT
, 5);
384 btn
= new wxButton(panel
, LboxTest_Create
, _T("&Create"));
385 sizerBtn
->Add(btn
, 0, wxLEFT
| wxRIGHT
, 5);
386 sizerLeft
->Add(sizerBtn
, 0, wxALIGN_CENTRE_HORIZONTAL
| wxALL
, 15);
389 wxStaticBox
*box2
= new wxStaticBox(panel
, -1, _T("&Change listbox contents"));
390 wxSizer
*sizerMiddle
= new wxStaticBoxSizer(box2
, wxVERTICAL
);
392 wxSizer
*sizerRow
= new wxBoxSizer(wxHORIZONTAL
);
393 btn
= new wxButton(panel
, LboxTest_Add
, _T("&Add this string"));
394 m_textAdd
= new wxTextCtrl(panel
, LboxTest_AddText
, _T("test item 0"));
395 sizerRow
->Add(btn
, 0, wxRIGHT
, 5);
396 sizerRow
->Add(m_textAdd
, 1, wxLEFT
, 5);
397 sizerMiddle
->Add(sizerRow
, 0, wxALL
| wxGROW
, 5);
399 btn
= new wxButton(panel
, LboxTest_AddSeveral
, _T("&Insert a few strings"));
400 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
402 btn
= new wxButton(panel
, LboxTest_AddMany
, _T("Add &many strings"));
403 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
405 sizerRow
= new wxBoxSizer(wxHORIZONTAL
);
406 btn
= new wxButton(panel
, LboxTest_Change
, _T("C&hange current"));
407 m_textChange
= new wxTextCtrl(panel
, LboxTest_ChangeText
, _T(""));
408 sizerRow
->Add(btn
, 0, wxRIGHT
, 5);
409 sizerRow
->Add(m_textChange
, 1, wxLEFT
, 5);
410 sizerMiddle
->Add(sizerRow
, 0, wxALL
| wxGROW
, 5);
412 sizerRow
= new wxBoxSizer(wxHORIZONTAL
);
413 btn
= new wxButton(panel
, LboxTest_Delete
, _T("&Delete this item"));
414 m_textDelete
= new wxTextCtrl(panel
, LboxTest_DeleteText
, _T(""));
415 sizerRow
->Add(btn
, 0, wxRIGHT
, 5);
416 sizerRow
->Add(m_textDelete
, 1, wxLEFT
, 5);
417 sizerMiddle
->Add(sizerRow
, 0, wxALL
| wxGROW
, 5);
419 btn
= new wxButton(panel
, LboxTest_DeleteSel
, _T("Delete &selection"));
420 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
422 btn
= new wxButton(panel
, LboxTest_Clear
, _T("&Clear"));
423 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
426 m_lbox
= new wxListBox(panel
, LboxTest_Listbox
,
427 wxDefaultPosition
, wxDefaultSize
,
430 sizerRight
->Add(m_lbox
, 1, wxGROW
| wxALL
, 5);
431 sizerRight
->SetMinSize(250, 0);
432 m_sizerLbox
= sizerRight
; // save it to modify it later
434 // the 3 panes panes compose the upper part of the window
435 sizerUp
->Add(sizerLeft
, 0, wxGROW
| (wxALL
& ~wxLEFT
), 10);
436 sizerUp
->Add(sizerMiddle
, 1, wxGROW
| wxALL
, 10);
437 sizerUp
->Add(sizerRight
, 1, wxGROW
| (wxALL
& ~wxRIGHT
), 10);
439 // the lower one only has the log listbox and a button to clear it
440 wxSizer
*sizerDown
= new wxStaticBoxSizer
442 new wxStaticBox(panel
, -1, _T("&Log window")),
445 m_lboxLog
= new wxListBox(panel
, -1);
446 sizerDown
->Add(m_lboxLog
, 1, wxGROW
| wxALL
, 5);
447 wxBoxSizer
*sizerBtns
= new wxBoxSizer(wxHORIZONTAL
);
448 btn
= new wxButton(panel
, LboxTest_ClearLog
, _T("Clear &log"));
450 sizerBtns
->Add(10, 0); // spacer
451 btn
= new wxButton(panel
, LboxTest_Quit
, _T("E&xit"));
453 sizerDown
->Add(sizerBtns
, 0, wxALL
| wxALIGN_RIGHT
, 5);
455 // put everything together
456 sizerTop
->Add(sizerUp
, 1, wxGROW
| (wxALL
& ~wxBOTTOM
), 10);
457 sizerTop
->Add(0, 5, 0, wxGROW
); // spacer in between
458 sizerTop
->Add(sizerDown
, 0, wxGROW
| (wxALL
& ~wxTOP
), 10);
460 // final initialization
464 panel
->SetAutoLayout(TRUE
);
465 panel
->SetSizer(sizerTop
);
468 sizerTop
->SetSizeHints(this);
470 // now that everything is created we can redirect the log messages to the
472 m_logTarget
= new LboxLogger(m_lboxLog
, wxLog::GetActiveTarget());
473 wxLog::SetActiveTarget(m_logTarget
);
476 LboxTestFrame::~LboxTestFrame()
481 // ----------------------------------------------------------------------------
483 // ----------------------------------------------------------------------------
485 void LboxTestFrame::Reset()
487 if ( m_radioSelMode
->GetSelection() == LboxSel_Single
&&
488 !m_chkSort
->GetValue() &&
489 m_chkHScroll
->GetValue() &&
490 !m_chkVScroll
->GetValue() )
496 m_radioSelMode
->SetSelection(LboxSel_Single
);
497 m_chkSort
->SetValue(FALSE
);
498 m_chkHScroll
->SetValue(TRUE
);
499 m_chkVScroll
->SetValue(FALSE
);
504 void LboxTestFrame::CreateLbox()
507 switch ( m_radioSelMode
->GetSelection() )
510 wxFAIL_MSG( _T("unexpected radio box selection") );
512 case LboxSel_Single
: flags
|= wxLB_SINGLE
; break;
513 case LboxSel_Extended
: flags
|= wxLB_EXTENDED
; break;
514 case LboxSel_Multiple
: flags
|= wxLB_MULTIPLE
; break;
517 if ( m_chkVScroll
->GetValue() )
518 flags
|= wxLB_ALWAYS_SB
;
519 if ( m_chkHScroll
->GetValue() )
520 flags
|= wxLB_HSCROLL
;
521 if ( m_chkSort
->GetValue() )
527 int count
= m_lbox
->GetCount();
528 for ( int n
= 0; n
< count
; n
++ )
530 items
.Add(m_lbox
->GetString(n
));
533 m_sizerLbox
->Remove(m_lbox
);
537 m_lbox
= new wxListBox(this, -1,
538 wxDefaultPosition
, wxDefaultSize
,
542 m_sizerLbox
->Add(m_lbox
, 1, wxGROW
| wxALL
, 5);
543 m_sizerLbox
->Layout();
548 // ----------------------------------------------------------------------------
550 // ----------------------------------------------------------------------------
552 void LboxTestFrame::OnButtonQuit(wxCommandEvent
& WXUNUSED(event
))
557 void LboxTestFrame::OnButtonReset(wxCommandEvent
& WXUNUSED(event
))
562 void LboxTestFrame::OnButtonCreate(wxCommandEvent
& WXUNUSED(event
))
567 void LboxTestFrame::OnButtonChange(wxCommandEvent
& WXUNUSED(event
))
569 wxArrayInt selections
;
570 int count
= m_lbox
->GetSelections(selections
);
571 wxString s
= m_textChange
->GetValue();
572 for ( int n
= 0; n
< count
; n
++ )
574 m_lbox
->SetString(selections
[n
], s
);
578 void LboxTestFrame::OnButtonDelete(wxCommandEvent
& WXUNUSED(event
))
581 if ( !m_textDelete
->GetValue().ToULong(&n
) ||
582 (n
>= (unsigned)m_lbox
->GetCount()) )
590 void LboxTestFrame::OnButtonDeleteSel(wxCommandEvent
& WXUNUSED(event
))
592 wxArrayInt selections
;
593 int n
= m_lbox
->GetSelections(selections
);
596 m_lbox
->Delete(selections
[--n
]);
600 void LboxTestFrame::OnButtonClear(wxCommandEvent
& WXUNUSED(event
))
605 void LboxTestFrame::OnButtonClearLog(wxCommandEvent
& WXUNUSED(event
))
610 void LboxTestFrame::OnButtonAdd(wxCommandEvent
& WXUNUSED(event
))
612 static size_t s_item
= 0;
614 wxString s
= m_textAdd
->GetValue();
615 if ( !m_textAdd
->IsModified() )
617 // update the default string
618 m_textAdd
->SetValue(wxString::Format(_T("test item %u"), ++s_item
));
624 void LboxTestFrame::OnButtonAddMany(wxCommandEvent
& WXUNUSED(event
))
626 // "many" means 1000 here
627 for ( size_t n
= 0; n
< 1000; n
++ )
629 m_lbox
->Append(wxString::Format(_T("item #%u"), n
));
633 void LboxTestFrame::OnButtonAddSeveral(wxCommandEvent
& WXUNUSED(event
))
636 items
.Add(_T("First"));
637 items
.Add(_T("another one"));
638 items
.Add(_T("and the last (very very very very very very very very very very long) one"));
639 m_lbox
->InsertItems(items
, 0);
642 void LboxTestFrame::OnUpdateUICreateButton(wxUpdateUIEvent
& event
)
644 event
.Enable(m_dirty
);
647 void LboxTestFrame::OnUpdateUIDeleteButton(wxUpdateUIEvent
& event
)
650 event
.Enable(m_textDelete
->GetValue().ToULong(&n
) &&
651 (n
< (unsigned)m_lbox
->GetCount()));
654 void LboxTestFrame::OnUpdateUIDeleteSelButton(wxUpdateUIEvent
& event
)
656 wxArrayInt selections
;
657 event
.Enable(m_lbox
->GetSelections(selections
) != 0);
660 void LboxTestFrame::OnUpdateUIClearButton(wxUpdateUIEvent
& event
)
662 event
.Enable(m_lbox
->GetCount() != 0);
665 void LboxTestFrame::OnUpdateUIAddSeveral(wxUpdateUIEvent
& event
)
667 event
.Enable(!(m_lbox
->GetWindowStyle() & wxLB_SORT
));
670 void LboxTestFrame::OnListbox(wxCommandEvent
& event
)
672 int sel
= event
.GetInt();
673 m_textDelete
->SetValue(wxString::Format(_T("%ld"), sel
));
675 wxLogMessage(_T("Listbox item %d selected"), sel
);
678 void LboxTestFrame::OnListboxDClick(wxCommandEvent
& event
)
680 wxLogMessage(_T("Listbox item %d double clicked"), event
.GetInt());
683 void LboxTestFrame::OnCheckOrRadioBox(wxCommandEvent
& WXUNUSED(event
))