After minimize/restore, several wx.Frame's showing order changed

Windows 10, wxPython 4.0.6, Python 3.7.4
I create several sub wx.Frame with style: wx.MINIMIZE_BOX | wx.FRAME_NO_TASKBAR | wx.FRAME_FLOAT_ON_PARENT. When sub frames are showing, after minimize->restore the main frame by clicking the icon on taskbar, the sub frames’ showing order are changed.
Sample code:

import wx

class MainFrame(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, id=-1, parent=parent, size=wx.Size(600, 500),
                          title='Test')
        self.panel = wx.Panel(self, id=-1, pos=(200, 300))
        self.button = wx.Button(self.panel, id=-1, label='button',
                                 pos=wx.Point(20, 56), size=wx.Size(87, 28))
        self.button.Bind(wx.EVT_BUTTON, self.OnButton, id=-1)
        self.frame1 = MyFrame(self, 'frame1')
        self.frame2 = MyFrame(self, 'frame2')
        self.frame3 = MyFrame(self, 'frame3')

    def OnButton(self, event):
        self.frame1.Show()
        self.frame2.Show()
        self.frame3.Show()

        event.Skip()

class MyFrame(wx.Frame):
    def __init__(self, parent, title):
        style = wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | \
                wx.MINIMIZE_BOX | wx.FRAME_NO_TASKBAR | wx.FRAME_FLOAT_ON_PARENT
        wx.Frame.__init__(self, id=-1, parent=parent, size=wx.Size(300, 200),
                          title=title, style=style)
        
if __name__ == '__main__':
    app = wx.App()
    frame = MainFrame(None)
    frame.Show()
    app.MainLoop()

Operations:

  1. Click the button.
    ->The order (from bottom to top): frame1->frame2->frame3
  2. Click the icon on taskbar to minimize, then restore.
    ->The order changed (from bottom to top): frame1->frame3->frame2

Linda,

See attached file, play with it and customize as needed.

ForLinda - wx.Frame - subframe ordering.py (1.9 KB)

Sláinte,
Thom

Try to use a vertical BoxSizer. Add frame1, frame2 et frame3 to the sizer.

Edit : the button should be added to the sizer. The sizer should be applied to the panel. All elements (button, frames) should be child of the panel.

Thom,
Thank you for the attachment. But how can I restore the showing order of frames same as the order before minimized. For example, if I set focus to frame2, changing the showing order to be frame1->frame3->frame2. After minimize->restore, how to restore to be the same order?

Linda

One could create a list that keeps track of the desired focus order for your subframes. Update the list at every EVT_SET_FOCUS event, i.e. the clicked (focused) subframe should be moved 1st in list.

Operations:

  1. list = [1,2,3], in __init__
  2. click frame2 -> update: list = [2,1,3]
  3. walk the list (reversed) on restore and show the corresponding subframe
  4. be creative

Good luck filling in the rest of the missing blanks yourself.

If use the BoxSizer, sub frames can not be dragged anywhere of the screen. Is that so? But I need subframes can be dragged anywhere.

Thom,
Sorry for late. I used EVT_SET_FOCUS event to count the orders of subframes, but still has problem. When it is restored, all frames are restored in order as my specified list, but after that, frame 2 is set focus unexpectedly. For example, if the list is [1, 2, 3] before minimized, after restore, it changed to be [1, 3, 2].
Please help to check what’s wrong in code?minimized-error.py (2.7 KB)

Linda

Linda,

After a quick code scan it generally seems ok. Have to look into it later this afternoon…

For now - if you haven’t done this yet - I suggest you first debug/watch the relevant events with WIT aka Widget Inspection Tool. I suspect that EVT_SET_FOCUS itself triggers an unhandled EVT_CHILD_FOCUS (sub)event which might disrupt things.

Thom

Thom,
I have used inspection tool, but it seems there is a little difference. When using the inspection tool, after restore, list is changed from [1,2,3] to [2,3,1]. In the last, subframe1’s EVT_CHILD_FOCUS event is triggered.
Minimize&Restore
Linda

I have changed the code. When main window is minimized, adding the process for hiding sub windows. Then show sub window when main window is restored. It seems work, but I’m not sure whether there is any other problem. minimized-error-ok.py (2.9 KB)

Linda, thanks. Great job!

Found 1 error: after subframe delete and minimize:

Traceback (most recent call last):
  File "minimized-error-ok.py", line 33, in OnMinimize
    frame.Hide()
RuntimeError: wrapped C/C++ object of type MyFrame has been deleted

I’ve further tested and refactored your code:

  • add OnClose method to cater for orderList error when subframe deleted (and minimize main)
  • add OnSetFocus method: aggregate from 3 OnSetFocus[123] methods
  • __init__: remove local funcList, combine subframes attribute binds
  • use of f-strings (does not work with python < 3.6)
  • add name parameter in MyFrame for use in close/focus methods
  • add _delete_orderlist_item method: avoid redundant code

Thus, main flaw was the above error when closing a subframe; rest is for taste, maintainability and the like.

See attachments ForLinda - Corrected - Refactored - minimized-error-ok.py (2.7 KB) and a DIFF report.zip (4.3 KB) for convenience.

Good luck.

Thom

Thom,
Thank you very much! I have added OnClose on my program, but forgot to add it on the sample code. The use of f-strings is new to me. Thank you for the reduced code. I have learned a lot.
Linda