Initalize Tkinter inside a class or method? - python

Is it possible to put all of my code to initalize my tKinter or pygame display into its own class, just to tidy things up. Its all code that gets executed once before I get into my main loop?
Im writing something that uses both a pygame graphic display and a tKinter frame for a GUI. It all works fine, but it seems so messy having all this with no indents right in my main line of code. Nothing clever, just reading the monitor resolution, then using that to adjust the size and location of my PyGame and Tkinter frames.
Ive edited code below to show my main loops, and how i update tkinter and pygame displays. It all works OK.
I just wonder if i could tidy things up by using a class to hold all the buttins etc that i want on the tkinter display.
Wish I could put it all in a class or something. Sorry, i'm a noob, having a blast playing with python!
import random
import math
import os
import pygame
import numpy as np
#from tkinter import *
#from tkinter import ttk
from tkinter import Tk, Button, Label, LabelFrame, PhotoImage, Radiobutton
from tkinter import messagebox, DISABLED, NORMAL, Menu
pygame.init()
infoObject = pygame.display.Info() #Read video mode full resolution
pygame.display.set_mode((infoObject.current_w, infoObject.current_h)) #Intialize pygame window to full screen mius 400 on left (to be used for tkinter main window)
SMALL_TEXT = pygame.font.Font('freesansbold.ttf', 12)
os.environ['SDL_VIDEO_WINDOW_POS'] = "%d,%d" % (0, 30) #set placement for next window in windows env
gameDisplay = pygame.display.set_mode((infoObject.current_w - 400,infoObject.current_h - 70), pygame.RESIZABLE)
pygame.display.set_caption('Collision Detection')
pygame.font.init() # Set up text ops
root = Tk()
geom = (str(400) + 'x' + str(infoObject.current_h - 70) + '+' + str(infoObject.current_w - 410) + '+' + str(0))
root.geometry(geom)
root.configure(background='gray70')
root.title('Vessel Control')
# Create a couple test buttons and labels on root form, to be updated by code in mainloop
lab = Label(root, text="Don't Push The Button!")
lab.grid(row=0, column=0)
but = Button(root, text="Push Me", command=changebut)
but.grid(row=1, column=0)
posxlab = Label(root, text='USV X Position (m): ')
posxlab.grid(row=2, column=0)
# Here i set up the rest of the junk for my program
# Then i start my own main loop, not usuing tkinters.
# Main loop
while not gameExit:
#And my full code is in here, a few thousand lines or so
pygame.display.update() #update pygame display
root.update_idletasks() #process tkinter events
root.update() #Update tkinter window
clock.tick(FRAME_RATE)
pygame.quit()
quit()

Related

Why Filedialogs opens on two differents places?

In this program the window is in full, zoomed i would say, if i decrease the window and the maximize again the window on full and then i click the button, i notice that the filedialog opens first on the left and then it's placed immediately on the center, try a couple of times and you will notice this, i hope at least. How to place the filedialog directly on the center avoiding this "flickering" effect? Thanks
from tkinter import *
from PIL import Image, ImageTk
from tkinter import messagebox
from tkinter import filedialog
def jpg_png():
try:
file = filedialog.askopenfilename(initialdir='C:\\Users\\quaranta\\Desktop')
except AttributeError:
pass
win = Tk()
win.state('zoomed')
btn_apri_jpg_png = customtkinter.CTkButton(win,text='Apri file',text_font=('Courier',13),text_color='white',fg_color='#00A254',hover_color='#00AF54',width=10,corner_radius=8,command=jpg_png)
btn_apri_jpg_png.grid(row=0,column=2,pady=(20,0),padx=(0,50))
win.mainloop()
This might be a customtkinter issue
I tried recreating your problem without using customtkinter (as you stated in your comment to "not import it")
I can't reproduce your flickering with this code. Can you confirm that it still happens without using customtkinter?
from tkinter import *
from tkinter import filedialog
def jpg_png():
try:
file = filedialog.askopenfilename()
except AttributeError:
pass
win = Tk()
win.state('zoomed')
btn_apri_jpg_png = Button(win, text='Apri file', width=10, command=jpg_png)
btn_apri_jpg_png.grid(row=0, column=2, pady=(20, 0), padx=(0, 50))
win.mainloop()

ImageGrab.grab not get widget of tkinter window, but screen area under it

Try to capture the image of a widget in tkinter window by following code, but just get the screen area under tkinter window.
import ctypes
import platform
from time import sleep
import tkinter as tk
from PIL import ImageGrab
if platform.system() == "Windows" and platform.release() == "10":
ctypes.windll.shcore.SetProcessDpiAwareness(1)
root = tk.Tk()
root.geometry("+0+0")
var = tk.StringVar()
var.set("Hello World")
entry = tk.Entry(root, width=40, bg='green', takefocus=False, textvariable=var)
entry.pack()
root.update()
# sleep(1)
x, y = entry.winfo_rootx(), entry.winfo_rooty()
width, height = entry.winfo_width(), entry.winfo_height()
im = ImageGrab.grab(bbox=(x, y, x+width, y+height)) # Grab image on screen
im.show()
root.mainloop()
It will be OK if line # sleep(1) replaced by sleep(1). Had been tried method update or update_idletasks, all got same results.
Is there any method to finalize tkinter window immediately ? So I don't need to sleep one second each time to grap image of a widget. Or I get wrong way to go it, any suggestion is welcome.
It is obvious right? It needs to take some time to show the window but the screenshot is captured quite quickly. What do I suggest? Put it inside a function and take advantage of the after method here.
def screenshot():
im = ImageGrab.grab(bbox=(x, y, x+width, y+height)) # Grab image on screen
im.show()
root.after(1000,screenshot) # Depending on the time required to take show the window

Tkinter buttons with images not appearing

So, i was trying to make a music player with python and tkinter and I had to set images for the buttons, but when I set an image for the button, the button does not appear on the output screen
Code:
from tkinter import *
import pygame
win = Tk()
win.title("Music player")
win.geometry("500x300")
# Images for buttons
back_png = PhotoImage("C:/1 Files and Folders/SHARAN/Python/SVE atom/Images/back.png")
back_button = Button(win, image=back_png, borderwidth=0).place(x=100, y=20)
win.mainloop()
tkinter requires a keyword for most arguments. Here you are missing the file= keyword.
back_png = PhotoImage(file="C:/1 Files and Folders/SHARAN/Python/SVE atom/Images/back.png")

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.

Showing Mouseposition with 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()

Categories