Button doesn't show up tkinter - python

I have a class that represents a Window that contains a canvas, a label and is soon to contain some color-coordinated buttons.
Here is the code:
class Canvas():
def __init__(self, width, height):
self.root = tk.Tk()
self.width = width
self.height = height
self.text_label = tk.Label(self.root, text="10",font=("Times New Roman", 20, "italic"))
self.text_label.pack()
self.canvas = tk.Canvas(master= self.root,width = self.width,height = self.height)
self.canvas.pack()
#======================
self.redBtn = tk.Button(master=self.root,text="hello",command=lambda:self.changeColor("Red"))
self.redBtn.pack()
#======================
self.root.mainloop()
canvas = Canvas(1980,1080)
Although I used redBtn.pack() on the button it doesn't show up.
Does anyone know why?

It worked. I can see number 10. Change this:
win = Window(1980,1080)
to
win = Canvas(1980,900)
So you can see the button on bottom.

Related

How to set a maximum limit for dragging in tkinter PanedWindow?

import tkinter as tk
root = tk.Tk()
my_paned_window = tk.PanedWindow(master=root)
frame1 = tk.Frame(master=my_paned_window, bg='snow')
frame2 = tk.Frame(master=my_paned_window)
tk.Label(master=frame1, text='frame1').pack()
tk.Label(master=frame2, text='frame2').pack()
my_paned_window.add(frame1)
my_paned_window.add(frame2)
my_paned_window.pack(fill=tk.BOTH)
root.mainloop()
In the above code, I don't want the frame1 to expand too much when dragged. How can I set a limit for this?
There are no straightforward ways to do this. You can achieve this either by setting minsize for frame2.
Something like this:
...
my_paned_window.add(frame1)
my_paned_window.add(frame2, minsize=550)
...
Another way is to return "break" when the sash position is greater than the max-width so it no longer can be moved.
minimal example:
import tkinter as tk
class PanedWindow(tk.PanedWindow):
def __init__(self, *args, **kwargs):
super(PanedWindow, self).__init__(*args, **kwargs)
self.max_width = {}
self.bind("<B1-Motion>", self.check_width)
self.bind("<ButtonRelease-1>", self.set_width)
def add(self, child, max_width=None, *args):
super(PanedWindow, self).add(child, *args)
self.max_width[child] = max_width
def check_width(self, event):
for widget, width in self.max_width.items():
if width and widget.winfo_width() >= width:
self.paneconfig(widget, width=width)
return "break"
def set_width(self, event):
for widget, width in self.max_width.items():
if width and widget.winfo_width() >= width:
self.paneconfig(widget, width=width-1)
root = tk.Tk()
my_paned_window = PanedWindow(master=root, sashwidth=5)
max_width = 500
frame1 = tk.Frame(master=my_paned_window, bg='red')
frame2 = tk.Frame(master=my_paned_window, bg='blue')
frame3 = tk.Frame(master=my_paned_window, bg="green")
tk.Label(master=frame1, text='frame1').pack()
tk.Label(master=frame2, text='frame2').pack()
my_paned_window.add(frame1, max_width=500)
my_paned_window.add(frame2)
my_paned_window.pack(fill=tk.BOTH, expand=True)
root.mainloop()

Having difficulties placing a frame within a frame with Tkinter

I am having issues trying to place a frame within a frame using classes/objects with python/tkinter. My goal is to simply place a frame in the north west corner of the outer frame instead of the whole window itself. I think I'm incorrectly referencing the outer frame in the inner frame class but I'm not 100% sure. I am fairly new to OOP and tkinter so forgive my ignorance and I appreciate the help.
Sample code:
from tkinter import *
class window():
def __init__(self, master):
self.master = master.minsize(500, 500)
master.maxsize(500,500)
self.outer_frame = Frame(master, width = 250, height = 250, bg = "red").place(anchor = CENTER, relx = 0.5, rely = 0.5)
def create_inner_window(self):
self.inner_frame = inner_frame(self.outer_frame)
class inner_frame():
def __init__(self, outer_frame):
self.inner_frame = Frame(master = outer_frame, width = 125, height = 125, bg = "blue").place(anchor = NW)
root = Tk()
my_window = window(root)
my_window.create_inner_window()
root.mainloop()
What I'm trying to accomplish:
What I get instead:

Tkinter <enter> and <leave> Events Not Working Properly

Forgive me in advance for my code, but I'm simply making this for friend of mine to automatically populate a GUI interface with song information, channel information for each song, and things such as images attached to the songs. Right now I'm only scraping from a playlist on Youtube and a playlist on Soundcloud. I have all of that properly working, but me being new to frontend development left me in a horrible spot to make a decent application for him. I had a lot in mind that I could have done, but now I'm simply creating buttons with each song title as the text. Here is an image of my progress. I still have to find a way to attach each image to each button for the on_enter event, but that is for later on. As you can see, I have a on_leave function commented out. I was using that to delete the self.image_window each time I left a button. Problem is even a minuscule amount of mouse movement would cause the window to be delete and recreated dozens of times. How do I make it static so when I am hovering over a button it doesn't spam create/delete the window?
Thanks!
from Tkinter import *
import json
import os
import webbrowser
class GUIPopulator(Frame):
def __init__(self, parent):
Frame.__init__(self)
self.parent = parent
self.configure(bg='PeachPuff2')
self.columnconfigure(20, weight=1)
self.rowconfigure(30, weight=1)
self.curtab = None
self.tabs = {}
self.pack(fill=BOTH, expand=1, padx=5, pady=5)
self.column = 0
self.row = 0
def on_enter(self, event):
self.image_window = Toplevel(self)
self.img_path = os.getcwd() + '/Rotating_earth_(large).gif'
self.img = PhotoImage(file=self.img_path)
#self.image_window.minsize(width=200, height=250)
self.image_window.title("Preview")
canvas = Canvas(self.image_window, width=200, height=200)
canvas.pack()
canvas.create_image(100, 100, image=self.img)
#def on_leave(self, enter):
def addTab(self, id):
tabslen = len(self.tabs)
tab = {}
if self.row < 30:
btn = Button(self, text=id,highlightbackground='PeachPuff2' ,command=lambda: self.raiseTab(id))
btn.grid(row=self.row, column=self.column, sticky=W+E)
btn.bind("<Enter>", self.on_enter)
#btn.bind("<Leave>", self.on_leave)
tab['id']=id
tab['btn']=btn
self.tabs[tabslen] = tab
self.raiseTab(id)
self.row +=1
else:
self.row = 0
self.column +=1
btn = Button(self, text=id,highlightbackground='PeachPuff2' ,command=lambda: self.raiseTab(id))
btn.grid(row=self.row, column=self.column, sticky=W+E)
tab['id']=id
tab['btn']=btn
self.tabs[tabslen] = tab
self.raiseTab(id)
def raiseTab(self, tabid):
with open(os.getcwd() + '/../PlaylistListener/CurrentSongs.json') as current_songs:
c_songs = json.load(current_songs)
print(tabid)
if self.curtab!= None and self.curtab != tabid and len(self.tabs)>1:
try:
#webbrowser.open(c_songs[tabid]['link'])
webbrowser.open_new('http://youtube.com')
except:
pass
def main():
root = Tk()
root.title('Playlist Scraper')
root.geometry("1920x1080+300+300")
t = GUIPopulator(root)
with open(os.getcwd() + '/../PlaylistListener/CurrentSongs.json') as current_songs:
c_songs = json.load(current_songs)
for song in c_songs:
t.addTab(song)
root.mainloop()
if __name__ == '__main__':
main()
Example of JSON file provided:
{
"F\u00d8RD - Shadows (feat. Samsaruh)": {
"page_title": "youtube",
"link": "youtube.com/watch?v=CNiV6Pne50U&index=32&list=PLkx04k4VGz1tH_pnRl_5xBU1BLE3PYuzd",
"id": "CNiV6Pne50U",
"channel": "youtube.com/watch?v=CNiV6Pne50U&index=32&list=PLkx04k4VGz1tH_pnRl_5xBU1BLE3PYuzd",
"image_path": [
"http://i4.ytimg.com/vi/CNiV6Pne50U/hqdefault.jpg",
"CNiV6Pne50U.jpg"
]
},
"Katelyn Tarver - You Don't Know (tof\u00fb remix)": {
"page_title": "youtube",
"link": "youtube.com/watch?v=7pPNv38JzD4&index=43&list=PLkx04k4VGz1tH_pnRl_5xBU1BLE3PYuzd",
"id": "7pPNv38JzD4",
"channel": "youtube.com/watch?v=7pPNv38JzD4&index=43&list=PLkx04k4VGz1tH_pnRl_5xBU1BLE3PYuzd",
"image_path": [
"http://i4.ytimg.com/vi/7pPNv38JzD4/hqdefault.jpg",
"7pPNv38JzD4.jpg"
]
},
"Illenium - Crawl Outta Love (feat. Annika Wells)": {
"page_title": "youtube",
"link": "youtube.com/watch?v=GprXUDZrdT4&index=7&list=PLkx04k4VGz1tH_pnRl_5xBU1BLE3PYuzd",
"id": "GprXUDZrdT4",
"channel": "youtube.com/watch?v=GprXUDZrdT4&index=7&list=PLkx04k4VGz1tH_pnRl_5xBU1BLE3PYuzd",
"image_path": [
"http://i4.ytimg.com/vi/GprXUDZrdT4/hqdefault.jpg",
"GprXUDZrdT4.jpg"
]
}
}
After some testing I have come up with some code I think you can use or is what you are looking for.
I have changes a few things and add some others.
1st we needed to create a place holder for the top window that we can use later in the code. So in the __init__ section of GUIPopulatior add self.image_window = None. We will talk about this part soon.
next I created the image path as a class attribute on init this can be changed later with update if need be.
next I added a bind() to the init that will help us keep the self.image_window placed in the correct location even if we move the root window. so we add self.parent.bind("<Configure>", self.move_me) to the __init__ section as well.
next we create the method move_me that we just created a bind for.
the way it is written it will only take effect if self.image_window is not equal to None this should prevent any errors while self.image_window is being used however I have not created the error handling to deal with what happens after the toplevel window is closed by the user. Its not difficult but I wanted to answer for the main issue at hand.
Here is the move_me method:
def move_me(self, event):
if self.image_window != None:
h = self.parent.winfo_height() # gets the height of the window in pixels
w = self.parent.winfo_width() # gets the width of the window in pixels
# gets the placement of the root window then uses height and width to
# calculate where to place the window to keep it at the bottom right.
self.image_window.geometry('+{}+{}'.format(self.parent.winfo_x() + w - 250,
self.parent.winfo_y() + h - 250))
next we need to modify the on_enter method to create the toplevel window if out class attribute self.image_window is equal to None if it is not equal to None then we can use the else portion of the if statement to just update the image.
Here is the modified on_enter method:
def on_enter(self, event):
if self.image_window == None:
self.image_window = Toplevel(self)
#this keeps the toplevel window on top of the program
self.image_window.attributes("-topmost", True)
h = self.parent.winfo_height()
w = self.parent.winfo_width()
self.image_window.geometry('+{}+{}'.format(self.parent.winfo_x() + w - 250,
self.parent.winfo_y() + h - 250))
self.img = PhotoImage(file=self.img_path)
self.image_window.title("Preview")
self.canvas = Canvas(self.image_window, width=200, height=200)
self.canvas.pack()
self.canv_image = self.canvas.create_image(100, 100, image=self.img)
else:
self.img = PhotoImage(file= self.img_path)
self.canvas.itemconfig(self.canv_image, image = self.img)
all that being said there are some other issues with your code that need to be addressed however this answer should point you in the right direction.
Below is a section of your code you need to replace:
class GUIPopulator(Frame):
def __init__(self, parent):
Frame.__init__(self)
self.parent = parent
self.configure(bg='PeachPuff2')
self.columnconfigure(20, weight=1)
self.rowconfigure(30, weight=1)
self.curtab = None
self.tabs = {}
self.pack(fill=BOTH, expand=1, padx=5, pady=5)
self.column = 0
self.row = 0
def on_enter(self, event):
self.image_window = Toplevel(self)
self.img_path = os.getcwd() + '/Rotating_earth_(large).gif'
self.img = PhotoImage(file=self.img_path)
#self.image_window.minsize(width=200, height=250)
self.image_window.title("Preview")
canvas = Canvas(self.image_window, width=200, height=200)
canvas.pack()
canvas.create_image(100, 100, image=self.img)
#def on_leave(self, enter):
With this:
class GUIPopulator(Frame):
def __init__(self, parent):
Frame.__init__(self)
self.parent = parent
self.configure(bg='PeachPuff2')
self.columnconfigure(20, weight=1)
self.rowconfigure(30, weight=1)
self.curtab = None
self.image_window = None
self.img_path = os.getcwd() + '/Rotating_earth_(large).gif'
self.tabs = {}
self.pack(fill=BOTH, expand=1, padx=5, pady=5)
self.parent.bind("<Configure>", self.move_me)
self.column = 0
self.row = 0
def move_me(self, event):
if self.image_window != None:
h = self.parent.winfo_height()
w = self.parent.winfo_width()
self.image_window.geometry('+{}+{}'.format(self.parent.winfo_x() + w - 250,
self.parent.winfo_y() + h - 250))
def on_enter(self, event):
if self.image_window == None:
self.image_window = Toplevel(self)
self.image_window.attributes("-topmost", True)
h = self.parent.winfo_height()
w = self.parent.winfo_width()
self.image_window.geometry('+{}+{}'.format(self.parent.winfo_x() + w - 250,
self.parent.winfo_y() + h - 250))
self.img = PhotoImage(file=self.img_path)
self.image_window.title("Preview")
self.canvas = Canvas(self.image_window, width=200, height=200)
self.canvas.pack()
self.canv_image = self.canvas.create_image(100, 100, image=self.img)
else:
self.img = PhotoImage(file= self.img_path)
self.canvas.itemconfig(self.canv_image, image = self.img)

Python/Tkinter: expanding fontsize dynamically to fill frame

I know you can get frame widgets to expand and fill all of the area available to them in their container via these commands: frameName.pack(fill = 'both', expand = True)
What would do the same for a text's font size? Currently my text is an attribute of a label widget. The label widget's parent is frameName.
I guess I could define my own function to call labelName.config(fontsize = N) to update the font size as the frame get's bigger, but I'm not sure how to correlate them.
This is what my program looks like right now:
Each of those blocks is a frame widget. I'd like the text to expand to fill up in some capacity the frame, and respond to resizing of the window as well.
You can use tkFont.font
When you initialize the label set the font to a variable such as:
self.font = SOME_BASE_FONT
self.labelName.config(font = self.font)
Then you can use:
self.font = tkFont.Font(size = PIXEL_HEIGHT)
This you can scale to the height of the label. You can bind a '<Configure>' Event to the widget, and make your callback function adjust the label size.
frameName.bind('<Configure>', self.resize)
def resize(self, event):
self.font = tkFont(size = widget_height)
For more info see the documentation here.
I've been trying to figure out how to get the text to automatically resize in tkinter.
The key to getting it working for me was to assign the calculated height to the size in the custom font object. Like so: self.label_font['size'] = height
Full example:
from tkinter import font
import tkinter as tk
class SimpleGUIExample:
def __init__(self, master):
self.master = master
self.master.title("A simple Label")
self.master.bind('<Configure>', self.resize)
self.label_font = font.Font(self.master, family='Arial', size=12, weight='bold')
self.label = tk.Label(self.master, text="Simple Label Resizing!")
self.label.config(font=self.label_font)
self.label.pack(fill=tk.BOTH, expand=tk.YES)
self.close_button = tk.Button(self.master, text="Close", command=master.quit)
self.close_button.pack()
def resize(self, event):
height = self.label.winfo_height()
width = self.label.winfo_width()
height = height // 2
print('height %s' % height)
print('width %s' % width)
if height < 10 or width < 200:
height = 10
elif width < 400 and height > 20:
height = 20
elif width < 600 and height > 30:
height = 30
else:
height = 40
print('height %s' % height)
self.label_font['size'] = height
print(self.label_font.actual())
root = tk.Tk()
simple_gui = SimpleGUIExample(root)
root.mainloop()

Centering and size a windows frame in Tkinter class python

I want to center a window frame ad set a size using a ratio according to screensize. But I cannot see where to modify my code correctly to perform such program. My program is the following example :
class App:
def __init__(self,master):
ScreenSizeX = master.winfo_screenwidth() # Get screen width [pixels]
ScreenSizeY = master.winfo_screenheight() # Get screen height [pixels]
ScreenRatio = 0.8 # Set the screen ratio for width and height
FrameSizeX = int(ScreenSizeX * ScreenRatio)
FrameSizeY = int(ScreenSizeY * ScreenRatio)
FramePosX = (ScreenSizeX - FrameSizeX)/2 # Find left and up border of window
FramePosY = (ScreenSizeY - FrameSizeY)/2
print FrameSizeX,FrameSizeY,FramePosX,FramePosY
#geometry(str(self.winfo_screenwidth())+"x"+str(self.winfo_screenheight())+"+0+0")
frame = Tkinter.Frame(master)
frame.pack()
self.button = Tkinter.Button(frame,text="Quit",fg="red",command=frame.quit)
self.button.pack()
self.hi_there = Tkinter.Button(frame,text="Hi!",command=self.say_hi)
self.hi_there.pack()
def say_hi(self):
print "hello !"
if __name__ == "__main__":
root = Tkinter.Tk()
app = App(root)
root.mainloop()
Why did you comment out the geometry line? It's quite close to what you need really. Try this:
master.geometry("%sx%s+%s+%s" % (FrameSizeX,FrameSizeY,FramePosX,FramePosY))
This is the final code working for this feature :
import Tkinter #Python integrated tool kit for interfaces
class App:
def __init__(self,master):
# Define frame size and position in the screen :
ScreenSizeX = master.winfo_screenwidth() # Get screen width [pixels]
ScreenSizeY = master.winfo_screenheight() # Get screen height [pixels]
ScreenRatio = 0.8 # Set the screen ratio for width and height
FrameSizeX = int(ScreenSizeX * ScreenRatio)
FrameSizeY = int(ScreenSizeY * ScreenRatio)
FramePosX = (ScreenSizeX - FrameSizeX)/2 # Find left and up border of window
FramePosY = (ScreenSizeY - FrameSizeY)/2
master.geometry("%sx%s+%s+%s"%(FrameSizeX,FrameSizeY,FramePosX,FramePosY))
frame = Tkinter.Frame(master)
frame.pack()
self.button = Tkinter.Button(frame,text="Quit",fg="red",command=frame.quit)
self.button.pack()
self.hi_there = Tkinter.Button(frame,text="Hi!",command=self.say_hi)
self.hi_there.pack()
def say_hi(self):
print "hello !"
if __name__ == "__main__":
root = Tkinter.Tk()
app = App(root)
root.mainloop()

Categories

Resources