How use event in other file? - python

I'm prepared two files. First with GUI class. Second file is a script where I want to use a GUI, Databases and Template classes. A Databases and Template classes works. I check it in other scripts.
Questions:
How can I use event(KeyRelase) form GUI class in script?
First:
from tkinter import *
from tkinter.font import Font
from tkinter.ttk import Separator
class GUI:
def __init__(self, master):
self.ent_InventoryNumber = Entry(self.frm_FirstColumn, font=fontStyle, width=35, borderwidth=2, justify=CENTER)
self.ent_InventoryNumber.insert(END, "Wprowadź TUTAJ numer inwentarzowy")
self.ent_InventoryNumber.grid(row=2, column=0, columnspan=2, padx=5, pady=20, ipadx=2, ipady=2)
self.ent_InventoryNumber.bind("<KeyRelease>", lambda x: self.searchChamber())
def searchChamber(self):
return self.ent_InventoryNumber.get()
Second file with script:
import Databases as Db
import Template
from GUI import GUI
def test(a):
print(a)
window = Tk()
myGUI = GUI(window)
window.mainloop()
# test(myGUI.searchChamber()) ???

bind works correctly in you code. Problem is that bind can't get value which you use with return - it can't assing it to any variable and you have to use this value directly in searchChamber or assign to some variable to use it later.
Other problem: when you close window then tkinter destroy all widgets and you have to keep value from Entry in some variable
def searchChamber(self):
self.result = self.ent_InventoryNumber.get()
and later get this variable
test(GUI.result)
In this example I use print() to see if bind executes function after every pressed key. I also use class variable self.result to keep value and use it after closing window.
GUI.py
import tkinter as tk
class GUI:
def __init__(self, master):
self.result = '' # default value as start
self.ent_InventoryNumber = tk.Entry(master)
self.ent_InventoryNumber.insert('end', "Wprowadź TUTAJ numer inwentarzowy")
self.ent_InventoryNumber.grid(row=2, column=0)
self.ent_InventoryNumber.bind("<KeyRelease>", self.searchChamber)
def searchChamber(self, event=None):
self.result = self.ent_InventoryNumber.get()
print('[DEBUG] searchChamber:', self.result)
main.py
import tkinter as tk
from GUI import GUI
window = tk.Tk()
myGUI = GUI(window)
window.mainloop()
print('result:', myGUI.result)

Related

Tkinter not displaying default Entry variable until button is added

I am trying to create a GUI in Python 3.9.1 with tkinter and am having issues getting a default value to show in an Entry box.
from tkinter import *
from tkinter import ttk
class GUI:
def __init__(self, root, *args):
self.root = root
self.initial_frame = ttk.Frame(self.root)
self.initial_frame.grid(row=0)
ttk.Label(self.initial_frame, text="User question here?").grid(row=1, column=1)
self.ext_len = StringVar(value=4)
ext_len_entry = ttk.Entry(self.initial_frame, textvariable=self.ext_len)
ext_len_entry.grid(row=1, column=2)
root = Tk()
GUI(root)
root.mainloop()
Note: official tkinter docs say to use from tkinter import * and from tkinter import ttk.
See this link and look in the Python section in the step-by-step walkthrough https://tkdocs.com/tutorial/firstexample.html
I've also tried using self.ext_len.set(4) after initializing the entry but before putting it on the grid. I've tried self.ext_len.insert(0,4) as well.
If I add a button with a callback that does nothing, the 4 shows up in the entry box. I found that I don't even have to render it on the grid. Just initializing it is enough. A button without a callback does not work.
Working code:
from tkinter import *
from tkinter import ttk
class GUI:
def __init__(self, root, *args):
self.root = root
self.initial_frame = ttk.Frame(self.root)
self.initial_frame.grid(row=0)
ttk.Label(self.initial_frame, text="User question here?").grid(row=1, column=1)
self.ext_len = StringVar(value=4)
ext_len_entry = ttk.Entry(self.initial_frame, textvariable=self.ext_len)
ext_len_entry.grid(row=1, column=2)
ttk.Button(self.initial_frame, text="Test button", command=self.test_func)
def test_func(self, *args):
pass
root = Tk()
GUI(root)
root.mainloop()
Why does initializing the button cause it to work?

gui class with two programs

i'm trying to make some sample GUI tkinter thats on one button try server status,and if it works,after click on button start it destroy gui and start some function that sends me file text. I've made gui,and server connection test button, but don't know how to destroy gui and start function.Thanks a lot :)
from tkinter import *
import requests, os
class form():
root = Tk()
wel = Label(root,text="Welcome")
serv = Entry(root,width=40)
def checkConn():
if(requests.get(serv.get()).status_code==200):
print("Succesfull")
def start(self):
root.destroy()
prov = Button(root,text="Proveri",width=35, command = checkConn)
zap = Button(root, text ="Zapocni",width=35,command =start)
wel.pack()
serv.pack()
prov.pack()
zap.pack()
root.mainloop()
form()
I would recommend using an __init__() function for setting up the GUI as well as class variables. I rewrote your code in the way I would write it but without the requests bit, just to show GUI function.
from tkinter import *
import requests
class form():
def __init__(self, master):
self.master = master
self.serv_text = StringVar() # StringVar to hold entry value
wel = Label(root, text="Welcome")
serv = Entry(root, width=40, textvariable=self.serv_text)
prov = Button(self.master, text="Proveri", width=35,
command=self.checkConn)
zap = Button(self.master, text ="Zapocni", width=35,
command=self.start)
wel.pack()
serv.pack()
prov.pack()
zap.pack()
def checkConn(self):
if(requests.get(self.serv_text.get()).status_code==200):
print("Succesfull")
else:
print('miss')
def start(self):
self.master.destroy()
root = Tk()
form(root)
root.mainloop()
You will find more examples and discussion in Best way to structure a tkinter application.

I can't get an image to load on the canvas in Tkinter python

I am having a big issue. The Canvas loads perfectly but the image does not display.
I started Python 1 week ago and I have no clue why does is not working. Can anyone please show me the way to solve the issue of the image not loading on the canvas?
from Tkinter import *
from PIL import ImageTk
from PIL import Image
class Fake_Virus:
def __init__(self, master):
self.master = master
master.title("Totally not a virus!")
b = Button(master, text="Help", command=self.prank)
b.pack(padx=10, pady=10, side=LEFT)
quit = Button(master, text="Close", command=self.close_window)
quit.pack(padx=10, pady=10, side=RIGHT)
photo = PhotoImage("eh.gif")
label = Label(image=photo)
label.image = photo # keep a reference!
label.pack()
f = Frame(master, height=150, width=150)
f.pack_propagate(0) # don't shrink
f.pack()
def prank(self):
print "work"
return
def close_window(self):
root.destroy()
return
root = Tk()
my_gui = Fake_Virus(root)
root.mainloop()
You should use the file option to initialize the photo image object.
This means you need to change photo = PhotoImage("eh.gif") to photo = PhotoImage(file="eh.gif")
Now your code will work. But a working code is not necessarily a good code. There are other issues with your code. Let me go through them quickly:
It is better to code import Tkinter as Tk than from Tkinter import *
Why that hyphen in your class name? Follow PEP8 so that, in the futur, people will find it easy to review and understand your code.
Good that you have written self.master = master (read complete code to know why) but then you have never used it. This means you made a good decision and you render it useless.
You set the title of the window within the initializer. It is better if you do that in a separate function so that whenever you want to add additional settings to your GUI (such as the size, font or whatever) you will only add code to that function instead of vomiting lot of trash inside the initializer which rather needs to be clean.
None of the widgets you created is 'selfed' (you may read Why explicit self has to stay)
It is better you create the widgets in a separate function otherwise your __init__() will be dirty.
Why do you use return in prank() and close_window()? By default, Python functions that do not return something return None anyway so it is useless to code that.
Why did you pack one button to left and the other one to right and then no pack siding for the label? Read about the pack() geometry manager.
Why you did not attach the label to a parent widget as you did for the 2 other buttons? All Tkinter widgets need to be clung into a parent widget. The grand parent of those widgets is an instance of Tkinter.Tk()
Why did you create that frame and then you never used it? You are not doing anything with it, so ..?
Given these remarks, I want to provide you an improved -but not perfect- version of your program. You can then follow this 'philosophy' to add or modifying existing widgets:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import Tkinter as Tk
from PIL import ImageTk
class FakeVirus:
def __init__(self, master):
self.master = master
self.configure_gui()
self.create_widgets()
def configure_gui(self):
self.master.title('Totally not a virus!')
def create_widgets(self):
self.create_buttons()
self.create_label_for_image()
def create_buttons(self):
self.help = Tk.Button(self.master, text='Help', command=self.prank)
self.help.pack(side=Tk.LEFT)
self.quit = Tk.Button(self.master, text='Close', command=self.close_window)
self.quit.pack(side=Tk.LEFT)
def create_label_for_image(self):
self.image_label = Tk.Label(self.master)
self.image_label.pack(side=Tk.LEFT)
self.load_image_to_label()
def load_image_to_label(self):
self.photo = ImageTk.PhotoImage(file='eh.gif')
self.image_label.image = self.photo
self.image_label.config(image=self.photo)
def prank(self):
print "work"
def close_window(self):
root.destroy()
if __name__ == '__main__':
root = Tk.Tk()
my_gui = FakeVirus(root)
root.mainloop()
The output of the above program is:

Attribute error in opening file dialog in python GUI using tkinter

I am starting to learn Python and the tkinter package and I am writing a program to load a text file on the GUI window. To open the file browser, I installed the button and its necessary function as shown in the below code. The program runs but when I click on the "browse" button, I am getting an attribute error saying : "'assign_1' object has no attribute 'var_filename'". It would be great if anyone could help me with this.
from tkinter import *
from tkinter import messagebox
from tkinter import simpledialog
from tkinter import filedialog
from math import *
from numpy import *
import string
root = Tk()
def close_window_callback(root):
if messagebox.askokcancel("Quit", "Do you really wish to quit?"):
root.destroy()
class assign_1:
def __init__(self,master):
self.master = master
frame = Frame(master)
frame.pack()
self.canvas = Canvas(master,width=1000,height=1000, bg="yellow")
self.button_browse = Button(frame, text="Browse",
command=self.browse_file)
self.button_browse.pack()
self.button_load = Button(frame, text="Load")
self.button_load.pack(side = LEFT)
self.canvas.pack(expand=YES, fill=BOTH)
def browse_file(self):
self.var_filename.set(filedialog.askopenfilename(filetypes=[("allfiles","*"),("pythonfiles","*.txt")]))
filename = self.var_filename.get()
print(filename)
root.protocol("WM_DELETE_WINDOW", lambda root_window=root: close_window_callback(root_window))
assign_1(root)
root.mainloop()
Although, as Rinzler pointed out, your indentation is wrong in the code you posted, that would lead to another error (AttributeError: assign_1 instance has no attribute 'browse_file'). So I'm guessing the indentation in the code you actually use is correct.
The problem is that you try to use self.var_filename.set(...) without having defined what self.var_filename is. If you want it to be a StringVar, which seems to be the case since you use set and get, you have to initialize it. To do this you should put self.var_filename = StringVar(master) in the class' __init__ function. A small example demonstrating this:
root = Tk()
class assign_1:
def __init__(self, master):
self.master = master
self.var_filename = StringVar(master)
self.button_browse = Button(master, text="Browse", command=self.browse_file)
self.button_browse.pack()
def browse_file(self):
self.var_filename.set(filedialog.askopenfilename(filetypes=[("allfiles","*"),("pythonfiles","*.txt")]))
filename = self.var_filename.get()
print(filename)
assign_1(root)
root.mainloop()
However, from the looks of it, in your case there is no need to use a tkinter StringVar, just use a normal string variable:
root = Tk()
class assign_1:
def __init__(self, master):
self.master = master
self.button_browse = Button(master, text="Browse", command=self.browse_file)
self.button_browse.pack()
def browse_file(self):
self.filename = filedialog.askopenfilename(filetypes=[("allfiles","*"),("pythonfiles","*.txt")])
print(self.filename)
assign_1(root)
root.mainloop()
The indentation is wrong. The function browse_file you wanted to define as method of the class assign_1 (use capitalise letters to declare name of classes) is a global function as you defined it.
You have also not defined self.var_filename anywhere, so it will then give you the error:
AttributeError: 'assign_1' object has no attribute 'var_filename'
Under the function close_window_callback, you have also wrong indentation.

askdirectory() changes focus to different window

I am using Tkinter to build two windows. One the main one, pressing a button leads to the creation of the second window.
This second window does not get focus immediately when it created. That I am able to fix by calling .focus_force(). However, when I call the askdirectory() function from tkFileDialog, the focus changes back to the first window.
How can I prevent that focus switch from happening, without simply calling focus_force() all over the place?
To replicate problem:
from Tkinter import *
from tkFileDialog import *
class app:
def __init__(self, master):
Button(master, command = make_new).grid()
def make_new(self):
root = Tk()
new = new_win(root)
root.mainloop() #here the focus is on the first window
class new_win:
def __init__(self, master):
f = askdirectory() #even after placing focus on second window,
#focus goes back to first window here
I am using Python 2.7.3. Thanks!
the little-documented wm_attributes method might help:
from Tkinter import *
import tkFileDialog
root = Tk()
top = Toplevel()
top.wm_attributes('-topmost', 1)
top.withdraw()
top.protocol('WM_DELETE_WINDOW', top.withdraw)
def do_dialog():
oldFoc = top.focus_get()
print tkFileDialog.askdirectory()
if oldFoc: oldFoc.focus_set()
b0 = Button(top, text='choose dir', command=do_dialog)
b0.pack(padx=100, pady=100)
def popup():
top.deiconify()
b0.focus_set()
b1 = Button(root, text='popup', command=popup)
b1.pack(padx=100, pady=100)
root.mainloop()

Categories