0

在 Python 中使用该select.select()方法时,有没有办法使用来自 GUI(Tkinter 条目)的输入从套接字发送数据?

select() 的输入列表接受 sys.stdin 或从服务器接收的数据,但无论如何要从 GUI 获取数据并将其发送出去?或者选择不能与 GUI 一起使用?

我已经进行了广泛的搜索,但是如果您有指向另一个线程的链接,我也将不胜感激。

import socket, select, threading, Queue, cPickle
from Tkinter import *
from Message import *

class GUI(Frame):

    def __init__(self, host="localhost",port=5678, root="Tk()"):
        Frame.__init__(self,root)
        self.nickname = raw_input("What is your screen name? ")
        self.inqueue = Queue.Queue()
        self.outqueue = Queue.Queue()
        self.root = root
        self.text = Text(self,height=10,width=40)
        self.scroll=Scrollbar(self)
        self.text.configure(yscrollcommand=self.scroll.set)
        self.scroll.grid(row=0, column=1, sticky=N+S)
        self.scroll.config(command=self.text.yview)
        self.text.grid(row=0,column=0)
        self.entry = Entry(self)
        self.entry.grid(row=1,column=0)
        self.pack()
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.connect((host, port))
        self.sock.send(self.nickname)
        self.thread1=threading.Thread(target=self.cmdloop)
        self.thread1.start()
        self.entry.bind("<Return>",self.enter)
        self.call()

    def enter(self,event):
        msg = Message(self.nickname,0,self.entry.get())
        self.entry.delete(0, END)
        msg = cPickle.dumps(msg)
        self.inqueue.put(msg)
        self.sock.send(msg)

    def call(self):
        self.processData()
        self.after(100,self.call)

    def cmdloop(self):
        while 1:
            sys.stdout.flush()
            # Wait for input from stdin & socket
            inputs, outputs, excepts = select.select([0,self.sock],[],[])

            for i in inputs:
                if i == 0:
                    data = sys.stdin.readline()
                    msg = Message(self.nickname,0,data)
                    msg = cPickle.dumps(msg)
                    self.inqueue.put(msg)
                    self.sock.send(msg)

                elif i == self.sock:
                    data = self.sock.recv(1024)
                    self.inqueue.put(data)

    def processData(self):
        while self.inqueue.qsize():
            try:
                msg = self.inqueue.get(0)
                msg = cPickle.loads(msg) 
                self.text.insert(END, msg.getusr()+": "+msg.getmsg())
                self.text.yview(END)
            except Queue.Empty:
                pass

if __name__ == "__main__":
    root = Tk()
    root.title("textarea")
    client = GUI(sys.argv[1],int(sys.argv[2]),root)
    root.mainloop()
4

3 回答 3

0

Select() 和 GUI 完全不相关。您可以从 GUI 小部件获取文本,并且可以通过套接字发送文本,因此您可以从 GUI 获取文本并像任何其他字符串一样通过套接字发送。

您是否知道入口小部件和文本小部件都有get获取文本的方法?您是否尝试过获取文本然后发送它,就像您调用readline而不是调用时一样self.text.get

于 2012-04-10T23:28:47.830 回答
0

如果要将操作绑定到条目修改、标准输入或套接字,则有一种更简单的方法,即不使用线程。这个想法是通过 Tkinter 将操作绑定到文件处理程序,而不是尝试为您自己的主循环提供选择和检索 Tkinter 事件。

例如,您可以依靠 Tkinter 主循环将函数绑定到文件描述符createfilehandler(fd,mask,callback)事件root.createfilehandler(sys.stdin,READABLE,callback)

这是一个演示应用程序

from Tkinter import *
import socket

master = Tk()

entry = Entry(master)
entry.pack()

def process(data):
    print "processing: {0}".format(data)

def stdin_callback(fd, mask):
    print "stdin"
    data = sys.stdin.readline()
    process(data[:-1])

def socket_callback(fd, mask):
    print "socket"
    try:
        data= sock.recv(1024)
        if data:
            process (data)
        else:
            close_socket ()
    except socket.error as ex:
        close_socket ()

def close_socket():
    #closing socket without removing filehandler may hurt
    sock.close()
    master.deletefilehandler(fileno)

def entry_callback(event):
    print "entry"
    process(event.widget.get())

entry.bind("<Return>", entry_callback)
master.createfilehandler(sys.stdin,READABLE, stdin_callback)

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(("localhost", 5678))
fileno = sock.fileno()
master.createfilehandler(fileno, READABLE, socket_callback)

master.mainloop()
于 2012-04-12T16:02:24.313 回答
0

我想我问的问题很糟糕,感谢那些尽管我措辞不佳但仍试图回答的人。我刚刚开始使用 Python。无论哪种方式,这是我的小组成员对我试图提出的问题找到的答案。我不知道是他自己写的还是在网站上找到的,但基本上只是对TKinterafter()调用的使用。

我们的主循环如下所示:

def cmdloop():
    (sread, swrite, sexc) = select.select( [sock], [], [], 0)
    for s in sread:
        ...
        ...
        ...
    app.after(500,cmdloop)

那半秒的休息让文本框调用inputBox.bind('<Return>', sendMsg)(以及等待在套接字中发送的消息)正常工作。sendMsg()然后简单地打了个sock.send()电话。

def sendMsg(event=''):
    message = inputBox.get()
    message += "\n"
    msg = Message(nickname,0,message,None) #Custom Class
    sock.send(pickle.dumps(msg))
    inputBox.delete(0,END)
    return
于 2012-06-15T06:44:55.597 回答