Why won't my wxFrame close properly?

98 views Asked by At

I am trying to build a basic messaging system, but I have hit a major roadblock in the process. I can't get the window to close without it not responding and me having to close it in the Task Manager. From what I've read online, it sounds like I need to close when a sys.exit(0) to exit all the threads and connections. I have been stuck on this problem for days so I would really appreciate an answer and explanation to why it doesn't work! The meat of the problem is in the close_window() function. It is run able provided you have a basic server that accepts a connection. Thanks!

import wx
import socket
import threading
import sys

class oranges(wx.Frame):
    def __init__(self,parent,id):

        ##Unimportant stuff
        wx.Frame.__init__(self,parent,id," Retro Message",size=(500,500))
        self.frame=wx.Panel(self)
        self.input_box=wx.TextCtrl(self.frame, -1,pos=(15,350),size=(455,120),style=wx.NO_BORDER| wx.TE_MULTILINE)
        self.messaging_box=wx.TextCtrl(self.frame, -1,pos=(15,15),size=(455,285),style=wx.NO_BORDER | wx.TE_MULTILINE|wx.TE_READONLY)
        send_button=wx.Button(self.frame,label="Send",pos=(350,315),size=(75,40))
        self.Bind(wx.EVT_BUTTON, self.sender,send_button)
        self.Bind(wx.EVT_CLOSE, self.close_window)
        self.counter = 1
        self.socket_connect = socket.socket()
        self.setup()

    def sender(self,event):
        self.socket_connect.send(self.input_box.GetValue())
        self.input_box.Clear()
        self.Refresh()

        ##Important stuff
    def close_window(self,event): #This is the function in question#
        self.counter = 0
        self.socket_connect.shutdown(socket.SHUT_RDWR)
        sys.exit(0)
    def setup(self):
        self.ip_enter = wx.TextEntryDialog(None, "Enter in the IP:", "Setup", "192.168.1.1")
        if self.ip_enter.ShowModal() ==wx.ID_OK:
            self.offical_ip = self.ip_enter.GetValue()
            try:
                self.socket_connect.connect((self.offical_ip,5003))
                self.username = "false" #Tells the server just to give the user a IP username
                self.Thread1 = threading.Thread(target = self.listening_connect)
                self.Thread1.start()
            except socket.error:
                self.error_connect()
        else:
            sys.exit(0)

    def listening_connect(self):
        self.socket_connect.send(self.username)
        while self.counter != 0:
            data = self.socket_connect.recv(1024)
            self.messaging_box.AppendText(data)
            self.Refresh()
            if not data:
                break
        self.socket_connect.close()         
    def error_connect(self):
        pop_ups = wx.MessageDialog(None, "Failed to Connect to Server!", 'Error', wx.OK)
        pop_ups.ShowModal()
        self.setup()

if __name__=="__main__":
    app=wx.App(False)
    window=oranges(parent=None,id=-1)
    window.Show()
    app.MainLoop()

Here is a basic server program that should work with it(I am unable to test it but it is very similar to the real one)

import socket

HOST = '192.168.1.1'
PORT=5003
s = socket.socket()
s.bind((HOST, PORT))
s.listen(1)
c,addr = s.accept()
while True:
    data = c.recv(1024)
    if not data:
        break
c.close()
1

There are 1 answers

1
Mike Driscoll On

You need to wait for the thread to end. Otherwise it's probably going to make the script hang. Why? Well the thread is separate from the GUI thread, so it doesn't get killed just because you closed down your wxPython application. Here is what I would recommend:

def close_window(self, event):
    self.Thread1.join()
    self.Destroy()

This makes the script wait for the thread to finish before closing the application. If you want the frame to disappear, then you should call self.Hide() before the join. Another method would be to put some logic in your thread where you can send it a message that tells it the application is shutting down, so the thread needs to abort.

You should probably check out the following Stack answer: