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 // ----------------------------------------------------------------------------
89 // ----------------------------------------------------------------------------
91 // ----------------------------------------------------------------------------
93 // Define a new application type, each program should derive a class from wxApp
94 class LboxTestApp
: public wxApp
97 // override base class virtuals
98 // ----------------------------
100 // this one is called on application startup and is a good place for the app
101 // initialization (doing it here and not in the ctor allows to have an error
102 // return: if OnInit() returns false, the application terminates)
103 virtual bool OnInit();
106 // Define a new frame type: this is going to be our main frame
107 class LboxTestFrame
: public wxFrame
111 LboxTestFrame(const wxString
& title
);
112 virtual ~LboxTestFrame();
116 void OnButtonReset(wxCommandEvent
& event
);
117 void OnButtonCreate(wxCommandEvent
& event
);
118 void OnButtonChange(wxCommandEvent
& event
);
119 void OnButtonDelete(wxCommandEvent
& event
);
120 void OnButtonDeleteSel(wxCommandEvent
& event
);
121 void OnButtonClear(wxCommandEvent
& event
);
123 void OnButtonClearLog(wxCommandEvent
& event
);
125 void OnButtonAdd(wxCommandEvent
& event
);
126 void OnButtonAddSeveral(wxCommandEvent
& event
);
127 void OnButtonAddMany(wxCommandEvent
& event
);
128 void OnButtonQuit(wxCommandEvent
& event
);
130 void OnListbox(wxCommandEvent
& event
);
131 void OnListboxDClick(wxCommandEvent
& event
);
133 void OnCheckOrRadioBox(wxCommandEvent
& event
);
135 void OnUpdateUIAddSeveral(wxUpdateUIEvent
& event
);
136 void OnUpdateUICreateButton(wxUpdateUIEvent
& event
);
137 void OnUpdateUIClearButton(wxUpdateUIEvent
& event
);
138 void OnUpdateUIDeleteButton(wxUpdateUIEvent
& event
);
139 void OnUpdateUIDeleteSelButton(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
;
184 // the listbox for logging messages
185 wxListBox
*m_lboxLog
;
188 // the text entries for "Add/change string" and "Delete" buttons
189 wxTextCtrl
*m_textAdd
,
195 // the log target we use to redirect messages to the listbox
199 // any class wishing to process wxWidgets events must use this macro
200 DECLARE_EVENT_TABLE()
204 // A log target which just redirects the messages to a listbox
205 class LboxLogger
: public wxLog
208 LboxLogger(wxListBox
*lbox
, wxLog
*logOld
)
211 //m_lbox->Disable(); -- looks ugly under MSW
215 virtual ~LboxLogger()
217 wxLog::SetActiveTarget(m_logOld
);
221 // implement sink functions
222 virtual void DoLog(wxLogLevel level
, const wxChar
*szString
, time_t t
)
224 // don't put trace messages into listbox or we can get into infinite
226 if ( level
== wxLOG_Trace
)
230 // cast is needed to call protected method
231 ((LboxLogger
*)m_logOld
)->DoLog(level
, szString
, t
);
236 wxLog::DoLog(level
, szString
, t
);
240 virtual void DoLogString(const wxChar
*szString
, time_t WXUNUSED(t
))
245 #ifdef __WXUNIVERSAL__
246 m_lbox
->AppendAndEnsureVisible(msg
);
247 #else // other ports don't have this method yet
250 // SetFirstItem() isn't implemented in wxGTK
252 m_lbox
->SetFirstItem(m_lbox
->GetCount() - 1);
257 // the control we use
260 // the old log target
265 // ----------------------------------------------------------------------------
267 // ----------------------------------------------------------------------------
269 IMPLEMENT_APP(LboxTestApp
)
271 // ----------------------------------------------------------------------------
273 // ----------------------------------------------------------------------------
275 BEGIN_EVENT_TABLE(LboxTestFrame
, wxFrame
)
276 EVT_BUTTON(LboxTest_Reset
, LboxTestFrame::OnButtonReset
)
277 EVT_BUTTON(LboxTest_Create
, LboxTestFrame::OnButtonCreate
)
278 EVT_BUTTON(LboxTest_Change
, LboxTestFrame::OnButtonChange
)
279 EVT_BUTTON(LboxTest_Delete
, LboxTestFrame::OnButtonDelete
)
280 EVT_BUTTON(LboxTest_DeleteSel
, LboxTestFrame::OnButtonDeleteSel
)
281 EVT_BUTTON(LboxTest_Clear
, LboxTestFrame::OnButtonClear
)
283 EVT_BUTTON(LboxTest_ClearLog
, LboxTestFrame::OnButtonClearLog
)
285 EVT_BUTTON(LboxTest_Add
, LboxTestFrame::OnButtonAdd
)
286 EVT_BUTTON(LboxTest_AddSeveral
, LboxTestFrame::OnButtonAddSeveral
)
287 EVT_BUTTON(LboxTest_AddMany
, LboxTestFrame::OnButtonAddMany
)
288 EVT_BUTTON(LboxTest_Quit
, LboxTestFrame::OnButtonQuit
)
290 EVT_TEXT_ENTER(LboxTest_AddText
, LboxTestFrame::OnButtonAdd
)
291 EVT_TEXT_ENTER(LboxTest_DeleteText
, LboxTestFrame::OnButtonDelete
)
293 EVT_UPDATE_UI_RANGE(LboxTest_Reset
, LboxTest_Create
,
294 LboxTestFrame::OnUpdateUICreateButton
)
296 EVT_UPDATE_UI(LboxTest_AddSeveral
, LboxTestFrame::OnUpdateUIAddSeveral
)
297 EVT_UPDATE_UI(LboxTest_Clear
, LboxTestFrame::OnUpdateUIClearButton
)
298 EVT_UPDATE_UI(LboxTest_DeleteText
, LboxTestFrame::OnUpdateUIClearButton
)
299 EVT_UPDATE_UI(LboxTest_Delete
, LboxTestFrame::OnUpdateUIDeleteButton
)
300 EVT_UPDATE_UI(LboxTest_Change
, LboxTestFrame::OnUpdateUIDeleteSelButton
)
301 EVT_UPDATE_UI(LboxTest_ChangeText
, LboxTestFrame::OnUpdateUIDeleteSelButton
)
302 EVT_UPDATE_UI(LboxTest_DeleteSel
, LboxTestFrame::OnUpdateUIDeleteSelButton
)
304 EVT_LISTBOX(LboxTest_Listbox
, LboxTestFrame::OnListbox
)
305 EVT_LISTBOX_DCLICK(wxID_ANY
, LboxTestFrame::OnListboxDClick
)
306 EVT_CHECKBOX(wxID_ANY
, LboxTestFrame::OnCheckOrRadioBox
)
307 EVT_RADIOBOX(wxID_ANY
, LboxTestFrame::OnCheckOrRadioBox
)
310 // ============================================================================
312 // ============================================================================
314 // ----------------------------------------------------------------------------
316 // ----------------------------------------------------------------------------
318 bool LboxTestApp::OnInit()
320 wxFrame
*frame
= new LboxTestFrame(_T("wxListBox sample"));
324 //wxLog::AddTraceMask(_T("listbox"));
325 wxLog::AddTraceMask(_T("scrollbar"));
331 // ----------------------------------------------------------------------------
332 // top level frame class
333 // ----------------------------------------------------------------------------
335 LboxTestFrame::LboxTestFrame(const wxString
& title
)
336 : wxFrame(NULL
, wxID_ANY
, title
, wxPoint(100, 100))
340 m_radioSelMode
= (wxRadioBox
*)NULL
;
344 m_chkSort
= (wxCheckBox
*)NULL
;
346 m_lbox
= (wxListBox
*)NULL
;
348 m_lboxLog
= (wxListBox
*)NULL
;
350 m_sizerLbox
= (wxSizer
*)NULL
;
353 m_logTarget
= (wxLog
*)NULL
;
356 wxPanel
*panel
= new wxPanel(this, wxID_ANY
);
359 What we create here is a frame having 3 panes: the explanatory pane to
360 the left allowing to set the listbox styles and recreate the control,
361 the pane containing the listbox itself and the lower pane containing
362 the buttons which allow to add/change/delete strings to/from it.
364 wxSizer
*sizerTop
= new wxBoxSizer(wxVERTICAL
),
365 *sizerUp
= new wxBoxSizer(wxHORIZONTAL
),
367 *sizerRight
= new wxBoxSizer(wxVERTICAL
);
370 static const wxString modes
[] =
377 wxStaticBox
*box
= new wxStaticBox(panel
, wxID_ANY
, _T("&Set listbox parameters"));
378 m_radioSelMode
= new wxRadioBox(panel
, wxID_ANY
, _T("Selection &mode:"),
379 wxDefaultPosition
, wxDefaultSize
,
380 WXSIZEOF(modes
), modes
,
381 1, wxRA_SPECIFY_COLS
);
383 m_chkVScroll
= new wxCheckBox(panel
, wxID_ANY
, _T("Always show &vertical scrollbar"));
384 m_chkHScroll
= new wxCheckBox(panel
, wxID_ANY
, _T("Show &horizontal scrollbar"));
385 m_chkSort
= new wxCheckBox(panel
, wxID_ANY
, _T("&Sort items"));
387 sizerLeft
= new wxStaticBoxSizer(box
, wxVERTICAL
);
389 sizerLeft
->Add(m_chkVScroll
, 0, wxLEFT
| wxRIGHT
, 5);
390 sizerLeft
->Add(m_chkHScroll
, 0, wxLEFT
| wxRIGHT
, 5);
391 sizerLeft
->Add(m_chkSort
, 0, wxLEFT
| wxRIGHT
, 5);
392 sizerLeft
->Add(5, 5, 0, wxGROW
| wxALL
, 5); // spacer
393 sizerLeft
->Add(m_radioSelMode
, 0, wxGROW
| wxALL
, 5);
395 wxSizer
*sizerBtn
= new wxBoxSizer(wxHORIZONTAL
);
396 wxButton
*btn
= new wxButton(panel
, LboxTest_Reset
, _T("&Reset"));
397 sizerBtn
->Add(btn
, 0, wxLEFT
| wxRIGHT
, 5);
398 btn
= new wxButton(panel
, LboxTest_Create
, _T("&Create"));
399 sizerBtn
->Add(btn
, 0, wxLEFT
| wxRIGHT
, 5);
400 sizerLeft
->Add(sizerBtn
, 0, wxALIGN_CENTRE_HORIZONTAL
| wxALL
, 15);
403 wxStaticBox
*box2
= new wxStaticBox(panel
, wxID_ANY
, _T("&Change listbox contents"));
404 wxSizer
*sizerMiddle
= new wxStaticBoxSizer(box2
, wxVERTICAL
);
406 wxSizer
*sizerRow
= new wxBoxSizer(wxHORIZONTAL
);
407 btn
= new wxButton(panel
, LboxTest_Add
, _T("&Add this string"));
408 m_textAdd
= new wxTextCtrl(panel
, LboxTest_AddText
, _T("test item 0"));
409 sizerRow
->Add(btn
, 0, wxRIGHT
, 5);
410 sizerRow
->Add(m_textAdd
, 1, wxLEFT
, 5);
411 sizerMiddle
->Add(sizerRow
, 0, wxALL
| wxGROW
, 5);
413 btn
= new wxButton(panel
, LboxTest_AddSeveral
, _T("&Insert a few strings"));
414 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
416 btn
= new wxButton(panel
, LboxTest_AddMany
, _T("Add &many strings"));
417 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
419 sizerRow
= new wxBoxSizer(wxHORIZONTAL
);
420 btn
= new wxButton(panel
, LboxTest_Change
, _T("C&hange current"));
421 m_textChange
= new wxTextCtrl(panel
, LboxTest_ChangeText
, wxEmptyString
);
422 sizerRow
->Add(btn
, 0, wxRIGHT
, 5);
423 sizerRow
->Add(m_textChange
, 1, wxLEFT
, 5);
424 sizerMiddle
->Add(sizerRow
, 0, wxALL
| wxGROW
, 5);
426 sizerRow
= new wxBoxSizer(wxHORIZONTAL
);
427 btn
= new wxButton(panel
, LboxTest_Delete
, _T("&Delete this item"));
428 m_textDelete
= new wxTextCtrl(panel
, LboxTest_DeleteText
, wxEmptyString
);
429 sizerRow
->Add(btn
, 0, wxRIGHT
, 5);
430 sizerRow
->Add(m_textDelete
, 1, wxLEFT
, 5);
431 sizerMiddle
->Add(sizerRow
, 0, wxALL
| wxGROW
, 5);
433 btn
= new wxButton(panel
, LboxTest_DeleteSel
, _T("Delete &selection"));
434 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
436 btn
= new wxButton(panel
, LboxTest_Clear
, _T("&Clear"));
437 sizerMiddle
->Add(btn
, 0, wxALL
| wxGROW
, 5);
440 m_lbox
= new wxListBox(panel
, LboxTest_Listbox
,
441 wxDefaultPosition
, wxDefaultSize
,
444 sizerRight
->Add(m_lbox
, 1, wxGROW
| wxALL
, 5);
445 sizerRight
->SetMinSize(250, 0);
446 m_sizerLbox
= sizerRight
; // save it to modify it later
448 // the 3 panes panes compose the upper part of the window
449 sizerUp
->Add(sizerLeft
, 0, wxGROW
| (wxALL
& ~wxLEFT
), 10);
450 sizerUp
->Add(sizerMiddle
, 1, wxGROW
| wxALL
, 10);
451 sizerUp
->Add(sizerRight
, 1, wxGROW
| (wxALL
& ~wxRIGHT
), 10);
453 // the lower one only has the log listbox and a button to clear it
455 wxSizer
*sizerDown
= new wxStaticBoxSizer
457 new wxStaticBox(panel
, wxID_ANY
, _T("&Log window")),
460 m_lboxLog
= new wxListBox(panel
, wxID_ANY
);
461 sizerDown
->Add(m_lboxLog
, 1, wxGROW
| wxALL
, 5);
463 wxSizer
*sizerDown
= new wxBoxSizer(wxVERTICAL
);
465 wxBoxSizer
*sizerBtns
= new wxBoxSizer(wxHORIZONTAL
);
467 btn
= new wxButton(panel
, LboxTest_ClearLog
, _T("Clear &log"));
469 sizerBtns
->Add(10, 0); // spacer
471 btn
= new wxButton(panel
, LboxTest_Quit
, _T("E&xit"));
473 sizerDown
->Add(sizerBtns
, 0, wxALL
| wxALIGN_RIGHT
, 5);
475 // put everything together
476 sizerTop
->Add(sizerUp
, 1, wxGROW
| (wxALL
& ~wxBOTTOM
), 10);
477 sizerTop
->Add(0, 5, 0, wxGROW
); // spacer in between
478 sizerTop
->Add(sizerDown
, 0, wxGROW
| (wxALL
& ~wxTOP
), 10);
480 // final initialization
484 panel
->SetSizer(sizerTop
);
487 sizerTop
->SetSizeHints(this);
490 // now that everything is created we can redirect the log messages to the
492 m_logTarget
= new LboxLogger(m_lboxLog
, wxLog::GetActiveTarget());
493 wxLog::SetActiveTarget(m_logTarget
);
497 LboxTestFrame::~LboxTestFrame()
504 // ----------------------------------------------------------------------------
506 // ----------------------------------------------------------------------------
508 void LboxTestFrame::Reset()
510 if ( m_radioSelMode
->GetSelection() == LboxSel_Single
&&
511 !m_chkSort
->GetValue() &&
512 m_chkHScroll
->GetValue() &&
513 !m_chkVScroll
->GetValue() )
519 m_radioSelMode
->SetSelection(LboxSel_Single
);
520 m_chkSort
->SetValue(false);
521 m_chkHScroll
->SetValue(true);
522 m_chkVScroll
->SetValue(false);
527 void LboxTestFrame::CreateLbox()
530 switch ( m_radioSelMode
->GetSelection() )
533 wxFAIL_MSG( _T("unexpected radio box selection") );
535 case LboxSel_Single
: flags
|= wxLB_SINGLE
; break;
536 case LboxSel_Extended
: flags
|= wxLB_EXTENDED
; break;
537 case LboxSel_Multiple
: flags
|= wxLB_MULTIPLE
; break;
540 if ( m_chkVScroll
->GetValue() )
541 flags
|= wxLB_ALWAYS_SB
;
542 if ( m_chkHScroll
->GetValue() )
543 flags
|= wxLB_HSCROLL
;
544 if ( m_chkSort
->GetValue() )
550 int count
= m_lbox
->GetCount();
551 for ( int n
= 0; n
< count
; n
++ )
553 items
.Add(m_lbox
->GetString(n
));
556 m_sizerLbox
->Detach(m_lbox
);
560 m_lbox
= new wxListBox(this, wxID_ANY
,
561 wxDefaultPosition
, wxDefaultSize
,
565 m_sizerLbox
->Add(m_lbox
, 1, wxGROW
| wxALL
, 5);
566 m_sizerLbox
->Layout();
571 // ----------------------------------------------------------------------------
573 // ----------------------------------------------------------------------------
575 void LboxTestFrame::OnButtonQuit(wxCommandEvent
& WXUNUSED(event
))
580 void LboxTestFrame::OnButtonReset(wxCommandEvent
& WXUNUSED(event
))
585 void LboxTestFrame::OnButtonCreate(wxCommandEvent
& WXUNUSED(event
))
590 void LboxTestFrame::OnButtonChange(wxCommandEvent
& WXUNUSED(event
))
592 wxArrayInt selections
;
593 int count
= m_lbox
->GetSelections(selections
);
594 wxString s
= m_textChange
->GetValue();
595 for ( int n
= 0; n
< count
; n
++ )
597 m_lbox
->SetString(selections
[n
], s
);
601 void LboxTestFrame::OnButtonDelete(wxCommandEvent
& WXUNUSED(event
))
604 if ( !m_textDelete
->GetValue().ToULong(&n
) ||
605 (n
>= (unsigned)m_lbox
->GetCount()) )
613 void LboxTestFrame::OnButtonDeleteSel(wxCommandEvent
& WXUNUSED(event
))
615 wxArrayInt selections
;
616 int n
= m_lbox
->GetSelections(selections
);
619 m_lbox
->Delete(selections
[--n
]);
623 void LboxTestFrame::OnButtonClear(wxCommandEvent
& WXUNUSED(event
))
629 void LboxTestFrame::OnButtonClearLog(wxCommandEvent
& WXUNUSED(event
))
635 void LboxTestFrame::OnButtonAdd(wxCommandEvent
& WXUNUSED(event
))
637 static size_t s_item
= 0;
639 wxString s
= m_textAdd
->GetValue();
640 if ( !m_textAdd
->IsModified() )
642 // update the default string
643 m_textAdd
->SetValue(wxString::Format(_T("test item %u"), ++s_item
));
649 void LboxTestFrame::OnButtonAddMany(wxCommandEvent
& WXUNUSED(event
))
651 // "many" means 1000 here
652 for ( size_t n
= 0; n
< 1000; n
++ )
654 m_lbox
->Append(wxString::Format(_T("item #%u"), n
));
658 void LboxTestFrame::OnButtonAddSeveral(wxCommandEvent
& WXUNUSED(event
))
661 items
.Add(_T("First"));
662 items
.Add(_T("another one"));
663 items
.Add(_T("and the last (very very very very very very very very very very long) one"));
664 m_lbox
->InsertItems(items
, 0);
667 void LboxTestFrame::OnUpdateUICreateButton(wxUpdateUIEvent
& event
)
669 event
.Enable(m_dirty
);
672 void LboxTestFrame::OnUpdateUIDeleteButton(wxUpdateUIEvent
& event
)
675 event
.Enable(m_textDelete
->GetValue().ToULong(&n
) &&
676 (n
< (unsigned)m_lbox
->GetCount()));
679 void LboxTestFrame::OnUpdateUIDeleteSelButton(wxUpdateUIEvent
& event
)
681 wxArrayInt selections
;
682 event
.Enable(m_lbox
->GetSelections(selections
) != 0);
685 void LboxTestFrame::OnUpdateUIClearButton(wxUpdateUIEvent
& event
)
687 event
.Enable(m_lbox
->GetCount() != 0);
690 void LboxTestFrame::OnUpdateUIAddSeveral(wxUpdateUIEvent
& event
)
692 event
.Enable(!(m_lbox
->GetWindowStyle() & wxLB_SORT
));
695 void LboxTestFrame::OnListbox(wxCommandEvent
& event
)
697 int sel
= event
.GetInt();
698 m_textDelete
->SetValue(wxString::Format(_T("%d"), sel
));
700 wxLogMessage(_T("Listbox item %d selected"), sel
);
703 void LboxTestFrame::OnListboxDClick(wxCommandEvent
& event
)
705 int sel
= event
.GetInt();
706 wxLogMessage(_T("Listbox item %d double clicked"), sel
);
709 void LboxTestFrame::OnCheckOrRadioBox(wxCommandEvent
& WXUNUSED(event
))