0

I have a problem with a school project that I am currently doing. I have to create and remove semicircles from circular clippings. And is there a possible solution that I part Tkinter window into three parts (header, body and footer)?

import tkinter
import threading
from tkinter import *
import tkinter as tk

root = tkinter.Tk()
root.geometry("800x800")
root.resizable(0, 0)

def menjajKanvas(c,arc):  # changeCanvas
    s=0
    while True:
        c.itemconfig(arc,extent=s,fill="red")
        s+=1
        time.sleep(0.01)
c = tk.Canvas(root, height=250, width=300, bg="blue")
c.pack()
arc = c.create_arc(10,50,240,210, extent=150, outline="red", tags=("arc",))\
threading.Thread(target=menjajKanvas,args=(c,arc)).start()
root.mainloop()
martineau
  • 119,623
  • 25
  • 170
  • 301
grokli
  • 17
  • 5
  • Does this answer your question? [tkinter: how to use after method](https://stackoverflow.com/questions/25753632/tkinter-how-to-use-after-method) – Thingamabobs Nov 14 '21 at 13:05
  • Hmm, not really, I need arc to stop at something like a 180 degree and start animation again, i tried after method but nothing changed. – grokli Nov 14 '21 at 13:17
  • you are right the answer in the provided link is incomplete. [See this instead](https://stackoverflow.com/a/63118515/13629335). In addition, calling tkinter widgets outside of the mainthread/mainloop will lead to an error. It is not clear why do you need a thread in this case. – Thingamabobs Nov 14 '21 at 13:21
  • When I delete the thread line of code, there is no animation at all just an outline of a 180 degree. I need an animation to stop at 180 degrees and start again in the loop. – grokli Nov 14 '21 at 13:37
  • You can use a [`ttk.Separator`](https://www.pythontutorial.net/tkinter/tkinter-separator/) to separate groups of widgets in a window. – martineau Nov 14 '21 at 19:17

2 Answers2

1

To achive what you want, you should use the after(ms,function,*arguments) method. You either can break the loop with after_cancel(alarm_id) or you stop calling the function within itself if, like in the sampel below.

In addition:

  1. import modules just once and stick to it
  2. Dont touch widgets outside of the thread of tkinters mainloop

import tkinter as tk

root = tk.Tk()
root.geometry("800x800")
root.resizable(0, 0)

s = 0
def menjajKanvas(arc):
    global s
    if s < 180:
        s+=1
        c.itemconfig(arc,extent=s,fill="red")
        root.after(10,menjajKanvas,arc)
    else:
        shrink_arc(arc)
def shrink_arc(arc):
    global s
    if s >= 0:
        s-=1
        c.itemconfig(arc,extent=s,fill="red")
        root.after(10,shrink_arc,arc)
    else:
        root.after(10,menjajKanvas,arc)
    
c = tk.Canvas(root, height=250, width=300, bg="blue")
c.pack()
arc = c.create_arc(10,50,240,210,
                   extent=150,
                   outline="red",
                   fill='red',
                   tags=("arc",))
menjajKanvas(arc)
root.mainloop()
Thingamabobs
  • 7,274
  • 5
  • 21
  • 54
  • Thank you guys very much, this is exactly what I was looking for! – grokli Nov 14 '21 at 15:32
  • @dcipko Please consider to [accept](https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work/5235#5235) and/or upvote the answers that helped you out. As we take the time for you, take the time for us. Happy coding! – Thingamabobs Nov 14 '21 at 15:34
  • Sure I did, one more question if u have time, is there a way to make the arc come back to 0 degrees and make it go in the loop? – grokli Nov 14 '21 at 16:51
  • @dcipko should this go for ever or do you want a button for this? I updated a for ever version of my code. For a button I recommand martineaus answer. – Thingamabobs Nov 14 '21 at 17:36
  • Yes, it should go forever, when it reaches 180 degrees, I need it to go back from 180 degrees to 0, like going backwards not disappear and start over. – grokli Nov 14 '21 at 17:42
  • omg, u are a life saver, thank you very much!!! <3 – grokli Nov 14 '21 at 17:56
1

Tkinter doesn't support threading in the sense that only one thread—usually the main one—can access it in multi-threaded applications. A workaround for that limitation can often be implemented by using the widget after() method to schedule periodic calls to a callback function that incrementally does what's needed.

Here's an example of how apply it to accomplish what you appear to be trying to do:

#from tkinter import *  # Avoid - See PEP 8 @ https://www.python.org/dev/peps/pep-0008/
import tkinter as tk

root = tk.Tk()
root.geometry("800x800")
root.resizable(0, 0)

def menjaj_kanvas(c, arc, s, extent, direction):  # Change canvas.
    global after_id
    if s not in range(extent+1):  # Limits exceeded?
        direction = -direction  # Reverse direction.
    c.itemconfig(arc, extent=s)
    after_id = root.after(100, menjaj_kanvas, c, arc, s-direction, extent, direction)

def stop_changing_canvas():
    global after_id
    root.after_cancel(after_id)

c = tk.Canvas(root, height=250, width=300, bg="blue")
c.pack()
tk.Button(root, text='Stop', command=stop_changing_canvas).pack()
tk.Button(root, text='Quit', command=root.quit).pack()

EXTENT = 150
arc = c.create_arc(10,50,240,210, extent=EXTENT, fill="red", outline="red")
after_id = root.after(100, menjaj_kanvas, c, arc, EXTENT, EXTENT, +1)  # Start updates.
root.mainloop()

Screenshot of it running

Screenshot

martineau
  • 119,623
  • 25
  • 170
  • 301
  • The documentation for cPython 3.10 states that you *can* make calls to tkinter from threads other than the one that created the `Tk` objects, with some caveats. See https://docs.python.org/3.10/library/tkinter.html#threading-model – Roland Smith Nov 14 '21 at 16:01
  • @RolandSmith *Because it is single-threaded, event handlers must respond quickly, otherwise they will block other events from being processed.* and *If the Tcl interpreter is not running the event loop and processing events, any tkinter calls made from threads other than the one running the Tcl interpreter will fail*. The point that martineau made is valid. But yes, threading with tkinter is possible. – Thingamabobs Nov 14 '21 at 16:08
  • @Atlas435: I never said threading was impossible. Thanks for the documentation link, it looks like they're finally getting around to documenting `tkinter` after all these years. BTW, do you know how to determine if you’re running a thread-aware Tcl/Tk build? – martineau Nov 14 '21 at 16:54
  • 1
    @martineau you can use `print(root.getvar("tcl_platform(threaded)"))`. Allmost all tkinter application are thread aware, because its very hard to get around it. My attempt to build a tkinter application that isnt thread aware stopt [here](https://www.tcl-lang.org/doc/howto/thread_model.html). – Thingamabobs Nov 14 '21 at 17:23