Here's the code I am using (one example):
import os
import win32api
from tkinter import *
from tkinter import ttk
from tkinter import filedialog
from PIL import ImageTk, Image
#...
def mainloop():
root = Tk()
mainframe = ttk.Frame(root)
mainframe.grid(column=0, row=0, sticky=(N,W,E,S))
root.columnconfigure(0, weight=1)
root.rowconfigure(0,weight=1)
#...
pillarImg = ImageTk.PhotoImage(Image.open("pillars.png"))
pillars_label = ttk.Label(root)
pillars_label['image'] = pillarImg
#...
rldir_entry = ttk.Entry(mainframe, width=40, textvariable=rldir)
pillars_entry = ttk.Entry(mainframe, width=10, textvariable=Pillars)
#...
rldir_entry.grid(column=0, row=0, columnspan=5, sticky=(W,E))
pillars_label.grid(column=0, row=1, columnspan=2, sticky=(N,W,E,S))
pillars_entry.grid(column=0, row=2, sticky=(W,E))
#...
root.mainloop()
mainloop()
This code results in the two entry boxes being above the image, even though I set the grid to have the image between the two entry boxes...?
Here's a pic of what I mean:
Ahh I just figured it out.
here:
pillars_label = ttk.Label(root)
I added the label to root.
While here:
rldir_entry = ttk.Entry(mainframe, width=40, textvariable=rldir)
the entry boxes are in the mainframe. lol.
Related
I'm making a GUI with Tkinter (Tcl/Tk version 8.6.12) on Python 3.9. Up until now, I mostly had experience with pure Tk, but wanted to try Ttk out. My problem is that running:
someText = tk.StringVar(value="Some Text")
ttk.Label(mainframe, textvariable=someText).grid(column=0, row=0, sticky=(W, E))
does reserve some space for the string, but doesn't display it. When using the tk.Label class, it works like a charm...
What am I doing wrong, or is the ttk.Label class broken?
EDIT: here is my full MNWE (I wrapped everything in a function because I will need to integrate everything with some other code I have already written and this is the best way I've found to do it):
from tkinter import *
from tkinter import ttk
def generateGUI():
# Generates the main window
root = Tk()
root.title("Some interesting title")
root.resizable(FALSE, FALSE)
# Adds a frame for themed tk
mainframe = ttk.Frame(root, padding="3 3 12 12")
mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
root.columnconfigure(0, weight=1) # setup the frame to scale with the window horizontally
root.rowconfigure(0, weight=1) # setup the frame to scale with the window vertically
# Creates a canvas
canv = Canvas(mainframe, bg="green")
canv.grid(column=0, row=0, sticky=(N, E, S, W))
# Sets some information panel up
info = ttk.Frame(mainframe)
info.grid(column=1, row=0, sticky=(N, E))
title = StringVar(value="<title>")
text1 = StringVar(value="<text1>")
text2 = StringVar(value="<text2>")
text3 = StringVar(value="<text3>")
# Adds the different labels
ttk.Label(info, font=25, textvariable=title).grid(column=0, row=0, sticky=N, columnspan=2)
ttk.Label(info, text="Info 1: ").grid(column=0, row=1, sticky=W)
ttk.Label(info, text="Info 2: ").grid(column=0, row=2, sticky=W)
ttk.Label(info, text="Info 3: ").grid(column=0, row=3, sticky=W)
ttk.Label(info, textvariable=text1).grid(column=1, row=1, sticky=E)
ttk.Label(info, textvariable=text2).grid(column=1, row=2, sticky=E)
ttk.Label(info, textvariable=text3).grid(column=1, row=3, sticky=E)
for child in mainframe.winfo_children():
child.grid_configure(padx=5, pady=5)
return root
gui = generateGUI()
gui.mainloop()
Your instance of StringVar is a local variable. Make it/them an instance variable if you're using classes, or a global variable if not.
def generateGUI():
global title
...
title = StringVar(value="<title>")
ttk.Label(info, font=25, textvariable=title)
This example code is working. You need to import ttk and change remove sticky.
why_no_sticky - good example on the link how grid works.
from tkinter import ttk
import tkinter as tk
mainframe = tk.Tk()
someText = tk.StringVar(value="Some Text")
label1 = ttk.Label(mainframe, textvariable=someText)
label1.grid(column=0, row=0)
mainframe.mainloop()
I need to center two buttons, and I may need to center more buttons, but I can't center more than one button, so I need help...
Here's the code:
from tkinter import *
from tkinter.ttk import *
import os
root = Tk()
root.geometry("325x100")
def click():
pass
def click2():
pass
button = Button(root, text="Button 1", command=click, width=25)
button.grid(row=0, column=0)
button2 = Button(root, text="Button 2", command=click2, width=25)
button2.grid(row=1, column=0)
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
root.mainloop()
I did a bit of testing and here is what i have come up with. I have used the .pack() method instead of the .grid() method and i have also used a frame. I am kind of new to Python, but here it is :)
from tkinter import *
from tkinter.ttk import *
import os
root = Tk()
root.geometry("325x100")
def click():
pass
def click2():
pass
frame = Frame(root)
frame.pack(padx = 20, pady = 12)
button = Button(root, text="Button 1", command=click, width=25)
button.pack()
button2 = Button(root, text="Button 2", command=click2, width=25)
button2.pack()
root.mainloop()
Here is what it looks like:
Don't add weight to the first row. It is forcing it to expand. You may want to consider something else, though. You may eventually put something else on that row, and you may need that thing to expand the row. In it's current state this will cause a "catch 22" for you. You may want to consider creating a frame to hold all of the buttons, and put that entire frame on the root.
immediate fix:
from tkinter import *
from tkinter.ttk import *
import os
root = Tk()
root.geometry("325x100")
def click():
pass
def click2():
pass
button = Button(root, text="Button 1", command=click, width=25)
button.grid(row=0, column=0)
button2 = Button(root, text="Button 2", command=click2, width=25)
button2.grid(row=1, column=0)
#this is forcing the top row to expand
#root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
root.mainloop()
possibly a better way:
from tkinter import *
from tkinter.ttk import *
import os
root = Tk()
root.geometry("325x100")
def click():
pass
def click2():
pass
#by not defining row and column in grid()
#~ row will be the next available one and column will be 0
button_frame = Frame(root)
button_frame.grid(sticky='nswe')
button_frame.grid_columnconfigure(0, weight=1)
#you only need to store a reference if you intend to change/reference/destroy/forget these
#if they are going to always be a button, as initially defined, a reference is dead weight
Button(button_frame, text="Button 1", command=click, width=25).grid()
Button(button_frame, text="Button 2", command=click2, width=25).grid()
#now you can use grid_rowconfigure without it destroying your button layout
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
root.mainloop()
I am trying to learn Tkinter and python. How can I open multiple images and save it on multiple canvas in Python 3? I also want the image to fit just perfect on to the size of the canvas.
Could someone show me to do this using simple code.
import tkinter
from tkinter import filedialog
import os
#from PIL import ImageTk, Image
from tkinter import *
import PIL.Image
from tkinter.filedialog import askopenfilename
import py_compile
mainWindow =tkinter.Tk()
mainWindow.title("Image")
mainWindow.geometry('640x480+800+200')
mainWindow.columnconfigure(0, weight=3)
mainWindow.columnconfigure(1, weight=1)
mainWindow.columnconfigure(2, weight=1)
mainWindow.rowconfigure(0, weight=3)
mainWindow.rowconfigure(1, weight=3)
mainWindow.rowconfigure(2, weight=5)
mainWindow.rowconfigure(3, weight=3)
leftFrame = tkinter.LabelFrame(mainWindow, text='PICTURE')
leftFrame.grid()
canvas = tkinter.Canvas(leftFrame, relief='sunken', borderwidth=5, bg= 'white', width=100, height=100)
canvas.grid(row=1, column=0)
canvas2 = tkinter.Canvas(leftFrame, relief='sunken', borderwidth=5, bg= 'white', width=100, height=100)
canvas2.grid(row=2, column=0)
canvas3 = tkinter.Canvas(leftFrame, relief='sunken', borderwidth=5, bg= 'white', width=100, height=100)
canvas3.grid(row=1, column=1)
canvas4 = tkinter.Canvas(leftFrame, relief='sunken', borderwidth=5, bg= 'white', width=100, height=100)
canvas4.grid(row=2, column=1)
def clicked():
print('hello')
open_img()
def open_img():
global photo
filename = filedialog.askopenfilename(initialdir = "E:/Images", filetypes = ())
photo = tkinter.PhotoImage(file=filename)
photo = photo.subsample(3,3)
canvas.create_image(0,0, anchor=CENTER, image=photo)
rightFrame = tkinter.LabelFrame(mainWindow, text='MENU')
rightFrame.grid()
button1 = tkinter.Button(rightFrame , text="Open", command=clicked)
button1.grid(row=1, column=2)
mainWindow.mainloop()
You would use one class with each image creating an instance of that class, but since you have not used a class and so are probably not familiar with the class structure, the following code combines everything into one class. Since I don't have the images, this opens a new Toplevel with a related "close" button instead of an image, each time the "open" button is clicked.
try:
import Tkinter as tk ## Python 2.x
except ImportError:
import tkinter as tk ## Python 3.x
from functools import partial
class OpenToplevels():
""" open and close additional Toplevels with a button
"""
def __init__(self):
self.root = tk.Tk()
self.button_ctr=0
but=tk.Button(self.root, text="Open a Toplevel",
command=self.open_another)
but.grid(row=0, column=0)
tk.Button(self.root, text="Exit Tkinter", bg="red",
command=self.root.quit).grid(row=1, column=0, sticky="we")
self.root.mainloop()
def close_it(self, id):
id.destroy()
def open_another(self):
self.button_ctr += 1
id = tk.Toplevel(self.root)
id.title("Toplevel #%d" % (self.button_ctr))
tk.Button(id, text="Close Toplevel #%d" % (self.button_ctr),
command=partial(self.close_it, id),
bg="orange", width=20).grid(row=1, column=0)
Ot=OpenToplevels()
I want my label to be displayed in the same column as the picture. Both of them are generated with a click. I place them in the same column of the grid, but the image is displayed in the neighbour column. What's the reason and how to correct it?
Here's my simplified code.
from tkinter import *
from tkinter import ttk
class App(Frame):
def __init__(self, master):
ttk.Frame.__init__(self, master, padding='20')
self.grid(column=0, row=0, sticky=(N, W, E, S))
self.create_button()
def create_button(self):
self.button = ttk.Button(self,
text="Click",
width=12,
command=lambda: self.display_name_and_picture()
).grid(column=2, columnspan=2, row=1, sticky=NW)
def display_name_and_picture(self):
random_label = ttk.Label(self, font=(None, 16), text='random random')
random_label.grid(row=0, column=5, sticky=N)
random_image = PhotoImage(file='random.gif')
label = Label(image=random_image)
label.image = random_image
label.grid(row=1, column=5, sticky=NW)
root = Tk()
root.title("Random something...")
root.geometry("600x300")
app = App(root)
root.mainloop()
The culprit is this line
label = Label(image=random_image)
You create label without specifying its parent, so its parent defaults to root. But random_label has app as its parent, and app in turn has root as its parent. So label is gridded side by side with app --- inside root --- and not inside app as you wished. Just change the above line to
label = Label(self, image=random_image)
and you should be fine.
(Well, not totally fine. You should also fix the things people pointed out in comments.)
I monkeyed around with this for a while and produced something that does what you are asking. I would love to have somebody explain why this works. The columns look goofy.
Check it out:
from tkinter import *
from tkinter import ttk
class App(Frame):
def __init__(self, master):
ttk.Frame.__init__(self, master, padding='20')
self.grid(column=0, row=0, sticky=(N, W, E, S))
self.create_button()
def create_button(self):
self.button = ttk.Button(self,
text="Click",
width=12,
command=self.display_name_and_picture
)
self.button.grid(column=0, columnspan=2, row=0, sticky=NW)
def display_name_and_picture(self):
random_label = ttk.Label(self, font=(None, 16), text='random random')
random_label.grid(row=0, column=2)
random_image = PhotoImage(file='random.gif')
label = Label(image=random_image)
label.image = random_image
label.grid(row=1, column=0)
root = Tk()
root.title("Random something...")
root.geometry("600x300")
app = App(root)
root.mainloop()
Using Tkinter,How can I toggle between images when a button is click. Having this code as reference, I can only load one image but I don't know how to make it behave the way I need.
from Tkinter import *
import ttk
from PIL import ImageTk, Image
def showImage(*args):
lbl['image'] = image_tk
root = Tk()
c = ttk.Frame(root, padding=(5, 5, 12, 0))
c.grid(column=0, row=0, sticky=(N,W,E,S))
root.grid_columnconfigure(0, weight=1)
root.grid_rowconfigure(0,weight=1)
fname = "A.jpg"
fname1 = "B.jpg"
image_tk = ImageTk.PhotoImage(Image.open(fname))
btn = ttk.Button(c, text="load image", command=showImage)
lbl1 = ttk.Label(c)
btn.grid(column=0, row=0, sticky=N, pady=5, padx=5)
lbl.grid(column=1, row=1, sticky=N, pady=5, padx=5)
root.mainloop()
How can I configure my ShowImage function or any other modification needed to be able to switch the image between fname and fname1
To change images on button clicks use the configure() method to the button to change the command argument and create a new ImageTk object to hold a reference of the second image.
from Tkinter import *
import ttk
from PIL import ImageTk, Image
def showImage():
lbl1.configure(image=image_tk)
btn.configure(text = "load image!", command=showImage1)
def showImage1():
lbl1.configure(image=image_tk1)
btn.configure(text = "load image!", command=showImage)
root = Tk()
c = ttk.Frame(root, padding=(5, 5, 12, 0))
c.grid(column=0, row=0, sticky=(N,W,E,S))
root.grid_columnconfigure(0, weight=1)
root.grid_rowconfigure(0,weight=1)
fname = "a.jpg"
image_tk = ImageTk.PhotoImage(Image.open(fname))
fname1 = "b.jpg"
image_tk1 = ImageTk.PhotoImage(Image.open(fname1)) # new image object
btn = ttk.Button(c, text="load image", command=showImage)
lbl1 = ttk.Label(c)
btn.grid(column=0, row=0, sticky=N, pady=5, padx=5)
lbl1.grid(column=1, row=1, sticky=N, pady=5, padx=5)
root.mainloop()