I am trying to showcase tables of monday and tuesday however the canvas rectangles seem to keep a very large gap between them.Is it possible to not have any gaps at all or have a very minimal gap?
class SmokingPlan:
def __init__(self, master):
self.master = master
self.master.title('Kill Smoking')
self.master.geometry("1200x1200")
#Monday
canvas_monday = Canvas(self.master)
canvas_monday.grid(row = 0, column = 3)
canvas_monday.create_rectangle(10,10, 150, 200)
canvas_monday.create_text(60,25, text = "Monday")
#Tuesday
canvas_tuesday = Canvas(self.master)
canvas_tuesday.grid(row=0, column = 5)
canvas_tuesday.create_rectangle(10,10, 150, 200)
canvas_tuesday.create_text(60,25, text = "Tuesday")
You are drawing two Canvas widgets. The Canvas widget has a default size. By changing the color of your canvas you will see why you have a gap in between.
import tkinter as tk
class SmokingPlan:
def __init__(self, master):
self.master = master
self.master.title('Kill Smoking')
self.master.geometry("1200x1200")
#Monday
canvas_monday = tk.Canvas(self.master, bg="blue")
canvas_monday.grid(row = 0, column = 0)
canvas_monday.create_rectangle(10,10, 150, 200)
canvas_monday.create_text(60,25, text = "Monday")
#Tuesday
canvas_tuesday = tk.Canvas(self.master, bg="yellow")
canvas_tuesday.grid(row=0, column = 1)
canvas_tuesday.create_rectangle(10,10, 150, 200)
canvas_tuesday.create_text(60,25, text = "Tuesday")
if __name__ == '__main__':
root = tk.Tk()
app = SmokingPlan(root)
root.mainloop()
Now you could set smaller canvas size or even better put both rectangles in the same canvas and change the coords.
Set Canvas size example:
canvas_monday = tk.Canvas(self.master, bg="blue", width=200)
will shrink your monday canvas as follow:
Related
So I've been using the canvas widget in tkinter to create a frame full of labels which has a scrollbar. All is working good except that the frame only expands to the size of the labels placed in it - I want the frame to expand to the size of the parent canvas.
This can easily be done if I use pack(expand = True) (which I have commented out in the code below) for the frame in the canvas but then then the scrollbar doesn't work.
Here's the appropriate bit of code:
...
self.canvas = Canvas(frame, bg = 'pink')
self.canvas.pack(side = RIGHT, fill = BOTH, expand = True)
self.mailbox_frame = Frame(self.canvas, bg = 'purple')
self.canvas.create_window((0,0),window=self.mailbox_frame, anchor = NW)
#self.mailbox_frame.pack(side = LEFT, fill = BOTH, expand = True)
mail_scroll = Scrollbar(self.canvas, orient = "vertical",
command = self.canvas.yview)
mail_scroll.pack(side = RIGHT, fill = Y)
self.canvas.config(yscrollcommand = mail_scroll.set)
self.mailbox_frame.bind("<Configure>", self.OnFrameConfigure)
def OnFrameConfigure(self, event):
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
I've also provided an image with colored frames so you can see what I'm getting at. The pink area is the canvas that needs filling by the mailbox_frame (You can see the scrollbar on the right):
Just for future reference in case anyone else needs to know:
frame = Frame(self.bottom_frame)
frame.pack(side = LEFT, fill = BOTH, expand = True, padx = 10, pady = 10)
self.canvas = Canvas(frame, bg = 'pink')
self.canvas.pack(side = RIGHT, fill = BOTH, expand = True)
self.mailbox_frame = Frame(self.canvas, bg = 'purple')
self.canvas_frame = self.canvas.create_window((0,0),
window=self.mailbox_frame, anchor = NW)
#self.mailbox_frame.pack(side = LEFT, fill = BOTH, expand = True)
mail_scroll = Scrollbar(self.canvas, orient = "vertical",
command = self.canvas.yview)
mail_scroll.pack(side = RIGHT, fill = Y)
self.canvas.config(yscrollcommand = mail_scroll.set)
self.mailbox_frame.bind("<Configure>", self.OnFrameConfigure)
self.canvas.bind('<Configure>', self.FrameWidth)
def FrameWidth(self, event):
canvas_width = event.width
self.canvas.itemconfig(self.canvas_frame, width = canvas_width)
def OnFrameConfigure(self, event):
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
Set a binding on the canvas <Configure> event, which fires whenever the canvas changes size. From the event object you can get the canvas width and height, and use that to resize the frame.
Just an updated answer which covers both horizontal and vertical scrollbars without breaking them.
def FrameWidth(self, event):
if event.width > self.mailbox_frame.winfo_width():
self.canvas.itemconfig(self.canvas_frame, width=event.width-4)
if event.height > self.mailbox_frame.winfo_height():
self.canvas.itemconfig(self.canvas_frame, height=event.height-4)
Only sets the frame height and width if they are less than the canvas width. Respects both Horizontal and Vertical scrollbars.
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'm quite new to Tkinter and this is my first program, can anyone tell me why the canvas is not showing up? I'm not getting any errors so I assume it is working but just not visible? I tried moving it up a layer but it was still invisible. Here is my code:
from Tkinter import *
import Tkinter as tk
class Application(Frame):
def __init__(self, master):
Frame.__init__(self, master)
self.frame = Frame(self.master)
self.master = master
self.window()
self.drawFigure()
# self.master.attributes('-fullscreen', True)
self.master.bind("<Escape>", self.end_fullscreen)
def window(self):
self.frame = Frame(self.master)
screen_width = self.frame.winfo_screenwidth() / 2
screen_height = self.frame.winfo_screenheight() / 2
self.master.geometry('%dx%d' % (screen_width, screen_height))
def end_fullscreen(self, event=None):
self.master.attributes("-fullscreen", False)
def drawFigure(self):
self.frame = Frame(self.master)
self.C = Canvas(self.frame, width=200, height=200, bg = 'red')
self.C.pack()
self.C.create_rectangle(50, 20, 150, 80, fill="#476042")
if __name__ == '__main__':
root = tk.Tk()
w = Application(root)
w.master.mainloop()
Appreciate all the input.
You import Tkinter and Tkinter as tk, which gets confusing.
Application inherits from Frame so you don't have to create additional frames inside. Certainly not more than one named self.frame.
How about this:
from Tkinter import *
class Application(Frame):
def __init__(self, master):
Frame.__init__(self, master)
self.master = master
self.pack()
self.window()
self.drawFigure()
self.master.bind("<Escape>", self.end_fullscreen)
def window(self):
screen_width = self.winfo_screenwidth() / 2
screen_height = self.winfo_screenheight() / 2
self.master.geometry('%dx%d' % (screen_width, screen_height))
def end_fullscreen(self, event=None):
self.master.attributes("-fullscreen", False)
def drawFigure(self):
self.C = Canvas(self, width=200, height=200, bg = 'red')
self.C.pack()
self.C.create_rectangle(50, 20, 150, 80, fill="#476042")
if __name__ == '__main__':
root = Tk()
w = Application(root)
w.master.mainloop()
You forgot to call pack() on the Frame you created in drawFigure():
def drawFigure(self):
self.frame = Frame(self.master)
self.frame.pack() # <--- There
self.C = Canvas(self.frame, width=200, height=200, bg = 'red')
self.C.pack()
self.C.create_rectangle(50, 20, 150, 80, fill="#476042")
You’re creating three sub frames of your parent, storing each of them as self.frame (so all but the last one are lost), and not placing any of them anywhere.
So, you’ve correctly placed the canvas on one of these invisible frames, but that doesn’t do any good.
I’m not sure what you’re trying to do with all these separate frames.
If you really need three sibling frames, you have to store them in separate variables, or in a list, or something, and you need to place them.
If you need one sibling frame, just create it once instead of three times, and again, you need to place it.
If you need three or one child frames instead of sibling frames, create them with self rather than self.master.
If you don’t need any sibling or child frames at all, don’t create them, and just place the canvas on self instead of self.frame.
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
I am trying to create buttons in a program to take the user to other screens. I have created the images on labels but not sure on how to make them into functioning buttons that take users to another page. You can see in my code the 2 buttons i need are the search quote and new quote. Thank you
from tkinter import *
class Window():
def __init__(self,master): #constructor
self.master = master
self.master.title("Borras Roofing Quotation System") #sets title of window
self.master.geometry("2160x1440") #sets size of window
self.master.configure(background = "white") # sets background colour of window.
self.Borras = PhotoImage(file = "Borras.Logo.PNG") #sets up image
self.BorrasLabel = Label(self.master, image = self.Borras, bg = "white", width='1000', height= '500') #puts image onto label
self.BorrasLabel.pack()
self.newquote = PhotoImage(file = "Process_New_Quote_Button.PNG") #sets up image
self.newquoteLabel = Label(self.master, image = self.newquote, bg = "white") #puts image onto label
self.newquoteLabel.place(x = 200, y = 500)
self.searchquote = PhotoImage(file = "Search_Current_Quote_Button.PNG") #sets up image
self.searchquoteLabel = Label(self.master, image = self.searchquote, bg = "white") #puts image onto label
self.searchquoteLabel.place(x = 800, y = 500)
root = Tk()
userPassWindow = Window(root)
root.mainloop()
You can use the inheritance and make each window child of the Toplevel widget.
Example:
from Tkinter import *
class search(Toplevel):
# Just inherits TopLevel window
def __init__(self, parent, master=None):
Toplevel.__init__(self, master)
#Save parent reference to modify parent view from search view
self.parent = parent
class quote(Toplevel):
def __init__(self, parent, master=None):
self.parent = parent
Toplevel.__init__(self, master)
class Window():
def __init__(self,master): #constructor
self.master = master
self.master.title("Borras Roofing Quotation System") #sets title of window
self.master.geometry("400x440") #sets size of window
self.master.configure(background = "white") # sets background colour of window.
self.Borras = PhotoImage(file = "Borras.Logo.PNG") #sets up image
self.BorrasLabel = Label(self.master, image = self.Borras, bg = "white") #puts image onto label
self.BorrasLabel.place(x = 10, y = 50)
self.newquote = PhotoImage(file = "Process_New_Quote_Button.PNG") #sets up image
self.newquoteLabel = Label(self.master, image = self.newquote, bg = "white") #puts image onto label
self.newquoteLabel.place(x = 150, y = 50)
self.searchquote = PhotoImage(file = "Search_Current_Quote_Button.PNG") #sets up image
self.searchquoteLabel = Label(self.master, image = self.searchquote, bg = "white") #puts image onto label
self.searchquoteLabel.place(x = 300, y = 50)
search_quote = Button(text="Search quote", command=self.search)
quote = Button(text="Quote", command=self.quote)
search_quote.pack()
quote.pack()
def search(self):
#Pass parent reference 'self'
search(self)
def quote(self):
quote(self)
root = Tk()
userPassWindow = Window(root)
root.mainloop()
For a start you need to use instances of Button, not Label if you want to achieve anything by clicking on it. If you add
command = anyfunction
as an argument to a button then the function will be run when the button is pressed (the function can be declared either inside or outside the Class, depending on what scope you want). From there use the
.pack_forget()
or
.place_forget()
procedure to remove items (though this does NOT delete them) and pack, place or grid the new items in your "window". If you are looking for actual screens to pack and forget pack then you should use tkinter Frames. Here is a useful link that will show you how to use each widget correctly:
http://effbot.org/tkinterbook