multiple tasks on tkinter canvas? - python-2.7

I am trying to update canvas background at the same time running a binding event.
(from code)In do_popup popup menu will be implemented and conti will continuously change the canvas background color. how can i use popup option while canvas is updating continuously.
Sample code:
from Tkinter import *
root = Tk()
def do_popup(event,w2):
print w2 # inplace of print some popupmenu will be implemented
def conti():
idt=1
while idt==1:
w.config(bg="red") # in place of red it will be a random color
w.update_idletasks()
w= Canvas(root, width=600, height=600)
w.grid(row=0, column=0)
line1 = w.create_line(200,200,300,300, width=10, tags="line1", fill="black")
w.tag_bind(line1, "<Button-3>", lambda e, w2="test1" :do_popup(e,w2))
f = Frame(root)
f.grid(row=0, column=1, sticky=N)
f1=Button(f, text='visual', command=lambda :conti())
f1.grid(row=0, column=1,columnspan=1, sticky=W+N+S+E)
mainloop()
will multiprocessing work?
I am using windows 7 32 bit with python 2.7.3
Thanks in advance

When your script enters the mainloop then the events are executed.
To make reoccurring updates I like to do this:
def conti():
try:
w.config(bg="red") # in place of red it will be a random color
finally:
# start conti after 10 milliseconds,
root.after(10, conti)
# could also be 0ms to handle events
root.after(0, conti)
You can see root.mainloop as
while not (root.quit was called):
root.update()
This way wou can do:
root.quit()
and conti automatically stops.
There is no concurrency as with threads in mainloops.
But you can put a mainloop() somewhere when you create an own dialog box and conti will go on.
If you use the modules tkMessageBox(Python2) or tkinter.messagebox(Python3) then you conti should run while the dialog is open.
Does this answer your questions?
PS: do root.protocol("WM_DELETE_WINDOW", root.quit) to make the mainloop end when you close the window.

Related

Wanting to get an output and run a programme together with Tkinter

What I want to be able to do is run a list of MIDI files, I have the programme to list them out and play them...
import os,fnmatch,pygame
pygame.mixer.init()
List = []
Song = 0
def Update():
List = []
for file in os.listdir('.'):
if fnmatch.fnmatch(file, '*.mid'):
List.append(file)
return List
List = Update()
while True:
while Song <= len(List):
pygame.mixer.music.load(List[Song])
pygame.mixer.music.play(1)
while pygame.mixer.music.get_busy() == True:
List = Update()
Song = Song + 1
Song = 0
This currently works with .mid files that it is in the same folder as, however I want to implement a slider with the programme to control the volume, I also have that code already...
from Tkinter import *
master = Tk()
def getThrottle(event):
Volume = Throttle.get()
Throttle = Scale(master, from_=0, to=100, tickinterval=10, length=200, orient=HORIZONTAL, command=getThrottle)
Throttle.set(0)
Throttle.pack()
mainloop()
What I want to know is how I can make both programmes run at the same time with a single variable global between both with that variable being Volume
Nevermind, I discovered how to run both a tkinter window and music at the same time, however a new problem is that the tkinter window is blank.
New question is "Why is the tkinter window blank?"

Tkinter - create flashing graphic on a canvas?

I'm using Tkinter (2.7) to try to create a finite loop that draws, then erases a rectangle on a canvas widget, like its flashing. After several days of trying everything I could find, I have to ask for help.
The problem:
The code below seems to create and delete the rectangle inside the program but not display it in the main window (root).
from Tkinter import *
root = Tk()
def make():
canvas.create_rectangle(20,20,60,60,fill="pink")
root.after(1000)
def unmake():
canvas.delete(ALL)
root.after(1000)
def loop():
count = 0
while count < 5:
make()
unmake()
count += 1
canvas = Canvas(root,width=100,height=100)
canvas.pack()
loop()
root.mainloop()
Things I've tried:
If I put a print instruction in the make() and unmake() functions these print at 1 second intervals, so I know the .after() method is working.
If I make an infinite loop with the make() function calling unmake() and unmake calling make() again, this does display the flashing rectangle in the main window (root);
def make():
box = canvas.create_rectangle(20,20,60,60,fill="pink")
root.after(1000,unmake)
def unmake():
canvas.delete(ALL)
root.after(1000,make)
If someone knows why Tkinter is behaving this way, I'd be very grateful for guidance. Thanks.
after() does not call any function in the code posted. The following code illustrates the basic idea
from Tkinter import *
root = Tk()
def make():
canvas.create_rectangle(20,20,60,60,fill="pink")
root.after(1000, unmake)
def unmake():
canvas.delete(ALL)
root.after(1000, make)
canvas = Canvas(root,width=100,height=100)
canvas.pack()
make()
root.mainloop()

Tabbed GUI keeps hanging on entry box

I have a very primitive GUI built with Tkinter. This is my first attempt at a GUI so I am struggling to understand what is going on (and with syntax). Here is what I have:
from __future__ import division, print_function
import os, ttk, tkFileDialog, Tkconstants
import Tkinter as tk
import datetime as dt
Tkinter = tk
# define OS version
version = '0.0.2'
class TestGUI(tk.Tk):
def __init__(self,parent):
tk.Tk.__init__(self,parent)
self.parent = parent
self.initialize()
# try building list of instruments and sites
if os.path.isfile('config'):
with open(''config','r') as config:
config = dict( [(r.split('=')[0].strip(), r.split('=')[1].strip()) for r in config.read().split('\n') if r[0]<>'#'] )
self.datapath = config['datapath']
else:
self.datapath = '../'
def initialize(self):
self.grid()
# set up tabs
self.geometry( "%dx%d+%d+%d" % (1500, 900, 200, 50) )
nb = ttk.Notebook(self)
nb.pack(fill='both',expand='yes')
f1 = tk.Frame(bg='green')
f2 = tk.Frame(bg='blue')
f3 = tk.Frame(bg='red')
f1.grid()
f2.grid()
f3.grid()
nb.add(f1, text='General'.ljust(12,' '))
nb.add(f2, text='Plot'.ljust(12,' '))
nb.add(f3, text='Analysis'.ljust(12,' '))
button = tk.Button(f2,text='I AM A BUTTON!')
button.pack(side='left', anchor='nw', padx=3, pady=5)
# insert button and text box for specifying data location
path_button = tk.Button(f1,text='Browse',command=self.askdirectory).pack(side='left', anchor='nw', padx=10, pady=15)
self.path_entry = tk.StringVar()
self.entry = tk.Entry(f1,textvariable=self.path_entry)
self.entry.grid(column=12,row=8,columnspan=10)
self.entry.bind("<Return>", self.OnPressEnter)
self.path_entry.set(u"Sites directory path...")
def OnButtonClick(self):
print("You clicked the button !")
def OnPressEnter(self,event):
print("You pressed enter !")
def askdirectory(self):
"""Returns a selected directoryname."""
self.datapath = tkFileDialog.askdirectory()
self.path_entry.set(self.datapath)
if __name__ == "__main__":
app = TestGUI(None)
app.title(version)
app.mainloop()
My problem is centered around the addition of an entry box here:
self.path_entry = tk.StringVar()
self.entry = tk.Entry(f1,textvariable=self.path_entry)
self.entry.grid(column=12,row=8,columnspan=10)
self.entry.bind("<Return>", self.OnPressEnter)
self.path_entry.set(u"Sites directory path...")
If I run the code as-is, it just hangs (it also hangs if I use "f2"; I suspect it is getting caught in the infinite loop without actually doing anything). However, if I change the parent from "f1" to "f3" or it works (the entry box is now in frame 3 instead of frame 1, but it at least does not hang on me). There is another issue even when f3 is used: the entry box's width/position never change despite my changing of column/row/columnspan values.
Does anyone know why the code is hanging when I specify "f1" or "f2" and how to fix it?
Does anyone know why my entry box position/size is not changing?
You have put widgets in f1 and f2 using the pack geometry manager:
button = tk.Button(f2,text='I AM A BUTTON!')
button.pack(side='left', anchor='nw', padx=3, pady=5)
#and
path_button = tk.Button(f1,text='Browse',command=self.askdirectory).pack(side='left', anchor='nw', padx=10, pady=15)
Mixing geometry managers can lead to your program hanging, so using grid to put in the Entry does exactly that.
From effbot.org:
Warning: Never mix grid and pack in the same master window. Tkinter will happily spend the rest of your lifetime trying to negotiate a solution that both managers are happy with. Instead of waiting, kill the application, and take another look at your code. A common mistake is to use the wrong parent for some of the widgets.
The problem you describe of the Entry not changing position is because it is the only widget there, so the row(s) and column(s) in which the entry is are the only ones which do not have a width and height of 0. To make rows and columns without widgets take up space, use grid_rowconfigure(index, weight=x) where x is non-zero. An example is given in this answer.
Again from effbot.org:
weight=
A relative weight used to distribute additional space between rows. A row with the weight 2 will grow twice as fast as a row with weight 1. The default is 0, which means that the row will not grow at all.

How do I use Tkinter to create a ball everywhere my mouse clicks?

I am trying to create a program that creates a ball every time the mouse clicks, wherever it clicks. I am new to Tkinter and its syntax, but it seems like a pretty useful GUI.
Thanks
Here is the code. This code also tracks whenever a key is pressed, and it prints the syntax for that key.
from Tkinter import *
root = Tk()
def key(event):
pressedkey = repr(event.char)
print "pressed", pressedkey
def callback(event):
canvas.focus_set()
print "clicked at", event.x, event.y
ball = canvas.create_oval(event.x-15, event.y-15, event.x+15, event.y+15, outline='black', fill='gray40', tags=('ball'))
canvas = Canvas(root, width =1224,height=1024,bg='white')
canvas.bind("<Key>", key)
canvas.bind("<Button-1>", callback)
canvas.pack()
root.mainloop()
Here is the Tkinter documentation

How do I wait for a certain number of buttons to be clicked in Tkinter/Python?

I'm trying to write a simple 'Simon' game, but I have hit a road block here, and honestly have no idea how to get around it.
So here, I made a class for the four buttons in the GUI:
class button:
def buttonclicked(self):
self.butclicked= True
def checkIfClicked(self):
if self.butclicked== True:
global pressed
pressed.append(self.color)
self.butclicked= False
def __init__(self, color1):
self.color= color1
self.button= tk.Button(root, text=' '*10, bg= self.color, command= self.buttonclicked)
self.button.pack(side='left')
self.butclicked=False
I then created four instances of this class in blue, red, yellow, and green as bb, rb, yb, and gb.
Once everything is packed into the Tk() module, it enters a while loop that appends a random color to a list activecolors. I try to use the following loop to wait until the list pressed is at least as long as the list activecolors before comparing the two to see if the user was correct:
while len(pressed)<len(activecolors):
sleep(.25)
print('In the check loop')
bb.checkIfClicked()
rb.checkIfClicked()
yb.checkIfClicked()
gb.checkIfClicked()
However, since it is stuck inside the while loop, the program can't tell that the button has been clicked. I thought adding the sleep method into the loop would allow the code to have time to do other things (such as process button clicks), but this is not the case. Any help is appreciated.
Here is the link to the full code, if you would like to see it. A warning though: it's not pretty.
Edit:
I ended up just changing the code to check the list only after a new button was clicked, telling the computer the code was ready. I've updated the Google Document if you'd like to see it.
You are making it too complicated. This program uses partial from functiontools to allow a variable to be passed to the function so one function handles all clicks (Python 2.7).
from Tkinter import *
from functools import partial
class ButtonsTest:
def __init__(self):
self.top = Tk()
self.top.title('Buttons Test')
self.top_frame = Frame(self.top, width =400, height=400)
self.colors = ("red", "green", "blue", "yellow")
self.colors_selected = []
self.num_clicks = 0
self.wait_for_number = 5
self.buttons()
self.top_frame.grid(row=0, column=1)
Button(self.top_frame, text='Exit',
command=self.top.quit).grid(row=2,column=1, columnspan=5)
self.top.mainloop()
##-------------------------------------------------------------------
def buttons(self):
for but_num in range(4):
b = Button(self.top_frame, text = str(but_num+1),
command=partial(self.cb_handler, but_num))
b.grid(row=1, column=but_num+1)
##----------------------------------------------------------------
def cb_handler( self, cb_number ):
print "\ncb_handler", cb_number
self.num_clicks += 1
this_color = self.colors[cb_number]
if (self.num_clicks > self.wait_for_number) \
and (this_color in self.colors_selected):
print "%s already selected" % (this_color)
self.colors_selected.append(this_color)
##===================================================================
BT=ButtonsTest()