扩展Tic-tac-toe游戏的功能(gtk + decorators + raw_input)

时间:2017-09-16 21:15:18

标签: python multithreading python-2.7 gtk python-decorators

前段时间我在Python(2.7)中编写了一个简单的Tic-tac-toe游戏,带有服务器脚本(每个连接的线程)和客户端脚本的多人版本。现在我想用gtk扩展客户端。我希望这是使用装饰器的一个例子。客户端脚本的工作方式是通过提示检索数据。我想写一个脚本,就像客户端的补丁(只是装饰客户端函数,调用新的gtk-client脚本和wallah)。我想这样做:

  • gtk-client从线程
  • 中的客户端脚本启动run_game()函数
  • 负责用户输入的函数有装饰器,执行代码,最后他们将数据提示(有可能吗?)

我的想法是通过gtk接口控制客户端脚本,但我遇到了一些问题:

  • 是否可以像键盘输入一样提示数据?
  • 是否可以从raw_input()获取数据,如果它不在主线程中?

修改: 好的,我找到了解决方案。我将创建将覆盖raw_input()函数(猴子路径)的装饰器。它应该是这样的:

  • gtk-client使用run_game()func创建线程。来自客户
  • run_game()被修饰(在函数调用之前覆盖raw_input())
  • now raw_input()通过Queue(queue.get())等待来自gtk-client的输入数据

这看起来是一个很好的解决方案,但这是我的另一个问题。我的gtk-client调用thread(run_game())。如果我不使用thread.join(),我的线程在执行时被阻塞或者打印功能无法将整个数据打印到控制台。如果我使用thread.join()创建冲突,因为线程等待队列中的数据。示例测试代码:

gtk-client.py

import gtk
import client as cliApp
from threading import Thread
from Queue import Queue 

# gtk stuff etc...

# lets say it is called on y_button_click, part of GameGtk class
def y_button_click(self, widget):
    cliApp.q.put('test msg')


# lets say that it is called in x_button_click
@run_game_decorator(func):
    def wrapper(*args):
        # some connecting/logging stuff
        cliApp.q = Queue()
        t = Thread(target = cliApp.test)
        t.start()
        # t.join() - worked until I added q.get() to new raw_input()
    return wrapper
# gtk still working after this function

client.py

def new_raw_input(label):
    print label
    return q.get()

def test():
    print 'Thread start'
    raw_input = new_raw_input
    a = raw_input("Type something: ")
    print a
    print 'Thread finished'

在这种情况下,我的线程只打印'Thread start'。如何处理这个问题?

1 个答案:

答案 0 :(得分:0)

好的,最后我找到了所有问题的解决方案。要模拟用户对raw_input()的输入,只需更改函数功能(猴子修补),如问题,编辑部分所示。

关于控制台中的打印错误 - 我通过添加sys.stdout.flush()来刷新缓冲区(解释here)并在将数据放入队列后等待线程来解决它。

<强> gtk-client.py

import gtk
import client as cliApp
from threading import Thread
from Queue import Queue
from time import sleep
import sys


# gtk stuff etc...

# lets say it is called on y_button_click, part of GameGtk class
def y_button_click(self, widget):
    cliApp.q.put('test msg')
    self.t.join()


# lets say that it is called in x_button_click
@run_game_decorator(func):
    def wrapper(*args):
        # some connecting/logging stuff
        cliApp.q = Queue()
        gtkWindow.t = Thread(target = cliApp.test)
        gtkWindow.t.start()
        sleep(0.1)
        sys.stdout.flusch()
    return wrapper
# gtk still working after this function