Python tkinter, canvas don't show - python

The canvas dosen't work for me with tkinter, i got menu working, also toplevel windows but not canvas. Here is my example:
class Interface(Frame):
def __init__(self, master=None):
self.__loadSettings()
Frame.__init__(self,master)
self.m=Menu(self)
menu = Menu(self.m, tearoff=0)
self.m.add_cascade(label="File", menu=menu)
menu.add_command(label="New", command=self.__newGame)
menu = Menu(self.m, tearoff=0)
self.m.add_cascade(label="Edit", menu=menu)
menu.add_command(label="Settings", command=self.__settings)
self.master.config(menu=self.m)
self.canvas= Canvas(self,height=500, width=500)
self.canvas.create_rectangle(100,100,400,400, fill="blue")
root = Tk()
ui = Interface(root)
ui.mainloop()
The windows and menu works, but not the canvas.

The first problem is that you put the canvas in a frame (an instance of Interface) but you never make this frame visible. Since this frame is designed to be the whole UI (I'm assuming), you can do this:
root = Tk()
ui = Interface(root)
ui.pack(side="top", fill="both", expand=True)
ui.mainloop()
Notice that I call pack on the ui object.
That only solves half of the problem. The second problem is that you aren't making the canvas visible in its parent. You can use pack, grid or place for that. Here I use pack:
self.canvas.pack(side="top", fill="both", expand=True)
You seem to have a third problem as well -- you're creating a menu but you aren't causing it to be visible, either. In the case of a menubar, you usually give it as the value of the menu attribute of a root window. In your case you might want to do something like this:
self.master.configure(menu=self.m)

Related

Creating a new window in tkinter that has the same widgets from the root window

I am wanting to create a tkinter window where when I click a button widget it opens a new window, showing all the widgets, exactly the same, from the root/original window. Essentially creating a second instance of the root window, where the application can have multiple users, using the same GUI, in different windows.
Any help is appreciated.
An example of one of my widgets:
summary_output = Text(
master=window,
height=8,
width=78,
bg="gray95",
borderwidth=2,
relief="groove",
font=("Arial", 12))
My window layout
window = Tk()
window.title("Data Viewer")
window.geometry("750x950")
window.configure(bg='white')
window.iconphoto(False, tk.PhotoImage(file='icon.png'))
I have this but cant seem to place the widgets from the root window:
def new_window():
newWindow = Toplevel(window)
newWindow.geometry("750x950")
newWindow.configure(bg='white')
newWindow.iconphoto(False, tk.PhotoImage(file='icon.png'))
upload_button.place(x=20, y=560)
mainloop()
Is their anyway to change the master to be any window?
Edit:
from tkinter import *
class StaticFrame(Frame):
def __init__(self,master,*args,**kwargs):
Frame.__init__(self,master,*args,**kwargs)
# All your widgets
Label(self,text='This is a reusable frame',font=(0,17)).place(x=0, y=0)
Button(self,text='Click me for nothing').pack()
Label(self,text='End of page').pack()
upload_button = Button(
self,
text="Edit Data",
fg="DodgerBlue4",
font=("Graph Type", 15),
height=1, width=12,
borderwidth=2,
relief="groove")
upload_button.place(x=20, y=50)
root = Tk() # First window
top = Toplevel(root) # Second window
root.geometry("750x968")
StaticFrame(root).pack() # Put the frame on the first window
StaticFrame(top).pack() # Put the frame on the second window
root.mainloop()
Result:
The concept used here is simple, create a "custom frame" that we will put onto these new windows, so that it will create the exact same frame, and widgets within it, inside different windows.
from tkinter import *
class StaticFrame(Frame):
def __init__(self,master,*args,**kwargs):
Frame.__init__(self,master,*args,**kwargs)
# All your widgets
Label(self,text='This is a reusable frame',font=(0,17)).pack()
Button(self,text='Click me for nothing').pack()
Label(self,text='End of page').pack()
root = Tk() # First window
top = Toplevel(root) # Second window
StaticFrame(root).pack() # Put the frame on the first window
StaticFrame(top).pack() # Put the frame on the second window
root.mainloop()
Very simple to code and has been explained with comments, if you do not know what classes and inheritance is then first do go through those. There are variety of other methods that come onto mind when I read this question, like even having an option database and storing the widgets in a list and recreating it based on its order, but this seems to be the easiest in a scratch.

Widgets disappear when main window moved off screen

I have a tkinter window that I have given a background picture by creating a Label widget with a PhotoImage instance (referencing the image instance through Label attributing).
However when I run the script and move the main window below the start menu (am using Windows 10) or past the sides of the screens for even one moment, all the widgets packed onto the Label (w/ background pic) completely disappear.
They only come back (somewhat) upon hovering over them with the mouse it seems. Also the background picture remains and continues to fill the screen. Could it be that the background picture Label is being "lifted" and makes it seem like the widgets are disappearing? If so, how can I prevent this from happening?
The fix that I have found for now is to not use a Label with a PhotoImage as the parent "frame", but instead use a typical Frame widget with only a background color, but this is not ideal.
import tkinter as tk
root = tk.Tk()
root.geometry('600x350+600+300')
root.resizable(width=False, height=False)
boxBg = '#666'
frameBg = '#fff'
#problem method
backgroundImg = tk.PhotoImage(file='program_media/background.png')
bgFrame = tk.Label(root, image=backgroundImg)
bgFrame.image = backgroundImg
#less than ideal solution so far
#bgFrame = tk.Frame(root, bg='#fff')
bgFrame.pack(expand=1, fill=tk.BOTH)
mainFrame = tk.Frame(bgFrame)
mainFrame.pack(side=tk.TOP)
title = tk.Label(mainFrame, text='Test String')
title.pack(side=tk.TOP)
#widget creation code packed within mainFrame
#...
#... All these widgets (including mainFrame above) are disappearing
#...
#end of widget creation code
root.mainloop()
See what I mean in this screenshot of BEFORE and AFTER moving the main window below the start menu.

How to move labels from one tab to another in notebook tkinter?

I'm starting to get to know Tkinter but i'm stuck at a point as i'm experimenting and practicing; i couldn't figure out how to move tkinter elements such as Frame or Labels from one tab to another in Tkinter Notebook.
A resourceful link or an answer concerning my problem would be very helpful!
P.S: It's my first time asking a question so apologies if i did something wrong.
It's fairly unusual to move widgets around between frames. Usually it's easiest just to delete the old widget and create a new one in the new location. However, it is possible to move widgets, though with some constraints.
Widgets exist in a tree-like structure, with the root window as the start of the tree. Except for the root window, all other widgets have a parent. You cannot move a widget to a different branch of the tree, so to move from one frame to another, both frames plus the label need to have the same parent.
Normally a widget will be placed in it's parent when using pack, place, or grid. You can change that by using the in_ parameter.
The following example illustrates the technique. Notice that the label to be moved (the_label) is a child of the notebook rather than a child of one of the tabs, and we use the in_ parameter to designate which frame should have the label.
import tkinter as tk
from tkinter import ttk
def moveToOne():
the_label.pack(in_=tab1, expand=True, padx=20, pady=20)
def moveToTwo():
the_label.pack(in_=tab2, expand=True, padx=20, pady=20)
root = tk.Tk()
notebook = ttk.Notebook(root)
toolbar = ttk.Frame(root)
toolbar.pack(side="top", fill="x")
notebook.pack(side="top", fill="both", expand=True)
tab1 = ttk.Frame(notebook)
tab2 = ttk.Frame(notebook)
notebook.add(tab1, text="Tab 1")
notebook.add(tab2, text="Tab 2")
the_label = tk.Label(notebook, text="Click a button to move me")
b1 = tk.Button(toolbar, text="Move to tab 1", command=moveToOne)
b2 = tk.Button(toolbar, text="Move to tab 2", command=moveToTwo)
b1.pack(side="left")
b2.pack(side="left")
# initialize it to be on the first tab
moveToOne()
root.mainloop()

Scrollbar not working on canvas

I'm creating a json editor in python using tkinter.
I've added a scrollbar by creating a Canvas, and putting a Frame inside it.
Then I set the Scrollbar command to canvas.yview.
Theres two things that are messing up, and I have no idea why.
When I press the scroll buttons (up and down arrows) the canvas is not scrolling
I am packing the scrollbar onto the window (root) right now instead of the frame, because whenever i pack it onto the frame, the tkinter application does not open, and my computer fan starts turning on... Anyone know what is going on here? (Therefore the scrollbar is tiny if you try to run the code)
Here is my code:
EDIT> Code shortened
import Tkinter as tk
import webbrowser
import os
import bjson as bj
class App:
def __init__(self, master):
self.window = master
self.window.geometry("800x450")
self.canvas = tk.Canvas(self.window, width=800, height=400)
self.master = tk.Frame(self.canvas, width=800, height=400)
self.canvas.pack()
self.master.place(x=0, y=0)
scrollbar = tk.Scrollbar(self.window)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
scrollbar.config(command=self.canvas.yview)
def init(self):
master = self.master
self.frames = {
"Home": HomeFrame(master)
}
self.openFrame = None
self.loadFrame("Home")
def loadFrame(self, frame):
self.openFrame = self.frames[frame]
self.openFrame.display()
def setTitle(self, t):
self.window.title(t)
class Frame:
def __init__(self, master):
self.master = master
self.frame = tk.Frame(master)
self.frame.grid(row=0, column=0, sticky='news')
self.init()
self.frame_create()
def display(self):
self.frame.tkraise() #raises frame to top
self.frame_load() #initializes the frame
def clear(self):
for widget in self.frame.winfo_children():
widget.destroy()
def init(self): pass
def frame_load(self): pass
def frame_create(self): pass
class HomeFrame(Frame):
def frame_create(self):
p = self.frame
for i in range(20):
tk.Label(p, text="This is content... " + str(i)).pack()
for j in range(2):
LineBreak(p)
def LineBreak(p):
tk.Label(p, text="").pack()
root = tk.Tk()
glob = {}
app = App(root)
app.init()
root.mainloop()
It is a bit long, and a bit messy, but you should see how I'm adding the scrollbar in the __init__ of App
Anyone have any idea what's going on, and how to fix it?
Thanks in advance!
There are many things wrong with your code. However, the problem with the scrollbar not working properly has to do with two things you are neglecting to do:
First, scrollbars and widgets require two way communication. The canvas needs to be told about the scrollbar, and the scrollbar needs to be told about the canvas. You are doing one but not the other:
self.canvas.configure(yscrollcommand=scrollbar.set)
scrollbar.configure(command=self.canvas.yview)
Second, you need to configure the scrollregion attribute of the canvas. This tells tkinter what part of the larger virtual canvas you want to be viewable. Typically this is done in a binding on the <Configure> method of the canvas, and usually you will want to set it to the bounding box of everything in the canvas. For the latter you can pass the string "all" to the bbox method:
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
If you know the exact size of the area you want to be scrollable, you can simply set it to that value (eg: scrollregion=(0,0,1000,1000) to scroll around in a region that is 1000x1000 pixels).
The reason for point #2 is that you can't use both pack and grid for widgets that share the same parent. When you do, you'll get the behavior you describe. That is because grid will try to layout all of the widgets. This may result in some widgets changing size. pack will notice the change in the size of one or more widgets and try to re-layout all of the widgets. This may result in some widgets changing size. grid will notice the change in the size of one or more widgets and try to re-layout all of the widgets. And so on.

Python Tkinter Tix: How to use ScrolledWindow with grid in Tix NoteBook

I'm adding several widgets to a Frame which is located in a tix.NoteBook. When there are too much widgets to fit in the window, I want to use a scrollbar, so I put tix.ScrolledWindow inside that Frame and add my widgets to this ScrolledWindow instead.
The problem is that when using the grid() geometry manager, the scrollbar appears, but it is not working (The drag bar occupies the whole scroll bar).
from Tkinter import *
import Tix
class Window:
def __init__(self, root):
self.labelList = []
self.notebook = Tix.NoteBook(root, ipadx=3, ipady=3)
self.notebook.add('sheet_1', label="Sheet 1", underline=0)
self.notebook.add('sheet_2', label="Sheet 2", underline=0)
self.notebook.add('sheet_3', label="Sheet 3", underline=0)
self.notebook.pack()
#self.notebook.grid(row=0, column=0)
tab1=self.notebook.sheet_1
tab2=self.notebook.sheet_2
tab3=self.notebook.sheet_3
self.myMainContainer = Frame(tab1)
self.myMainContainer.pack()
#self.myMainContainer.grid(row=0, column=0)
scrwin = Tix.ScrolledWindow(self.myMainContainer, scrollbar='y')
scrwin.pack()
#scrwin.grid(row=0, column=0)
self.win = scrwin.window
for i in range (100):
self.labelList.append((Label(self.win)))
self.labelList[-1].config(text= "Bla", relief = SUNKEN)
self.labelList[-1].grid(row=i, column=0, sticky=W+E)
root = Tix.Tk()
myWindow = Window(root)
root.mainloop()
Whenever I change at least one of the geometry managers from pack() to grid(), the problem occurs. (Actually, I'd prefer using grid() for all containers.)
When I don't use the NoteBook widget, the problem does not occur either. The other examples here all seem to rely on pack().
Any ideas?
Many thanks,
Sano
I solved it without using ´tix.scrolledWindow´. Instead, I went for the autoscrollbar suggested by Fred Lundh here.
The main problem was the adaption to the NoteBook widget. First, I tried to put the scrollbar to the root, so that they would surround the whole window. Now, I wanted to change the hook for the scrollbar whenever I changed a tab, but the ´raisecmd´ of the Notebook did not work. Next, I thought of using the configure event on each tab - whenever a new tab is raised, its size changes and configure is called.
Well, after much trying without ever being satisfied I changed my approach and put the scrollbars inside of the tabs. The tabs and all subcontainers must get the ´grid_columnconfigure(0, weight=1)´ and ´grid_rowconfigure(0, weight=1)´ settings, or else they will not grow with the tabs.

Categories