Little square issue (reprise)

The “little black square” issue mentioned in the thread

“Oddness with wx.Notebook”

https://groups.google.com/forum/#!topic/wxpython-users/NRAXzaPU5d8 ,

and the earlier thread linked from that one, seems to not be confined

to wx.Notebook-based applications.

The attached sample application produces a square of around 20x20 pixels in

the top left corner of a wx.Frame, or its child wx.Panel, without any

wx.Notebook instance.

The attached application simply toggles between displaying one of two

different blue-gray colored images (after the user presses a key). The square

is clearly visible in the top left corner while toggling is in progress.

When the user presses a key a second time, the toggling stops, and the final

image is displayed correctly.

The color of the “little square” seems to depend on the background color of the

frame or panel that is the parent of the wx.StaticBitmap.

For convenience, the application defines some variables at the top that control

various different tests I tried.

I also experimented with binding the EVT_ERASE_BACKGROUND event to an empty

function, but it did not noticably affect the displayed bitmaps.

I have obtained the same result on two different systems, using Python 3.5.2,

wx.Python 4.0.0b2 on a 64-bit Windows 7 PC. One system was a desktop, and the

other a laptop, which may imply that the suggestion that it is a graphics

driver issue is unlikely.

The CallAfter() suggestion from Tim is not applicable in this context where the

square is visible long after Frame1.init’s work is done.

The application is intended to be a MWE - in my real application, I’m capturing

images off a camera and displaying them in a bitmap.

Any ideas on how to get around the little squares will be gratefully

implemented :slight_smile:

little_square.py (4.71 KB)

Whenever you see the “little squares” on Windows it is usually due to the widgets being created by default in a visible state. Since Windows doesn’t buffer the display like the other platforms do then you can see the widget momentarily in that state, where it has a size but no content yet, or whatever. For example when adding a new page to a notebook it’s possible to see the new panel for a moment before it has a paint event handler, or child widgets, before it has had the size changed to match the notebook’s client area, and before the notebook has been told to manage the new panel as a page.

In this case you are seeing the static bitmap widget at its default size of (20,20) and before the image has been assigned to it. By the time the next refresh comes along the widget will have sized itself to its default size that matches the image size and is ready to draw the image in the paint handler. In this case the simplest way to avoid seeing an incorrect initial state is to create the widget with an initial size that matches the image size.

        self._sbmp = wx.StaticBitmap(self._parent_wnd, wx.ID_ANY,

                                     wx.Bitmap(image1 if (i & 0x01) else image2),

                                     size=(640,480))

A more general approach would be to use the 2-phase create approach and hide the widget before it is created:

        self._sbmp = wx.StaticBitmap()

        self._sbmp.Hide()

        self._sbmp.Create(self._parent_wnd, wx.ID_ANY,

                          wx.Bitmap(image1 if (i & 0x01) else image2))

        self._sbmp.Show()
···

On Thursday, January 11, 2018 at 12:38:20 PM UTC-8, Adrian Hill wrote:

Any ideas on how to get around the little squares will be gratefully

implemented :slight_smile:

Robin Dunn

Software Craftsman

Adrian Hill wrote:

The "little black square" issue mentioned in the thread
"Oddness with wx.Notebook"
Redirecting to Google Groups ,
and the earlier thread linked from that one, seems to not be confined
to wx.Notebook-based applications.

The attached sample application produces a square of around 20x20
pixels in
the top left corner of a wx.Frame, or its child wx.Panel, without any
wx.Notebook instance.

But this is a very different situation. Your square is briefly visible,
but goes away when things settle down.

I would also point out that your application is leaking windows. Every
time you toggle, you create a new wx.StaticBitmap, which ends up making
a huge stack of StaticBitmap controls. You can see that with a Windows
"spy" tool. Remember that a window continues to live even after the
Python reference is gone. It doesn't die until you delete the window
via wx.

If I modify your sample very slightly to replace this:
# Currently-displayed static bitmap.
self._sbmp = None
with this:
# Currently-displayed static bitmap.
self._sbmp = wx.StaticBitmap(self._parent_wnd, wx.ID_ANY)

and then just set a new bitmap into that single control, rather than
creating a new control:
while self._keep_looping:
# Show a bitmap of the current image.
self._sbmp.SetBitmap(
wx.Bitmap(image1 if (i & 0x01) else
image2))

the little square does not appear. So, the square appears to be related
to redrawing a window that contains no controls.

···

--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.

Robin and Tim,

Thanks very much for the responses. I really appreciate it, and (of course)

both your suggestions solved the “little square” issue.

Tim, thanks too for pointing out the leaking windows.

One futher question, if I may, with reference to your statement

“It doesn’t die until you delete the window via wx.”:

In general, deleting the window via wx means (in this example) using self._sbmp.Destroy()?

Is this only necessary for wx.Window-derived objects?

Should the wx.Image instances also have a call to Destroy() added, or is that

not necessary?

I read Window Deletion Overview — wxPython Phoenix 4.2.3a1 documentation, but

it does not mention Destroy() for non-Window items.

The wx.Image — wxPython Phoenix 4.2.3a1 documentation does not

offer much as to when Destroy() ought to be called.

Thanks again,

Adrian

···

Tim, thanks too for pointing out the leaking windows.

One futher question, if I may, with reference to your statement
"It doesn't die until you delete the window via wx.":
In general, deleting the window via wx means (in this example) using self._sbmp.Destroy()?

Yes. You pass a "parent" into the constructor of each wx.Window-derived object The parent keeps a reference until Destroy happens. This is a huge convenience; it means you don't have to keep a reference to every window you create. You can just call
    wx.StaticText( self, -1, "Hello" )
without saving the object, and the text window will live on.

Is this only necessary for wx.Window-derived objects?

Right.

Should the wx.Image instances also have a call to Destroy() added, or is that
not necessary?

Not necessary. When you replace the image, the last reference to the previous one will be released, and it will be deleted.

···

On Jan 13, 2018, at 7:55 AM, Adrian Hill <hill.adrian86@gmail.com> wrote:

Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.

Tim,

Thanks for the clear explanation - much appreciated. (I’m finding WIT to be a very useful tool too.)

Adrian

···

On Saturday, January 13, 2018 at 10:16:34 PM UTC-7, Tim Roberts wrote:

On Jan 13, 2018, at 7:55 AM, Adrian Hill hill.a...@gmail.com wrote:

Tim, thanks too for pointing out the leaking windows.

One futher question, if I may, with reference to your statement

“It doesn’t die until you delete the window via wx.”:

In general, deleting the window via wx means (in this example) using self._sbmp.Destroy()?

Yes. You pass a “parent” into the constructor of each wx.Window-derived object The parent keeps a reference until Destroy happens. This is a huge convenience; it means you don’t have to keep a reference to every window you create. You can just call

wx.StaticText( self, -1, "Hello" )

without saving the object, and the text window will live on.

Is this only necessary for wx.Window-derived objects?

Right.

Should the wx.Image instances also have a call to Destroy() added, or is that

not necessary?

Not necessary. When you replace the image, the last reference to the previous one will be released, and it will be deleted.


Tim Roberts, ti...@probo.com

Providenza & Boekelheide, Inc.