Updating Old wxPython App: Invalid Window Calling Super/Parent Method

Question:

I am trying to update an old app that was written for Python 2.7 with wxWidgets/wxPython 2.8. I am trying to make it compatible with my current system’s versions of Python (3.10) & wxPython (4.0).

I have come across an error trying to call a super/parent method. The class is derived from wx.ScrolledWindow.

The old code snippet is (ui/panel.py starting at line 74):

def SetScrollbars(window):
  if isinstance(window, wx.ScrolledWindow):
    window.SetScrollbars(20, 20, 0, 0)

## A wx.ScrolledWindow that sets scrollbars by default
class ScrolledPanel(wx.ScrolledWindow, PanelBase):
  def __init__(self, parent, win_id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize,
      style=wx.HSCROLL|wx.VSCROLL, name="scrolledPanel"):
    wx.ScrolledWindow.__init__(self, parent, win_id, pos, size, style, name)
    SetScrollbars(self)

  ## Override inherited method to also update the scrollbars
  def Layout(self):
    layout = wx.ScrolledWindow.Layout(self)
    self.UpdateScrollbars()
    return layout

The error is:

  File "ui/panel.py", line 87, in Layout
    layout = wx.ScrolledWindow.Layout(self)
wx._core.wxAssertionError: C++ assertion "m_widget" failed at ../src/gtk/window.cpp(2888) in DoSetSize(): invalid window

I searched for how to call parent/super methods in Python & found from this question that Python has a super() function.

So I changed line 87:

-    layout = wx.ScrolledWindow.Layout(self)
+    layout = super().Layout()

The same error is reported:

  File "/home/jordan/Development/Debreate/code/ui/panel.py", line 87, in Layout
    layout = super().Layout()
wx._core.wxAssertionError: C++ assertion "m_widget" failed at ../src/gtk/window.cpp(2888) in DoSetSize(): invalid window

I suppose calling the parent/super method either way is correct. So that must not be the issue.

My system’s version of wxWidgets is 3.0.5.1. I found the assertion check line in the wxWidgets source code. The checking function, wxCHECK_RET, "Checks that the condition is true, and returns if not". So the window is invalid. I just don’t understand why as this worked with older versions of wxWidgets/wxPython.

Asked By: AntumDeluge

||

Answers:

wx.ScrolledWindow is an alias for ScrolledPanel since version 2.9.0. In older versions, it was a standalone class.
Try reading up on https://docs.wxpython.org/wx.lib.scrolledpanel.html
as its replacement.

Answered By: Rolf of Saxony

As was suggesting by Rolf of Saxony, switching to wx.lib.scrolledpanel.ScrolledPanel solves the problem:

from wx.lib.scrolledpanel import ScrolledPanel as sp

class ScrolledPanel(sp, PanelBase):
  def __init__(self, parent, win_id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize,
      style=wx.HSCROLL|wx.VSCROLL, name="scrolledPanel"):
    sp.__init__(self, parent, win_id, pos, size, style, name)
    sp.SetupScrolling(self)

But I also want to note that I was able to work around the problem by calling Layout on the parent window:

  ## Override inherited method to also update the scrollbars
  def Layout(self):
    layout = self.GetParent().Layout(self)
    self.UpdateScrollbars()
    return layout

But using wx.lib.scrolledpanel.ScrolledPanel is probably the proper way to upgrade.

Answered By: AntumDeluge