Trouble starting Python Threading loop - python

I am attempting to make a simple "chat" client in python. I have the basics and everything but I cannot get my threading to work at all. This is a still a work in progress so not all the code is there yet and I know that but if you do have any suggestion as a whole that would be greatly appreciated.
from Tkinter import *
import time
import socket
import thread
import threading
HOST = 'localhost'
PORT = 5454
fromserver = ''
data = ''
#Declares socket information
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
s.bind((HOST,PORT))
#Loop for receiving
def receivingloop():
global fromserver
while 1:
fromserver = s.recv(30)
time.sleep(.5)
class ChatClient:
def __init__(self, master):
#Use Global fromserver
global fromserver
global data
#Create both frames
top_frame = Frame(master)
bot_frame = Frame(master)
#Create and pack the Buttons
self.send_but = Button(bot_frame, \
text='Send',\
command=self.sending)
self.quit_but = Button(bot_frame, \
text='Quit', \
command=client_window.destroy)
self.send_but.pack(side=LEFT)
self.quit_but.pack(side=LEFT)
#Create and pack label
self.received_lab = Label(top_frame,\
text=(fromserver))
self.received_lab.pack()
self.sent_lab = Label(top_frame,\
text='Message Sent: ' +data)
self.sent_lab.pack()
self.sending_entry = Entry(top_frame, \
width=10)
self.sending_entry.pack()
#Pack Frames
top_frame.pack()
bot_frame.pack()
#Function to send stuff
def sending(self):
global data
s.sendto(data,(HOST,PORT))
data = str(self.sending_entry.get())
print data
#Start the thread
l1 = threading.Thread(target=receivingloop)
l1.start()
client_window = Tk()
chat_client = ChatClient(client_window)
client_window.mainloop()

If I'm not mistaken I would say the receivingloop method takes the self element but the self argument you need only by classes and this method is not in a class
Try this:
#Loop for receiving
def receivingloop():
global fromserver
while 1:
fromserver = s.recv(30)
time.sleep(.5)

Your function is defined with a variable called 'self', it looks like you previously had this function in a class, but decided to extract it from the class later on.
Anyway, to fix your problem, it should just be:
def receivingloop():
Note that the 'self' part from the function arguments has been removed.
Also, you might want to add global data to your send function.

Related

Multiple listboxs bound to same function

Honestly, I do not feel like this should be happening, but it is.
self.marketList.bind('<<ListboxSelect>>', self.market_selected)
self.jobsList.bind('<<ListboxSelect>>', self.job_selected)
There really isn't any more interaction between these two functions. When you click on an item in the marketList box, it's supposed to bring up the jobs in the jobsList box. Currently, it is applying the binding two both boxes. When I click on a job entry in the jobsBox, it clears the jobs and my troubleshooting is showing that it's calling market_selected. I'm not sure why this is happening, but it's really messing with what I'm trying to do with it.
How can I ensure that my binding is on only one widget, and won't be applied to multiple widgets?
edit:
I'm told that this isn't enough code to reproduce the error.
This is all the relevant code.
As I said previously, self.market_selected is called when I click on anything in the jobsList
edit #2
I uploaded the entire script.
import MarketWizard
import JobWizard
import SpanWalkerDocuments as swd
import tkinter as tk
from tkinter import *
from tkinter import ttk
import SpanWalkerDocuments as SpanWalker
class SpanWalker:
def __init__(self):
self.root = tk.Tk()
self.root.title('Luke Spanwalker')
self.root.resizable(True, True)
self.MainFrame = Frame(self.root, bg='red')
self.sidebarFrame = Frame(self.root, bg='blue')
self.tabControl = ttk.Notebook(self.sidebarFrame)
self.marketFrame = Frame(self.tabControl)
self.clientFrame = Frame(self.tabControl)
self.jobsFrame = Frame(self.tabControl)
self.polesFrame = Frame(self.MainFrame, height=100, width=50)
self.tabControl.add(self.marketFrame, text="Markets")
self.tabControl.add(self.jobsFrame, text="Jobs")
self.tabControl.add(self.clientFrame, text="Clients")
#self.tabControl.add(self.polesFrame, text="Poles")
self.tabControl.pack(expand=1, fill="both")
self.MainFrame.grid(row=0, column=1)
self.sidebarFrame.grid(row=0, column=0)
#Awesome, our tabbed control is ready.
#Now, we need to make the listBox widgets that will actually display our data.
self.marketList = Listbox(self.marketFrame)
self.jobsList = Listbox(self.jobsFrame)
self.polesList = Listbox(self.polesFrame)
#Binding functions! Yay for binding functions!
self.marketList.bind('<<ListboxSelect>>', self.market_selected)
self.jobsList.bind('<<ListboxSelect>>', self.job_selected)
self.curMarket = ""
self.markets = []
self.jobs = []
self.poles = []
def UpdateMarkets (self):
if len(self.markets) > 0:
self.markets.clear()
self.marketList.delete(0, END)
for mark in swd.Market.objects:
self.markets.append(mark)
for m in range(0, len(self.markets)):
self.marketList.insert(m, self.markets[m].title)
def OpenMarketWizard(self):
mw = MarketWizard.MarketWizard()
mw.RunMarketWizard(self.root)
def market_selected(self, event):
print("Market Selected")
selection = self.marketList.curselection()
selectedMarket = ",".join([self.marketList.get(i) for i in selection])
self.PopulateJobs(selectedMarket)
def PopulateJobs(self, market):
self.jobs.clear()
self.jobsList.delete(0, END)
self.GetJobs(market)
for j in range(0, len(self.jobs)):
self.jobsList.insert(j, self.jobs[j].jobName)
def GetJobs(self, market):
marketJobs = []
jobs = []
if market =="":
return
for j in swd.Job.objects:
jobs.append(j)
print("Market = {0}".format(market))
for i in jobs:
if i.market == market:
self.jobs.append(i)
def job_selected(self, event):
print("Job Selected")
selection = self.jobsList.curselection()
selectedJob = ",".join([self.jobsList.get(i) for i in selection])
print("The selected job is: {0}".format(selectedJob))
def PopulateMarkets(self):
self.marketList.destroy()
for m in range(0, len(self.markets)):
marketList.insert(m, self.markets[m].title)
def OpenJobWizard(self):
jw = JobWizard.JobWizard()
jw.RunJobWizard(self.root)
#We need to pack everything that belongs in our tabbed function.
def marketListDisplay(self, show):
if show == True:
self.marketList.pack(fill="both")
self.UpdateMarkets()
self.newButton=Button(self.marketFrame, text="Open Market Wizard", command=lambda:self.OpenMarketWizard())
self.newButton.pack()
self.refreshButton=Button(self.marketFrame, text="Refresh Markets", command=lambda:self.UpdateMarkets())
self.refreshButton.pack()
else:
self.marketList.forget_pack()
def jobsListDisplay(self, show):
if show==True:
self.jobsList.pack()
self.newButton = Button(self.jobsFrame, text="Create New Job / Open Job Wizard", command=lambda:self.OpenJobWizard())
self.newButton.pack()
else:
self.jobsList.forget_pack()
def polesListDisplay(self, show):
if show==True:
self.polesList.pack()
else:
self.polesList.forget_pack()
#Query, why not put them all in a function?
sp = SpanWalker()
sp.marketListDisplay(True)
sp.polesListDisplay(True)
sp.jobsListDisplay(True)
The answer was given by acw1668. I just added exportselection=0 during the creation process for the listboxes, and it worked perfectly.
Sorry for the confusion, y'all, I've never really asked for help on here before.
Thanks for the help!

How to solve Problem with Multiprocessing in Tkinter?

Over here I am using multiprocessing to run multiple algorithms in tkinter. At first I tried using threading, but it can't work properly in my program. Below is an idea of my program workflow, it works something like this, but just different functions:
from tkinter import *
from multiprocessing import Process
def SquarFunc(Square):
for i in range(1,1000):
Square.set(str(i**2))
def CubeFunc(Cube):
for i in range(1,1000):
Cube.set(str(i**3))
if __name__ == "__main__":
window= Tk()
Square= StringVar()
Cube= StringVar()
window.geometry("500x500")
A= Label(window, textvariable= Square)
A.place(x=200, y=200)
B= Label(window, textvariable= Cube)
B.place(x=300, y=300)
Squaring= Process(target=SquarFunc, args=(Square, ))
Cubing= Process(target=CubeFunc, args=(Cube, ))
Squaring.start()#Error originates here
Cubing.start()
Squaring.join()
Cubing.join()
window.mainloop()
The error produced is this:
TypeError: cannot pickle '_tkinter.tkapp' object
Anybody knows how to fix this?? thanks in advance!
Here is an example of how to communicate with other processes if using multiprocessing (explanation is in comments, time.sleep is used just for the example because otherwise those loops will complete in a few microseconds):
from tkinter import Tk, StringVar, Label
from multiprocessing import Process, Manager
import time
def square_func(d, name):
for i in range(1, 1000):
# update data in the shared dict
d[name] = i
time.sleep(0.1)
def cube_func(d, name):
for i in range(1, 1000):
# update data in the shared dict
d[name] = i
time.sleep(0.1)
def update_string_vars(d, *variables):
for var in variables:
# get the value from shared dict
value = d[str(var)]
if value is not None:
# set string var to the value
var.set(str(value))
# schedule this to run again
window.after(100, update_string_vars, d, *variables)
# cleanup process upon closing the window in case
# processes haven't finished
def terminate_processes(*processes):
for p in processes:
p.terminate()
if __name__ == "__main__":
window = Tk()
window.geometry("500x500")
# bind the terminator to closing the window
window.bind('<Destroy>', lambda _: terminate_processes(
square_process, cube_process))
square_var = StringVar()
cube_var = StringVar()
Label(window, text='Square:').pack()
Label(window, textvariable=square_var).pack()
Label(window, text='Cube:').pack()
Label(window, textvariable=cube_var).pack()
# create the manager to have a shared memory space
manager = Manager()
# shared dict with preset values as to not raise a KeyError
process_dict = manager.dict({str(square_var): None, str(cube_var): None})
square_process = Process(
target=square_func, args=(process_dict, str(square_var))
)
cube_process = Process(
target=cube_func, args=(process_dict, str(cube_var))
)
square_process.start()
cube_process.start()
# start the updater
update_string_vars(process_dict, square_var, cube_var)
window.mainloop()
Useful:
Sharing state between processes
shortly about tkinter and processes
See also:
I strongly advise against using wildcard (*) when importing something, You should either import what You need, e.g. from module import Class1, func_1, var_2 and so on or import the whole module: import module then You can also use an alias: import module as md or sth like that, the point is that don't import everything unless You actually know what You are doing; name clashes are the issue.
I strongly suggest following PEP 8 - Style Guide for Python Code. Function and variable names should be in snake_case, class names in CapitalCase. Don't have space around = if it is used as a part of keyword argument (func(arg='value')) but have space around = if it is used for assigning a value (variable = 'some value'). Have space around operators (+-/ etc.: value = x + y(except here value += x + y)). Have two blank lines around function and class declarations. Object method definitions have one blank line around them.

GUI status in Python Tkinter

EDIT: Made some changes based on feedback in comments.
I am trying to use a statusTextF function to show a WAIT/READY message on python GUI.
I have defined, at the beginning, when the GUI is drawn.
statusText = True
and then call the following when i want it to wait:
statusText = False
I call statusText as a global variable everywhere I use it, and I have the statusTextF function as shown below:
def statusTextF():
if statusText == True:
statusTitle = tk.Label(root,text="READY")
statusTitle.config(font=statusFont,bg="light green")
statusX = 500
statusY = 450
statusTitle.place(x=statusX,y=statusY)
separation = 45
else:
statusTitle = tk.Label(root,text="WAIT")
statusTitle.config(font=statusFont,bg="light red")
statusX = 500
statusY = 450
statusTitle.place(x=statusX,y=statusY)
separation = 45
I am seeing 'READY' all the time though.
What could be wrong?
Now, it doesn't display anything, and also I get a light red is unknown colour error.
Here's a demonstration of how to do something like you want. It doesn't use a Queue for communication between the main GUI thread and the status updating thread since the amount of information being exchanged between them is so minimal. It instead uses a threading.Lock to control access to a global variable shared between them. Note that it's also implicitly being used to protect updates to the separation global.
Using a queue.Queue to exchange the information ought be fairly easy to implement — should you need one for some reason — since they don't need a separate Lock because they implement "all the required locking semantics" interally.
Note: I've tried to (mostly) follow the PEP 8 - Style Guide for Python Code to make it fairly readable — which I strongly suggest you read (and also follow).
import random
import time
import tkinter as tk
import tkinter.font as tkFont
import threading
class StatusUpdater(threading.Thread):
# # Not really needed since it doesn't do anything except call superclass ctor here.
# def __init__(self, *args, **kwargs):
# super().__init__(*args, **kwargs) # Initialize base class constructor.
def run(self):
global status_flag_lock, status_flag # Must declare these to change their values.
while True:
# Randomly update status_flag.
value = random.randint(0, 100)
with status_flag_lock:
status_flag = bool(value % 2) # True if odd number.
time.sleep(.5) # Pause updating for a little while.
def statusTextF():
global status_flag_lock, separation # Must declare these to change their values.
with status_flag_lock:
if status_flag:
statusTitle.config(text="READY", bg="light green")
separation = 45
else:
statusTitle.config(text="WAIT", bg="pink")
separation = 55
root.after(250, statusTextF) # Continue the polling.
status_flag_lock = threading.Lock() # To control concurrent access.
root = tk.Tk()
root.geometry('600x600')
STATUS_FONT = tkFont.Font(family='Courier', size=8)
STATUS_X, STATUS_Y = 500, 450
status_flag = True
separation = 45
statusTitle = tk.Label(root, text="UNKNOWN", font=STATUS_FONT, bg="gray50")
statusTitle.place(x=STATUS_X, y=STATUS_Y)
status_updater = StatusUpdater(daemon=True)
status_updater.start() # Start updating of status flag.
root.after(250, statusTextF) # Start polling status every 250 millisecs.
root.mainloop()

Python - Functions & Execution order

I want to use the bot_create function with a button but I keep getting (on line 20) the problem "bots not defined" so I moved the function down below the button but got the problem "bot_create not defined".
I didn't get this problem using C++ and I'm new to Python. How should I arrange the functions?
import tkinter as tk
import numpy as np
import multiprocessing as mp
bots_max = 1000 # Maximum number of bots
bot = []
bot_count = 0
# Menu functions
def save_field():
pass
# Field functions
def field_clear():
pass
# Bots functions
def bots_create():
bot[bot_count] = bots
bot_count += 1
main = tk.Tk()
field_sides = 600
ctrls_width = 200
main.geometry("800x600")
main.resizable(0, 0)
main.title("Swarm Simulator v1.0")
# Controls menu on left side
button1 = tk.Button(main, text = "Button 1").pack(side = "left", command = bots_create())
class environment:
def __init__():
pass
class wall:
def __init__():
pass
# Bots
class bots:
alive = True
def __init__():
alive = True
# Field where bots live
field = tk.Canvas(main, width = field_sides, height = field_sides, bg = "white").pack(side = "right")
for particle in bots:
print("|")
main.mainloop()
Here's a version of your code that fixes all the syntactic problems, and so compiles (what I really mean is that my IDE now thinks its ok). It also runs, but I don't know if it does what you intended. See my comments in the code:
import tkinter as tk
import numpy as np
import multiprocessing as mp
# moved your class defs up to fix problems with accessing them before they are defined
class environment:
def __init__(self): # need a self param here
pass
class wall:
def __init__(self): # need a self param here
pass
# Bots
class bots:
alive = True
def __init__(self): # need a self param here
alive = True
bots_max = 1000 # Maximum number of bots
bot = []
# bot_count = 0 # this no longer does anything. use `len(bot)` to get the number of objects in the 'bot' list
# Menu functions
def save_field():
pass
# Field functions
def field_clear():
pass
# Bots functions
def bots_create():
# bot[bot_count] = bots # this will crash as it is referring to a non-existent location in the list
# also, your use of "bots" here makes no sense
# bot_count += 1 # this makes 'bot_count' a local variable, which is not what you want
bot.append(bots()) # not sure this is what you want, but this creates a new 'bots' object and adds it to the 'bot' list
main = tk.Tk()
field_sides = 600
ctrls_width = 200
main.geometry("800x600")
main.resizable(0, 0)
main.title("Swarm Simulator v1.0")
# Controls menu on left side
button1 = tk.Button(main, text = "Button 1").pack(side = "left", command = bots_create())
# Field where bots live
field = tk.Canvas(main, width = field_sides, height = field_sides, bg = "white").pack(side = "right")
for particle in bot: # maybe you want to iterate over the 'bot' list instead of the 'bots' type?
print("|")
main.mainloop()
As #khelwood says, it seems that you should swap the use of the names bot and bots per the way you are using them

display output in Text from module

I am working on a tool to log on a motorolla modem, i get it working and display the output on the python console, this tool have 2 part one part with the gui and the button, label and text frame.
i would like to get the output displayed on the Gui and not to the console.
how can i get that done
here is the files :
from Tkinter import *
import motorola
class Application(object):
def init(self):
self.fen = Tk()
self.fen.title("Motorola tool V 0.1")
self.fen.geometry("720x480")
Label(self.fen,
text = "IP address").grid(row=0)
#self.entree = MaxLengthEntry(self.fen, maxlength=5)
self.entree1 = Entry(self.fen)
self.entree1.grid(row=0, column=1)
Label(self.fen,
text = "Password").grid(row=2)
#self.entree = MaxLengthEntry(self.fen, maxlength=5)
self.entree2 = Entry(self.fen)
self.entree2.grid(row=2, column=1)
Button(self.fen, text = 'Connect',
command = self.launch).grid(row = 3, column=2)
Button(self.fen, text = 'Disconect',
command = self.exits).grid(row = 3, column=3)
Button(self.fen, text = 'Quit',
command = self.fen.quit).grid(row = 5, sticky = E)
self.output = Text(self.fen)
self.output.grid(row = 7, column = 1)
self.fen.mainloop()
def launch(self):
self.ip = self.entree1.get()
self.passw = self.entree2.get()
print self.ip, self.passw
if self.passw == "":
self.entree2.config(bg = 'red')
self.fen.after(1000, self.empty)
else:
self.f = motorola.Motorola(self.ip, self.passw)
self.f.sh_dsl()
def empty(self):
self.entree2.configure(bg='white')
def exits(self):
try:
self.f.disconnect()
except AttributeError:
print "You are not connected"
a = Application()
motorola file :
class Motorola(object):
def init(self, ip, passw):
self.ip = ip
self.passw = passw
print "connect on the modem"
self.tn = telnetlib.Telnet(self.ip, '2323' , timeout =5)
self. tn.read_until("login: ")
self.tn.write('radadmin\r\n')
self.tn.read_until("Password:")
self.tn.write(self.passw+"\r\n")
data = self.tn.read_until(">")
print "you are connected"
print data,
def disconnect(self):
self.tn.close()
print "disconnect from the modem"
import telnetlib
once i connect on the modem with the button which launch motorola module, how can the data could be displayed on the frame text of the gui module ?
Thank you
The basic idea is that you have to replace each print with some code that adds the string to the GUI.
The trick is that a Motorola instance probably doesn't know how to do that. So, what you want to do is pass it something—self, or self.output, or best of all, a function (closure) that appends to self.output. Then the Motorola code doesn't have to know anything about Tk (and doesn't have to change if you later write a wx GUI); it just has a function it can call to output a string. For example:
def outputter(msg):
self.output.insert(END, msg + "\n")
self.f = motorola.Motorola(self.ip, self.passw, outputter)
Then, inside the Motorola object, just store that parameter and call it everywhere you were using print:
def __init__(self, ip, passw, outputter):
self.outputter = outputter
# ...
self.outputter("connect on the modem")
That almost does it, but how you do handle the magic trailing comma of the print function, or even simple things like multiple arguments or printing out numbers? Well, you just need to make outputter a little smarter. You could look at the interface of the Python 3 print function for inspiration:
def outputter(*msgs, **kwargs):
sep = kwargs.get("sep", " ")
end = kwargs.get("end", "\n")
self.output.insert(END, sep.join(msgs) + end)
You could go farther—converting non-strings to strings (but not breaking Unicode), etc.—but really, why? If you're trying to get too fancy with print or with your outputter function, you probably want to let str.format do the heavy lifting instead…
Anyway, now, instead of:
print data,
You do:
self.outputter(data, end='')
And all of your other print statements are trivial.

Categories

Resources