3

I am retired and trying to get to grips with Python (as you can probably tell from the code!) and am trying to program a simple game using a laptop and tablet (both running Python 3.3.5 under Windows 8).
My problem in a nutshell is this:
I have two simple working programs (below): one waits for a button click and changes the screen colour, the other waits for a message from a comms client and changes the screen colour.
What's the simplest way to combine these into one ongoing program, so we are waiting for either screen or comms activity which may come in any order?
I've tried various ways I've discovered on this site and others around threading and waiting, but none seem ideal. I would appreciate any help!

# PROGRAM 1 - wait for user to click button
from tkinter import *
win1 = Tk()
win1.attributes('-fullscreen', True)

def turnorange():
    win1.configure(bg='orange')
def turnwhite():
    win1.configure(bg='white')

btn1 = Button( win1 , text='Click for orange' , command=turnorange)
btn1.place(x=100,y=100)
btn2 = Button( win1 , text='Click for white' , command=turnwhite)
btn2.place(x=250,y=100)
btn_end = Button( win1 , text='Close' , command=exit)
btn_end.place(x=200,y=200)
win1.mainloop()

# PROGRAM 2 - wait for message from client
from tkinter import *
import socket
win1 = Tk()
win1.attributes('-fullscreen', True)

def changecolour(col): 
    win1.configure(bg=col)
    win1.update()

def startup():
    ss = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    ss.bind((socket.gethostname(), 8089))
    ss.listen(5)
    while True:
        conn, address = ss.accept()
        colour = conn.recv(64).decode()
        if len(colour) > 0:
            changecolour(colour)
            data = 'whatever'
            conn.send(data.encode())

btn = Button( win1 , text='Click to listen' , command=startup)
btn.place(x=100,y=100)
win1.mainloop()
colinj
  • 33
  • 5
  • The problem with your current code is that `startup` is blocking; you need to find a way to poll for new connections so the `mainloop` can keep monitoring other events. – Ethan Furman Jul 01 '15 at 07:20
  • Thanks. That sounds like the nub of the problem. Isn't there an effective way to do this in Python? – colinj Jul 01 '15 at 07:38

2 Answers2

1

The problem with your current code is that startup is blocking; you need to find a way to poll for new connections so the mainloop can keep monitoring other events.

Try this socket tutorial to get a feel for the basics, and this question for some specifics on using non-blocking sockets.

In order to have your socket checking code run periodically, check out tk's after.

Community
  • 1
  • 1
Ethan Furman
  • 63,992
  • 20
  • 159
  • 237
0

These links gave me a great insight into what was going on, and I have solved the problem now.

Program 3 combines Programs 1 and 2 and runs on my laptop. Program 4 runs on a Windows tablet. In Program 3 if we press btn1 or btn2 it is processed only once we have a connection from the tablet, so the tablet just needs to send a regular message, say every 0.2 seconds: "A" to change colour to cyan, otherwise it reverts to cornsilk.

This works so I'm happy. I'd be even happier if I understood how it breaks out of the while True loop to process the events!

from tkinter import *
# PROGRAM 3 on LAPTOP: wait for message from tablet OR for user to click button
import socket
win1 = Tk()
win1.attributes('-fullscreen', True)

def turnorange():
    changecolour('orange')
def turnyellow():
    changecolour('yellow')

def changecolour(col): 
    win1.configure(bg=col)
    win1.update()

def startup():
    ss = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    ss.bind((socket.gethostname(), 8089))
    ss.listen(5)

    while True:
        conn, address = ss.accept()
        colour = conn.recv(64).decode()
        if len(buf) > 0:
            if buf == "A":
                changecolour('cyan')
            else:
                changecolour('cornsilk')
        data = 'whatever'
        conn.send(data.encode())

btn = Button( win1 , text='Click to listen' , command=startup)
btn.place(x=100,y=100)

btn1 = Button( win1 , text='Click for orange' , command=turnorange)
btn1.place(x=300,y=100)
btn2 = Button( win1 , text='Click for yellow' , command=turnyellow)
btn2.place(x=400,y=100)

win1.mainloop()


# PROGRAM 4 on TABLET: sends message to laptop (a) when button clicked, and (b) every 0.2 seconds
from tkinter import *
import socket

win1 = Tk()
win1.attributes('-fullscreen', True)

def sendstuff(data):
    cs = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    cs.connect(('192.168.1.7', 8089))
    cs.sendall(data.encode())
    buf = cs.recv(64).decode()
    cs.close()

def clicked():
    sendstuff("A")

def sendroutine():
    sendstuff("X")
    win1.after(200, sendroutine) # time delay, 1000 =1 sec during test, 200 = 0.2 secs when live

btn1 = Button( win1 , text='Start' , command=sendroutine, width = 20, height = 3)
btn1.place(x=200,y=200)
btn2 = Button( win1 , text='Click for cyan' , command=clicked, width = 20, height = 3)
btn2.place(x=400,y=200)

win1.mainloop()
colinj
  • 33
  • 5