2

TCP サーバーと TCP クライアントがあります。
を使用して、以下のコードの GUI バージョンを作成したいと思います。 GUI インターフェイス スクリプトの準備はできていますが、2 つのスクリプトをマージする際に問題が発生しています。

ソケット スクリプトと GUI をマージするにはどうすればよいですか?

私のソケットサーバー

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

私の GUI スクリプト(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()
4

1 に答える 1

2

簡単に言うと、最初のスクリプトを関数にカプセル化します。関数をwxPythonアプリにインポートします。イベントハンドラーから関数を呼び出します。関数の応答をGUIに伝えます。

ただし、無限ループが含まれないようにソフトウェアを再設計する必要があります。イベントハンドラーは短時間だけ実行する必要があります。別の方法は、関数を別のスレッドで実行し、応答をGUIと通信し、メインGUIスレッドからスレッドを終了する機能を追加することです。

これらの線に沿った何か:

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

ただし、これは終了時に別のスレッドを終了しません。tcpServer.accept()ブロッキング操作です。ブロッキングなしの方法でソケットに接続する方法について、この回答を調べることをお勧めします。そうすれば、共有フラグのいくつかの種類を使用してスレッドを簡単に終了できます。

于 2013-02-19T11:08:23.063 に答える