0

Some time ago I wrote a simple Tic-tac-toe game in Python (2.7), multiplayer version with server script (thread per connection) and client script. Now I want to extend client with gtk. I would like this to be an example of the use of decorators. Client script works in such a way that it retrieves data through the prompt. I want to write a script with will be something like a patch for client (just decorate clients functions, call new gtk-client script and wallah). I thought to do it that way:

  • gtk-client starts run_game() function from client script in thread
  • functions responsible for user input have decorators, that executes code and at the end they puts data to prompt (it is possible?)

This is my idea to control client script by gtk interface, but I came across some problems:

  • is it possible to put data to prompt like a keyboard input?
  • is it possible to get data from raw_input() if it is not in main thread?

Edit: Ok, I found a solution. I will create decorator who will overwrite raw_input() function (monkey pathing). It should look like this:

  • gtk-client creates thread with run_game() func. from client
  • run_game() is decorated (overwrite raw_input() before function call)
  • now raw_input() waits for input data from gtk-client by Queue (queue.get())

It looks like a good solution, but here is my another problem. My gtk-client calls thread (run_game()). If I do not use thread.join(), my thread is blocked in execution or print function can't print whole data to console. If I use thread.join() that creates a conflict, because thread waits for data in queue. Example test codes:

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'

In this case my thread prints only 'Thread start'. How to handle this problem?

  • If I understand your question right, your request is possible. However it comes with a price. The price of controlling all the Gtk widgets from your own GUI loop. Linux Mint does this for some of their dialogs and the code gets complicated quickly. – theGtknerd Sep 16 '17 at 22:21

1 Answers1

0

Ok, finally I found solution for all my problems. To simulate user input to raw_input() just change function funcionality (monkey patching) as shown in question, edited section.

Regarding to print errors in console - I resolvet it by adding sys.stdout.flush() to flush buffers (explained here), and waiting for thread after putting data to queue.

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