Unable to display image label in second Tkinter frame - python-3.x

I am trying to build a simple gui using Tkinter. The application involves a smaller secondary frame opening up over the primary one upon pressing a button. This secondary frame must contain an image. Image labels appear easily on the primary frame, but on the secondary frame, the image label appears as an empty box the size of the image, with whatever background colour I set.
Here's how I'm doing it:
#send diagram page
def send_diagram():
send_diagram_frame=tk.Frame(frame, bg="#D4BAEC")
send_diagram_frame.place(relx=0.5, rely=0.5, relheight=0.7, relwidth=0.7, anchor="center")
send_diagram_entry_working_image=Image.open('/home/raghav/RemEdi/design/assets/generic_page_entry.png')
send_diagram_entry_image=ImageTk.PhotoImage(send_diagram_entry_working_image)
send_diagram_entry_label=tk.Label(send_diagram_frame, image=send_diagram_entry_image)
send_diagram_entry_label.place(relx=0.5, rely=0.5, anchor="center")
return
As visible, send_diagram() is the command for the button.
I have tried adding another smaller frame inside the secondary frame to contain the image, but that did not work either.
Any help would be greatly helpful. Thanks!

You are creating the new image inside a function, with it's own local namespace. When the function ends the reference to the image will be garbage collected.
You can fix this by saving a reference to the image in the Label widget. Put this line in the function after the image is created:
send_diagram_entry_label.image = send_diagram_entry_image

Here is working code. I have try it and it's working for me.
def make_label_image(parent, img):
label = tk.Label(parent, image=img)
label.place(relx=0.5, rely=0.5, anchor="center")
def send_diagram():
send_diagram_fram = tk.Frame(frame, bg="#D4BAEC")
send_diagram_frame.place(relx=0.5, rely=0.5, relheight=0.7, relwidth=0.7, anchor="center")
send_diagram_fram.pack_propagate(0)
send_diagram_fram.pack()
img = ImageTk.PhotoImage(Image.open('C:/Users/xxxx/Desktop/logo.jpg'))
make_label_image(send_diagram_fram, img)

Related

Displaying Images Using Python Events

I am creating a small program that should display an image overlayed the main window based on a button click event. However, whenever I test the code that should be doing this, I get this error: AttributeError: 'int' object has no attribute '_create'
Here is the appropriate code:
def display_image(event):
fail_image = tk.PhotoImage(file="./RedXMark.png")
Canvas.create_image(0, 0, image=fail_image, anchor="nw")
# Later in the code:
root.bind('<t>', display_image)
I have been trying to use Tkinter's labels to display the image and, while I wouldn't get an error, it wouldn't display the image. The image is in the same folder as the program and is saved with that exact name.
Any advice would be welcome!
You must call create_image on an instance of the Canvas class, but you're calling it on the class itself.
something = tk.Canvas(...)
...
something.create_image(0, 0, image=fail_image, anchor="nw")

Add a QWidget inside a QFrame

I'm developing a desktop software using Python3 and QtDesigner for the Graphic User Interface.
My problem is the seguent: i'm trying to automate the creation of many QRadioButtons over a QFrame (The RadioButtons must stay inside the frame [as...children?]).
Now, i see that i can only create new widgets inside a Layout (e.g. "MyLayout.addWidget(QRadioButton")) and it's not possible to do something like "MyFrame.addWidget(QRadioButton)". I need these widgets inside the frame cause then i can place them in the correct position with "MyRB.move(X,Y)".
With QtDesigner is possible to place many Widgets (like RadioButtons) in a frame that has a 'broken layout' so i can choose X,Y coordinates but i need to create and place a variable number of those.
Is it possible to create Qwidgets inside a QFrame?
[EDIT]
according to musicamante's comment, i got that's a parent problem.
I tried to insert a Label and a RadioButton in the main window:
def __init__(self):
super().__init__()
uic.loadUi('DSS_GUI2.ui',self) # i load the GUI with QtDesigner
LB1 = QLabel('MyLabel',self)
RB1 = QRadioButton('MyRadioButton',self)
...
This very simple example works fine but when i try to add a Label through a function
def myFunction(self):
LB1 = QLabel('MyLabel')
LB1.setObjectName('LABEL_1')
LB1.setParent(self.myFrame)
the Widget is inserted but it is not visible, in fact adding this lines to check his presence
WidgetList = self.myFrame.findChildren(QLabel)
for item in WidgetList:
print(item.objectName())
i see in the console that the Label is there.
Do you know why it's not visible?
Try
def myFunction(self):
LB1 = self.sender()
LB1.QLabel('MyLabel')
LB1.setObjectName('LABEL_1')
LB1.setParent(self.myFrame)
You can call self.myFunction() in parent.
If you wanted to pass label, you could:
def myFunction(self, label):
LB1 = self.sender()
LB1.QLabel(label)
LB1.setObjectName(label)
LB1.setParent(self.myFrame)

Restoring deleted picture on canvas in python tkinter

I am creating a program where I make use of a check button to delete and recover a background image in python tkinter. I got the deleting part. Can someone help with the recovering part? I want to recover the image on clicking the check button.
You can do the same with your background image as I have done with the hi variable.
Like this:
import tkinter as tk
root = tk.Tk()
var = tk.IntVar()
def test():
if var.get():
hi.grid_remove()
else:
hi.grid(column=0, row=1)
hi = tk.Label(text="hi")
hi.grid(column=0, row=1)
c_b = tk.Checkbutton(text="Check", variable=var, command=test)
c_b.grid(column=0, row=0)
root.mainloop()
Note: Don't use destroy(). Use grid.remove or grid.forget() instead, otherwise your image won't be recovered.
I prefer using grid.remove, because if you need to do some change to a widget after making it disappear. Then to get it back grid.forget also won't work properly.

Tkinter best button text flipping method

So I'm working on a tkinter project and one issue I come across is finding a way to flip/rotate a button object's text vertically. One way I can kinda cheat into making this happen is putting a canvas object on top of the button with the canvas being drawn last (as shown below) but is there a cleaner way to approach this by just manipulating the Button object attributes?
from tkinter import*
root = Tk()
windowDimensions = (1300,600)
root.title("Mapper")
root.geometry(str(windowDimensions[0])+"x"+str(windowDimensions[1]))
button1=Button(root,text='',width=2,height=9)
button1.place(x=0,y=20)
can = Canvas(root,width=15,height=80)
can.place(x=2,y=30)
can.create_text(0, 80, anchor="nw", angle=90,text='hello',font=("Purisa", 12))
root.mainloop()
Edit: A problem I get with doing it this way is any place where the canvas is on the button, it obstructs the ability to click where the canvas is.
Your best option (which isn't a great option) is to screenshot the button, rotate it in an image editor, and then use that image in your button instead of text.
from tkinter import*
root = Tk()
# .gif file encoded as base64
vert_button_data = '''
R0lGODlhDQBCAKUkAAAAAAAANgAAYDYAADYANjYAYGAAAGAANmAAYAA2hzY2h4c2AGA2h4c2NgBg
qzZghzZgq2BgNqtgAKtgNjaHhzaHzmCHh6uHNs6HNmCr8PCrYIfOq4fO8PDOh6vwq6vw8M7w8PDw
q/DwzvDw8P//////////////////////////////////////////////////////////////////
/////////////////////////////////////////////ywAAAAADQBCAAAG/sCRcEgsGo+cpFJJ
PDgPAWeUGKpSMFUM5Qggdo2DDAiU+RY7BoXCoDmOQp1OqLisN5/4A7XqqfqPAm5EERVLRwcGeEd+
f0gZGR9uGQQSEgUcXB1CHQFcXkdhHx8ZA0doBQUGmotxc0QOhZFuGhgNCLAcskUiIbQNAg5HHxwV
DwYSRMQQCBMYckUHAxYbIG5wtQwOGRzVRrwaFwEJRiAcGQ4KCxhE5woNEhodIkXw8oL3+Pn35pCS
lJaYjABYxcnTEDNEQo0qZeRUqlVG4DxLVofJkDyKhjDaSLFiQCEYn+zZWEVYhWAjUBYRoOELwoMj
XILiAOBDBYZnoj201oqOIMePI/BEEanRDwBGbl4avKdUyBIAhi4+SURUCMlG+oIAADs=
'''
windowDimensions = (1300,600)
root.title("Mapper")
root.geometry("{}x{}".format(*windowDimensions))
button1_image = PhotoImage(data=vert_button_data)
button1=Button(root,image=button1_image)
button1.place(x=0,y=20)
root.mainloop()
You'll lose the hover animation but again that's something you can recreate with images.
To get the base64 encoded data from a .gif you can use this:
import codecs
with open('export.gif', 'rb') as f:
print(codecs.encode(f.read(), 'base64').decode())

Sometimes the Tkinter canvas doesn't load

I am writing a program which involves drawing rectangles on the tkinter canvas. Here is the code that creates the canvas and the window it is a part of. (This is within an object, and the root.mainloop() is called later outside of the object, and the drawing is also present elsewhere)
self.root = tk.Tk()
self.root.title = "Game"
self.root.resizable(0,0)
self.root.geometry('{}x{}'.format(500, 500))
#create drawing canvas
self.canvas_base = tk.Canvas(self.root, bg="white", width=500, height=500)
self.canvas_base.bind("<Up>", lambda event1, arg1=0: self.arrow_press(event1,arg1)) #bind up key
self.canvas_base.bind("<Right>", lambda event2, arg2=1: self.arrow_press(event2,arg2)) #bind right key
self.canvas_base.bind("<Down>", lambda event3, arg3=2: self.arrow_press(event3,arg3)) #bind down key
self.canvas_base.bind("<Left>", lambda event4, arg4=3: self.arrow_press(event4,arg4)) #bind left key
self.canvas_base.focus_set() #give the window keyboard focus
self.canvas_base.pack()
The problem I've noticed is that sometimes no canvas is generated, as the white background fails to appear and I'm left with the grey/off-white basic background for the window. No errors pop up in the console, and other code within the window runs fine. Is this a normal problem with the canvas, or is it something to do with the code?
Considering the size of my code, and the fact that I have no idea what is exactly causing the issue. I decided to just post the main initialization, but if the drawing/anything else within the code would have an impact, I can post that too. Also, nothing else is being done with the canvas.
EDIT:
This seems to occur with the creation of the canvas full stop, and is probably a Python error. By running similar code as the entirety of a file, and waiting a period before I run it each time, the first time I run it after an hour or so causes no Canvas to appear.

Resources