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())
Related
Problem statement
I have written a code in Python on which a user can draw on a tkinter GUI canvas. The program is capable of taking the app's screenshot but saving the canvas content to a viewable image file (such as .jpg or .png) is not properly done yet.
Screenshots
What I draw on the tkinter app's canvas.
What the code (given below) saved.
What I expect.
I have tried and will expect
A number of possible solutions from the internet (including Stack Overflow) have been tried but somehow the process cannot be completed successfully. After drawing whatever on the canvas, the saved image will have nothing but a dot whether it is in *.jpg or *.png. I need the image of the full canvas with all the colorful drawings on it in that saved image file.
For any reference, here is my code
from tkinter import Tk, Canvas, Button
from PIL import Image, ImageDraw
X = 0
Y = 0
app = Tk()
def set_xy(click):
global X, Y
X, Y = click.x, click.y
def draw_line(drag):
global X, Y
draw_panel.create_line((X, Y, drag.x, drag.y), fill="black", capstyle="round", smooth=True)
draw.line([(X, Y), (drag.x, drag.y)], fill="black", joint="curve")
X, Y = drag.x, drag.y
def save(event=None):
# ATTENTION: This is not working properly
image.save("image.png", "png")
# App's drawing panel
draw_panel = Canvas(app, background="white", cursor="dot")
draw_panel.place(x=0, relwidth=1.0, y=0, relheight=1.0)
# Invisible canvas for saving as an image later on
image = Image.new("RGB", (draw_panel.winfo_width(), draw_panel.winfo_height()), "white")
draw = ImageDraw.Draw(image)
# Mouse and Key bindings
draw_panel.bind('<Button-1>', set_xy)
draw_panel.bind('<B1-Motion>', draw_line)
app.bind('<s>', save) # press 's' to save the drawing as .png
app.mainloop()
Addition Informations:
HOST: Windows 10 Version 20H2 (OS Build 19042.2130)
IDE: PyCharm 2022.2 (Community Edition) (Build #PC-222.3345.131)
Language: Python 3.10.6
Framework: tkinter Tk/Tcl 8.6
Library: pillow 9.2.0
Any solution shall be highly appreciated, and I shall be thankful.
That's a nice idea and there is just one piece missing. You set the size of the image to the size of the canvas before you call mainloop() for the first time. The canvas does not have a size at this time because the window has not been initiated, yet.
You need to force an update before getting the width and height. Then, it works fine:
# Invisible canvas for saving as an image later on
draw_panel.update()
image = Image.new("RGB", (draw_panel.winfo_width(), draw_panel.winfo_height()), "white")
draw = ImageDraw.Draw(image)
If you print the draw_panel.winfo_width() before and after calling the update, you see what I mean. Before update(), width and height are both 1. Afterwards, they are 200, as they should be.
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)
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.
This question already has an answer here:
PhotoImage not showing up the image associated with it
(1 answer)
Closed 3 years ago.
I'm trying to add in an image to a screen and its not displaying.
Followed other Stack overflow solutions and the Effbot solution and neither worked. Ive moved the image around and it still isnt displaying so its not where its displaying. Not getting any Error messages either.
image = PhotoImage("newspaper-extra-computer-icons-breaking-newsnewspaper.jpg")
image_label = Label(news_aggregator,image = image)
image_label.image = image
image_label.place(x=400,y = 200)
Just expecting the image to be displayed.
The main problem is you are missing file= in PhotoImage().
Try this:
PhotoImage(file='path_to_image.gif')
That said tkinter only supports a hand full of formats.
The PhotoImage class can read GIF and PGM/PPM images from files
For working with other formats you will need PIL.
If you need to work with other file formats, the Python Imaging Library (PIL) contains classes that lets you load images in over 30 formats, and convert them to Tkinter-compatible image objects:
You can see all there here on the documentation.
For your file try this:
import tkinter as tk
from PIL import ImageTk
root = tk.Tk()
image = ImageTk.PhotoImage(file="newspaper-extra-computer-icons-breaking-newsnewspaper.jpg")
image_label = tk.Label(root, image=image)
image_label.image = image
image_label.place(x=400, y=200)
root.mainloop()
Keep in mind due to you using place() the above code will not be showing the image as it is off frame. You will need to expand the window.
I'm currently using an embedded turtle canvas in a tkinter window. While it's intuitive that all I need to do is set my turtle to turtle.RawTurtle(canvas), there are some functions that just don't work, and I can't figure out why.
t.clear();t.pu();t.speed(0);t.ht();t.tracer(0)
But I get the error:
AttributeError: 'RawTurtle' object has no attribute 'tracer'
Despite this, many other functions work, such as clear, penup, speed, and hideturtle.
Is there any way of disabling screen updates until the drawing is finished, then manually updating the canvas, with RawTurtle?
The tracer() method is a method of the turtle's screen, not the turtle itself. To get access to it, when embedded under a tkinter window, wrap the canvas in a turtle screen:
screen = turtle.TurtleScreen(canvas)
t = turtle.RawTurtle(screen)
which should give you access to the various screen methods. Then you should be able to use screen.tracer(0) to turn off drawing updates and screen.update() to show the finished drawing. A more complete example:
import tkinter as tk
import turtle
root = tk.Tk()
canvas = turtle.ScrolledCanvas(root)
canvas.pack(side=tk.LEFT)
screen = turtle.TurtleScreen(canvas)
t = turtle.RawTurtle(screen)
t.hideturtle()
# t.speed('fastest')
screen.tracer(0)
t.penup()
t.sety(-100)
t.pendown()
t.circle(100)
screen.update()
screen.mainloop()