Using sockets with wxpython
Question: I have a TCP server and a TCP client.  
I want to make a GUI version of the code below, using
[wxpython](/questions/tagged/wxpython "show questions tagged 'wxpython'").  
I have the GUI interface script ready, but, I am having problems merging the
two scripts.

How do I merge my socket script(s) and my GUI?

**My socket server**

    
    
    from socket import *
    from time import ctime
    import random
    
    bufsiz = 1024
    port = random.randint(1025,36000)
    host = 'localhost'
    addr = (host, port)
    print 'Port:',port
    
    tcpServer = socket(AF_INET , SOCK_STREAM)
    tcpServer.bind(addr)
    tcpServer.listen(5)
    try:
        while True:
            print 'Waiting for connection..'
            tcpClient, caddr = tcpServer.accept()
            print 'Connected To',caddr
    
            while True:
                data = tcpClient.recv(bufsiz)
                if not data:
                    break
                tcpClient.send('[%s]\nData\n%s' % (ctime(),data))
                print data
            tcpClient.close()
    
    except KeyboardInterrupt:
        tcpServer.close()
    
    raw_input('Enter to Quit')
    

**My GUI script** (made using wxglade)

    
    
    #!/usr/bin/env python
    # -*- coding: iso-8859-15 -*-
    # generated by wxGlade 0.6.5 (standalone edition) on Mon Feb 18 19:50:59 2013
    
    import wx
    
    # begin wxGlade: extracode
    # end wxGlade
    
    
    class MyFrame(wx.Frame):
        def __init__(self, *args, **kwds):
            # begin wxGlade: MyFrame.__init__
            kwds["style"] = wx.DEFAULT_FRAME_STYLE
            wx.Frame.__init__(self, *args, **kwds)
            self.chat_log = wx.TextCtrl(self, -1, "", style=wx.TE_MULTILINE | wx.TE_READONLY)
            self.text_send = wx.TextCtrl(self, -1, "")
    
            self.__set_properties()
            self.__do_layout()
    
            self.Bind(wx.EVT_TEXT_ENTER, self.text_e, self.text_send)
            # end wxGlade
    
        def __set_properties(self):
            # begin wxGlade: MyFrame.__set_properties
            self.SetTitle("frame_1")
            self.SetSize((653, 467))
            self.chat_log.SetMinSize((635, 400))
            self.text_send.SetMinSize((635, -1))
            self.text_send.SetFocus()
            # end wxGlade
    
        def __do_layout(self):
            # begin wxGlade: MyFrame.__do_layout
            sizer_1 = wx.FlexGridSizer(1, 1, 1, 1)
            sizer_1.Add(self.chat_log, 0, 0, 0)
            sizer_1.Add(self.text_send, 0, wx.ALL, 1)
            self.SetSizer(sizer_1)
            self.Layout()
            # end wxGlade
    
        def text_e(self, event):  # wxGlade: MyFrame.<event_handler>
            text = self.text_send.GetValue()
            self.chat_log.AppendText("\n"+text)
            self.text_send.SetValue("")
            event.Skip()
    
    # end of class MyFrame
    
    class MyMenuBar(wx.MenuBar):
        def __init__(self, *args, **kwds):
            # begin wxGlade: MyMenuBar.__init__
            wx.MenuBar.__init__(self, *args, **kwds)
            self.File = wx.Menu()
            self.Append(self.File, "File")
            self.View = wx.Menu()
            self.Append(self.View, "View")
    
            self.__set_properties()
            self.__do_layout()
            # end wxGlade
    
        def __set_properties(self):
            # begin wxGlade: MyMenuBar.__set_properties
            pass
            # end wxGlade
    
        def __do_layout(self):
            # begin wxGlade: MyMenuBar.__do_layout
            pass
            # end wxGlade
    
    # end of class MyMenuBar
    if __name__ == "__main__":
        app = wx.PySimpleApp(0)
        wx.InitAllImageHandlers()
        frame_1 = MyFrame(None, -1, "")
        app.SetTopWindow(frame_1)
        frame_1.Show()
        app.MainLoop()
    


Answer: In a nutshell: Encapsulate your first script into a function. Import your
function into the wxPython app. Call the function from some event handler.
Communicate back your function response to the GUI.

However, you would need to redesign your software so it does not contain
infinite loop. Event handlers should run for short time only. Another way
would be to run your function in a separate thread, communicate the response
with GUI and add ability to terminate the thread from your main GUI thread.

Something along these lines:

    
    
    import wx
    from socket import *
    from time import ctime
    import random
    import threading
    
    bufsiz = 1024
    port = random.randint(1025,36000)
    host = 'localhost'
    addr = (host, port)
    
    class MainWindow(wx.Frame):
        def __init__(self, *args, **kwargs):
            wx.Frame.__init__(self, *args, **kwargs)
    
            self.panel = wx.Panel(self)
            self.text = wx.TextCtrl(self.panel, style=wx.TE_MULTILINE)
    
            self.sizer = wx.BoxSizer()
            self.sizer.Add(self.text, 1, wx.ALL | wx.EXPAND, 5)
    
            self.panel.SetSizerAndFit(self.sizer)  
            self.Show()
    
            self.thread = threading.Thread(target=self.Server)
            self.thread.start()
    
        def Print(self, text):
            wx.CallAfter(self.text.AppendText, text + "\n")
    
        def Server(self):
            self.Print("Port: {}".format(port))
    
            tcpServer = socket(AF_INET , SOCK_STREAM)
            tcpServer.bind(addr)
            tcpServer.listen(5)
            try:
                while True:
                    self.Print("Waiting for connection...")
                    tcpClient, caddr = tcpServer.accept()
                    self.Print("Connected To {}".format(caddr))
    
                    while True:
                        data = tcpClient.recv(bufsiz)
                        if not data:
                            break
                        tcpClient.send('[%s]\nData\n%s' % (ctime(), data))
                        self.Print(data)
                    tcpClient.close()
    
            except KeyboardInterrupt:
                tcpServer.close()
    
    app = wx.App(False)
    win = MainWindow(None)
    app.MainLoop()
    

This however does not terminate another thread upon exit. `tcpServer.accept()`
is blocking operation. You may want to look into this
[answer](http://stackoverflow.com/questions/5308080/python-socket-accept-
nonblocking) how to connect to socket in a non-blocking way. Then you would be
able to easily terminate your thread using some kins of shared flag.

