RobertR
RobertR

Reputation: 755

Threading with Twisted with Tkinter

I am currently working on a Battleship game project (for learning purposes) that uses tkinter for the UI and, because I want this program to be able to run on two computers for multiplayer, twisted for data transfer. This is my first time using twisted however I have used tkinter many times.

I know both twisted and tkinter run in loops so it is normally not possible to have these running in the same thread. So I found out there's two ways to get around this: tksupport and running twisted's reactor in a separate thread.

However, I tried to import tksupport from twisted.internet but it said that it didn't exist. I checked my twisted folder in my site-packages to be sure and it is indeed not there, but even the twisted docs claim it is. I assuming that this is because I am running python 3.5 and tksupport hasn't been ported over yet, but If this is not the case, please let me know.

Also, as for the solution with threading, I discovered there's some controversy over putting twisted's reactor in it's own thread. Is it ok to put the reactor in its own thread, and, if so, what precautions should I take?

Thanks.

Upvotes: 1

Views: 902

Answers (2)

SamuelN
SamuelN

Reputation: 146

I currently have twisted 17.9.0 and python 3.6. In reference to the answer above, tksupport for python 3 is now available with twisted, so no need to create your own tksupport module.

Upvotes: 1

ohmu
ohmu

Reputation: 19780

I took a look at the source code for twisted.internet.tksupport and it appears it has not been ported to support Python 3. The culprit is the line importing the tkinter modules:

import tkSimpleDialog, tkMessageBox

In Python 3 the equivalent would be:

from tkinter import simpledialog, messagebox

To get around this until Twisted supports Tkinter for Python 3, you should be able create your own tksupport module:

# tksupport.py
from tkinter import simpledialog, messagebox
from twisted.internet import task

_task = None

def install(widget, ms=10, reactor=None):
    """Install a Tkinter.Tk() object into the reactor."""
    installTkFunctions()
    global _task
    _task = task.LoopingCall(widget.update)
    _task.start(ms / 1000.0, False)

def uninstall():
    """Remove the root Tk widget from the reactor.

    Call this before destroy()ing the root widget.
    """
    global _task
    _task.stop()
    _task = None

def installTkFunctions():
    import twisted.python.util
    twisted.python.util.getPassword = getPassword

def getPassword(prompt = '', confirm = 0):
    while 1:
        try1 = simpledialog.askstring('Password Dialog', prompt, show='*')
        if not confirm:
            return try1
        try2 = simpledialog.askstring('Password Dialog', 'Confirm Password', show='*')
        if try1 == try2:
            return try1
        else:
            messagebox.showerror('Password Mismatch', 'Passwords did not match, starting over')

__all__ = ["install", "uninstall"]

And following a slightly modified version of Twisted's Tkinter example you would do:

import tkinter as tk
from twisted.internet import reactor

import tksupport

root = tk.Tk()

# Install the Reactor support
tksupport.install(root)

# at this point build Tk app as usual using the root object,
# and start the program with "reactor.run()", and stop it
# with "reactor.stop()".

Upvotes: 1

Related Questions