Why do I get a small window when I close a dialog in wxPython?

107 views Asked by At

I have a wx.Frame that calls a wx.Dialog.

Now, they all work accordingly and open nicely. The thing is that when they do, they also open a small "window" that sits on the top left corner of my frame, and after that comes out I'm unable to automatically resize my frame with my mouse. Closing the dialog has no effect, as that small window still sits there.

Inside my wx.Frame I have the following event call:

def OnTerminalSettings(self, event):
    """Open Terminal settings dialog"""
    dlg = TerminalSettingsDialog(self, wx.ID_ANY, "", settings=TerminalPanel(self).settings)
    dlg.ShowModal()
    dlg.Destroy()

and TerminalSettingsDialog wx.Dialog looks something like this:

class TerminalSettingsDialog(wx.Dialog):
    """Simple dialog with common terminal settings."""

    def __init__(self, *args, **kwds):
        self.settings = kwds['settings']
        del kwds['settings']
        kwds["style"] = wx.DEFAULT_DIALOG_STYLE
        wx.Dialog.__init__(self, *args, **kwds)
        self.checkbox_echo = wx.CheckBox(self, wx.ID_ANY, "Local Echo")
        self.checkbox_unprintable = wx.CheckBox(self, wx.ID_ANY, "Show unprintable characters")
        self.radio_box_newline = wx.RadioBox(self, wx.ID_ANY, "Newline Handling", choices=["CR only", "LF only", "CR+LF"], majorDimension=0, style=wx.RA_SPECIFY_ROWS)
        self.button_ok = wx.Button(self, wx.ID_ANY, "OK")
        self.button_cancel = wx.Button(self, wx.ID_ANY, "Cancel")

        self.__set_properties()
        self.__do_layout()

        self.__attach_events()
        self.checkbox_echo.SetValue(self.settings.echo)
        self.checkbox_unprintable.SetValue(self.settings.unprintable)
        self.radio_box_newline.SetSelection(self.settings.newline)

    def __set_properties(self):
        self.SetTitle("Terminal Settings")
        self.radio_box_newline.SetSelection(0)
        self.button_ok.SetDefault()

    def __do_layout(self):
        sizer_2 = wx.BoxSizer(wx.VERTICAL)
        sizer_3 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_4 = wx.StaticBoxSizer(wx.StaticBox(self, wx.ID_ANY, "Input/Output"), wx.VERTICAL)
        sizer_4.Add(self.checkbox_echo, 0, wx.ALL, 4)
        sizer_4.Add(self.checkbox_unprintable, 0, wx.ALL, 4)
        sizer_4.Add(self.radio_box_newline, 0, 0, 0)
        sizer_2.Add(sizer_4, 0, wx.EXPAND, 0)
        sizer_3.Add(self.button_ok, 0, 0, 0)
        sizer_3.Add(self.button_cancel, 0, 0, 0)
        sizer_2.Add(sizer_3, 0, wx.ALL|wx.ALIGN_RIGHT, 4)
        self.SetAutoLayout(1)
        self.SetSizer(sizer_2)
        sizer_2.Fit(self)
        sizer_2.SetSizeHints(self)
        self.Layout()

    def __attach_events(self):
        self.Bind(wx.EVT_BUTTON, self.OnOK, id = self.button_ok.GetId())
        self.Bind(wx.EVT_BUTTON, self.OnCancel, id = self.button_cancel.GetId())

    def OnOK(self, events):
        """Update data with new values and close dialog."""
        self.settings.echo = self.checkbox_echo.GetValue()
        self.settings.unprintable = self.checkbox_unprintable.GetValue()
        self.settings.newline = self.radio_box_newline.GetSelection()
        self.EndModal(wx.ID_OK)

    def OnCancel(self, events):
        """Do not update data, but rather close dialog."""
        self.EndModal(wx.ID_CANCEL)

I don't know if this is important, but the frame holds a top wx.Panel which in turn contains other two wx.Panels. I want to be able to have a terminal in one of such panels.

I got the code for the terminal from the PySerial examples, so I guess they are working just fine.

Can anyone please lend me a hand?

Addendum

This is the code inside TerminalPanel:

class TerminalPanel(wx.Panel):
    def __init__(self, *args, **kwds):
        self.serial = serial.Serial()
        self.serial.timeout = 0.5    #make sure that the alive event can be checked from time to time
        self.settings = TerminalSetup()  #Placeholder for the settings
        self.thread = None
        self.alive = threading.Event()

        kwds["style"] = wx.DEFAULT_FRAME_STYLE
        wx.Panel.__init__(self, *args, **kwds)
        TextPanel.text_ctrl_output = wx.TextCtrl(self, -1, "", style=wx.TE_MULTILINE)

        self.__do_layout()
        # self.OnPortSettings(None)  #Call setup dialog on startup, opens port
        if not self.alive.isSet():
            self.Close()


    def StartThread(self):
        """Start the receiver thread."""
        self.thread = threading.Thread(target=self.ComPortThread)
        self.thread.setDaemon(1)
        self.alive.set()
        self.thread.start()


    def StopThread(self):
        """Stop the receiver thread, wait until it's finished."""
        if self.thread is not None:
            self.alive.clear()  #Clear alive event for thread
            self.thread.join()  #Wait until thread has finished
            self.thread = None  #Set flag as empty


    def __do_layout(self):
        """Set general layout """
        sizer_1 = wx.BoxSizer(wx.VERTICAL)
        sizer_1.Add(self.text_ctrl_output, 1, wx.EXPAND, 0)
        self.SetAutoLayout(1)
        self.SetSizer(sizer_1)
        self.Layout()
1

There are 1 answers

4
RobinDunn On BEST ANSWER
dlg = TerminalSettingsDialog(self, wx.ID_ANY, "", settings=TerminalPanel(self).settings)

This statement is creating a new instance of TerminalPanel that is a child of self each time you create an instance of the dialog. That is your extra window. If you already have an instance somewhere of TerminalPanel then you should probably be getting the settings object from it instead of making a new one.