Many beginner questions, trying to learn wxWidgets

This forum can be used to talk about general design strategies, new ideas and questions in general related to wxWidgets. If you feel your questions doesn't fit anywhere, put it here.
Post Reply
ab396356
In need of some credit
In need of some credit
Posts: 5
Joined: Fri Jun 01, 2018 6:46 am

Many beginner questions, trying to learn wxWidgets

Post by ab396356 »

I am using Visual Studio 2017, wxWidgets 3.0.4, wxFormBuilder 3.7.0.

As an exercise, I am trying to create a simple program that generates a valid XML file from user input (the contents of the XML are unimportant).

I use XRC to keep the interface as separate from the code as possible.

Aside from the plenty questions below, I'm also in need of style guidance, as in: am I structuring my code incorrectly when using wxWidgets? Should the frame be a member data of the app? Should the event Bind()'s happen in the frame constructor instead of the app OnInit()? And so on. Basically let me know if you spot bad practices.

Now on to the questions themselves, numbered for convenience. Feel free to skip answering the ones you don't feel like, but please number your answers accordingly.
  1. Is the way I associate the Escape with the frame closing the proper way to do it? See xmlapp_frame::on_key_up(). If not, how else to associate Escape with closing the frame?
  2. Why is the frame background color not the usual color from Windows, but a dark grey?
  3. How to make the wxGridSizer split the two columns at 25-75 instead of 50-50? Or should another sizer be used?
  4. The wxFormBuilder utility doesn't set minimum size of frame in XRC, is this on purpose?
  5. How come the application closes when the Close button on the titlebar is clicked, despite that event not being handled by my code? (Asking because in some tutorial code I remember it was handled as EVT_CLOSE.)
  6. How to set the file path text in the file picker as read-only?
  7. I noticed I had to include <wx/valnum.h> for wxFloatingPointValidator but not <wx/valtext.h> for wxTextValidator. I'd therefore like to know which headers exactly wxprec.h and wx.h can be relied to include, by themselves, regardless of wxWidgets version. For example if I include <wx/valtext.h> or <wx/image.h> by hand to make sure future users won't get a compilation error, am I paranoid to do so?
  8. How to make the input fields (wxTextCtrl) stretch only horizontally when the window is resized, but not stretch vertically?
  9. Is it overzealous to include all wxWidgets .lib files? And if yes, how can I figure out which ones are unneeded, other than by trial and error as by removing and restoring them in the linker parameters?
  10. Despite using validators to associate data with the input fields, I still had to override wxFrame::TransferDataFromWindow(). Does this mean that validators only update the data when the dialog/frame is closed?
  11. Finally there is a coding bug somewhere in xmlapp_frame::on_generate(): when that function terminates, the program crashes with an exception pointing inside ~ConvertedBuffer() at:

    Code: Select all

    C:\wxWidgets-3.0.4\include\wx\string.h:3490
Thank you very much for you patience.

Attached are a screenshot and the source code. The screenshot shows the ugly background color of the frame and the undesirable vertical stretching of the text inputs.
XML Generator.png
XML Generator.png (41.62 KiB) Viewed 3073 times
Attachments
exp02-xmlgen.zip
(14.72 KiB) Downloaded 134 times
User avatar
doublemax
Moderator
Moderator
Posts: 19116
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Many beginner questions, trying to learn wxWidgets

Post by doublemax »

Should the frame be a member data of the app?
You can do that if you need access to the pointer later.
Should the event Bind()'s happen in the frame constructor instead of the app OnInit()?
Override the xmlapp_frame constructor, everything related to the frame should happen there.

1) That's one way to do it. But you should call ev.Skip() if you don't handle the event.
Other ways would be to have a menu entry with an accelerator or a separate wxAcceleratorTable assigned to the frame. http://docs.wxwidgets.org/trunk/classwx ... table.html

2) Use a wxPanel as the only child of the wxFrame and create all controls as children of that panel

3) Use a wxFlexgridSizer and mark only the 2nd column as "growable".

5) The default EVT_CLOSE handler of wxFrame destroys the frame and if that's the last toplevel window in the application, the application will terminate

6) You can get a pointer to the wxTextCtrl with wxPickerBase::GetTextCtrl().

9) In the documentation for each class, you see in which library it is.

11) Get a complete backtrace to see exactly where is crashes.
Use the source, Luke!
ab396356
In need of some credit
In need of some credit
Posts: 5
Joined: Fri Jun 01, 2018 6:46 am

Re: Many beginner questions, trying to learn wxWidgets

Post by ab396356 »

doublemax wrote:Other ways would be to have a menu entry with an accelerator or a separate wxAcceleratorTable assigned to the frame.
I tried this however I don't know what ID I'm supposed to use for the Close button on the titlebar. I tried wxID_CLOSE and wxID_CLOSE_FRAME, as in the following code:

Code: Select all

const std::vector<wxAcceleratorEntry> acc_entries = {
    {wxACCEL_NORMAL, WXK_ESCAPE, wxID_CLOSE_FRAME}
};

const wxAcceleratorTable acc_table(acc_entries.size(), acc_entries.data());

frame->SetAcceleratorTable(acc_table);
doublemax wrote:2) Use a wxPanel as the only child of the wxFrame and create all controls as children of that panel
Thanks, done this, but now the problem is that the wxPanel's minimum size and proportion=0 are ignored and the frame can be resized to the point where none of its controls are visible. This isn't a big problem though, so if there isn't an easy solution, so be it.
doublemax wrote:5) The default EVT_CLOSE handler of wxFrame destroys the frame and if that's the last toplevel window in the application, the application will terminate
So what you are saying is that EVT_CLOSE should be handled just to be safe? Which would mean wxEVT_CLOSE_WINDOW if using Bind() instead of macro based event tables, yes?
doublemax wrote:6) You can get a pointer to the wxTextCtrl with wxPickerBase::GetTextCtrl().
That is not what I was looking for: I want to display the filename but keep it uneditable, so that the user is forced to choose a valid filename by browsing to it, while the filename itself shown just for reassurance.
doublemax wrote:11) Get a complete backtrace to see exactly where is crashes.
Apparently the problem was caused by the wxXmlDocument destructor delete'ing all its nodes, which were on the stack.

Thanks for the help so far and I'm still looking forward to answers for the other questions.
User avatar
doublemax
Moderator
Moderator
Posts: 19116
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Many beginner questions, trying to learn wxWidgets

Post by doublemax »

I tried this however I don't know what ID I'm supposed to use for the Close button on the titlebar. I tried wxID_CLOSE and wxID_CLOSE_FRAME, as in the following code:
Use wxID_CLOSE, but you will need an additional event handler for that. The key event will not get automatically mapped to the wxEVT_CLOSE event.
So what you are saying is that EVT_CLOSE should be handled just to be safe? Which would mean wxEVT_CLOSE_WINDOW if using Bind() instead of macro based event tables, yes?
Not necessarily, it depends on the application. In many cases it's totally fine that closing the window terminates the application.
doublemax wrote:
6) You can get a pointer to the wxTextCtrl with wxPickerBase::GetTextCtrl().
That is not what I was looking for: I want to display the filename but keep it uneditable, so that the user is forced to choose a valid filename by browsing to it, while the filename itself shown just for reassurance.
Sorry, i should have been more elaborate. Once you have a pointer to the wxTextCtrl, you can e.g. call Enable(false) on it. Or you could try wxWindow::ToggleWindowStyle() to set the wxTE_READONLY style flag (Not all flags can be changed after a control is created, i don't know it if works with wxTE_READONLY, but might be worth a try).

doublemax wrote:
2) Use a wxPanel as the only child of the wxFrame and create all controls as children of that panel
Thanks, done this, but now the problem is that the wxPanel's minimum size and proportion=0 are ignored and the frame can be resized to the point where none of its controls are visible. This isn't a big problem though, so if there isn't an easy solution, so be it.
There are two possible solutions:
1 (for when you're using a GUI editor): Put the wxPanel a sizer and assign that sizer to the frame
2 (to do it with code): Call main_sizer->SetSizeHints( frame_pointer )
Use the source, Luke!
ab396356
In need of some credit
In need of some credit
Posts: 5
Joined: Fri Jun 01, 2018 6:46 am

Re: Many beginner questions, trying to learn wxWidgets

Post by ab396356 »

doublemax wrote:Use wxID_CLOSE, but you will need an additional event handler for that. The key event will not get automatically mapped to the wxEVT_CLOSE event.
Two questions:
  1. According to the docs and auto-complete, there is no wxEVT_CLOSE, instead there is wxEVT_CLOSE_WINDOW. Does this mean that the latter is equivalent to the EVT_CLOSE used in the event table macros?
  2. I have tried the code below (see attachment for full source) and it doesn't work. Does this mean the accelerator requires a button with an ID_CLOSE be put on the form? (Which being loaded from XRC means I cannot use ID_CLOSE or any other ID anyway.)

    Code: Select all

    xmlapp_frame::xmlapp_frame()
    {
        Bind(wxEVT_BUTTON, &xmlapp_frame::on_exit, this, XRCID("m_button3"));
        Bind(wxEVT_CLOSE_WINDOW, &xmlapp_frame::on_close, this, wxID_CLOSE);
        Bind(wxEVT_BUTTON, &xmlapp_frame::on_generate, this, XRCID("m_button2"));
    }
    
    void xmlapp_frame::on_close(wxCloseEvent &)
    {
        Destroy();
    }
doublemax wrote:Sorry, i should have been more elaborate. Once you have a pointer to the wxTextCtrl, you can e.g. call Enable(false) on it.
Thanks, works nicely. Coding style question, would you do the above in a way other than by using dynamic_cast? I'm also considering if I should check for a nullptr return but I guess that's overly paranoid.

Code: Select all

dynamic_cast<wxPickerBase *> (frame->FindWindowByName("m_filePicker2"))
    ->GetTextCtrl()->Enable(false);
doublemax wrote:1 (for when you're using a GUI editor): Put the wxPanel a sizer and assign that sizer to the frame
Unfortunately this part of the example project keeps getting worse. See the attached screenshot for how bad it looks by default. The unseen controls become visible on resize. At this point I'd greatly appreciate specific detail on what it is I'm doing wrong and what must be fixed about the XRC. The current sizer layout is as follows:

Code: Select all

wxFrame {
    wxBoxSizer {
        wxPanel {
            wxBoxSizer {
                wxStaticBoxSizer { ... }
                wxStaticBoxSizer { ... }
                wxBoxSizer { ... }
            }
        }
    }
}
Finally, question 10 is still of importance to me, and I'll reword it here: how come, despite of using validators to associate text fields with the frame's member data, I still had to override the wxFrame::TransferDataFromWindow() function to "manually" update the object data? Do the validators only transfer data when the dialog/frame is closed?
Screenshot of the program.
Screenshot of the program.
XML Generator.png (28.83 KiB) Viewed 2974 times
Attachments
exp02-xmlgen-v2.zip
Full code for the example project.
(15.56 KiB) Downloaded 129 times
PB
Part Of The Furniture
Part Of The Furniture
Posts: 4193
Joined: Sun Jan 03, 2010 5:45 pm

Re: Many beginner questions, trying to learn wxWidgets

Post by PB »

ab396356 wrote:Finally, question 10 is still of importance to me, and I'll reword it here: how come, despite of using validators to associate text fields with the frame's member data, I still had to override the wxFrame::TransferDataFromWindow() function to "manually" update the object data? Do the validators only transfer data when the dialog/frame is closed?
(I did not read the attached source code)

I believe there is a difference in behavior between (modal) wxDialogs and wxFrames, where it is more automatic with wxDialogs which have default OnOK handler. The validators were probably designed with modal dialogs as the usual use case; validation should not be done on any closing the window, e.g. the application should not annoy users about invalid data when they close the dialog with Cancel.

See http://docs.wxwidgets.org/3.1/overview_ ... or_dialogs
User avatar
doublemax
Moderator
Moderator
Posts: 19116
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Many beginner questions, trying to learn wxWidgets

Post by doublemax »

According to the docs and auto-complete, there is no wxEVT_CLOSE, instead there is wxEVT_CLOSE_WINDOW. Does this mean that the latter is equivalent to the EVT_CLOSE used in the event table macros?
wxEVT_CLOSE_WINDOW was named wxEVT_CLOSE in earlier wx versions, apparently it was forgotten to also rename the macro EVT_CLOSE to EVT_CLOSE_WINDOW.
I have tried the code below (see attachment for full source) and it doesn't work. Does this mean the accelerator requires a button with an ID_CLOSE be put on the form? (Which being loaded from XRC means I cannot use ID_CLOSE or any other ID anyway.)
Just leave the ID out, which will then default to wxID_ANY, meaning "any window".

Code: Select all

dynamic_cast<wxPickerBase *> (frame->FindWindowByName("m_filePicker2"))->GetTextCtrl()->Enable(false);
Ugly stuff like this is one of the many reasons why i don't use GUI editors :)
Unfortunately this part of the example project keeps getting worse. See the attached screenshot for how bad it looks by default.
Looks fine to me, what's the problem with it?
At this point I'd greatly appreciate specific detail on what it is I'm doing wrong and what must be fixed about the XRC.
Sorry once again. As i don't use GUI editors i can only tell you how to fix this with code, but i don't know with checkbox to check (or whatever) in a GUI editor.
Use the source, Luke!
Post Reply