Home / Paul's FAQs / wxWidgets Newbie FAQ

wxWidgets Newbie FAQ

Last Updated: March, 2007

The following FAQ discusses everything I had to figure out as I was learning wxWidgets. I hope you find this list useful! If you do, please let me know.

PART I: Getting Started

Q: Why can't I do fancy GUI feature <insert wish here> on wxWidgets?

Q: What books do you recommend?

Q: How do I get started?

Q: Where is the official FAQ? Souldnít it be someplace obvious?

PART II: Common Newbie Questions

Q: Where do I put bitmaps for toolbars and bitmap buttons? Should they go on the heap or on the stack? And should I release them?

Q: What's the difference between _T("my text") and wxT("my text")

Q: How do I create ".xpm" bitmaps which I can include in my source code?

Q: How to I get pull-down menus to work nicely in my wxToolBar?

Q: But I want to make the little down arrow a part of the actual button, so that it highlights when you mouse over it.

PART III: Linking and Compiling

Q: What does "Universal" mean?

Q: How do I get my wxGrid control (or other advanced control) to link?

Q: I want to use something in the "contrib" directory (Styled Text Class, animate, plot, etc.). How do I compile it?

Q: What are the other steps before I can use something in the "contrib" directory?

Q: Why do I get all of these linking errors when I try and use an wxHtmlListBox (or any other object with HTML capability) ?

Q: What else do I need to do to implement a wxHtmlListBox?

PART IV: Sizers

Q: Why canít I get my stupid wxSizer to recognize the minimum size of my sub-objects?

Q: My wxBoxSizer is behaving bizarrely. Either: 1) My AddStretchSpacer() is not stretching, or 2) Iím getting these huge weird gaps around my buttons.

Q: How do I add items to a GridSizer (wxFlexGridSizer or wxGridSizer) ?

Q: Can I get an actual code example for how to use wxFlexGridSizer?

Q: Why doesnít my combo box get centered vertically with a sizer?

Q: How can I ensure that a frame with an embedded splitter window doesnít get sized too small?

Q: I use SetMinSize() to set the minimum size of my window, then I add it to my sizer with wxFIXED_MINSIZE, but it gets ignored. WHY?

PART V: Other User Interface Behavior

Q: How do I prevent TAB navigation from navigating to a specified control?

Q: How can I make a text control that selects itís entire contents whenever it gains the keyboard focus?

Q: How do I make a text control which implements auto-complete ?

Q: Can the above two text controls be combined into one?

PART VI: wxStyledTextControl (the wxWidgets Scintilla wrapper)

Q: Where can I get better documentation on wxStyledTextCtrl and Scintilla?

Q: Can I get any more help on implementing the wxWidgets Scintilla wrapper in my application?

Q: How do I implement smart-indentation with my wxWidgets Scintilla wrapper?

Q: Where is the documentation for wxCharBuffer?

Q: Why does wxStyledTextCtrl::GetTextRaw() returns one less character than is actually in my file?

PART VII: Miscellaneous Quirkyness

Q: How can I tell if a wxTreeItemId is valid?

Q: Why doesnít wxID_ANY work with wxMenu?

Q: When I use wxSplitterWindow->SetSashSize(10), why doesn't the sash get erased/redrawn when I move it?

Q: Why do I get the "Couldn't add an image to the image list" error with my toolbars?

PART I: Getting Started

Q: Why can't I do fancy GUI feature <insert wish here> on wxWidgets?

Using wxWidgets requires a certain frame of mind. Specifically, you need to give up on replicating exactly some Windows or Macintosh application you've seen elsewhere. If you want to have unlimited possibilities for your GUI interface - if that is really a requirement - then you should learn MFC on Windows, GTK on Linux, and Cocoa on Macintosh, and write in those native languages.

Of course, learning three interface languages, and all of their eccentricities, is about 100x the amount of work it takes to learn and use wxWidgets, which I can tell you (having programmed all three) is a relatively clean GUI interface.

So my recommendation is this: get comfortable with the limitations that wxWidgets imposes. First off, they aren't that bad, and second, it saves you a ton of work. Realize that there are some trade-offs in using a cross-platform GUI tool.

I realize that this is something of a Zen response, i.e. learn to not let it bother you. But hey, we can all learn something from the Buddhists.

Q: What books do you recommend?

There is only one book. It was written by the creators of "wxWidgets" (Julian Smart and Kevin Hock) and is called "Cross-Platform GUI Programming with wxWidgets". It is published by Prentice Hall, 2005.

It is well worth the price. You also get a CD in the book which makes installation of the system much easier, and it also comes with a smaller version of the dialogblocks builder and image file converter programs.

Q: How do I get started with a Windows Installation?

Follow these steps: (Instructions shown for MS-Windows only. For Macintosh, see my other FAQ).

  1. First, you need to install a compiler and get it working. On Windows, I use Visual Studio 2005 Standard Edition. On Macintosh, I use the Mac OS-X Development system (XCode, which uses gcc underneath). I hear that you can also use MinGW on Windows.

    So, install your compiler and make sure you can compile something, like a basic "Hello World" C program from a command-line prompt.

  2. Download the software from http://www.wxwidgets.org.

  3. Compile wxWidgets.

    The simplest way to do this is to go to the /wxwidgets/build/<arch> directory and type in the proper "make" command. For example, if you are using a Microsoft compiler, you would change your working directory to "c:\wxwidgets\build\msw" and then type "nmake -f makefile.vc". Note: the build/msw directory also has other build scripts for other compilers.

    This will build a debug version by default. You may also wish to build a release version. Do this with "nmake -f makefile.vc BUILD=release".

  4. Check that the libraries exist.

    Go to c:\wxwidgets\lib\vc_lib and check that it is full of useful looking libraries.

  5. Compile and run the minimal sample application.

    Go to c:\wxwidgets\samples\minimal and type "nmake -f "makefile.vc". Run the program by entering "vc_mswd\minimal" at the command-line prompt and then pressing RETURN.

  6. Compile and run the minimal sample application within your favorite IDE.

    The following instructions demonstrate how to compile and run the minimal sample program inside Visual Studio.

    1. Create a brand-new project. Make it empty.
    2. Copy over the "minimal.cpp" file into your project. Rename it if you'd like. Then add it into your project.
    3. Now, within Visual Studio, go to the c:\wxwidgets\samples\minimal directory and open the "minimal.dsp" project. Your Visual Studio will likely need to convert it.
    4. Now, copy over the following settings (aka properties) from the "minimal.dsp" project into your new project:
      • Additional Include Directories (under C++/General)
      • Preprocessor Defines (under C++/Preprocessor)
      • Runtime Library (under C++/Code Generation) -> Multithreaded DLL
      • Additional Library Directories (under Linker/General)
      • Additional Dependencies (under Linker/Input, may also be called "libraries")
      • Additional Command Line Options (under C++/Command Line)
      • Linker Subsystem (under Linker/System)
      • Character Set (under Configuration Properties/General) -> Not Set
      Notes:
      • I recommend opening a blank Notepad text document, copying all of the settings to that, and then copy them back into your new project.
      • As you copy over the settings, you will need to change the directory paths so they are appropriate for your new project. For example, the directory path ".\..\..\include" will probably need to be changed to something like "C:\wxwidgets\include".
      • If things do not link or compile, I recommend comparing the "Command Lines" for both projects. Tweak the properties in your project until the command lines look the same.
    5. Now compile, link, and test your own copy of the "minimal" project.
    6. Now that you have "minimal" running, use it as the starting point for your own application. Good luck!

Q: Where is the official FAQ? Souldnít it be someplace obvious?

FAQ Locations:

PART II: Common Newbie Questions

Q: Where do I put bitmaps for toolbars and bitmap buttons? Should they go on the heap or on the stack? And should I release them?

Bitmaps are managed in wxWidgets with reference counting. Go ahead and create the bitmap on the stack. When you pass it to "AddTool" or "wxBitmapButton", these routines will point to the bitmap data and will increment it's reference count. When your stack variable goes away, the bitmap data will not be released until all of the objects which point to it are also released and it's reference count has been reduced to zero.

For example:

#include "icons/new.xpm"
void MyClass::MyFunction() {
  wxBitmap bmpNew(new_xpm);
  m_toolBar->AddTool(weID_NEW, bmpNew, wxT("New"), 
                     wxT("My new toolbar button."));
}

In the example above, the bitmap is loaded into the local variable "bmpNew", and then transferred to the toolbar button which will increase it's reference from 1 to 2. When "MyFunction()" exits, "bmpNew" will be released, but the bitmap data will hang around until the toolbar button is also released (which will happen automatically when the application shuts down and the frame is released).

Q: What's the difference between _T("my text") and wxT("my text")

There is none. They are both used to translate ASCII text to Unicode (by converting "string" to L"string") whenever you do a Unicode build. Therefore: Never use string literals by themselves, always wrap them in _T() or wxT().

Q: How do I create the ".xpm" bitmap files which I can then #include into my source code?

Here I am going to encourage you to spend money. Seriously. wxWidgets is a really wonderful toolkit, the product of many, many years of work. And this is one way in which you can help support it's primary developers.

Specifically, either 1) buy the book, OR 2) purchase Dialog Blocks from Anthemion Software. Either way, you will get a program called "ImageBlocks", which you can then user to convert image files into .xmp files that can be #include-d into your software. Anthemion software is owned by Julian Smart, the primary developer of wxWidgets.

Otherwise, there is no good solution for producing ".xpm" bitmap files. The only other possibility that I know of is netpbm, which you can download and compile, or download as part of Cygwin. Once you have downloaded the tools, you may be able to execute a command such as this:

giftopnm test.gif | ppmtoxpm > test.xpm

This command mostly worked for me. The image came out right, but the colors were wrong (I had to locate the transparent color and change it to "none"). The other problem is that it cluttered up my Cygwin binaries with a lot of needless little programs Eventually, I decided to delete all of that junk and simply re-install Cygwin (which I mostly use for the Unix/MS-DOS command-line utilities).

Also, I'm told that GIMP (the GNU Image Processor) can save XPM files. So I guess that's an option too.

So really, just buy the book. The book is great. You are getting sleepy. Buy the book. Buuuuuyyyyy thhhhhheeeee booooooook.

Q: How to I get pull-down menus to work nicely in my wxToolBar?

Use my handy "wxMenuToolBar" class.

Q: But I want to make the little down arrow a part of the actual button, so that it highlights when you mouse over it.

Sorry, but you can't. As far as I can tell, standard toolbar buttons are fixed in both width and height. You can't create a toolbar button which is twice as wide as the others.

So the alternative is to put an actual wxBitmapButton on the toolbar, as a control, right? But, unfortunately, it won't behave as a normal toolbar button. It won't highlight in response to a mouse over in the same way. You might be able to fake it out (with multiple images, and then test for mouse-over and change the image to one which has the box drawn around it), but unfortunately this wouldn't appear the same on all of the different platforms. On Macintosh, especially, it would look silly.

So, it's best just to leave all of the toolbar buttons the same size. If you want, you can put a little down triangle inside the bitmap button, but only if the button stays the same size.

PART III: Linking, Compiling, and Components

Q: What does "Universal" mean?

"Universal" does *not* refer to "Universal Binaries" (for example, Universal binaries which work both in Mac OS/X and the original Mac OS 9).

Instead, "Universal" means that wxWidgets uses a set of GUI components which are implemented entirely within wxWidgets. This means that wxWidgets does *not* use the native components (buttons, toolbars, etc) inside the operating system, but rather, has re-implemented all of the components into it's own "Universal" set of components.

The "Universal" widgets makes porting more dependable. Since they use only minimal native code, they can be more similar across platforms.

But is this what you really want? Isn't the whole point of wxWidgets that it uses the native widgets of each platform, so that cross-platform code doesn't look cross-platform?

Anyway, you decide. Personally, I haven't tried using the Universal widgets. Maybe someday.

Q: How do I get my wxGrid control (or other advanced control) to link?

Link in "wxmsw26d_adv.lib" (or whatever is needed by your particular system setup).

Q: I want to use something in the "contrib" directory (Styled Text Class, animate, plot, etc.). How do I compile it?

Set your working directory to c:\wxWidgets\contrib\build\<ITEM-YOU-WANT> and then compile it with your version of "make". For example:

cd c:\wxWidgets\contrib\build\stc
nmake -f makefile.vc

Q: What are the other steps before I can use something in the "contrib" directory?

  1. Include "c:\wxwidgets\contrib\include" in the list of include directories to search in your Makefile or IDE settings.
  2. Include the appropriate include file for the item you wish to use, as in: #include "wx/stc/stc.h"
  3. Add the appropriate library to your library listings in your Makefile or IDE settings. The library will be stored in c:\wxWidgets\lib\<COMPILER>_lib\wx<port><version><d?>_<item>.lib. For example: wxmsw26d_stc.lib (an MSW debug implementation within version 2.6).

Q: Why do I get all of these linking errors when I try and use an wxHtmlListBox (or any other object with HTML capability) ?

MyFile.obj : error LNK2001: unresolved external symbol "protected: virtual class wxColour __thiscall wxHtmlListBox::GetSelectedTextBgColour(class wxColour const &)const " (?GetSelectedTextBgColour@wxHtmlListBox@@MBE?AVwxColour@@ABV2@@Z)

MyFile.obj : error LNK2001: unresolved external symbol "protected: virtual class wxColour __thiscall wxHtmlListBox::GetSelectedTextColour(class wxColour const &)const " (?GetSelectedTextColour@wxHtmlListBox@@MBE?AVwxColour@@ABV2@@Z)

MyFile.obj : error LNK2001: unresolved external symbol "protected: virtual class wxString __thiscall wxHtmlListBox::OnGetItemMarkup(unsigned int)const " (?OnGetItemMarkup@wxHtmlListBox@@MBE?AVwxString@@I@Z)

(etc.)

This is because you need to link with the wxWidgets HTML library. Add "wxmsw26d_html.lib" to your library path and then recompile (of course, change "msw" and "26d" to your specific needs, as necessary).

Q: What else do I need to do to implement a wxHtmlListBox?

In order to use wxHtmlListBox, you will need to create a new child class. For example, the following is a minimal implementation of wxHtmlListBox:

= = = = = in your header file = = = = =

#include "wx/htmllbox.h"

class myHtmlListBox : public wxHtmlListBox
{
public:
  myHtmlListBox (wxWindow* parent, wxWindowID id = wxID_ANY, 
                const wxPoint& pos = wxDefaultPosition, 
                const wxSize& size = wxDefaultSize, 
                long style = 0, 
                const wxString& name = wxVListBoxNameStr);

protected:
  virtual wxString OnGetItem(size_t n) const;

  DECLARE_NO_COPY_CLASS(weClassContentsListBox)
};

= = = = = in your source file = = = = =

myHtmlListBox::weClassContentsListBox(wxWindow* parent, wxWindowID id, 
                const wxPoint& pos, const wxSize& size, 
                long style, const wxString& name) :
    wxHtmlListBox(parent, id, pos, size, style, name)
{
}

wxString 
myHtmlListBox::OnGetItem(size_t n) const
{
  return wxString("list <b>HelloWorld</b>");  // << Change this to return something more useful
}

PART IV: Sizers

Q: Why canít I get my stupid wxSizer to recognize the minimum size of my sub-objects?

This is a common problem, and one which can be a little tricky, especially when panels are involved.

Basically, there are two things you need to do to get a sizer to recognize the minimum sizes of sub-objects:

  1. Make sure to call wxSizer::SetSizeHints after you have created the sub-objects.
  2. Make sure that all of your panels have a sizer over them and under them.

For example, the following is a "monitor" window which I created in wxWidgets. It contains a text box, and three buttons. Since I wanted menu commands, I put the whole thing inside of a wxPanel, which itself was inside of a wxFrame.

The basic hierarchy of the objects and sizers are as follows:

myFrame (wxFrame)
-  wxBoxSizer(wxVERTICAL)  =>  (pFrameSizer in the example below)
                                // Can be any orientation, only has a single object, the wxPanel
    -  myPanel (wxPanel)
        -  wxBoxSizer(wxVERTICAL)  =>  (pPanelSizer in the example below)
                                        // holds the text control and the buttons sub-sizer
            -  wxTextCtrl()  //  Added with wxGROW
            -  wxBoxSizer(wxHORIZONTAL)   //  holds the three buttons, wxGROW
                -  wxButton()
                -  wxButton()
                -  StretchSpace()  // wxGROW
                -  wxButton()

Now, once this was done, I need to propagate the minimum size hints up the hierarchy. I do this by calling SetSizerAndFit() from the bottommost window to the topmost:

  myPanel->SetSizerAndFit(pPanelSizer)
  myFrame->SetSizerAndFit(pFrameSizer)

I also heard (by reading the message boards) that you might also have to call mSizer->SetSizeHints(myWindow) to tell the window what itís minimum size should be. However, this seems to be done automatically by SetSizerAndFit(), so I suspect itís only needed in dynamic cases where you are adding and subtracting things from the window in real-time.

=== complete example ===

CMyFrame::CMyFrame(const wxString& title)
       : wxFrame(NULL, weID_FRAME, title)
{
.
.
.
  wxBoxSizer *pFrameSizer = new wxBoxSizer(wxVERTICAL);

  wxPanel *pPanel = new wxPanel(this);
  pFrameSizer->Add(pPanel, 1, wxGROW);

  wxBoxSizer *pPanelSizer = new wxBoxSizer( wxVERTICAL );

  m_pLog = new wxTextCtrl(pPanel, weID_MONITOR_LOG, "", wxDefaultPosition, wxSize(200,200), wxTE_READONLY | wxTE_DONTWRAP);
  pPanelSizer ->Add(m_pLog, 1, wxGROW | wxALIGN_CENTER | wxFIXED_MINSIZE, 0);

  wxBoxSizer *pButtonsSizer = new wxBoxSizer(wxHORIZONTAL);
  pPanelSizer ->Add(pButtonsSizer, 0, wxGROW | wxALL, 10);

  wxButton *pSave = new wxButton(pPanel, weID_MONITOR_SAVE, wxT("Save"));
  pButtonsSizer->Add(pSave, 0, wxRIGHT | wxALIGN_LEFT, 10);
  wxButton *pClear = new wxButton(pPanel, weID_MONITOR_CLEAR, wxT("Clear"));
  pButtonsSizer->Add(pClear, 0, wxRIGHT | wxALIGN_LEFT, 10);

  pButtonsSizer->AddStretchSpacer();

  wxButton *pClose = new wxButton(pPanel, wxID_CLOSE);
  pButtonsSizer->Add(pClose, 0, wxALIGN_RIGHT);

  pPanel->SetSizerAndFit(pPanelSizer);
  this->SetSizerAndFit(pFrameSizer);

//  Fit();

  SetSize(wxSize(400, -1));   // Set the initial frame size, can be larger than the minimum size
}

Q: My wxBoxSizer is behaving bizarrely. Either: 1) My AddStretchSpacer() is not stretching, or 2) Iím getting these huge weird gaps around my buttons.

The wxBoxSizer does not work very well when it is nested inside of other wxBoxSizers. This has to do with the fact that there is only one "wxGROW" flag, rather than two (for example, life would be so much easier if there was both a wxGROW_VERTICAL and a wxGROW_HORIZONTAL).

So, for example, suppose you have the following situation:

--------------------------------------------------
|                                                |
|                 [text control]                 |
|                                                |
--------------------------------------------------
|  [button-a]             [button-b]  [button-c] |
--------------------------------------------------

In this example, you would want [button-a] to be left justified, and [button-b] and [button-c] to be right justified. In between [button-a] and [button-b] you put in a StretchSpacer which is supposed to grow when the window is stretched right, and the text control grows when the window is stretched down.

So, you might expect to use the following structure:

wxBoxSizer(wxVERTICAL)
  wxTextControl  -  proportion=1, wxGROW
  wxBoxSizer(wxHORIZONTAL)
    wxButton  (button-a)
    AddStretchSpacer()
    wxButton  (button-b)
    wxButton  (button-c)

But this would be wrong, because what you end up getting is something like this:

--------------------------------------------------
|                                                |
|                 [text control]                 |
|                                                |
--------------------------------------------------
|        [button-a] [button-b] [button-c]        |
--------------------------------------------------

All of the buttons are centered, and the stretch spacer has dissappeared!

The problem is that the nested wxBoxSizer is only taking up the minimum amount of horizontal space necessary, it does not automatically stretch, left to right, to fill up all available space.

So, you might try and fix it by doing the following:

wxBoxSizer(wxVERTICAL)
  wxTextControl  -  proportion=1, wxGROW
  wxBoxSizer(wxHORIZONTAL)  -  proportion=1, wxGROW  << ADDED wxGROW
    wxButton  (button-a)
    AddStretchSpacer()
    wxButton  (button-b)
    wxButton  (button-c)

This works, in that stretch spacer is back, but now there is this weird space around the buttons:

--------------------------------------------------
|                                                |
|                 [text control]                 |
|                                                |
--------------------------------------------------
|  [button-a]             [button-b]  [button-c] |
|                                                |
|                                                |
--------------------------------------------------

The problem here is that now the wxBoxSizer for the buttons is growing properly left-to-right, but it is also growing top-to-bottom. And because proportion=1, it is providing exactly as much space to the buttons (top-to-bottom) as it is to the text control (because both parts have proportion=1, they are both stretched equally).

And note, changing "proportion=0" doesnít help any.

So, how can this problem be solved?

The answer is to use the wxFlexGridSizer. With this control, you can individually specify how different cells are grown, and in what dimensions. The new structure would be as follows:

wxFlexGridSizer(2,1,0,0) =>  2 rows and 1 column
  AddGrowableCol(0,1)  =>  Make the only column, column 0, grow-able
  AddGrowableRow(0,1)  =>  Make only row 0 grow-able, leave row 1 fixed
  wxTextControl  -  proportion =1, wxGROW
  wxBoxSizer(wxHORIZONTAL)  -  proportion=1, wxGROW
    wxButton  (button-a)
    AddStretchSpacer()
    wxButton  (button-b)
    wxButton  (button-c)

And now things work, as expected. The wxBoxSizer around the buttons is free to grow to fill out all the space to which it is alloted, and the wxFlexGridSizer guarantees that it is growable in the horizontal dimension (because it is inside a growable column) but not in the vertical dimension (because it is *not* inside a growable row).

--------------------------------------------------
|                                                |
|                 [text control]                 |
|                                                |
--------------------------------------------------
|  [button-a]             [button-b]  [button-c] |
--------------------------------------------------

Q: How do I add items to a GridSizer (wxFlexGridSizer or wxGridSizer) ?

Use the ->Add() function, just like with any sizer. Note that cells in the grid sizer are filled up left-to-right, then top-to-bottom (just like reading this paragraph).

Q: Can I get an actual code example for how to use wxFlexGridSizer?

Uh, sure. Try this one on for size. It implements the layout described in the previous Question. The following code is called within a wxDialog constructor:

  wxBoxSizer *pDialogSizerOuter = new wxBoxSizer(wxVERTICAL);
  
  // Create an "inner" sizer so we can add a nice 10 pixel border around
  //   all of the inner contents
  wxFlexGridSizer *pDialogSizerInner = new wxFlexGridSizer(2,1, 0, 0);
  pDialogSizerInner->AddGrowableCol(0);
  pDialogSizerInner->AddGrowableRow(0);

  //** The text entry box (minimum size = 400x300)
  wxTextCtrl *m_pMyTextEntry = wxTextCtrl(this, myID_TEXT_ENTRY,
                  wxDefaultPosition, wxSize(400,300));
  pDialogSizerInner->Add(pMyTextEntry, 1, 
        wxBOTTOM | wxGROW | wxALIGN_CENTER | wxFIXED_MINSIZE, 10);

  wxBoxSizer *pButtonsSizer = new wxBoxSizer(wxHORIZONTAL);

  wxButton *pButtonA = 
        new wxButton(this, myID_BUTTON_A, wxT("button-a"));
  pButtonsSizer->Add(pButtonA, 0, wxRIGHT, 10);

  pButtonsSizer->AddStretchSpacer(1);

  wxButton *pButtonB = 
        new wxButton(this, myID_BUTTON_B, wxT("button-b"));
  pButtonsSizer->Add(pButtonB, 0, wxRIGHT, 10);

  wxButton *pButtonC = 
        new wxButton(this, myID_BUTTON_C, wxT("button-c"));
  pButtonsSizer->Add(pButtonC);

  pDialogSizerInner->Add(pButtonsSizer, 1, wxGROW);

  // The 10 pixel border is added here
  pDialogSizerOuter->Add(pDialogSizerInner, 1, wxGROW | wxALL, 10);

  SetSizerAndFit(pDialogSizerOuter);

Q: Why doesnít my combo box get centered vertically with a sizer?

Suppose you have the following code:

  wxBoxSizer *horizSizer = new wxBoxSizer(wxHORIZONTAL);
  headerSizer->Add(m_comboLabel, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, 10);
  headerSizer->Add(m_comboBox, 1, wxGROW | wxALIGN_CENTER_VERTICAL);

What you may find is that the label is centered vertically, but the combo box (for reasons I have been unable to trace) is positioned at the top. I think this may be a bug.

The solution is to create an embedded vertical sizer with two stretchable spacers around the combo box:

  wxBoxSizer *horizSizer = new wxBoxSizer(wxHORIZONTAL);
  headerSizer->Add(m_comboLabel, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, 10);
  wxBoxSizer *comboSizer = new wxBoxSizer(wxVERTICAL);
  comboSizer->Add(0,0,1);
  comboSizer->Add(m_comboBox, 0, wxGROW);
  comboSizer->Add(0,0,1);
  headerSizer->Add(comboSizer, 1, wxGROW | wxALIGN_CENTER_VERTICAL);

Q: How can I ensure that a frame with an embedded splitter window doesnít get sized too small?

I've tried using sizers to do this, but ultimately found out that it was simpler (and more reliable) to compute the minimum sizes myself.

For example, after creating the sizer, both of itís windows, and all of the nested components and associated sizers, do the following:

MyFrame::MyFrame(const wxString& title)
       : wxFrame(NULL, wxID_ANY, title)
{
  .
  .
  .
  wxSize rightSize = m_right->GetMinSize();   // Get the minimum size of the right pane
  wxSize leftSize = m_left->GetMinSize();       // Get the minimum size of the left pane
  int panesX = leftSize.x+rightSize.x+10;        // Add 10 to leave room for splitter borders+sash
  int panesY = leftSize.y > rightSize.y ? leftSize.y : rightSize.y;
  SetMinSize(wxSize(panesX , panesY));
  Fit();
  // Now set the starting size for your window to whatever you want (just make sure itís
  // larger than the minimum sizes)
  SetSize(wxSize(590, 400));
}

Q: I use SetMinSize() to set the minimum size of my window, then I add it to my sizer with wxFIXED_MINSIZE, but it gets ignored. WHY?

This is because wxFIXED_MINSIZE does not pay attention to the SetMinSize() values (perhaps it should), but instead it pays attention to the size of the window.

So, instead of using SetMinSize() to set the minimum size, use SetSize(). Then wxFIXED_MINSIZE, will take as the windowís minimum size the current size of the window and everything will be fine.

PART V: Other User Interface Behavior

Q: How do I prevent TAB navigation from navigating to a specified control?

The only way Iíve found to do this is to create a sub-class of the control, and implement the SetFocusFromKbd() function. Whenever SetFocusFromKbd() is called by wxWidgets, simply call "Navigate()" to move away again:

class wxMyButton : public wxBitmapButton
{
public:
.
.
.

  void SetFocusFromKbd() { Navigate(); }

};

But note: this may not work for when people press SHIFT-TAB to move backwards through the tabs (more research is needed).

Q: How can I make a text control that selects itís entire contents whenever it gains the keyboard focus?

Such a text control would behave like the URL entry box of a web browser. The problem is how to handle the standard mouse-click processing. My solution sets a flag, and then waits for idle time (after all standard processing is over), to select the contents.

For example, try the following:

= = = = = = = = = mytextctrl.h = = = = = = = = =

// * Special text control which selects the entire contents
//   whenever it gains input focus

#ifndef MY_TEXT_CTRL_H
#define MY_TEXT_CTRL_H

class myTextCtrl: public wxTextCtrl {
public:
  myTextCtrl(wxWindow* parent, wxWindowID id, 
             const wxString& value = "", 
             const wxPoint& pos = wxDefaultPosition, 
             const wxSize& size = wxDefaultSize, 
		 long style = 0, 
             const wxValidator& validator = wxDefaultValidator, 
	       const wxString& name = wxTextCtrlNameStr);

  void DoSetFocus( wxFocusEvent &event );
  void DoIdle( wxIdleEvent &event );

private:
  bool m_bDoSelectAll;

  DECLARE_EVENT_TABLE()
};

#endif

= = = = = = = = = mytextctrl.cpp = = = = = = = = =

#include "wx/wxprec.h"


#ifdef __BORLANDC__
    #pragma hdrstop
#endif

#ifndef WX_PRECOMP
    #include "wx/wx.h"
#endif

#include "mytextctrl.h"

BEGIN_EVENT_TABLE(myTextCtrl, wxTextCtrl)
  EVT_SET_FOCUS(myTextCtrl::DoSetFocus)
  EVT_IDLE(myTextCtrl::DoIdle)
END_EVENT_TABLE()


myTextCtrl:: myTextCtrl (wxWindow* parent, wxWindowID id, const wxString& value, 
             const wxPoint& pos, const wxSize& size, 
			 long style, const wxValidator& validator, 
			 const wxString& name)
  : wxTextCtrl(parent, id, value, pos, size, style, validator, name)
{
  m_bDoSelectAll = false;
}


void 
myTextCtrl::DoSetFocus( wxFocusEvent &event )
{
  m_bDoSelectAll = true;
}


void 
myTextCtrl::DoIdle( wxIdleEvent &event )
{
  if(m_bDoSelectAll) {
    // Needs to be delayed until after all other mouse-down
    // related events have been processed
    SetSelection(-1,-1);
    m_bDoSelectAll = false;
  }
}

Q: How do I make a text control which implements auto-complete ?

The tricky part here is handling the backspace and delete keys. This can be done by checking for the EVT_KEY_DOWN() event to set a flag which ignores autocomplete on the next text entry event (and then clear the flag during the next idle time).

It works something like this:

= = = = = = = = = mytextctrl.h = = = = = = = = =

// * Special text control which implements auto-completion

#ifndef MY_TEXT_CTRL_H
#define MY_TEXT_CTRL_H

class myTextCtrl: public wxTextCtrl {
public:
  myTextCtrl(wxWindow* parent, wxWindowID id, 
             const wxString& value = "", 
             const wxPoint& pos = wxDefaultPosition, 
             const wxSize& size = wxDefaultSize, 
		 long style = 0, 
             const wxValidator& validator = wxDefaultValidator, 
	       const wxString& name = wxTextCtrlNameStr);

  void TextEntered( wxCommandEvent &event );
  void DoIdle( wxIdleEvent &event );
  void DoKeyDown( wxKeyEvent &event );

  // Note:  You will need to implement some class which holds
  //        a list of items to be searched for auto-complete
  //        (in this example, it is called "mylist")
  void SetMyList(myList *pList) { m_pList = pList; }

private:
  bool m_bDoSelectAll;
  bool m_bIgnoreNextTextEdit;
  myList *m_pList;

  DECLARE_EVENT_TABLE()
};

#endif

= = = = = = = = = mytextctrl.cpp = = = = = = = = =

//*** myTextCtrl
//
// Implements auto-completion

#include "wx/wxprec.h"

#ifdef __BORLANDC__
    #pragma hdrstop
#endif

#ifndef WX_PRECOMP
    #include "wx/wx.h"
#endif

#include "mytextctrl.h"

BEGIN_EVENT_TABLE(myTextCtrl, wxTextCtrl)
  EVT_TEXT(wxID_ANY, myTextCtrl::TextEntered) 
  EVT_IDLE(myTextCtrl::DoIdle)
  EVT_KEY_DOWN(myTextCtrl::DoKeyDown) 
END_EVENT_TABLE()


myTextCtrl:: myTextCtrl (wxWindow* parent, wxWindowID id, const wxString& value, 
             const wxPoint& pos, const wxSize& size, 
			 long style, const wxValidator& validator, 
			 const wxString& name)
  : wxTextCtrl(parent, id, value, pos, size, style, validator, name)
{
  m_bIgnoreNextTextEdit = false;
  m_pList = NULL;
}


void 
myTextCtrl::DoIdle( wxIdleEvent &event )
{
  m_bIgnoreNextTextEdit = false;
  event.Skip();
}


void 
myTextCtrl::TextEntered( wxCommandEvent &event )
{
  wxString sVal;
  char *szVal;
  char *szListName;
  POS pos;
  long iPoint;

  if(m_bIgnoreNextTextEdit) {
    m_bIgnoreNextTextEdit = false;
    event.Skip();
    return;
  }

  iPoint = GetInsertionPoint();

  // First, if the cursor is at the end of the text
  if(GetInsertionPoint() != GetLastPosition()) {
    event.Skip();
    return;
  }

  // Second, if the text so far is the prefix of a class in the catalog
  sVal = GetValue();
  szVal = (char*)sVal.c_str();

  // Get the first matching value from the sorted list
  //
  // Note:  You will need to implement the GetFirstFrom() routine
  // As part of whatever list you want to auto-complete based on
  // Code assumes that szListName == NULL if nothing with a matching
  // prefix is found
  szListName = m_pList->GetFirstFrom(szVal);

  if(szListName && strncmp(szVal, szClassName, strlen(szVal)) == 0 &&
       strlen(szVal) < strlen(szClassName)) {
    // Third, write the entire name of the first matching class 
    //    into the text string
    SetValue(wxString(szClassName));

    // Fourth, select the text from the current cursor position to 
    //    the end of the text
    SetSelection(iPoint, -1);
  }
}


void 
myTextCtrl::DoKeyDown( wxKeyEvent &event )
{
  int kc = event.GetKeyCode();

  // This is necessary to ignore edits after a BACKSPACE or DELETE
  //   key (points when auto-complete should be momentarily turned off)
  if(kc == WXK_DELETE  ||  kc == WXK_NUMPAD_DELETE || kc == WXK_BACK || 
     kc == WXK_CLEAR)
    m_bIgnoreNextTextEdit = true;

  event.Skip();
}

Q: Can the above two text controls be combined into one?

Sure! (this is left as an exercise for the student)

PART VI: wxStyledTextControl (the wxWidgets Scintilla wrapper)

Q: Where can I get better documentation on wxStyledTextCtrl and Scintilla?

Switch to wxScintilla and read itís documentation where everything is very well documented.

Q: Can I get any more help on implementing the wxWidgets Scintilla wrapper in my application?

Yeah, the sample code provided with wxWidgets actually adds another layer (a wrapper around the wrapper) that takes a little detective work to figure out. Here's a simper code snippet from my implementation:

wxChar* MyKeyWords = 
  _T("new delete class ")
  _T("if else while do switch case default for foreach break continue on_continue on_done on_break on_exit return ")
  _T("int char float string bool data byte typeid dynamic ")
  _T("const weakref private ref synchronized ")
  _T("mod isa has ")
  _T("hexdata ascii unicode ")
  _T("true false null ");
.
.
.
  m_classHeader = new wxStyledTextCtrl(m_right, weID_CLASS_MEMBERS, wxPoint( 0, 0 ),
                       wxSize( 300, 150 ), wxSIMPLE_BORDER);
  wxFont m_codeFont(8, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
  m_classHeader->SetLexer(wxSTC_LEX_CPP);

  {
    int Nr;
    for (Nr = 0; Nr < wxSTC_STYLE_LASTPREDEFINED; Nr++)
        m_classHeader->StyleSetFont (Nr, m_codeFont);
  }

  m_classHeader->StyleSetForeground(wxSTC_C_COMMENT, wxColor(0,100,0));
  m_classHeader->StyleSetForeground(wxSTC_C_COMMENTLINE, wxColor(0,125,0));
  m_classHeader->StyleSetForeground(wxSTC_C_STRING, wxColor(128,0,0));
  m_classHeader->StyleSetForeground(wxSTC_C_WORD, wxColor(0,0,200));
  m_classHeader->SetKeyWords(0,MyKeyWords);

  m_classHeader->SetTabWidth (2);
  m_classHeader->SetUseTabs (false);
  m_classHeader->SetTabIndents (true);
  m_classHeader->SetBackSpaceUnIndents (true);
  m_classHeader->SetIndent (2);

Q: How do I implement smart-indentation with my wxWidgets Scintilla wrapper?

You need to derive a sub-class from wxStyledTextCtrl, and then handle the EVT_STC_CHARADDED() event. Look for a carriage return, check the indentation of the previous line, and then make the new line equal in indentation. Here's some code snippets to help:

class MyStyledTextCtrl : public wxStyledTextCtrl
{
public:  
  MyStyledTextCtrl (wxWindow *parent, wxWindowID id = wxID_ANY,
          const wxPoint &pos = wxDefaultPosition,
          const wxSize &size = wxDefaultSize,
          long style = wxSUNKEN_BORDER|wxVSCROLL
         );

  ~MyStyledTextCtrl ();

  void OnCharAdded (wxStyledTextEvent &event);

  DECLARE_EVENT_TABLE()
};

BEGIN_EVENT_TABLE(MyStyledTextCtrl, wxStyledTextCtrl)
  EVT_STC_CHARADDED (wxID_ANY,  MyStyledTextCtrl::OnCharAdded)
END_EVENT_TABLE()

MyStyledTextCtrl::MyStyledTextCtrl(wxWindow *parent, wxWindowID id,
            const wxPoint &pos,
            const wxSize &size,
            long style)
    : wxStyledTextCtrl (parent, id, pos, size, style) {
}

MyStyledTextCtrl::~MyStyledTextCtrl() {}

void 
MyStyledTextCtrl::OnCharAdded (wxStyledTextEvent &event) {
    char chr = (char)event.GetKey();
    int currentLine = GetCurrentLine();
    // Change this if support for mac files with \r is needed
    if (chr == '\n') {
        int lineInd = 0;
        if (currentLine > 0) {
            lineInd = GetLineIndentation(currentLine - 1);
        }
        if (lineInd == 0) return;
        SetLineIndentation (currentLine, lineInd);
        GotoPos(PositionFromLine (currentLine) + lineInd);
    }
}

Q: Where is the documentation for wxCharBuffer?

wxCharBuffer is one of many buffer class types, all of which have the same class structure. The routines in wxCharBuffer are as follows:

wxCharBuffer(const char *str)
Constructor - Uses strdup() to copy the string to an internal memory buffer

wxCharBuffer(size_t len=0)

Constructor - Creates an empty memory buffer of <len> chars. NOTE: len is the length of the buffer, which should be large enough to include the terminating Ď\0í character.

~wxCharBuffer()

Destructor - free()ís the internal memory buffer back to the heap, if any

char *release()

Returns the internal memory buffer so it can be released (or ignored) by the caller

wxCharBuffer& operator=(const char *str)

Can use the Ď=í operator to assign a string to the buffer, releases the internal memory (if any) back to the heap and does strdup() to create the new buffer of strings

wxCharBuffer& operator=(const wxCharBuffer& src)

Moves the buffer from the src to the destination, using Ď=í, releasing the destination buffer (if it exists). The source ends up empty, with no internal memory buffer.

char *data()

returns a pointer to the internal memory buffer.

operator[]

returns a character selected from []

Q: Why does wxStyledTextCtrl::GetTextRaw() returns one less character than is actually in my file?

Because there is a bug in the glue code. Make the following change to wxWidgets/contrib/src/stc/stc.cpp and then re-make your stc libraries:

wxCharBuffer wxStyledTextCtrl::GetTextRaw()
{
    int len  = GetTextLength()+1;  /// <<< ADD 1 HERE
    wxCharBuffer buf(len);
    SendMsg(SCI_GETTEXT, len, (long)buf.data());
    return buf;
}

PART VII: Miscellaneous Quirkyness

Q: How can I tell if a wxTreeItemId is valid?

When you get the currently selected item from a wxTreeCtrl, the wxTreeCtrl::GetSelection() routine "returns an invalid item" if there is nothing selected.

But how do you tell if an ID is valid or invalid? Simple. Use the undocumented wxTreeItemId::IsOk() routine.

For example:

/********************/
/* OnTreeSelChanged */
/********************/
void 
MyDialog::OnTreeSelChanged( wxTreeEvent& event )
{
  wxTreeItemId id = m_pMyTree->GetSelection();

  if(id.IsOk()) {
    // Process the selected item here
  }
}

Q: Why doesnít wxID_ANY work with wxMenu?

You can not pass "wxID_ANY" to any of the wxMenu->Append() methods. These methods require that you specify positive ID numbers (and will automatically generate positive ID numbers for you if you specify wxID_ANY, which is negative). This is unfortunate, since itís possible that the automatically generated IDs (which are positive) might conflict with yours. This happened to me. What are the chances?

Anyway, just donít pass wxID_ANY whenever you create menus.

Q: When I use wxSplitterWindow->SetSashSize(10), why doesn't the sash get erased/redrawn when I move it?

Right. Instead of a nice, simple, grey sash, you will see the fragments of the window which formerly occupied the space of the sash.

Basically, this is not implemented in wxMSW (the Windows version of wxWidgets).

The width of the sash is not passed into: wxRendererNative::Get().DrawSplitterSash() and so this routine will only draw a standard size (3-pixel) sash. The rest of the sash is not drawn and so retains what was displayed there before the sash was moved.

So, it's a bug. So, I guess don't use SetSashSize(). It may work in 2.8, I don't know.

Q: Why do I get the "Couldn't add an image to the image list" error with my toolbars?

Sometimes this happens when your tool size != your image size. In my case, I wanted to have larger buttons with more space around the toolbar images. And so, my images were smaller than my toolbar tools.

Specifically, this occured when:

For example, my source code looked like this:

toolSize.Set(22, 22);
m_pToolBar = new wxToolBar(this, -1, wxDefaultPosition,
                         wxDefaultSize,
                         wxTB_FLAT | wxTB_HORIZONTAL | wxNO_BORDER);
m_pToolBar->SetToolBitmapSize(wxSize(22,22));
.
.
.
wxBitmap bmpBack(back_xpm);   // both of these images are 16x15
wxBitmap bmpNoBack(noback_xpm);

m_pToolBar->AddTool(weID_BACK, wxT("Back"), bmpBack, bmpNoBack,
                             wxITEM_NORMAL, wxT("Return to previous page."));
 

The problem occurs when the system is creating the image list for the disabled images. This is only required when some disabled images are actually specified.

What happens is that wxToolBar::Realize() code tries to create images of the smaller, disabled-bitmap size, and then add them onto an image list of the larger, tool-size image list. It does this for the images for the tools which do *not* have a disabled-image supplied. Unfortunately, this causes the dreaded "Couldn't add an image to the image list" error.

Anyway, the following patch to the wxWidgets source code solves the problem:

wxwidgets:

--- src/msw/tbar95.cpp ---
.
.
.
bool wxToolBar::Realize()
{
.
.
.
if ( m_disabledImgList )
{
    wxBitmap bmpDisabled = tool->GetDisabledBitmap();
.
.
.
    MapBitmap(bmpDisabled.GetHBITMAP(), w, h);

// >>> ADD THESE LINES >>>>
    if(w != m_defaultWidth || h != m_defaultHeight) { // here
        int xOffset = wxMax(0, (m_defaultWidth - w)/2);
        int yOffset = wxMax(0, (m_defaultHeight - h)/2);
        wxImage imgLarger = bmpDisabled.ConvertToImage();
        wxBitmap bmpLarger(
                imgLarger.Resize(wxSize(m_defaultWidth,m_defaultHeight),
                                  wxPoint(xOffset,yOffset)));
        bmpDisabled = bmpLarger;
    }
// <<< ADD THESE LINES <<<

    m_disabledImgList->Add(bmpDisabled);
}
.
.
.

In some post I read somewhere, someone (Robin?) mentioned that there might be a fix checked into CVS. So this may be fixed in 2.8.2 .