Unable fetch text variable data in class in tkinter - python

I am trying to fetch the data from text variable and image in a function name loopCap and display it in __init__ function where I have created a canvas but due to mentioned below error I am not able to move further
For text Error:
*(args + self._options(cnf, kw))))
_tkinter.TclError: unknown option "-textvariable"
For Image Error:
self.put_photo = canvas.create_image(70, 250, image=self.photo, anchor='nw')
AttributeError: 'StartPage' object has no attribute 'photo'
Actual Code Sample:
import tkinter as tk
from tkinter import *
from tkinter.filedialog import asksaveasfile
from tkinter import messagebox
from PIL import ImageTk, Image
im = "BG.jpg"
class SampleApp(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self._frame = None
self.ard_stat = read_json(JSON_PATH)
self.switch_frame(StartPage)
def switch_frame(self, frame_class):
"""Destroys current frame and replaces it with a new one."""
new_frame = frame_class(self)
if self._frame is not None:
self._frame.destroy()
self._frame = new_frame
self._frame.pack()
class StartPage(tk.Frame):
def loopCap(self):
with open(JSON_PATH) as json_file1:
self.data = json.load(json_file1)
print(self.data)
if self.data['status'] == 'ACTIVE': # and (self.data['RH_img']!= 'null' or self.data['LH_img']!= 'null')
a = self.text.set(self.data['status'])
if self.data['RH_img'] == 'NA':
self.img = Image.open(Press)
self.img.load()
self.photo = ImageTk.PhotoImage(self.img)
self.label['image'] = self.photo
self.master.after(500, self.loopCap)
def __init__(self, master):
super().__init__(master)
self.master.config(bg='black')
Frame2 = tk.Frame(self.master)
Frame2.pack(fill='both',expand = True)
self.photo_back = ImageTk.PhotoImage(im)
lab_1 = tk.Label(Frame2, image=self.photo_back)
lab_1.image = self.photo_back
lab_1.place(x=0, y=0, relwidth=1, relheight=1)
canvas = Canvas(Frame2, width=1000, height=700)
canvas.place(x=0, y=0, relwidth=1, relheight=1)
canvas.create_image(0, 0, image=self.photo_back, anchor='nw')
self.text = tk.StringVar()
canvas.create_text(230, 170, fill="white", font="Times 20 bold",
textvariable=self.text, anchor="w")
self.label = tk.Label(canvas)
self.put_photo = canvas.create_image(70, 250, image=self.photo, anchor='nw')
canvas.itemconfig(self.put_photo, image=self.photo)
self.master.after(500, self.loopCap)
if __name__ == "__main__":
app = SampleApp()
app.mainloop()
Any suggestions will be a great help.

Try replacing "textvariable=" with "text="
canvas.create_text(230, 170, fill="white", font="Times 20 bold", text=self.text, anchor="w")

Related

creating new window from inside a class is merging content to the parent window in tkinter python

I am trying to create a new window from within a window in Tkinter but all my new content is added to the parent window, not in the new window.
the first window
the second window
Here is my code:
from tkinter import *
from tkinter import font
import tkinter as tk
NORMAL_PADDING = 3
class AllPages(tk.Frame):
def __init__(self, master):
super().__init__(master)
self.pack()
self.font = font.Font(family='JetBrains Mono', name='jbm', size=12, weight='normal')
self.posts = [
{
"title": "huhu"
}
]
self.posts_container = tk.Frame()
for post in self.posts:
postf = tk.Frame(self.posts_container, bg="#ffffff", borderwidth=1, relief="solid")
post_t = tk.Label(postf, text=post["title"], bg="#ffffff", borderwidth=0, font=self.font)
post_edit = tk.Button(postf, text="Edit", bg="#ffffff", borderwidth=0, relief="solid", highlightbackground="#ffffff", highlightcolor="#ffffff", highlightthickness=1, font=self.font, command= lambda: self.modify_post_form(post))
post_t.pack(side="left")
post_edit.pack(side="right")
postf.pack(anchor=W, fill='x', pady=NORMAL_PADDING)
self.posts_container.pack(fill='both', ipadx=NORMAL_PADDING, padx=NORMAL_PADDING)
def modify_post_form(self, post):
newW = Toplevel()
app = CreatePostForm(newW)
class CreatePostForm(tk.Frame):
def __init__(self, master, post=None):
super().__init__(master)
self.pack()
if not ("jbm" in font.names()):
self.font = font.Font(family='JetBrains Mono', name='jbm', size=12, weight='normal')
else:
self.font = font.nametofont("jbm")
self.label_width = 20
self.input_width = 40
self.title_container = tk.Frame()
self.title_label = tk.Label(self.title_container, text="Title:", font=self.font, width=self.label_width, anchor=W)
self.title_input = tk.Entry(self.title_container, width=self.input_width, borderwidth=1, relief="solid", font=self.font)
self.title_label.pack(side="left")
self.title_input.pack(side="right")
self.title_container.pack(anchor=W, pady=NORMAL_PADDING)
self.title = tk.StringVar()
self.title_input["textvariable"] = self.title
root = tk.Tk()
myapp = AllPages(root)
myapp.pack()
myapp.mainloop()
The first window is created by the AllPages() class. then AllPages().modify_post_form() creates a new window using Toplevel() and pass it to CreatePostForm() class. CreatePostForm() should then populates the new window with some new content but whatever CreatePostForm() creates is going to the parent window, not to the new window created using Toplevel().
How can I fix this?
Thank you.
The problem in the above code is that both classes didn't specify the window it should create content into. Here is the working code:
from tkinter import *
from tkinter import font
import tkinter as tk
NORMAL_PADDING = 3
class AllPages(tk.Frame):
def __init__(self, master):
super().__init__(master)
self.pack()
self.font = font.Font(family='JetBrains Mono', name='jbm', size=12, weight='normal')
self.posts = [
{
"title": "huhu"
}
]
self.posts_container = tk.Frame(self)
for post in self.posts:
postf = tk.Frame(self.posts_container, bg="#ffffff", borderwidth=1, relief="solid")
post_t = tk.Label(postf, text=post["title"], bg="#ffffff", borderwidth=0, font=self.font)
post_edit = tk.Button(postf, text="Edit", bg="#ffffff", borderwidth=0, relief="solid", highlightbackground="#ffffff", highlightcolor="#ffffff", highlightthickness=1, font=self.font, command= lambda: self.modify_post_form(post))
post_t.pack(side="left")
post_edit.pack(side="right")
postf.pack(anchor=W, fill='x', pady=NORMAL_PADDING)
self.posts_container.pack(fill='both', ipadx=NORMAL_PADDING, padx=NORMAL_PADDING)
def modify_post_form(self, post):
newW = Toplevel()
app = CreatePostForm(newW)
class CreatePostForm(tk.Frame):
def __init__(self, master, post=None):
super().__init__(master)
self.pack()
if not ("jbm" in font.names()):
self.font = font.Font(family='JetBrains Mono', name='jbm', size=12, weight='normal')
else:
self.font = font.nametofont("jbm")
self.label_width = 20
self.input_width = 40
self.title_container = tk.Frame(self)
self.title_label = tk.Label(self.title_container, text="Title:", font=self.font, width=self.label_width, anchor=W)
self.title_input = tk.Entry(self.title_container, width=self.input_width, borderwidth=1, relief="solid", font=self.font)
self.title_label.pack(side="left")
self.title_input.pack(side="right")
self.title_container.pack(anchor=W, pady=NORMAL_PADDING)
self.title = tk.StringVar()
self.title_input["textvariable"] = self.title
root = tk.Tk()
myapp = AllPages(root)
myapp.pack()
myapp.mainloop()
Thank you to all the people who commented and helped me.

How to add buttons and labels on frame if its resizable

i have a code:
from tkinter import *
from PIL import Image, ImageTk
root = Tk()
root.geometry("900x580")
class Example(Frame):
def __init__(self, master, *pargs):
Frame.__init__(self, master, *pargs)
self.image = Image.open("eth_background.png")
self.img_copy= self.image.copy()
self.background_image = ImageTk.PhotoImage(self.image)
self.background = Label(self, image=self.background_image)
self.background.pack(fill=BOTH, expand=YES)
self.background.bind('<Configure>', self._resize_image)
self.widget = Button(self, text='Hello world', command=self.quit)
self.widget.pack(side=LEFT)
def _resize_image(self,event):
new_width = event.width
new_height = event.height
self.image = self.img_copy.resize((new_width, new_height))
self.background_image = ImageTk.PhotoImage(self.image)
self.background.configure(image = self.background_image)
e = Example(root)
e.pack(fill=BOTH, expand=YES)
root.mainloop()
I did that bacground is automaticly resize, but now i cant add buttons or lables on a frame. I found it:
from Tkinter import *
class Hello(Frame):
def __init__(self, parent=None):
Frame.__init__(self, parent)
self.pack()
self.make_widgets()
def make_widgets(self):
widget = Button(self, text='Hello world', command=self.quit)
widget.pack(side=LEFT)
if __name__ == '__main__': Hello().mainloop()
but it obviously doesnt work, how i can do that frame, resizable bacground, and buttons on it?

How to use 2nd Tkinter window to change image in 1st?

Quick summary: The green button is supposed to change when an image is selected, but it doesn't:
I have a Tkinter window-A with a button that when pressed will use a separate Python file to create a new window-B. Window-B has two buttons: new screen-snip or select image from folder. The method used for this is supposed to then change self.image_selected so that it can be used to update the button in window-A to have this new image.
I've tried both lines of code below, and neither are working. I'm not getting any errors either:
self.button.configure(image = img.image_selected) # first try
self.button['image'] = img.image_selected # second try
Here is my code (simplified for clarity):
import tkinter as tk
import get_image_or_snip
class ButtonImg:
def __init__(self, master):
self.newWindow = None
self.master = master
self.title = "My Minimum Reproducible Example"
self.fontA = ("arial", 20, "bold")
self.canvas = tk.Canvas(height = 5)
self.canvas.pack()
self.button = tk.Button(bg="#93d9cc", height = 5, text = "Select Image",
font = self.fontA, command = self.changeImage)
self.button.pack(fill="both")
def changeImage(self):
self.newWindow = tk.Toplevel(self.master)
img = get_image_or_snip.AcquireImage(self.newWindow)
self.button.configure(image = img.image_selected)
#self.button['image'] = img.image_selected
root = tk.Tk()
app = ButtonImg(root)
root.mainloop()
Here is the aforementioned get_image_or_snip.py code:
import tkinter as tk
from tkinter import filedialog
from PIL import ImageTk, Image
import snipping_tool
class AcquireImage:
def __init__(self, master):
self.master = master
self.fontA = ("arial", 20, "bold")
self.frame = tk.Frame(master, bg="#1B2631")
self.frame.pack(fill="both", expand=True)
self.button1 = tk.Button(self.frame, text="Select Image File", padx=10, pady=10, bg="#d9a193",
font = self.fontA, command =lambda: self.show_dialogs(1))
self.button1.grid(row=0, column=0, sticky="nsew")
self.button2 = tk.Button(self.frame, text="Get Screen Snip", padx=10, pady=10, bg="#d9a193",
font = self.fontA, command=lambda: self.show_dialogs(2))
self.button2.grid(row=0, column=1, sticky="nsew")
self.image_selected = None
self.master.mainloop()
def show_dialogs(self, method):
if method == 1:
ret = filedialog.askopenfilename()
load_img = Image.open(ret)
self.image_selected = ImageTk.PhotoImage(load_img)
if method == 2:
ret = snipping_tool.get_snip()
self.image_selected = ret
def main():
root = tk.Tk()
AcquireImage(root)
root.mainloop()
if __name__ == '__main__':
main()
If you add print() before and after get_image_or_snip.AcquireImage(self.newWindow) in changeImage() then you should see only first text because you run second mainloop() and it never ends this loop and never go back to changeImage() and never runs self.button.configure(image=img.image_selected)
You should use only one mainloop() and eventually use
root.wait_window(self.newWindow)
to wait until you close second window and then it will run self.button.configure(image=img.image_selected)
But there are other problems.
It removes image from memory memory when second windows is destroyed so you have to assign it to variable in first window.
Button use height in chars when you sent text but when you assign image then it use height in pixels and you have to change it from 5 to image.height()`
All code in one file
import tkinter as tk
from tkinter import filedialog
from PIL import ImageTk
class AcquireImage:
def __init__(self, master):
self.master = master
self.fontA = ("arial", 20, "bold")
self.frame = tk.Frame(master, bg="#1B2631")
self.frame.pack(fill="both", expand=True)
self.button1 = tk.Button(self.frame, text="Select Image File", padx=10, pady=10, bg="#d9a193",
font=self.fontA, command=lambda:self.show_dialogs(1))
self.button1.grid(row=0, column=0, sticky="nsew")
self.button2 = tk.Button(self.frame, text="Get Screen Snip", padx=10, pady=10, bg="#d9a193",
font=self.fontA, command=lambda:self.show_dialogs(2))
self.button2.grid(row=0, column=1, sticky="nsew")
self.image_selected = None
def show_dialogs(self, method):
if method == 1:
ret = filedialog.askopenfilename(initialdir='/home/user/images/')
if ret:
self.image_selected = ImageTk.PhotoImage(file=ret)
self.master.destroy()
elif method == 2:
self.image_selected = snipping_tool.get_snip()
class ButtonImg:
def __init__(self, master):
self.newWindow = None
self.master = master
self.title = "My Minimum Reproducible Example"
self.fontA = ("arial", 20, "bold")
self.canvas = tk.Canvas(height=5)
self.canvas.pack()
self.button = tk.Button(bg="#93d9cc", height=5, text="Select Image",
font=self.fontA, command=self.changeImage)
self.button.pack(fill="both")
def changeImage(self):
print('open second window')
self.newWindow = tk.Toplevel(self.master)
img = AcquireImage(self.newWindow)
self.master.wait_window(self.newWindow)
print('close second window')
if img.image_selected: # check if image was selected
self.image = img.image_selected
self.button.configure(image=self.image, height=self.image.height())
root = tk.Tk()
app = ButtonImg(root)
root.mainloop()
BTW: If you want to change image without closing second window then you should send first window (or button from first window) as argument to second window and change image in show_dialogs()
import tkinter as tk
from tkinter import filedialog
from PIL import ImageTk
class AcquireImage:
def __init__(self, master, first_window):
self.master = master
self.first_window = first_window
self.fontA = ("arial", 20, "bold")
self.frame = tk.Frame(master, bg="#1B2631")
self.frame.pack(fill="both", expand=True)
self.button1 = tk.Button(self.frame, text="Select Image File", padx=10, pady=10, bg="#d9a193",
font=self.fontA, command=lambda:self.show_dialogs(1))
self.button1.grid(row=0, column=0, sticky="nsew")
self.button2 = tk.Button(self.frame, text="Get Screen Snip", padx=10, pady=10, bg="#d9a193",
font=self.fontA, command=lambda:self.show_dialogs(2))
self.button2.grid(row=0, column=1, sticky="nsew")
self.image_selected = None
def show_dialogs(self, method):
if method == 1:
ret = filedialog.askopenfilename(initialdir='/home/user/images/')
if ret:
self.image_selected = ImageTk.PhotoImage(file=ret)
self.first_window.image = self.image_selected
self.first_window.button.configure(image=self.first_window.image, height=self.first_window.image.height())
elif method == 2:
self.image_selected = snipping_tool.get_snip()
class ButtonImg:
def __init__(self, master):
self.newWindow = None
self.master = master
self.title = "My Minimum Reproducible Example"
self.fontA = ("arial", 20, "bold")
self.canvas = tk.Canvas(height=5)
self.canvas.pack()
self.button = tk.Button(bg="#93d9cc", height=5, text="Select Image",
font=self.fontA, command=self.changeImage)
self.button.pack(fill="both")
def changeImage(self):
self.newWindow = tk.Toplevel(self.master)
img = AcquireImage(self.newWindow, self) # first window as `self` but you can send `self.button`
root = tk.Tk()
app = ButtonImg(root)
root.mainloop()
EDIT: Doc about creating Dialog Windows

Filling frame with color

I'm trying to fill the frame with the buttons so it extends the background-color to the end of the window both sides, this worked when doing .pack() but not .grid().
My code:
from tkinter import *
class App:
def __init__(self):
self.root = Tk()
self.width = 800
self.height = 400
self.root.geometry("{}x{}".format(self.width, self.height))
self.root.resizable(False, False)
self.menu_bar()
self.tool_bar()
self.name = Label(self.root, text="Tester", bg="black", fg="white")
self.root.mainloop()
def menu_bar(self):
self.menu = Menu(self.root)
self.root.config(menu=self.menu)
self.subMenu = Menu(self.menu)
self.menu.add_cascade(label="File", menu=self.subMenu)
self.subMenu.add_command(label="New Project...")
self.subMenu.add_command(label="Properties")
self.subMenu.add_separator()
self.subMenu.add_command(label="Do nothing")
def tool_bar(self):
self.toolbar = Frame(self.root, bg="#555555")
self.insert_button = Button(self.toolbar, text="Insert", bg="#555555", fg="white", activeforeground="white",
activebackground="#008CBA", borderwidth=0)
self.insert_button.grid(row=0, column=0)
self.print_buttom = Button(self.toolbar, text="Print", bg="#555555", fg="white", activeforeground="white",
activebackground="#008CBA", borderwidth=0,
command=self.root.quit)
self.print_buttom.grid(row=0, column=1)
self.toolbar.grid(row=0, column=0, sticky=EW)
if __name__ == '__main__':
App()
Thanks for answers in advance.
You can set a weight to your column.
class App:
def __init__(self):
self.root = Tk()
...
self.root.columnconfigure(0,weight=1)
...

Integrate a picture with Tkinter

I am a begginner in Python. I'm trying to display a picture with Tkinter in a window, but I don't success...
This is a piece of my code :
import serial
import time
import sys
import os
from Tkinter import *
root = Tk()
root.title("Title")
root.geometry("500x500")
[...]
class Application(Frame):
def __init__(self, master):
""" Initialize the Frame"""
Frame.__init__(self,master)
self.create_widgets()
def create_widgets(self):
[...]
try:
self.photo=PhotoImage('buttongreen.gif')
pic = Canvas(self,width =256, height = 256, bg ='blue')
pic.grid(row=6, columnspan=2,column=0,padx = 10, pady =10)
pic.create_image(256,256, image=self.photo)
"""self.panel = Label(self, image = photo)
self.panel.pack(side = "bottom", fill = "both", expand = "yes")"""
except:
print "Unable to load image"
[...]
app = Application(root)
app.grid()
root.mainloop()
The problem is that the canvas is displaying only the background, not the picture, can you tell me what is wrong please?
Note : The buttongreen.gif is in the same folder that my .py
self.photo=PhotoImage('buttongreen.gif')
Should be...
self.photo=PhotoImage(file = 'buttongreen.gif')
You need file= in self.photo = PhotoImage(file='buttongreen.gif')
Working example
from Tkinter import *
root = Tk()
root.title("Title")
root.geometry("500x500")
class Application(Frame):
def __init__(self, master):
""" Initialize the Frame"""
Frame.__init__(self, master)
self.create_widgets()
self.grid()
def create_widgets(self):
try:
self.photo = PhotoImage(file='buttongreen.gif') # file =
pic = Canvas(self, width=256, height=256, bg='blue')
pic.grid(row=6, columnspan=2, column=0, padx=10, pady=10)
pic.create_image(256, 256, image=self.photo)
except:
print "Unable to load image"
app = Application(root)
root.mainloop()

Categories