Opened 4 years ago

Last modified 23 months ago

#12369 confirmed defect

Display glitch for wxStaticBox in wxNotebook on Windows

Reported by: joostn Owned by:
Priority: normal Milestone: 3.2.0
Component: wxMSW Version: stable-latest
Keywords: wxStaticBoxSizer wxNotebook display glitch Cc: joost@…
Blocked By: Blocking:
Patch: no

Description

I have a wxNotebook, containing wxScrolledWindow, containing a wxStaticBox and wxStaticBoxSizer, containing multiple controls.

Since wx2.9 there is a display glitch when resizing the window or when switching to different notebook pages: wxChoice and wxButton controls randomly disappear and wxTextCtrls are shown without border.

This happens on Windows 7 64 bit, I haven't yet tried on other windows versions.

This minimal sample application shows the problem:

#include "wx/wx.h"
#include <wx/notebook.h>

class MyApp : public wxApp
{
public:
    bool OnInit();
};

class MyFrame : public wxFrame
{
public:
    MyFrame();
};

DECLARE_APP(MyApp)
IMPLEMENT_APP(MyApp)

bool MyApp::OnInit()
{
    wxApp::OnInit();
    MyFrame *frame = new MyFrame();
    SetTopWindow(frame);
    frame->Show();
    return true;
}

MyFrame::MyFrame()
    : wxFrame(NULL, wxID_ANY, wxString(wxT("Test")), wxDefaultPosition, wxSize(600,400))
{
    wxNotebook *notebook= new wxNotebook( this, wxID_ANY);

    wxScrolledWindow* scrolledWin = new wxScrolledWindow(notebook, wxID_ANY);
    scrolledWin->SetSizer(new wxBoxSizer(wxVERTICAL));
    notebook->AddPage(scrolledWin, _("Page 1"));

    wxStaticBox* staticBox = new wxStaticBox(scrolledWin, wxID_ANY, _("Static Box"));
    wxStaticBoxSizer *staticBoxSizer = new wxStaticBoxSizer(staticBox, wxHORIZONTAL);
    scrolledWin->GetSizer()->Add(staticBoxSizer, 0, wxGROW|wxALL, 5);

    wxChoice* choice = new wxChoice(scrolledWin, wxID_ANY);
    staticBoxSizer->Add(choice);

    wxTextCtrl* textCtrl = new wxTextCtrl(scrolledWin, wxID_ANY);
    staticBoxSizer->Add(textCtrl);

    wxChoice* choice2 = new wxChoice(scrolledWin, wxID_ANY);
    staticBoxSizer->Add(choice2);
}

The problem is visible in the attached screenshots:

Attachments (3)

img1.jpg download (32.3 KB) - added by joostn 4 years ago.
Initial screenshot
img2.jpg download (30.3 KB) - added by joostn 4 years ago.
After resizing the window
xp.jpg download (16.0 KB) - added by joostn 4 years ago.
On windows XP 32 bit

Download all attachments as: .zip

Change History (14)

Changed 4 years ago by joostn

Initial screenshot

Changed 4 years ago by joostn

After resizing the window

comment:1 Changed 4 years ago by joostn

  • Cc joost@… added

comment:2 Changed 4 years ago by joostn

Problem occurs on XP 32bit as well, see screenshot. The themed gradient background of the notebook page is corrupted as well.

Changed 4 years ago by joostn

On windows XP 32 bit

comment:3 Changed 4 years ago by joostn

  • Version changed from 2.9.1 to 2.9-svn

Problem still exists in trunk (19-08-2010)

comment:4 Changed 4 years ago by joostn

By the way the problem can be worked around by creating the controls as children of the staticbox instead of siblings. This is the recommended way for 2.9 but e.g. DialogBlocks will only create them as siblings. I think the old way should still work.

comment:5 Changed 4 years ago by joostn

Here's a workaround for those migrating from 2.8. Call ReparentAllStaticBoxItemsInWindow for all frames containing wxStaticBoxes. This reparents all controls in the staticbox:

void TnhUtilities::ReparentAllStaticBoxItemsInWindow(wxWindow *window)
{
  std::vector<wxWindow*> staticboxes;
  GetAllWindowChildrenOfClass(window, CLASSINFO(wxStaticBox), staticboxes);
  for(size_t i=0; i < staticboxes.size(); i++)
  {
    wxStaticBox *staticbox=(wxStaticBox*)staticboxes[i];
    ReparentStaticBoxItems(staticbox);
  }
}

// private:
void TnhUtilities::GetAllWindowChildrenOfClass(wxWindow *window, const wxClassInfo *classinfo, std::vector<wxWindow*> &items)
{
  if(window->IsKindOf(classinfo))
  {
    items.push_back(window);
  }
  const wxWindowList& children=window->GetChildren();
  size_t numchildren=children.GetCount();
  for(size_t i=0; i < numchildren; i++)
  {
    wxWindow *child=(wxWindow*)children[i];
    if(!child->IsTopLevel())
    {
      GetAllWindowChildrenOfClass(child, classinfo, items);
    }
  }
}

void TnhUtilities::ReparentStaticBoxItems(wxStaticBox *staticbox)
{
#ifdef __WXMSW__
  wxSizer *sizer=staticbox->GetContainingSizer();
  ReparentStaticBoxItems2(staticbox, sizer);
#endif
}

void TnhUtilities::ReparentStaticBoxItems2(wxStaticBox *staticbox, wxSizer *sizer)
{
  wxWindow *staticboxparent=staticbox->GetParent();
  size_t numitems=sizer->GetItemCount();
  for(size_t i=0; i < numitems; i++)
  {
    wxSizerItem *item=sizer->GetItem(i);
    if(item->IsWindow())
    {
      wxWindow *window=item->GetWindow();
      if(window->GetParent() == staticboxparent)
      {
        window->Reparent(staticbox);       
      }
    }
    else if(item->IsSizer())
    {
      wxSizer *childsizer=item->GetSizer();
      ReparentStaticBoxItems2(staticbox, childsizer);
    }
  }
}

comment:6 Changed 4 years ago by vadz

  • Milestone set to 2.9.2
  • Status changed from new to confirmed

I can indeed see this bug. It looks like we paint the (themed) background over the children...

comment:7 Changed 4 years ago by etxmato

Hello,

The workaround works great for wxStaticBoxSizers in wxNotebooks however I use a structure something like:

wxNotebook
-> wxPanel
    -> wxStaticBoxSizer
-> wxPanel
    -> wxChoiceBook
         -> wxPanel
              -> wxStaticBoxSizer

For some reason the workaround doesn't for the second StaticBox (i.e. a StaticBox within a ChoiceBook within a NoteBook), and fine for the first. Actually without the workaround the boxes are drawn 'ok' (some controls disapear in certain cases) and with the workaround the boxes are completely empty.

Any suggestions for adapting the workaround to handle this?
Or maybe fixing the problem manually in the wxWidgets code?

Cheers, Marcel.

comment:8 Changed 4 years ago by joostn

Yes I'm still noticing display glitches too, even when the controls are created as children of the static box (or reparented using the workaround). So the problem is not limited to the case where controls are created as siblings.

I don't have a solution but I'll try to prepare a test app later when I have time.

comment:9 Changed 4 years ago by vadz

  • Milestone changed from 2.9.2 to 3.0

I still don't know how to fix this and won't have time for it before 2.9.2 so resetting the milestone. A simple way to reproduce the bug would still be very, very welcome.

comment:10 Changed 23 months ago by staticinline

I've confirmed that the original example posted still exhibits the described behavior on the latest svn73045 (Win7). However, it appears to work fine when making the controls children of the staticbox, as I believe remains the recommended approach.

Note that I too use DialogBlocks to generate XRC, and ticket:14431 now causes XRC to place controls as children of the staticbox, according to recommendations, so I no longer need the workaround with the ReparentAllStaticBoxItemsInWindow given above. For people using DialogBlocks to generate C++ instead, I understand DialogBlocks 4.40 also 'added "Parenting" property to wxStaticBoxSizer, to change code generation between creating box children as siblings, and creating them as true children.'

Moreover, ticket:13151 reporting related behavior appears resolved now.

Should this issue be closed? or is the original example still expected to work unchanged or raise an error?

comment:11 Changed 23 months ago by vadz

  • Milestone changed from 3.0 to 3.2

Ideal would be to fix it even when using static box as sibling because there must be a lot of existing code doing this. But as I still have no idea about how to actually do it, it's not a priority for 3.0 any more, now that it works correctly with the recommended approach.

Thanks for testing!

Note: See TracTickets for help on using tickets.