Phoenix icon indicating copy to clipboard operation
Phoenix copied to clipboard

The hidden wx.Frame is shown automatically and can not be hidden after restoring from minimize

Open Lind2020 opened this issue 5 years ago • 9 comments

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()

Lind2020 avatar Apr 20 '20 06:04 Lind2020

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.

Lind2020 avatar Apr 21 '20 01:04 Lind2020

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.

RobinD42 avatar Apr 22 '20 21:04 RobinD42

Adding "call Show before the Hide", can hide the frame, but it can not resolve the problem: it is shown automatically after unminimized.

Lind2020 avatar Apr 23 '20 00:04 Lind2020

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.

RobinD42 avatar Apr 23 '20 21:04 RobinD42

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.

Lind2020 avatar Apr 24 '20 00:04 Lind2020

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.

EDI-Systems avatar Oct 24 '23 16:10 EDI-Systems

This is a C++ issue, not a python issue. I'm using the C++ version directly with static linkage.

EDI-Systems avatar Oct 24 '23 16:10 EDI-Systems

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.

EDI-Systems avatar Oct 25 '23 07:10 EDI-Systems

Opened an issue in main repo https://github.com/wxWidgets/wxWidgets/issues/23997

EDI-Systems avatar Oct 25 '23 09:10 EDI-Systems