Child frame sends parent main frame back after Hide() if a wcColourPickerCtrl has been opened

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
Gabriele Giuseppini
Experienced Solver
Experienced Solver
Posts: 56
Joined: Fri Oct 12, 2018 6:12 pm
Location: Amsterdam, the Netherlands

Child frame sends parent main frame back after Hide() if a wcColourPickerCtrl has been opened

Post by Gabriele Giuseppini »

Dear all,

My main frame opens on demand a child frame ("SettingsWindow") where the user may change settings. I am using a frame rather than a dialog as this frame has a costly initialization and thus I want to keep re-using it each time the user needs to open it, and from what I've understood so far it seems that using EndModal() would imply that the dialog gets destroyed each time.

I manage opening the settings window from the main frame via Show(), while the window is closed by a settings window's event handler that invokes Hide().

I have noticed that after a wxColourPickerCtrl - child of SettingsWindows - has been opened and subsequently closed, after closing the settings window the main frame goes behind other frames on my desktop (Windows 7) - I have to use the taskbar or click on a visible portion of it to bring it forward again. This does not happen if, for example, I just click a button on the settings window.

Here's a minimal example:

Code: Select all

class TestFrame : public wxFrame
{
public:

    TestFrame(wxWindow* parent);
    void Open();

private:

    void OnCloseButton(wxCloseEvent & event);

    wxColourPickerCtrl * mColorPicker;
};

// ----------------------------------------------------------------------------
// main frame
// ----------------------------------------------------------------------------

// frame constructor
MyFrame::MyFrame(const wxString& title)
       : wxFrame(
           nullptr,
           wxID_ANY,
           title,
           wxDefaultPosition,
           wxDefaultSize,
           wxDEFAULT_FRAME_STYLE,
           _T("Main Frame"))
{
    Maximize();
    Centre();

    // set the frame icon
    SetIcon(wxICON(sample));

#if wxUSE_MENUS
    // create a menu bar
    wxMenu *fileMenu = new wxMenu;

    // the "About" item should be in the help menu
    wxMenu *helpMenu = new wxMenu;
    helpMenu->Append(Minimal_Test, "&Test\tF1", "Run test");

    fileMenu->Append(Minimal_Quit, "E&xit\tAlt-X", "Quit this program");

    // now append the freshly created menu to the menu bar...
    wxMenuBar *menuBar = new wxMenuBar();
    menuBar->Append(fileMenu, "&File");
    menuBar->Append(helpMenu, "&Help");

    // ... and attach this menu bar to the frame
    SetMenuBar(menuBar);
#else // !wxUSE_MENUS
    // If menus are not available add a button to access the about box
    wxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
    wxButton* aboutBtn = new wxButton(this, wxID_ANY, "About...");
    aboutBtn->Bind(wxEVT_BUTTON, &MyFrame::OnAbout, this);
    sizer->Add(aboutBtn, wxSizerFlags().Center());
#endif // wxUSE_MENUS/!wxUSE_MENUS

#if wxUSE_STATUSBAR
    // create a status bar just for fun (by default with 1 pane only)
    CreateStatusBar(2);
    SetStatusText("Welcome to wxWidgets!");
#endif // wxUSE_STATUSBAR

    this->Show(true);
}

// event handlers

void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
{
    // true is to force the frame to close
    Close(true);
}

void MyFrame::OnTest(wxCommandEvent& WXUNUSED(event))
{
    auto frame = new TestFrame(this);
    frame->Open();
}

////////////////////////////////////////////////////////////////////////


TestFrame::TestFrame(wxWindow* parent)
{
    Create(
        parent,
        wxID_ANY,
        _("Settings"),
        wxDefaultPosition,
        wxSize(400, 200),
        wxCAPTION | wxCLOSE_BOX | wxMINIMIZE_BOX | wxFRAME_FLOAT_ON_PARENT | wxFRAME_NO_TASKBAR,
        _T("Settings Window"));

    this->Bind(wxEVT_CLOSE_WINDOW, &TestFrame::OnCloseButton, this);

    wxBoxSizer * sizer = new wxBoxSizer(wxVERTICAL);

    mColorPicker = new wxColourPickerCtrl(this, wxID_ANY, wxColour("WHITE"),
        wxDefaultPosition, wxDefaultSize);
    mColorPicker->SetToolTip("Sets the single color of the ocean.");
    sizer->Add(mColorPicker);

    auto button = new wxButton(this, wxID_ANY, "Just a button");
    sizer->Add(button);

    SetSizerAndFit(sizer);

    Centre(wxCENTER_ON_SCREEN | wxBOTH);
}

void TestFrame::Open()
{
    this->Raise();
    this->Show();
}

void TestFrame::OnCloseButton(wxCloseEvent & /*event*/)
{
    this->Hide();
}
This is running on Windows 7 64-bit and using wxWidgets 3.1.2.

What am I doing wrong?

Thank you in advance for your help.
User avatar
doublemax
Moderator
Moderator
Posts: 19160
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Child frame sends parent main frame back after Hide() if a wcColourPickerCtrl has been opened

Post by doublemax »

I don't think you did anything wrong. I noticed that the issue goes away if you remove the wxFRAME_FLOAT_ON_PARENT. So it might be a bug in wxWidgets.

Try opening a bug report at http://trac.wxwidgets.org
Use the source, Luke!
Gabriele Giuseppini
Experienced Solver
Experienced Solver
Posts: 56
Joined: Fri Oct 12, 2018 6:12 pm
Location: Amsterdam, the Netherlands

Re: Child frame sends parent main frame back after Hide() if a wcColourPickerCtrl has been opened

Post by Gabriele Giuseppini »

Thank you so much as always for your help - removing the wxFRAME_FLOAT_ON_PARENT style indeed makes it work!

I have created https://trac.wxwidgets.org/ticket/18535 for this issue.
Gabriele Giuseppini
Experienced Solver
Experienced Solver
Posts: 56
Joined: Fri Oct 12, 2018 6:12 pm
Location: Amsterdam, the Netherlands

Re: Child frame sends parent main frame back after Hide() if a wcColourPickerCtrl has been opened

Post by Gabriele Giuseppini »

Dear all, after removing wxFRAME_FLOAT_ON_PARENT, if the user clicks on the visible portion of the main frame, the child frame disappears from view - it's sent back. Is there a way to force the child frame to be always on top of the parent as long it's visible?

I basically need the same behavior as Dialog::ShowModal, except that, as explained in my original post, I would like to be able to keep re-using the same window over and over, hence I went for a wxFrame for the child window rather than for wxDialog.
Gabriele Giuseppini
Experienced Solver
Experienced Solver
Posts: 56
Joined: Fri Oct 12, 2018 6:12 pm
Location: Amsterdam, the Netherlands

Re: Child frame sends parent main frame back after Hide() if a wcColourPickerCtrl has been opened

Post by Gabriele Giuseppini »

Well, never mind - wxSTAY_ON_TOP doe the trick!
Post Reply