I am writing a python code using Tkinter/canvas.
root = tk.Tk()
canvas = tk.Canvas(root, width=1800, height=900, borderwidth=0, highlightthickness=0, bg="white")
canvas.pack()
photo = tk.PhotoImage(file='image2.png')
root.photo = photo
canvas.create_image(1000,500,image=photo)
this is my background which I work with, works perfectly fine, but then I have a little problem with some parts. I need to put another image there in 1 part of the loop/code/if and in another part I need to "hide" it so I can show it and hide whenever I want. This is how i create it, but I can't solve the hiding part.
shine = tk.PhotoImage(file='svetlo.png')
smaller_image = shine.subsample(6, 6)
Svetlo = canvas.create_image(260, 830, image=smaller_image)
and my second problem is how I show date and time. RN I am using this
time1 = canvas.create_text(1000,500,text = strftime('%H:%M:%S'))
But it show just one time and doesnt change (obviously) and I dont know, how to make it work. I tried to find a solution, but only thing I found was only label and it doesn't work with my canvas, I need that time at the canvas. Thank you
Related
I've made a GUI using Tkinter. For the time being, I set the geometry to '962x652' and made it so the user can't resize it by using .resizable(0, 0). I'm now looking for a way to make it so when the GUI is resized, all the elements change size as well along side it, preferably with the aspect ratio locked.
Is there a way to achieve this whilst making it so only the element change size visibly without changing actually changing size? For example, if my GUI contains a scrolledtext box, if the user was to resize the GUI, the scrolledtext will also increase in size, but so will the text and each line of text in it will stay in the same line. I hope that makes sense.
I've add some code down below to show what I'm working with. This should have a similar effect to what I currently have:
import tkinter as tk
from tkinter import *
from tkinter import scrolledtext
TrialGUI = Tk()
TrialGUI.title('Resize GUI')
TrialGUI.geometry('962x652+0+0')
#Remove the following so you can resize the GUI
TrialGUI.resizable(0, 0)
#These are the two frames. I've changed their colour so they are visible when they are resized.
ABC1b = Frame(TrialGUI, bg='lightpink', bd=20, width=900, height=600)
ABC1b.grid(row=0, column=0)
ABC2 = Frame(TrialGUI, bg='lightblue', bd=20, width=452, height=600)
ABC2.grid(row=0, column=1)
#This is the text box
txtQuestion = scrolledtext.ScrolledText(ABC1b, wrap=tk.WORD, width=42, height=10, font=(14))
txtQuestion.grid(row=0, column=0, columnspan=4, pady=3)
#This inserts text into it. I made it insert which line the text should be in so it is easier to check if it is still in the same line when it is resized.
txtQuestion.insert(tk.INSERT, 'This should be in the first line.----------------------------------- This should be in the second line.------------------------------ This should be in the third line.----------------------------------')
TrialGUI.mainloop()
If anyone decides to play around with this code, remember to remove TrialGUI.resizable(0, 0) so it can be resized.
I am currently trying to make a scrollable list of entries using tkinter in Python 3. While looking for some documentation, I found this: Adding a scrollbar to a group of widgets in Tkinter. It is really great and works really fine with Labels, but it doesn't seem to work with Entries. You'll find right here my code which creates a 2x25 list of entries through which I would like to be able to scroll:
import tkinter as tk
class MainPage(tk.Frame):
def __init__(self, racine):
super().__init__(master=racine)
self.grid()
self.entriesCanvas = tk.Canvas(self, borderwidth=0, background="white")
self.entriesFrame = tk.Frame(self.entriesCanvas, background="white")
self.scrollbar = tk.Scrollbar(self, command=self.entriesCanvas.yview)
self.entriesCanvas.configure(yscrollcommand=self.scrollbar.set)
self.entriesCanvas.grid(column=0, row=2, columnspan=2)
self.scrollbar.grid(column=3, row=2, sticky='ns')
# self.entriesFrame.grid()
self.entriesCanvas.create_window((0, 0), window=self.entriesFrame,
anchor='nw', tags='self.entriesFrame')
# self.entriesFrame.grid()
self.entriesCanvas.bind('<Configure>', self.onFrameConfigure)
self.entries = []
for i in range(50):
self.entries.append(tk.Entry(self.entriesFrame, font=('arial', 30)))
self.entries[i].grid(column=i % 2, row=i//2)
def onFrameConfigure(self, event):
self.entriesCanvas.configure(scrollregion=self.entriesCanvas.bbox("all"))
if __name__ == "__main__":
root = tk.Tk()
mainPage = MainPage(root)
root.mainloop()
Notice I commented two lines out. If you "activate" the first line, there will be a scrollbar and one can scroll through the entries, but it is strangely zoomed. On the other hand, if you "activate" the second line, the GUI will be as I would like it to be, but without the possibility to scroll, and it seems to show all entries (even if there are 1000 entries, therefore making a window which is 20 times the size of your screen).
Do you know where my mistake is?
Okay, so I found a way to have my program doing what I want. I just changed the method
def onFrameConfigure(self, event):
self.entriesCanvas.configure(scrollregion=self.entriesCanvas.bbox("all"))
by
def onFrameConfigure(self, event):
self.entriesCanvas.configure(scrollregion=self.entriesCanvas.bbox("all"), width=self.entriesFrame.winfo_width())
(I basically only added a parameter to ask the canvas to be the width of the frame.)
I don't know if it is perfect (as I still use .grid() istead of .pack()), but it works.
Thank you for giving me the source Tkinter: How to get frame in canvas window to expand to the size of the canvas?, it really helped me find where my mistake was.
I truely apologise for my English, I know I make a lot of mistakes.
I'm trying to make a script which will enable me to dynamically update an image object and then post the updated image to a Tkinter Canvas widget. The code here is prototype code, just to get the basics down. The aim here is to put a blue pixel on the image being displayed by the canvas, at the click location.
Something very strange is going on here. I'm using the Wing IDE, and if I run this code through the debugger, with a breakpoint at any line in the woohoo function, and then continue execution after hitting the breakpoint, the code works exactly as expected- putting a blue pixel on the image. If I run the code normally, or through the debugger with no breakpoints, the image is never updated. This leads me to the conclusion that there is some internal wizardry going on which I haven't got much hope of understanding without aid.
I'd really like to know the best way to go about this (or any way, I guess), and if someone could explain to me what's going on under the hood that'd be really cool. Thanks.
from Tkinter import *
from PIL import Image, ImageTk
def woohoo(event):
original.putpixel((event.x,event.y),(0,0,255))
newpic = ImageTk.PhotoImage(original)
c.create_image((0,0),image=newpic, anchor="nw")
main = Tk()
c = Canvas(main, width=300, height=300)
main.geometry("300x300+0+0")
c.pack()
original = Image.open("asc.bmp")
picture = ImageTk.PhotoImage(original)
c.create_image((0,0),image=picture, anchor="nw")
c.bind("<Button-1>", woohoo)
main.mainloop()
My guess is, you're creating a new image in a function. The reference to the image is a local variable. When the function exits, the reference is garbage collected which causes the new image to be destroyed. Most likely, running interactively causes the garbage collector to run differently (perhaps more lazily?)
Changed a little of the other post to work with Python 3+ :
from tkinter import *
def stuff(event):
global picture3
picture3 = PhotoImage(file='picture2.png')
c.itemconfigure(picture2, image = picture3)
main = Tk()
c = Canvas(main, width=300, height=300)
c.pack()
picture = PhotoImage(file='picture1.png')
picture2 = c.create_image(150,150,image=picture)
c.bind("<Button-1>", stuff)
main.mainloop()
try it like this:
from Tkinter import *
from PIL import Image, ImageTk
def woohoo(event):
global picture #
original.putpixel((event.x,event.y),(0,0,255))
picture = ImageTk.PhotoImage(original)#
c.itemconfigure(myimg, image=picture)#
main = Tk()
c = Canvas(main, width=300, height=300)
main.geometry("300x300+0+0")
c.pack()
original = Image.open("asc.bmp")
picture = ImageTk.PhotoImage(original)
myimg = c.create_image((0,0),image=picture, anchor="nw")#
c.bind("<Button-1>", woohoo)
main.mainloop()
I am experimenting with Tkinter, as I was trying to figure out is there a way to set the tkinter's window size without using canvas. I came upon this how to set frame size question on SO's Question & Answer. So I went ahead and test it by writing a very small program to display a text label. But I found out it is "missing", or disappear when I use frame.pack_propagate(0)
import tkinter as tk
root = tk.Tk()
frame = tk.Frame(root, width=400, height=400)
# Does not work at the moment, textBox is missing
# frame.pack_propagate(0)
frame.pack()
textBox = tk.Label(frame, text="(x,y): ")
textBox.pack()
root.mainloop()
So my question is, can you explain why my textBox (Label) is not appearing when I use the frame.pack_propagate(0) instead of frame.pack() method? And secondly, is there a way to set the window size without using a canvas? I want to know because I am writing a series of small programs to teach my friend about tkinter, before introducing canvas to him. It would be nice if the window size are all the same across my tkinter samples. And I am just wondering as well (curious). Thank you very much.
I am using python 3.2.2 on MAC OS 10.5.8.
pack_propagate only sets a flag, it doesn't cause the frame to be placed in the widget. It is not a substitute for calling pack.
In other words you must do this:
# put the frame in its parent
frame.pack()
# tell frame not to let its children control its size
frame.pack_propagate(0)
# put the textbox in the frame
textBox.pack()
To answer your second question: Yeah, there is a way.
tkinters Tk do have the Tk.geometry function. When you just call it without arguments, you will get the current geometry in form of 'widthxheight+x+y', so for example (on Windows 10) '200x200+26+26' when you create your first Tk window. Using that format you can resize the Tk by, e.g., writing: root.geometry('400x500+60+60') to set the width to 400, the height to 500 and place it at the coordinates (60|60).
This works for Tk alswell as for Toplevel. But Toplevel also takes the arguments height and width when initialized or configured. If you want them to keep their size when packing something inside just use root.pack_propagate(False) on them.
By the way there is something similar for the grid manager: root.grid_propagate(False)
I'm creating a GUI using Tkinter/ttk in Python 2.7, and I'm having an issue where a Frame will resize itself once a widget is placed inside of it. I am new to Python and haven't used Tkinter before.
example:
ROOT = Tk()
FRAME = ttk.Frame(ROOT, width=300, height=300, relief='groove')
FRAME.grid()
ROOT.mainloop()
will produce a grooved frame 300x300, if i place a widget inside it like so:
ROOT = Tk()
FRAME = ttk.Frame(ROOT, width=300, height=300, relief='groove')
BUTTON = ttk.Button(FRAME, text="DON'T READ THIS TEXT")
FRAME.grid()
BUTTON.grid()
ROOT.mainloop()
the frame will shrink down to fit the button. Any way to force the frame not to resize?
To force the frame to keep its original dimensions turn "geometry propagation" off. In your case you would call FRAME.grid_propagate(False).
Speaking as someone with over 15 years of Tk experience, might I suggest that you almost certainly don't need this feature. Tk's ability to "shrink to fit" is really great, and makes it really easy to create GUIs with proper resize behavior. Once you start turning geometry propagation off you'll find you'll either have GUIs with bad resize behavior, or you'll spend a lot of time tweaking sizes and widget placement.
if you want to add padding, then use widg.grid(ipadx=..., ipady=..., padx=..., pady=...)
otherwise, you will need to add more context on what layout you're trying to achieve
This works for me:
app = Application()
app.master.title('Example')
app.master.geometry('640x480')
app.mainloop()
Apllication is Frame in my case with grid layout. It resizes to size of master window, so we need to change size of master window.
This should do the job: ROOT.geometry("640x480")