The hidden wx.Frame is shown automatically and can not be hidden after restoring from minimize
Operating system: windows 10 (64-bit) wxPython version: 4.0.6 (same as 4.0.2) Python version: 3.7
Description of the problem: I create a sub wx.Frame with style: wx.FRAME_FLOAT_ON_PARENT, first open the sub frame, then minimize the main frame. After restoring from minimize, close the sub frame (using Hide()). Then minimize->restore again. The sub frame is shown automatically, and can not be hidden. I have tested that at this time, frame.IsShown() returns False. Sample as follows.
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.frame = MyFrame(self)
def OnButton(self, event):
self.frame.Show()
event.Skip()
class MyFrame(wx.Frame):
def __init__(self, parent):
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='Sub', style=style)
self.Bind(wx.EVT_CLOSE, self.OnClose)
def OnClose(self, evt):
self.Hide()
if __name__ == '__main__':
app = wx.App()
frame = MainFrame(None)
frame.Show()
app.MainLoop()
I need to hide the sub frame, not close the sub frame. The detail operations are: 1.Click the button to open the sub frame. 2.Click the minimize button of the main frame. (-> All the frames are minimized.) 3.Click the icon in taskbar to restore the main frame. 4.Click the "×" button of the sub frame. 5.Click the minimize button of the main frame again. 6.Click the icon in taskbar to restore the main frame. -> Problem: the sub frame is shown. And can not use "×" button to hide it.
I need the sub frame shown on main frame when it loses focus, so I used wx.FRAME_FLOAT_ON_PARENT.
It looks like the current status of the IsShown flag is getting out of sync for the child window, due to it being raised when the parent is unminimized. IOW, wxWIdgets thinks it's still hidden so when you call Hide it doesn't do anything. So a possible workaround would be to call Show before the Hide. Doing the Hide via wx.CallAfter may be needed, like this:
def OnClose(self, evt):
self.Show()
wx.CallAfter(self.Hide)
BTW, I believe the behavior of minimizing/restoring children with the parent in cases like this is Windows-specific. So if you need to run on multiple platforms you may need some platform-specific code, or to rethink your design.
Adding "call Show before the Hide", can hide the frame, but it can not resolve the problem: it is shown automatically after unminimized.
There probably isn't any way around that other than not using the main frame as the other frame's parent, but that of course negates the value of wx.FRAME_FLOAT_ON_PARENT. You can check on wx-users to see if anybody there has any ideas.
Thank you all the same. I use SetTransparent to set sub frame transparent when it is hiding. It seems work. But I'm not sure whether there are other problems.
I also have this issue in wxWidgets 3.2.1/msw. Can confirm that, after restoring the parent, the wxWidgets still thinks that the child is hidden (by consulting the IsShown with an assert), yet, the child is shown. I have looked through the source code and can confirm that the flag propagation in frame.cpp and toplevel.cpp is correct, and matches with the current status of the window. But the display still pops up, so there must be somewhere that dieplays the window without even checking this flag.
See void wxFrame::IconizeChildFrames(bool bIconize) and bool wxFrame::HandleSize(int WXUNUSED(x), int WXUNUSED(y), WXUINT id) for details. These function seem correct.
Thank you Lind2020 for the workaround. I will apply it now.
Thank you all the same. I use SetTransparent to set sub frame transparent when it is hiding. It seems work. But I'm not sure whether there are other problems.
This is a C++ issue, not a python issue. I'm using the C++ version directly with static linkage.
Thank you all the same. I use SetTransparent to set sub frame transparent when it is hiding. It seems work. But I'm not sure whether there are other problems.
Setting transparent will render modal windows non-modal anymore. We still need a way to completely hide the window.
Opened an issue in main repo https://github.com/wxWidgets/wxWidgets/issues/23997