使用Python中的select.select()输入GUI

时间:2012-04-10 16:03:22

标签: python sockets tkinter

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

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

3 个答案:

答案 0 :(得分:0)

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

您是否知道条目小部件和文本小部件都有get方法来获取文本?您是否尝试过提取文本,然后像调用readline而不是self.text.get一样发送文本?

答案 1 :(得分:0)

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

您可以依靠Tkinter mainloop通过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()

答案 2 :(得分:0)

我想我问的问题很糟糕,感谢那些尽管我的措词不好而试图回答的人。我刚开始使用Python。无论哪种方式,这是我的小组成员找到的问题的答案,我正在尝试询问。我不知道他是自己写的还是在网站上发现的,但它基本上只是使用了TKinter after()电话。

我们的主循环如下:

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