0

I am trying to make a version of Butterflies on Desktop in python. I am trying to use a transparent window that displays the animation of a butterfly. But I am Encountering an issue, I cannot figure out how to make this window move on the screen. I have tried using: root.geometry("200x200+100+100")

But this only moves the window when starting the script, and does not move it after the window has been created.

Does anyone know how I can reliably move the window? I does not have to be smooth, or an animation. I have been researching for a while now, and nothing works.

Main Code:

from tkinter import *
import tkinter as tk
from random import randint

root=Tk()
def main():
    root.geometry(("200x200+"+(randint(10,100))+"+"+(randint(10,100))))

root.after(2000,main())
root.mainloop()

P.S. I have looked at the stackoverflow question called "how to move the entire window to a place on the screen", but it only tells me how to move it originally. Not during the loop. (I am on macOSX)

1 1
  • 3
  • 2
  • You shouldn't use `while True` loops, when using `tkinter` like this. Also when do you want to move the window? On a button press, every x seconds? Look at [this](https://stackoverflow.com/a/459131/11106801) – TheLizzard Jan 14 '23 at 22:08
  • Thx, @TheLizzard , I will do this instead of while True, but I still don't know how to move the window.(Every X seconds) – 1 1 Jan 14 '23 at 22:10
  • Look at the question I linked. Then inside the function do the `root.geometry` stuff. The link shows you how to create `tkinter` loops – TheLizzard Jan 14 '23 at 22:12
  • I saw that, I edited the code a little and ran it, but root.geometry() still is not moving the window. – 1 1 Jan 14 '23 at 22:16
  • 1
    You missed the point in the link. Add `root.after(2000, main)` inside `main`. – TheLizzard Jan 14 '23 at 22:18
  • Like This? '''from tkinter import * import tkinter as tk from random import randint root=Tk() def main(): root.geometry(str("200x200+"+str(randint(10,100))+"+"+str(randint(10,100)))) root.after(10,main()) root.after(10,main()) root.mainloop()''' – 1 1 Jan 14 '23 at 22:26
  • No, there should be brackets after `main` like this: `root.after(10, main)` – TheLizzard Jan 14 '23 at 22:30
  • The randint(10,100) is return None. – toyota Supra Jan 15 '23 at 02:53
  • `root.after(2000, main())` immediate runs `main()` and passes the result (`None`) to `after`. – Bryan Oakley Jan 15 '23 at 19:33

1 Answers1

1
  1. My solution is to create a thread in the 'move window' function that auto executes every x seconds.
  2. Note that the 'move_window' function executes itself, not stopping the tkinter thread
import threading
from random import randint
from tkinter import *


def move_window():
    root.geometry(f"200x200+{int(randint(10, 100))}+{int(randint(10, 100))}")
    timer = threading.Timer(1, move_window)
    timer.start()


if __name__ == '__main__':
    root = Tk()
    move_window()
    root.mainloop()

However, looking at the comments, I noticed that we can do it with the tkinter module itself called 'after', here the interval is in milliseconds, that is, 1000 = 1 second, it also works

from random import randint
from tkinter import *


def move_window():
    root.geometry(f"200x200+{int(randint(10, 100))}+{int(randint(10, 100))}")
    root.after(500, move_window)


if __name__ == '__main__':
    root = Tk()
    move_window()
    root.mainloop()

Doing some tests I even realized that it can be done with multiple windows, and their respective widgets!

from random import randint
from tkinter import *


class SbApp(Tk):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.r = Label(self, text='000')
        self.r.pack()
        self.geometry('100x100+500+0')
        self.update()

    def update(self):
        self.geometry(f"200x200+{int(randint(500, 1000))}+{int(randint(10, 100))}")
        self.r.config(text=f'{randint(0, 100)}')
        self.after(500, self.update)


class App(Tk):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.root = self
        for i in range(10):
            SbApp()
            
        self.move_window()

    def move_window(self):
        self.root.geometry(f"200x200+{int(randint(10, 100))}+{int(randint(10, 100))}")
        self.root.after(500, self.move_window)


if __name__ == '__main__':
    root = App()
    root.mainloop()

enter image description here

Collaxd
  • 425
  • 3
  • 12