Showing Mouseposition with python - python

I want to track my mouse-position and show that in a tiny window.
For that, I created this piece of code:
#! /usr/bin/python
from Tkinter import *
from Xlib import display
def mousepos():
data = display.Display().screen().root.query_pointer()._data
return data["root_x"], data["root_y"]
root = Tk()
strl = "mouse at {0}".format(mousepos())
lab = Label(root,text=strl)
lab.pack()
root.title("Mouseposition")
root.mainloop()
This little script shows the mouse-position on startup but doesn't refresh it on mouse-movement. I don't get behind it (did I say that I'm new to python?).
I think I have to use an event from Xlib that tells my script when the mouse is moving...
How do I refresh my mouse-position?

Use root.after to call update periodically.
Use strl = tk.StringVar() and tk.Label(...,textvariable=strl) to
allow the Label text to change.
Call strl.set() to change the Label text.
A default value for screenroot equal to display.Display().screen().root was added
to mousepos so that most of that long chain of function calls are
not repeated every time mousepos is called. Calling mousepos() without any arguments will continue to work as usual.
import Tkinter as tk
import Xlib.display as display
def mousepos(screenroot=display.Display().screen().root):
pointer = screenroot.query_pointer()
data = pointer._data
return data["root_x"], data["root_y"]
def update():
strl.set("mouse at {0}".format(mousepos()))
root.after(100, update)
root = tk.Tk()
strl = tk.StringVar()
lab = tk.Label(root,textvariable=strl)
lab.pack()
root.after(100, update)
root.title("Mouseposition")
root.mainloop()

Related

Why doesn't Tkinter Entry's get function return anything?

I'm trying to use two dialogs to get manual input, and then work with that data.
All source I've found claim I should use the get() function, but I wrote a simple mini program yet, and I can't make the second dialog work.
I hope someone can tell me what I'm doing wrong. Here's a file:
from tkinter import *
from tkinter.filedialog import askdirectory
from tkinter import messagebox
def getpath():
def selectPath():
path_ = askdirectory()
path.set(path_)
root = Tk()
root.title('select path')
path = StringVar()
def close():
if(path.get()==""):
messagebox.showinfo("","nothing")
else:
root.withdraw()
root.quit()
Label(root,text="path:").grid(row=0,column=0)
Entry(root,textvariable = path).grid(row=0,column=1)
Button(root,text="select",command=selectPath).grid(row=0,column=2)
Button(root,text="enter",command=close).grid(row=0,column=3)
root.mainloop()
return path.get()
def getname():
def get_need_name():
name = need_name.get()
print('hereherehere'+name) #does not work
root = Tk()
root.title('select name')
need_name = StringVar()
Label(root,text="name:").grid(row=0,column=0)
entry = Entry(root,bd=10,textvariable=need_name)
entry.grid(row=0,column=1)
Button(root,text="enter", font=16, bg="silver", relief='groove', command=get_need_name).grid(row=0,column=2)
root.mainloop()
return name.get()
def main():
path = getpath()
print("mypath:"+path)
print('******************')
print('done!')
name = getname()
print("myname:"+name)
if __name__ == '__main__':
main()
This give me two dialogs I can type in, but only the first dialog works.
The reason is that you are creating multiple instances of Tk, and you don't destroy the instances when you are done with them. This causes two problems. First is a memory leak. Each time you call one of these functions you create a new window and a new tcl interpreter.
The second problem is that the first root window becomes the default window when a root isn't specified. When you create a StringVar in the second function, because you didn't specify which root window it belongs to it will be assigned to the first root window. When you use it as the target of textvariable in a second instance of Tk, tkinter thinks the variable doesn't exist so it creates a new one for the second window. However, your reference is still to the one created in the first root window and is never updated by user input in the second window.
Confusing? Yes, which is why you typically shouldn't be creating more than one instance of Tk.
To make your code work with as few changes as possible and to remove the memory leak caused by not destroying the windows, you can change the last couple of lines in your method to look like the following. This destroys the root window when you are done with it, removing the memory leak and the side effect of having more than one root window.
root = Tk()
...
root.mainloop()
value = path.get()
root.destroy()
return value
The second dialog should look similar:
root = Tk()
...
root.mainloop()
value = name.get()
root.destroy()
return value
This retrieves the value after mainloop exits but before the underlying tcl interpreter is deleted, and then destroys the window and its tcl interpreter.
The next time you create an instance of Tk, that instance will become the new default root, and any new instance of StringVar will go to that root.
Another solution would be to specify the master for the StringVar instance, but that leaves the memory leak in place so it's only half of a solution.
Arguably a better solution is to create a single root window, and either reuse it or create instances of Toplevel rather than Tk. Effbot has some decent documentation on how to create a modal window with wait_window.
After some testing, and googling the root.quit() is the problem
here is a working example for you to look at and mess with.
from tkinter import *
from tkinter.filedialog import askdirectory
from tkinter import messagebox
root = Tk()
path = StringVar()
def select_path():
#uses the return value to set no need to create an additional variable
path.set(askdirectory())
def close():
if path.get() == "":
messagebox.showinfo("","Please select path")
else:
get_name_frame.tkraise()
def get_name():
print("hereherehere", name.get())
get_path_frame = Frame(root)
get_path_frame.grid(row=0, column=0, sticky="nsew")
Label(get_path_frame,text="path:").grid(row=0,column=0)
Entry(get_path_frame,textvariable = path).grid(row=0,column=1)
Button(get_path_frame,text="select",command=select_path).grid(row=0,column=2)
Button(get_path_frame,text="enter",command=close).grid(row=0,column=3)
get_name_frame = Frame(root)
get_name_frame.grid(row=0, column=0,sticky="nsew")
Label(get_name_frame, text="name: ").grid(row=0, column=0)
name = StringVar()
entry = Entry(get_name_frame, bd=10, textvariable = name)
entry.grid(row=0, column=1)
Button(get_name_frame,text="enter", font=16, bg="silver", relief='groove', command=get_name).grid(row=0,column=2)
get_path_frame.tkraise()
root.mainloop()

fix a delay issue when switching from one window to another using TKinter?

I'm developing a GUI using TKinter for a kiosk based application and I've developed a basic code which switches from one window to another on button click.
Below is the code I've tried and it runs successfully. However I'm finding some delay issues when switching from one window to another. When user presses the button on the root window, there is sufficient amount of delay occurred before second screen display. I've tested it step by step and realised that the way image opened and displayed, it takes sufficient processing time and that creates a delay issues.
try:
from Tkinter import *
import Tkinter as tk
except ImportError:
from tkinter import *
import tkinter as tk
from functools import partial
from PIL import ImageTk, Image
def test(root):
root.withdraw()
master1 = tk.Toplevel()
coverPhoto = Image.open('/home/pi/x.jpg')
coverPhoto = ImageTk.PhotoImage(coverPhoto)
lblBackground = Label(master1, width=ws, height=hs, image=coverPhoto)
lblBackground.photo = coverPhoto
lblBackground.pack(fill=BOTH, expand=YES)
master1.config(width=ws, height=hs)
master1.attributes('-fullscreen', True)
master1.mainloop()
return
root = tk.Tk()
ws = root.winfo_screenwidth()
hs = root.winfo_screenheight()
root.title(' Sample test ')
idPhoto = Image.open('/home/pi/x.jpg')
idPhoto = ImageTk.PhotoImage(idPhoto)
lblImg = Label(root, width=ws, height=hs, image=idPhoto)
lblImg.photo = idPhoto
lblImg.pack(fill=BOTH, expand=YES)
startImg = Image.open('/home/pi/y.jpg' )
startImg = ImageTk.PhotoImage(startImg)
button = tk.Button(lblImg, image=startImg, highlightthickness=1, bd=0, command=lambda : test(root))
button.image = startImg
button.place(x=0, y=hs - 120, width=ws, height=120)
root.attributes('-fullscreen', True)
root.config(width=ws, height=hs)
root.mainloop()
Is there any other calling way which will take less time in processing? I want a smooth go when changing from one screen to another?
You could load all images before you start the mainloop.
That would of course increase the startup time of the application, but it should reduce window switch times.
Edit: Also place all the ImageTk.PhotoImage calls after root = tk.Tk() but before the mainloop. That is, take the code for coverPhoto out of test, and put it between root and mainloop.
Edit2: A white flash when a window closes is probably caused by the relatively slow graphics hardware on the raspberry pi, combined with how X11 works.
Instead of two top-pevel windows, try using a tkinter.ttk.Notebook with two "tabs". Hide and unhide the relevant tabs in the same X11 window.

How to make this script run in the background and listen for a "copy" action?

The script below does is if I copy a link like this: http://urlshortener.io/s/1234rIHs/?s=https%3A%2F%2Fexample.com%2Fsome_content%2F, it will change to
example.com/some_content/ if I clicked the button.
Is there a way that when I run this script then it will listen in the background for a "copy" action, and then if I copy some text in my browser, it will automatically slice the text I just copied and I won't need to click the button?
Right now, I still have to click the button in order for the slicing to happen.
from tkinter import *
from urllib import parse
from tkinter import Tk
root = Tk()
root.title("Slicer")
root.geometry('304x70')
lbl = Label(root, text="Link")
lbl.pack()
def clicked():
clip = root.clipboard_get()
clip = parse.unquote(clip)[45:]
root.clipboard_clear()
root.clipboard_append(clip)
lbl.configure(text= clip)
btn = Button(root, text="Slice", command=clicked, height = 3, width = 40)
btn.pack()
root.mainloop()
You can use pyperclip. Run an infinite loop, keep detecting for urls in the loop, modify when found.
import pyperclip, time
# Modify is_url and modify_url, according to your need
def is_url(s):
return True
def modify_url(url_string):
return "Hello World"
while True:
on_clip = pyperclip.paste()
if is_url(on_clip):
pyperclip.copy(modify_url(on_clip))
time.sleep(0.1)

Python running clock in separate window

I thought I would make a running clock program. I have this code which works for what I want it to do, but I want it to be fancy and output it to a new window. I thought of a message box but that would need constant closing.
Is there way around this, or should I just stick to using the console?
x=0
import datetime
import time
while x<10:
currentTime=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
time.sleep(1)
print(str(currentTime))
EDIT:
This is what i have now but the window goes all over the place.
try:
from Tkinter import *
except ImportError:
from tkinter import *
import datetime
import time
x=0
while x<10:
root = Tk()
prompt = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
label1 = Label(root, text=prompt, width=len(prompt))
label1.pack()
def close_after_1s():
root.destroy()
root.after(1000, close_after_1s)
root.mainloop()
You're missing the point of Tk. The entire thing is a loop(hence the mainloop) and you keep destroying and creating a new window, hence the all over the place.
I think you just want something to update every sec:
from Tkinter import Tk,StringVar,Label
import datetime
def update():
global prompt,root
prompt.set(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
root.after(1000, update)
root = Tk()
prompt = StringVar()
label1 = Label(root, textvar=prompt, width=len(prompt.get()))
label1.pack()
update()
root.mainloop()
and my suggestion is to put all of this in a class. Google some Tk examples.

No errors but wont run

So I have this code:
try:
# for Python2
from Tkinter import *
except ImportError:
# for Python3
from tkinter import *
class Injector():
def __openInjector(self):
root = Tk()
root.geometry('600x400')
root.title('Toontown Rewritten Injector')
root.resizable(False, False)
def __init__(self):
self.code = ''
self.__openInjector()
def runInjectorCode(self):
exec(self.code.get(1.0, 'end'), globals())
def __openInjector(self):
root = Tk()
root.geometry('600x400')
root.title('Toontown Rewritten Injector')
root.resizable(False, False)
frame = Frame(root)
self.code = Text(frame, width=70, height=20)
self.code.pack(side='left')
Button(root, text='Inject!', command=self.runInjectorCode).pack()
scroll = Scrollbar(frame)
scroll.pack(fill='y', side='right')
scroll.config(command=self.code.yview)
self.code.config(yscrollcommand=scroll.set)
frame.pack(fill='y')
Injector()
In the IDLE console it works fine and does everthing I want it to do. But whenever I run the .py file on my Desktop. The black window appears, then just closes and nothing happens. Any help?
First, you have two methods in your class with the same name. The first one gets overwritten by the second one. At the end of that second one, you need the following line:
root.mainloop()
This will actually run the GUI. It's needed when running from a script, but not when running within the interactive interpreter.
Add it at the end of the second __openInjector:
...
self.code.config(yscrollcommand=scroll.set)
frame.pack(fill='y')
root.mainloop()
At the end of your second __openInjector method, add the line: root.mainloop().
This is necessary for Tkinter to run your code. mainloop is really nothing more than an infinite loop that waits for events. An event may be a user interaction, such as clicking a button.
My guess is you don't need mainloop when running interactively for purely convenience reasons.

Categories