Setting size of frames and dialogs under wxPython 4.1.1

Since upgrading from wxPython 4.1.0 to 4.1.1 today, some of my applications are not setting the size of their frames and dialogs correctly.

Most of my applications use a mixin class which reads values from a config file including width and height and then passes those values to the frame or dialog’s SetSize() method. Using this technique with V4.1.0 (and previous versions) worked fine, but doesn’t work for several of my applications under V4.1.1.

I’ve run some of these applications in debug and they are getting the correct values from the config file, but when they call SetSize() the window is not being set to the specified size. No exceptions are thrown and there are no warnings output to the command line. I’ve tried to identify any common features of the applications that are affected, compared to those that aren’t, but so far I have not been able to find any. I also haven’t managed to create a simple example that demonstrates the problem yet.

Are there any changes in V4.1.1 relating to setting the size of frames and dialogs that might help me narrow the search?

I am using Python 3.8.5, wxPython 4.1.1 gtk3 (phoenix) wxWidgets 3.1.5, Linux Mint 20.

I have created a simple app using wxGlade which demonstrates the problem:

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
#
# generated by wxGlade 0.9.6 on Fri Nov 27 19:37:11 2020
#

import wx

# begin wxGlade: dependencies
# end wxGlade

# begin wxGlade: extracode
# end wxGlade


class MyFrame(wx.Frame):
    def __init__(self, *args, **kwds):
        # begin wxGlade: MyFrame.__init__
        kwds["style"] = kwds.get("style", 0) | wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, *args, **kwds)
        self.print_size_button = wx.Button(self, wx.ID_ANY, "Print Size")
        self.close_button = wx.Button(self, wx.ID_ANY, "Close")

        self.__set_properties()
        self.__do_layout()
        # end wxGlade

        self.Bind(wx.EVT_BUTTON, self.OnClose,     self.close_button)
        self.Bind(wx.EVT_BUTTON, self.OnPrintSize, self.print_size_button)
        self.SetSize((300, 300))

    def __set_properties(self):
        # begin wxGlade: MyFrame.__set_properties
        self.SetTitle("Set Frame Size Test")
        # end wxGlade

    def __do_layout(self):
        # begin wxGlade: MyFrame.__do_layout
        main_sizer = wx.BoxSizer(wx.VERTICAL)
        bottom_sizer = wx.BoxSizer(wx.HORIZONTAL)
        top_sizer = wx.BoxSizer(wx.HORIZONTAL)
        top_sizer.Add((20, 20), 1, wx.ALIGN_CENTER_VERTICAL, 0)
        top_sizer.Add(self.print_size_button, 0, wx.ALIGN_CENTER_VERTICAL, 0)
        top_sizer.Add((20, 20), 1, wx.ALIGN_CENTER_VERTICAL, 0)
        main_sizer.Add(top_sizer, 1, wx.ALL | wx.EXPAND, 4)
        static_line = wx.StaticLine(self, wx.ID_ANY)
        main_sizer.Add(static_line, 0, wx.EXPAND, 0)
        bottom_sizer.Add((20, 20), 1, wx.EXPAND, 0)
        bottom_sizer.Add(self.close_button, 0, 0, 0)
        bottom_sizer.Add((20, 20), 1, wx.EXPAND, 0)
        main_sizer.Add(bottom_sizer, 0, wx.BOTTOM | wx.EXPAND | wx.TOP, 4)
        self.SetSizer(main_sizer)
        main_sizer.Fit(self)
        self.Layout()
        # end wxGlade

    def OnClose(self, _event):
        self.Destroy()

    def OnPrintSize(self, _event):
        size = self.GetSize()
        print(size)


# end of class MyFrame

class MyApp(wx.App):
    def OnInit(self):
        self.frame = MyFrame(None, wx.ID_ANY, "")
        self.SetTopWindow(self.frame)
        self.frame.Show()
        return True

# end of class MyApp

if __name__ == "__main__":
    app = MyApp(0)
    app.MainLoop()

When I run this on a PC under wxPython 4.1.1, the border of the frame is drawn for a fraction of a second with a size of (300, 300) but it then snaps back to a smaller size and the complete frame is displayed. When I click on the “Print Size” button it outputs “(141, 104)”.

If I run the same app on a PC under Python 3.8.5, wxPython 4.1.0 gtk3 (phoenix) wxWidgets 3.1.4, Linux Mint 20, then the frame is fully displayed at size (300, 300) which is confirmed when I click on the “Print Size” button.

I have just tried on Windows and there it seems to work fine. It prints (300,300).
Windows 10, 64 bit; Python 3.9.0 64 bit, wxPython 4.1.1.

Does it change anything when you comment out main_sizer.Fit ?

Yes, if I comment out main_sizer.Fit then it works OK on v4.1.1 on Linux.

Would you mind sending me or posting the wxg file? I have just tried with wxGlade 0.9.6fix2 and 1.0.0 beta and I don’t see Fit in the generated code.
Fit is for Dialogs which should be shrinked to fit the contained widgets.

I also tried using wxGlade v1.0.0b1 it still included the main_size.Fit call in the output.

The site wouldn’t let me upload the .wxg file, so I have pasted it here:

<?xml version="1.0"?>
<!-- generated by wxGlade 0.9.6 on Fri Nov 27 20:02:29 2020 -->

<application class="MyApp" encoding="UTF-8" for_version="3.0" header_extension=".h" indent_amount="4" indent_symbol="space" is_template="0" language="python" mark_blocks="1" name="app" option="0" overwrite="0" path="/home/richardt/Development/python/exp/hci/wxpython/frame_size/set_frame_size.py" source_extension=".cpp" top_window="frame" use_gettext="0" use_new_namespace="1">
    <object class="MyFrame" name="frame" base="EditFrame">
        <title>Set Frame Size Test</title>
        <style>wxDEFAULT_FRAME_STYLE</style>
        <object class="wxBoxSizer" name="main_sizer" base="EditBoxSizer">
            <orient>wxVERTICAL</orient>
            <object class="sizeritem">
                <option>1</option>
                <border>4</border>
                <flag>wxALL|wxLEFT|wxRIGHT|wxTOP|wxBOTTOM|wxEXPAND</flag>
                <object class="wxBoxSizer" name="top_sizer" base="EditBoxSizer">
                    <orient>wxHORIZONTAL</orient>
                    <object class="sizeritem">
                        <option>1</option>
                        <border>0</border>
                        <flag>wxALIGN_CENTER_VERTICAL</flag>
                        <object class="spacer" name="spacer" base="EditSpacer">
                            <width>20</width>
                            <height>20</height>
                        </object>
                    </object>
                    <object class="sizeritem">
                        <option>0</option>
                        <border>0</border>
                        <flag>wxALIGN_CENTER_VERTICAL</flag>
                        <object class="wxButton" name="print_size_button" base="EditButton">
                            <label>Print Size</label>
                        </object>
                    </object>
                    <object class="sizeritem">
                        <option>1</option>
                        <border>0</border>
                        <flag>wxALIGN_CENTER_VERTICAL</flag>
                        <object class="spacer" name="spacer" base="EditSpacer">
                            <width>20</width>
                            <height>20</height>
                        </object>
                    </object>
                </object>
            </object>
            <object class="sizeritem">
                <option>0</option>
                <border>0</border>
                <flag>wxEXPAND</flag>
                <object class="wxStaticLine" name="static_line" base="EditStaticLine">
                    <style>wxLI_HORIZONTAL</style>
                </object>
            </object>
            <object class="sizeritem">
                <option>0</option>
                <border>4</border>
                <flag>wxTOP|wxBOTTOM|wxEXPAND</flag>
                <object class="wxBoxSizer" name="bottom_sizer" base="EditBoxSizer">
                    <orient>wxHORIZONTAL</orient>
                    <object class="sizeritem">
                        <option>1</option>
                        <border>0</border>
                        <flag>wxEXPAND</flag>
                        <object class="spacer" name="spacer" base="EditSpacer">
                            <width>20</width>
                            <height>20</height>
                        </object>
                    </object>
                    <object class="sizeritem">
                        <option>0</option>
                        <border>0</border>
                        <object class="wxButton" name="close_button" base="EditButton">
                            <label>Close</label>
                        </object>
                    </object>
                    <object class="sizeritem">
                        <option>1</option>
                        <border>0</border>
                        <flag>wxEXPAND</flag>
                        <object class="spacer" name="spacer" base="EditSpacer">
                            <width>20</width>
                            <height>20</height>
                        </object>
                    </object>
                </object>
            </object>
        </object>
    </object>
</application>

You have explicitely deactivated the size setting for the frame in wxGlade. So Fit code is generated.

Just check and set it again:

grafik

grafik

Thanks Dietmar, explicitly setting the size of the frame does fix the problem.

I have also tried doing the same with one of my applications that showed the problem earlier and it is now responding to the size settings in its config file correctly.

I can’t remember why I started deactivating the frame/dialog sizes in wxGlade as it was a long time ago, but until v4.1.1 it had not caused a problem.

The different wx/Python versions and platforms behave differently when specifying things that don’t match together.

I had a look and with wxGlade 1.0 usually you would not use a sizer as direct child.
In this case the Fit code would never be generated even without size being defined.
I think I should fine-tune user interface and code generation a bit.

I have changed wxGlade 1.0.0b2 to generate the Fit() code in such a case.
Generally, this is not too useful, though. A frame should fill the available space. Only dialogs should be resized to fit the contents.

Your example could be made much simpler. The “Close” button does not need the spacers around:
grafik
The “Print” button does need the spacers if the layout should be exactly what you’ve uploaded, but in most cases there are simpler options.