Everyone
Startpage works fine.
However, I changed the frame to Pageone using change_img().
Pageone did not appear on the screen.
I enlarged the entire screen by clicking the square on the top right of the printed frame.
Pageone appears at the bottom.
I don't know why Pageone's text and buttons don't appear at the top of the frame
Please help.
import sys
import serial
import threading
import queue
import tkinter as tk
#import tkinter
import tkinter.ttk as ttk
import time
import tkinter.messagebox
from PIL import ImageTk, Image
class StartApp(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self._frame = None
self.switch_frame(None, StartPage)
self.geometry("1500x950+100+100")
self.resizable(width=True, height=True)
def switch_frame(self, Canvas, frame_class):
if Canvas is not None:
Canvas.delete("all")
new_frame = frame_class(self)
if self._frame is not None:
print( '{} destory'.format(self._frame))
self._frame.destroy()
self._frame = new_frame
print(new_frame)
self._frame.pack()
class StartPage(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master)
self.no= 10
self.is_charged= False
#self.img = ImageTk.PhotoImage(Image.open("images/10_image.png"))
#n can't be zero, recommend 0.25-4
n = 3
self.image = Image.open("images/10_image.png")
[imageSizeWidth, imageSizeHeight] = self.image.size
newImageSizeWidth = int(imageSizeWidth * n)
if 1:
newImageSizeHeight = int(imageSizeHeight*n)
else:
newImageSizeHeight = int(imageSizeHeight/n)
self.image = self.image.resize((newImageSizeWidth, newImageSizeHeight), Image.ANTIALIAS)
self.img = ImageTk.PhotoImage(self.image)
self.Canvas1 = tk.Canvas(width = 1500, height = 950)
#self.Canvas1.config(bg="blue")
self.Canvas1.pack()
self.Canvas1.create_image(1500/2,950/2,image = self.img)
# Canvas1.config(bg="blue",width = newImageSizeWidth, height = newImageSizeHeight)
#Canvas1.config(bg="blue")
#Canvas1.pack(side="left", anchor="ne")
# images
self.my_images = []
self.my_images.append(tk.PhotoImage(file = "images/10_image.png"))
self.my_images.append(tk.PhotoImage(file = "images/11_image.png"))
self.my_images.append(tk.PhotoImage(file = "images/12_image.png"))
self.my_image_number = 0
# set first image on canvas
self.image_on_canvas = self.Canvas1.create_image(0, 0, anchor = "nw", image = self.my_images[self.my_image_number])
self.after(500, self.change_img)
def change_img(self):
# next image
self.my_image_number += 1
# return to first image
if self.my_image_number == len(self.my_images):
self.my_image_number = 0
self.master.switch_frame(self.Canvas1, PageOne)
# change image
else:
self.Canvas1.itemconfig(self.image_on_canvas, image = self.my_images[self.my_image_number])
self.after(500, self.change_img)
class PageOne(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master)
tk.Label(self, text="This is page one").pack(side="top")
tk.Button(self, text="Return to start page",
command=lambda: master.switch_frame(None, StartPage)).pack()
class PageTwo(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master)
tk.Label(self, text="This is page two").pac`enter code here`k(side="top", fill="x", pady=10)
tk.Button(self, text="Return to start page",
command=lambda: master.switch_frame(None, StartPage)).pack()
if __name__ == "__main__":
root= StartApp()
root.mainloop()
It is because self.Canvas1 is not child of StartPage, it is child of root (StartApp) window. So even StartPage is destroyed, self.Canvas1 is still there.
Change the following line in StartPage.__init__():
self.Canvas1 = tk.Canvas(width = 1500, height = 950) # child of `root`
to
self.Canvas1 = tk.Canvas(self, width = 1500, height = 950) # child of `StartPage`
Related
import tkinter as tk
import PIL
from PIL import ImageTk
from PIL import Image, ImageTk
from tkinter import Frame
button_flag = True
def click():
"""
respond to the button click
"""
global button_flag
# toggle button colors as a test
if button_flag:
self.button1.config(bg="white")
self.button_flag = False
else:
sef.button1.config(bg="green")
self.button_flag = True
class Example(Frame):
def __init__(self, master, *pargs):
Frame.__init__(self, master, *pargs)
self.image = Image.open('slide 1.png')
self.img_copy= self.image.copy()
self.photo = tk.PhotoImage(file="video.png")
self.photo1 = self.photo.subsample(2, 2)
self.background_image = ImageTk.PhotoImage(self.image)
self.background = tk.Label(self, image=self.background_image, text="heyyy")
self.background.pack(fill="both", expand=True)
self.background.bind('<Configure>', self._resize_image)
self.button1 = tk.Button(root, compound=tk.TOP, width=155, height=55, image=self.photo1,
text="optional text", bg='green', command=click)
self.button1.pack()
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)
root = tk.Tk()
root.title('webmanager')
root.state('zoomed')
e = Example(root)
e.pack(fill="both", expand=True)
root.mainloop()
I also would like to know if this can be aplicable to slide shows (ie adding a button to each picture). well for now the only thing ive accomplished is making the button look like a header and then the image follows but fairly the both are resizable. but i really need the image to fill the screen and then the button on it. THANKS
I want to have two tkinter windows. A button should be in the first window, and a reaction text should be in the second window.
My questions:
Must the second window have no modal?
How do I make the second window movable?
How can I give information to second window via callback function?
Thanks in advance for answers and advice!
Here is some code that may help you:
from tkinter import *
class App:
def __init__(self):
self.window1 = Tk()
self.window2 = Toplevel()
self.button = Button(self.window1, bd = 5, text = "Click Me!", command = self.update)
self.button.pack()
self.label = Label(self.window2, bd = 5, text = "Button has not been clicked.")
self.label.pack()
def update(self):
self.label.config(text = "Button has been clicked!")
self.window2.update()
app = App()
Explanation:
The first line imports tkinter
In the next line, we create a class. At the bottom of the code, we create an object using that class. This is useful because when the object is created, the functions in the class are already defined, so the function definition can be after when it is called.
After we declare our class, in __init__, we write code that will run when an object is created from that class. The code creates two windows. One contains a button, and the other one contains a label. The button has a command parameter to run the class function, update.
In update, we change the label text and update the window.
I have not next questions. My problems solution is here:
import tkinter as tk
class ViewOnMoon(tk.Toplevel):
def __init__(self, parent = None, draw = None):
tk.Toplevel.__init__(self, parent)
self.transient(parent)
self.title('View')
self.minsize(height = 300, width = 300)
fr_canvas = tk.Frame(self)
fr_canvas.place(relx=0.23, rely=0.01, anchor="nw")
self.canv_w = 200
self.canv_h = 200
self.canvas = tk.Canvas(fr_canvas, bg='white', width = self.canv_w, height=self.canv_h)
self.canvas.grid(column = 0, row = 0)
return
class GuiMoonMove(tk.Frame):
def __init__(self, master):
mon_h = 600
mon_w = 1250
tk.Frame.__init__(self, master)
self.frame = tk.Frame(master, width=1000, height=200, bd=2)
self.master.title('Move')
self.master.minsize(height = mon_h, width = mon_w)
fr_canvas = tk.Frame(self.master)
fr_canvas.place(relx=0.23, rely=0.01, anchor="nw")
fr_button = tk.Frame(self.master)
fr_button.place(relx=0.02, rely=0.06, anchor="nw")
self.canv_h = 600
self.canv_w = 950
self.lbl_view = tk.BooleanVar()
chb_view_on_moon = tk.Checkbutton(fr_button, text="Pohled na Měsíc", variable = self.lbl_view, \
onvalue=True, offvalue=False,command = self.callback)
chb_view_on_moon.grid(column= 0, row= 4,pady = 10)
self.canvas = tk.Canvas(fr_canvas, bg='white', width = self.canv_w, height=self.canv_h)
self.canvas.grid(column = 0, row = 0)
def callback(self,*args):
if self.lbl_view.get()==True:
self.view_on_moon = ViewOnMoon(parent = self.master)
else:
self.vom.destroy()
if __name__=="__main__":
root = tk.Tk()
app = GuiMoonMove(master = root)
app.mainloop()
I am attempting to having a frame display an image that's opened through filedialog. My current method initializes the frame in Step1 with "image1path", and then I'd like to update it to some "image2path" specified by the user. I am attempting to do this through the Data.currentJPEG attribute.
Is there a better way that involves not initializing with a "dummy" image?
If this is the correct way, why do my commented out lines at the bottom return: " 'str' object has no attribute '_bind' " when Step1 is not a string. I thought Step1 was what allowed self.bind to work on the startPage. Is this not the correct method of updating the image in the frame?
Bonus side question: if I change weight=100 to weight=1 in the start page lines, why does the open .jpg button's location scale at all?
This code structure can be found here
Resizing an image this way can be found here
The method I attempt to use follows this answer, where a new function is called when the button is pressed that updates the image. However, I believe I am running into issues because my image uses the resizing function as well.
import os
import tkinter as tk
from PIL import Image, ImageTk
from tkinter import filedialog
image1path='mainGraphic.jpg'
cwd = os.getcwd()
# where opened file data with be stored
class Data():
# this sets initial values for the class attributes
def __init__(self):
self.currentJPEG=image1path
class program(tk.Tk):
def __init__(self,*args,**kwargs):
tk.Tk.__init__(self,*args,**kwargs)
self.title('program name')
container = tk.Frame(self)
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
# frames are laid ontop of each other, startPage shown first
self.frames = {}
for Frame in (StartPage, Step1):
frame = Frame(container, self)
self.frames[Frame] = frame
frame.grid(row = 0, column = 0, sticky="nsew")
frame.columnconfigure(0, weight=1)
frame.rowconfigure(0, weight=1)
self.show_frame(StartPage)
def show_frame(self,cont):
frame = self.frames[cont]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self,parent)
# scale rows and columns (make button scaling negligible)
self.rowconfigure(0,weight=0)
self.rowconfigure(1,weight=100) #bonus question refers to these 2 lines
self.columnconfigure(0,weight=100)
# button to open an image in Step 1,
# must pass program so app.showframe is available,
# must pass Step1 so the image attributes are available?
button = tk.Button(self, text='Open .jpg File in new frame',
command=lambda: Step1.openJPEG(program))
button.grid(row=0, column=0, sticky='ew')
# add the main graphic
self.canvas = tk.Canvas(self,bg='black')
self.canvas.grid(row=1, column=0, sticky='nsew')
self.img_copy = Image.open(image1path)
self.image = None #this is overriden every time the image is redrawn so there is no need to make it yet
self.bind("<Configure>",self.resizeImage)
def resizeImage(self,event):
origin = (0,0)
size = (event.width, event.height)
if self.bbox("bg") != origin + size:
self.canvas.delete("bg")
self.image = self.img_copy.resize(size)
self.background_image = ImageTk.PhotoImage(self.image)
self.canvas.create_image(*origin,anchor="nw",image=self.background_image,tags="bg")
self.canvas.tag_lower("bg","all")
class Step1(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
# give even weight to each subframe
self.rowconfigure(0, weight=1)
self.columnconfigure(0, weight=100)
self.columnconfigure(1, weight=100)
# Frame1, this is on the left and empty
frame1 = tk.Frame(self, bg="grey")
frame1.grid(row=0, column=0, sticky='nsew')
# Frame2, this is where image preview is
frame2 = tk.Frame(self, bg="grey")
frame2.grid(row=0, column=1, sticky='nsew')
# scale rows and columns with equal weight
frame2.rowconfigure(0,weight=1)
frame2.columnconfigure(0,weight=100)
frame2.columnconfigure(1,weight=100)
# initialize where image preview will be in frame2
self.canvas = tk.Canvas(frame2,bg='black')
self.canvas.grid(row=0, column=1, sticky='nsew')
self.img_copy = Image.open(Data.currentJPEG)
self.image = None
self.bind("<Configure>",self.resizeImage)
def resizeImage(self,event):
origin = (0,0)
size = (event.width, event.height) # these need to get height/width of their frame, not Step1
if self.bbox("bg") != origin + size:
self.canvas.delete("bg")
self.image = self.img_copy.resize(size)
self.background_image = ImageTk.PhotoImage(self.image)
self.canvas.create_image(*origin,anchor="nw",image=self.background_image,tags="bg")
self.canvas.tag_lower("bg","all")
# update the image in frame2 using opened jpeg image
def openJPEG(program):
filePath = filedialog.askopenfilename(initialdir=cwd,
filetypes=(("JPEG",".jpg"),("All Files","*.*")),
title="Open JPEG")
try:
with open(filePath) as image: #***need a better 'try' statement for only jpeg is opened'
app.show_frame(Step1)
except:
print('could not open image')
return
## update image preview from mainGraphic to opened JPEG; these lines aren't working
Data.currentJPEG=filePath
#Step1.img_copy = Image.open(Data.currentJPEG)
#Step1.image = None
#Step1.bind("<Configure>",Step1.resizeImage)
# initalize data class
Data=Data()
# run program
app = program()
If all you want to do is to let your user manually select a file, and then have your tkinter GUI display it, you just need a Button and a Canvas.
Code:
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import matplotlib.image as mpimg
from tkinter import filedialog
import tkinter as tk
import os
class program(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
# Create a button to load a jpg
self.button = tk.Button(self, text="Load image", command=self.openJPEG)
self.button.pack()
# Create a canvas on which to show the jpg
self.frame = tk.Frame(self)
self.frame.pack(fill=tk.BOTH, expand=1)
self.create_canvas()
def openJPEG(self):
# Display a dialog for the user to select a jpg file,
filePath = filedialog.askopenfilename(initialdir=os.getcwd(),
filetypes=(("JPEG",".jpg"),
("All Files","*.*")),
title="Open JPEG")
# Show the selected jpg on the canvas
img = mpimg.imread(filePath)
self.ax1.imshow(img)
self.canvas1.draw()
def create_canvas(self):
""" Add a canvas to plot images """
self.fig1 = Figure(frameon=False, figsize=(6, 4.5))
self.canvas1 = FigureCanvasTkAgg(self.fig1, master=self.frame)
self.canvas1.get_tk_widget().pack(fill=tk.BOTH, expand=1)
self.ax1 = self.fig1.add_axes([0, 0, 1, 1])
self.ax1.axis('off')
# Run program
app = program()
app.mainloop()
If you want to keep your multiple classes structure, you will have to make better use of the root part of your GUI (called controller in your subframes) to communicate between the different frames. See the code below to get you started:
import os
import tkinter as tk
from PIL import Image, ImageTk
from tkinter import filedialog
# where opened file data with be stored
class Data():
# this sets initial values for the class attributes
def __init__(self):
self.currentJPEG=""
class program(tk.Tk):
def __init__(self, Data):
tk.Tk.__init__(self)
self.Data = Data
container = tk.Frame(self)
container.pack(fill="both", expand=True)
# frames are laid ontop of each other, startPage shown first
self.frames = {}
for Frame in (StartPage, Step1):
frame = Frame(container, self)
self.frames[Frame] = frame
frame.grid(row = 0, column = 0, sticky="nsew")
self.show_frame(StartPage)
def show_frame(self,cont):
frame = self.frames[cont]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
# button to open an image in Step 1,
button = tk.Button(self, text='Open .jpg File in new frame',
command= self.openJPEG)
button.grid(row=0, column=0, sticky='ew')
# add empty canvas
self.canvas = tk.Canvas(self,bg='black')
self.canvas.grid(row=1, column=0, sticky='nsew')
def openJPEG(self):
self.openJPEG
filePath = filedialog.askopenfilename(initialdir=os.getcwd(),
filetypes=(("JPEG",".jpg"),
("All Files","*.*")),
title="Open JPEG")
# Update the image in Step1 frame
self.controller.Data.currentJPEG = filePath
self.controller.frames[Step1].show_current_image()
# Show Step1 frame
self.controller.show_frame(Step1)
class Step1(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
# Frame2, this is where image preview is
frame2 = tk.Frame(self, bg="grey")
frame2.grid(row=0, column=1, sticky='nsew')
# initialize where image preview will be in frame2
self.canvas = tk.Canvas(frame2,bg='black')
self.canvas.grid(row=0, column=1, sticky='nsew')
def show_current_image(self):
self.image = Image.open(self.controller.Data.currentJPEG)
self.background_image = ImageTk.PhotoImage(self.image)
self.canvas.create_image(0, 0, anchor="nw", image=self.background_image,
tags="bg")
# initalize data class
Data = Data()
# run program
app = program(Data)
app.mainloop()
I am using Tkinter with python for a simple UI where I have a text widget and a button. When the button is pressed I want the cursor focus to be set on the text widget, using focus_set() method.
I don't understand why the focus_set() is not working in my code. I think it might be because my text widget is within a frame (frame1) and I cannot properly access this widget in my startPaus() method. Any ideas how I can fix the problem??
class TypingField(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.submit_tog = True
self.initUI()
def initUI(self):
self.parent.title("Text Field")
self.pack(fill = BOTH, expand=True)
frame1 = Frame(self, width = 50, height =25)
frame1.pack(fill = X, expand=True)
self.scroll = Scrollbar(frame1)
self.scroll.pack(side = "right", fill = Y)
self.text = Text(frame1)
self.text.pack(fill=Y)
self.scroll.config(command=self.text.yview)
self.text.config(yscrollcommand=self.scroll.set)
frame2 = Frame(self)
frame2.pack(fill=X, expand=True)
self.submit = Button(frame2,text="Start Test")
self.submit.bind("<Button-1>", self.startPause)
self.submit.pack(fill=X)
def startPause(self, event):
if self.submit_tog:
self.submit.configure(text = "Pause")
self.text.focus_set()
else:
self.submit.configure(text = "Start Test")
self.submit_tog = not self.submit_tog
The following works on my machine. Note that the focus is always on the Text widget for the code you posted, enter something to see this, because the focus is never set elsewhere, but in the code below it alternates between the Text widget and the Button to illustrate.
class TypingField():
def __init__(self, parent):
self.parent = parent
self.submit_tog = True
self.initUI()
def initUI(self):
self.parent.title("Text Field")
frame1 = Frame(self.parent, width = 50, height =25)
frame1.pack(fill = X, expand=True)
self.scroll = Scrollbar(frame1)
self.scroll.pack(side = "right", fill = Y)
self.text = Text(frame1)
self.text.pack(fill=Y)
self.scroll.config(command=self.text.yview)
self.text.config(yscrollcommand=self.scroll.set)
frame2 = Frame(self.parent)
frame2.pack(fill=X, expand=True)
self.submit = Button(frame2,text="Start Test")
self.submit.bind("<Button-1>", self.startPause)
self.submit.pack(fill=X)
def startPause(self, event):
if self.submit_tog:
self.submit.configure(text = "Text Focus")
self.text.focus_set()
else:
self.submit.configure(text = "Button Focus")
self.submit.focus_set()
self.submit_tog = not self.submit_tog
root=Tk()
TypingField(root)
root.mainloop()
I am new to python so I was trying to make a GUI, in that I have to place a button in a particular position.
I tried using self.nxt_form.place(x=200,y=100) instead of self.nxt_form.pack().
But the button disappeared and only the frame appeared when it ran. Can you tell me how to place the button in a particular position?
Here is the code:
import tkinter as tk
class Main_form:
def __init__(self, root,title="Simulated MTBF"):
self.root = root
self.frame = tk.Frame(self.root)
"""Button nxt_form which moves to next form"""
self.nxt_form = tk.Button(self.frame, text = 'Next Form', width = 25,command = self.new_window)
self.nxt_form.pack()
self.frame.pack()
"""command to open new window by clicking Button """
def new_window(self):
self.newWindow = tk.Toplevel(self.root)
self.app = Demo2(self.newWindow)
class Demo2:
def __init__(self, root):
self.root = root
self.frame = tk.Frame(self.root)
self.quitButton = tk.Button(self.frame, text = 'Quit', width = 25, command = self.close_windows)
self.quitButton.pack()
self.frame.pack()
def close_windows(self):
self.root.destroy()
def main():
root = tk.Tk()
app = Main_form(root)
root.mainloop()
if __name__ == '__main__':
main()
when i am using tkinter i used column and row to position objects
self.btn = tk.Button(self, text = "button")
self.btn.grid(row = 1, column = 1)
EDIT - expanded on information in response to comment (below)
I would make an label and change its width and height to make the spacing you need (note im a beginer at python as well so this is probly a bad way but it works)
from tkinter import *
import tkinter as tk
from tkinter.ttk import Combobox,Treeview,Scrollbar
class MainMenu(Frame):
def __init__(self, master):
""" Initialize the frame. """
super(MainMenu, self).__init__(master)
self.grid()
self.create_GUI()
def create_GUI(self):
frame1 = tk.LabelFrame(self, text="frame1", width=300, height=130, bd=5)
frame1.grid(row=0, column=0, columnspan=3, padx=8)
#the frame is not needed but it is a good thing to use as can group
#parts of your interface together
self.text1 = Entry(frame1)
#note if you were not using frames would just put self here
self.text1.grid(row = 1, column = 0)
self.text2 = Label(frame1, text = "",height = 10)
self.text2.grid(row = 2 , column = 0)
self.text3 = Entry(frame1)
self.text3.grid(row = 3, column = 0)
root = Tk()
root.title("hi")
root.geometry("500x500")
root.configure(bg="white")
app = MainMenu(root)
root.mainloop()
Also note that you can not use pack and grid together what you could do is group your objects in different frames then use grid in one frame and pack in a different frame. I personally prefer to use grid to pack as it gives you more control over your object then pack does