I need help on this. I'm just started to learn Tkinter and I have some difficulties to do this:
Image: Main window with a new window
Basically, what I want is to do is to create a frame in the main window (root or master) that pop-out initially. This frame will contain labels and buttons; besides, it will be above other labels and buttons. Similar to the image I posted. I tried to achieve this by creating a new window but the new window comes with title, minimize, maximize and close button which it is something I do not want. I want to achieve I similar result like the image I posted. Thank you in advance.
If you do not need a floating window, you can just create a frame and use place to place it in the center of the window.
Here's a basic example:
import tkinter as tk
class Popout(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent, background="black", padx=10, pady=10)
title = tk.Label(self, text="How to play", font=("Helvetica", 16), anchor="w",
background="black", foreground="white")
instructions = tk.Label(self, text="The goal of Klondike is to blah blah blah...",
background="black", foreground="white", anchor="w")
cb = tk.Checkbutton(self, text="Do not show again", highlightthickness=0,
background="black", foreground="white")
oneof = tk.Label(self, text="1 of 6", background="black", foreground="white")
close_btn = tk.Button(self, text="Close", background="black", foreground="white")
next_btn = tk.Button(self, text="Next", background="black", foreground="white")
self.grid_columnconfigure(0, weight=1)
self.grid_rowconfigure(1, weight=1)
title.grid(row=0, column=0, columnspan=2, sticky="ew")
oneof.grid(row=0, column=2, sticky="ne")
instructions.grid(row=1, column=0, columnspan=3, sticky="nsew", pady=10)
cb.grid(row=2, column=0, sticky="w")
close_btn.grid(row=3, column=1, sticky="ew", padx=10)
next_btn.grid(row=3, column=2, sticky="ew")
root = tk.Tk()
root.geometry("600x400")
p = Popout(root)
p.place(relx=.5, rely=.5, anchor="center")
root.mainloop()
Related
I'm making a game based off of the periodic table with tkinter. I made the particle frame just fine, so I decided to copy the code and reuse it for the element frame, changing only the variable names. But for some reason, even though the particle frame works just fine, nothing shows up for the element frame. Here is my full code:
# Boilerplate
import random
import periodictable as pt
from tkinter import *
root = Tk()
root.title('Periodic Table Game')
root.geometry('350x250')
LightBlue = "#b3c7d6"
Menu = Frame(root)
elementFrame = Frame(root)
particleFrame = Frame(root)
settingsFrame = Frame(root)
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
for AllFrames in (Menu, elementFrame, particleFrame, settingsFrame):
AllFrames.grid(row=0, column=0, sticky='nsew')
AllFrames.configure(bg=LightBlue)
def show_frame(frame):
frame.tkraise()
show_frame(Menu)
# Menu Frame
Menu.grid_columnconfigure(0, weight=1)
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
MenuTitle = Label(Menu, text="Periodic Table Game", font=("Arial", 15), bg=LightBlue)
MenuTitle.grid(row=0, column=0, pady=25)
MenuTitle.grid_rowconfigure(1, weight=1)
MenuTitle.grid_columnconfigure(1, weight=1)
MenuButton1 = Button(Menu, width=25, text="Guess The Particles", command=lambda: show_frame(particleFrame))
MenuButton1.grid(row=1, column=0)
MenuButton2 = Button(Menu, width=25, text="Guess The Element Name", command=lambda: show_frame(elementFrame))
MenuButton2.grid(row=2, column=0, pady=5)
SettingsButton = Button(Menu, width=25, text="Settings", command=lambda: show_frame(settingsFrame))
SettingsButton.grid(row=3, column=0)
# Particle Frame
particleFrame.grid_columnconfigure(0, weight=1)
BackButtonF2 = Button(particleFrame, text='Back', command=lambda: show_frame(Menu))
BackButtonF2.grid(row=0, column=0, sticky=W)
ParticleLabel = Label(particleFrame, text='testing', bg=LightBlue)
ParticleLabel.grid(row=1, column=0, pady=15)
ParticleEntry = Entry(particleFrame)
ParticleEntry.grid(row=2, column=0, pady=10)
ParticleEnter = Button(particleFrame, text='Enter', width=10)
ParticleEnter.grid(row=3, column=0, pady=10)
# Element Frame
elementFrame.grid_columnconfigure(0, weight=1)
BackButtonF3 = Button(particleFrame, text='Back', command=lambda: show_frame(Menu))
BackButtonF3.grid(row=0, column=0, sticky=W)
ElementLabel = Label(particleFrame, text='testing', bg=LightBlue)
ElementLabel.grid(row=1, column=0, pady=15)
ElementEntry = Entry(particleFrame)
ElementEntry.grid(row=2, column=0, pady=10)
ElementEnter = Button(particleFrame, text='Enter', width=10)
ElementEnter.grid(row=3, column=0, pady=10)
root.mainloop()
Why does identical code work only with one frame?
Precisely, because you copied the code you don't spot where the issue is.
When you are defining the element frame widgets you are placing them all into particleFrame.
Example:
BackButtonF3 = Button(particleFrame, text='Back', command=lambda: show_frame(Menu))
should be
BackButtonF3 = Button(elementFrame, text='Back', command=lambda: show_frame(Menu))
Your problem will be solved.
Change this particleFrame, to elementFrame
snippet code:
BackButtonF3 = Button(elementFrame, text='Back', command=lambda: show_frame(Menu))
BackButtonF3.grid(row=0, column=0, sticky=W)
ElementLabel = Label(elementFrame, text='testing', bg=LightBlue)
ElementLabel.grid(row=1, column=0, pady=15)
ElementEntry = Entry(elementFrame)
ElementEntry.grid(row=2, column=0, pady=10)
ElementEnter = Button(elementFrame, text='Enter', width=10)
ElementEnter.grid(row=3, column=0, pady=10)
Screenshot before:
Screenshot after same as elementFrame and particleFrame:
I have packaged a group a widgets into a single widget as follows:
class RunOptions(tk.Frame):
def __init__(self, master=None):
super().__init__(master, bg='green')
self.label = tk.Label(self, text='Options:')
self.folder_button_label = tk.Label(self, text='Select a Folder', bg='white')
self.folder_button = tk.Button(self, text='Select Image Folder')
self.template_button = tk.Button(self, text='Select Template')
self.template_frame = ImageCanvas(self, height=64, width=64)
self.label.grid(row=0, sticky='W')
self.folder_button.grid(row=1, column=1, sticky='W')
self.folder_button_label.grid(row=1, column=0, sticky='W')
self.template_button.grid(row=2, column=1, sticky='W')
self.template_frame.grid(row=2, column=0, sticky='W')
and
class DetectionCanvas(tk.Frame):
def __init__(self, master=None):
super().__init__(master)
self.xml_var = tk.IntVar()
self.detectframe = ImageCanvas(self, label='Detection:', height=175, width=175)
self.x_out = tk.Label(self, bg='white', text='X:', anchor='w')
self.y_out = tk.Label(self, bg='white', text='Y:', anchor='w')
self.w_out = tk.Label(self, bg='white', text='W:', anchor='w')
self.h_out = tk.Label(self, bg='white', text='H:', anchor='w')
self.xml_check = tk.Checkbutton(self, text=' Save XML File',variable=self.xml_var)
self.detectframe.grid(row=0, column=0, rowspan=4)
self.x_out.grid(row=0, column=1)
self.y_out.grid(row=1, column=1)
self.w_out.grid(row=2, column=1)
self.h_out.grid(row=3, column=1)
self.xml_check.grid(row=4, column=0, sticky='w')
def display_out(self, *args):
pass
both of these widgets are all arranged in a large empty canvas (purple) using grid, but that doesn't matter here because the issue is in the individual widgets themselves:
I want the buttons in the options to anchor to the left, filling in the gap between the label. For the detection widget I want the labels to anchor left towards the canvas. I've tried anchoring and using sticky but nothing in the second column seems to move.
I am new to the Tkinter module. I only have experience with PyQt5. I am playing with a couple widgets in my Frame. They are three buttons, and I am trying to expand their size relative to the size of the window. To do this I am using w.columnconfigure(n, weight=1). This should spread the 3 buttons I have across the window Frame. This is the code I am running. I have tried with the w.columnconfigure before placing the widgets in the grid, and, as seen in the posted code, after the widgets are placed in the grid. I noticed no difference or functionality. Is there a convention? Anyway, appreciate any guidance!
def create_widgets(self):
""" Create three buttons that do nothing. """
self.bttn1 = Button(self, text="I do nothing")
self.bttn2 = Button(self)
self.bttn2.configure(text="Me too!")
self.bttn3 = Button(self)
self.bttn3["text"] = "Same here!"
self.bttnCt = Button(self)
self.bttnCt["text"] = "Total Clicks: 0"
self.bttnCt["command"] = self.update_count
self.bttn1.grid(row=0, column=0, sticky=W+E)
self.bttn2.grid(row=0, column=1, sticky=W+E)
self.bttn3.grid(row=0, column=2, sticky=W+E)
self.bttnCt.grid(row=1, column=1, sticky=W+E)
bttn_list = [self.bttn1, self.bttn2, self.bttn3, self.bttnCt]
for k, i in enumerate(bttn_list):
i.columnconfigure(k, weight=1)
#self.bttn1.columnconfigure(0, weight=1)
#self.bttn2.columnconfigure(1, weight=3)
#self.bttn3.columnconfigure(2, weight=1)
#self.bttnCt.columnconfigure(3, weight=1)
columnconfigure() or rowconfigure() functions are applied to the window or frame, of which the widget is a part of. Here you are applying it on the button itself. Apply it on on its parent basically.
Here is a small example.
import tkinter as tk
app = tk.Tk()
bttn1 = tk.Button(app, text="I do nothing")
bttn2 = tk.Button(app, text='Me too!')
bttn3 = tk.Button(app, text='Same here!')
bttnCt = tk.Button(app, text='Total Clicks: 0')
bttn1.grid(row=0, column=0, sticky="ew")
bttn2.grid(row=0, column=1, sticky="ew")
bttn3.grid(row=0, column=2, sticky="ew")
bttnCt.grid(row=1, column=1, sticky="ew")
bttn_list = [bttn1, bttn2, bttn3, bttnCt]
for i in range(len(bttn_list)):
app.columnconfigure(i, weight=1) ## Not the button, but the parent
app.mainloop()
Thanks for taking time to look at this. I've been struggling with this for almost a week and its driving me crazy.
I have a horizontal Paned Window which is supposed to stretch from the bottom of my toolbar to the bottom of my window, but it's sticking only to the bottom of the root window. Eventually I want to have a Treeview widget in the left pane and thumbnails in the right pane.
Can anyone help me to get the Paned Window to stick NSEW? Do I need to put it inside another frame?
I'm using Python 2.7 on Windows 7. (This isn't my whole program, just a sample to demonstrate the problem.)
#!/usr/bin/env python
# coding=utf-8
from Tkinter import *
from ttk import *
class MainWindow:
def null(self):
pass
def __init__(self):
self.root = Tk()
self.root.geometry("700x300")
self.root.resizable(width=TRUE, height=TRUE)
self.root.rowconfigure(0, weight=1)
self.root.columnconfigure(0, weight=1)
self.menubar = Menu(self.root)
File_menu = Menu(self.menubar, tearoff=0)
self.menubar.add_cascade(label="Pandoras Box", menu=File_menu)
File_menu.add_command(label="Black Hole", command=self.null)
self.root.config(menu=self.menubar)
self.toolbar = Frame(self.root, relief=RAISED)
self.toolbar.grid(row=0, column=0, sticky='NEW')
self.toolbar.grid_columnconfigure(0, weight=1)
self.toolbar.rowconfigure(0, weight=1)
dummy = Button(self.toolbar, text="Tool Button")
dummy.grid(row=0, column=0, sticky='EW')
Find = Label(self.toolbar, text="Search")
Search = Entry(self.toolbar)
Find.grid(row=0, column=5, sticky='E', padx=6)
Search.grid(row=0, column=6, sticky='E', padx=8)
self.info_column = Frame(self.root, relief=RAISED, width=100)
self.info_column.grid(row=0, column=5, rowspan=3, sticky='NSW')
self.info_column.grid_rowconfigure(0, weight=1)
self.info_column.grid_columnconfigure(0, weight=1)
self.rootpane = PanedWindow(self.root, orient=HORIZONTAL)
self.rootpane.grid(row=1, column=0, sticky='NS')
self.rootpane.grid_rowconfigure(0, weight=1)
self.rootpane.grid_columnconfigure(0, weight=1)
self.leftpane = Frame(self.rootpane, relief=RAISED)
self.leftpane.grid(row=0, column=0, sticky='NSEW')
self.rightpane = Frame(self.rootpane, relief=RAISED)
self.rightpane.grid(row=0, column=0, sticky='NSEW')
''' THESE BUTTONS ARE SUPPOSED TO BE INSIDE PANED WINDOW STUCK TO THE TOP!'''
but_left = Button(self.leftpane, text="SHOULD BE IN LEFT PANE UNDER TOOLBAR FRAME")
but_left.grid(row=0, column=0, sticky='NEW')
but_right = Button(self.rightpane, text="SHOULD BE IN RIGHT PANE UNDER TOOLBAR FRAME")
but_right.grid(row=0, column=0, sticky='NEW')
self.rootpane.add(self.leftpane)
self.rootpane.add(self.rightpane)
self.SbarMesg = StringVar()
self.label = Label(self.root, textvariable=self.SbarMesg, font=('arial', 8, 'normal'))
self.SbarMesg.set('Status Bar:')
self.label.grid(row=3, column=0, columnspan=6, sticky='SEW')
self.label.grid_rowconfigure(0, weight=1)
self.label.grid_columnconfigure(0, weight=1)
self.root.mainloop()
a = MainWindow()
Short answer: the space you see between the buttons and the toolbar frame is because you allow the row containing the toolbar to resize, instead of the row containing the PanedWindow... To get what you want, replace:
self.root.rowconfigure(0, weight=1)
with
self.root.rowconfigure(1, weight=1)
Other comments:
Try to avoid wildcard imports. In this case, it makes it difficult to differentiate between tk and ttk widgets
To allow resizing of widgets aligned using grid(), .rowconfigure(..., weight=x) must be called on the widget's parent not the widget itself.
background colors are very useful to debug alignment issues in tkinter.
Code:
import Tkinter as tk
import ttk
class MainWindow:
def __init__(self):
self.root = tk.Tk()
self.root.geometry("700x300")
self.root.resizable(width=tk.TRUE, height=tk.TRUE)
self.root.rowconfigure(1, weight=1)
self.root.columnconfigure(0, weight=1)
self.toolbar = tk.Frame(self.root, relief=tk.RAISED, bg="yellow")
self.toolbar.grid(row=0, column=0, sticky='NEW')
self.toolbar.columnconfigure(0, weight=1)
dummy = ttk.Button(self.toolbar, text="Tool Button")
dummy.grid(row=0, column=0, sticky='EW')
Find = tk.Label(self.toolbar, text="Search")
Search = ttk.Entry(self.toolbar)
Find.grid(row=0, column=5, sticky='E', padx=6)
Search.grid(row=0, column=6, sticky='E', padx=8)
self.info_column = tk.Frame(self.root, relief=tk.RAISED, width=100, bg="orange")
self.info_column.grid(row=0, column=5, rowspan=2, sticky='NSW')
self.rootpane = tk.PanedWindow(self.root, orient=tk.HORIZONTAL, bg="blue")
self.rootpane.grid(row=1, column=0, sticky='NSEW')
self.leftpane = tk.Frame(self.rootpane, bg="pink")
self.rootpane.add(self.leftpane)
self.rightpane = tk.Frame(self.rootpane, bg="red")
self.rootpane.add(self.rightpane)
''' THESE BUTTONS ARE SUPPOSED TO BE INSIDE PANED WINDOW STUCK TO THE TOP!'''
but_left = ttk.Button(self.leftpane, text="SHOULD BE IN LEFT PANE UNDER TOOLBAR FRAME")
but_left.grid(row=0, column=0, sticky='NEW')
but_right = ttk.Button(self.rightpane, text="SHOULD BE IN RIGHT PANE UNDER TOOLBAR FRAME")
but_right.grid(row=0, column=0, sticky='NEW')
self.label = tk.Label(self.root, text="Status:", anchor="w")
self.label.grid(row=3, column=0, columnspan=6, sticky='SEW')
self.root.mainloop()
a = MainWindow()
I tried to find out why, but maybe don't know the right questions. I have a project where I'm trying to create a dashboard for my car. The problem is that when I try to make a canvas object from another class appear my GUI starts but does not show anything. If I start the GUI without asking for the canvas to appear the GUI works and shows the screen. I'm new to Python. My version is 3.5
My Main program:
from tkinter import*
from helperThingys import Helpers
root = Tk()
root.geometry("800x480")
bgLeft = Frame(root, bg="black", width=200, height=480)
bgLeft.pack_configure(fill=BOTH, expand=1, side=LEFT)
bgMiddle = Frame(root, bg="black", width=400, height=480)
bgMiddle.pack_configure(fill=BOTH, expand=1, side=LEFT)
bgRight = Frame(root, bg="black", width=200, height=480)
bgRight.pack_configure(fill=BOTH, expand=1, side=LEFT)
# These are really gif images read to labels to be able to grid them
# now just plain text labels for convenience.
label_4hi = Label(bgLeft, text="ok", bg="green")
label_4lo = Label(bgLeft, text="ok", bg="green")
label_lock = Label(bgLeft, text="ok", bg="green")
label_batt = Label(bgMiddle, text="ok", bg="red")
label_fuelF = Label(bgLeft, text="ok", bg="orange")
label_glow = Label(bgLeft, text="ok", bg="yellow")
label_hb = Label(bgMiddle, text="ok", bg="blue")
label_indL = Label(bgMiddle, text="ok", bg="green")
label_indR = Label(bgMiddle, text="ok", bg="green")
label_lowFuel = Label(bgLeft, text="ok", bg="red")
label_lowOil = Label(bgLeft, text="ok", bg="red")
label_park = Label(bgMiddle, text="ok", bg="red")
label_pwrS = Label(bgLeft, text="ok", bg="red")
label_rFog = Label(bgLeft, text="ok", bg="orange")
label_temp = Label(bgLeft, text="ok", bg="red")
label_gauge = Label(bgMiddle, text="ok", bg="red")
# Middle frame
bgMiddle.rowconfigure(0, minsize=46, weight=1)
bgMiddle.rowconfigure(1, minsize=217, weight=5)
bgMiddle.rowconfigure(2, minsize=217, weight=5)
bgMiddle.columnconfigure(0, minsize=80)
bgMiddle.columnconfigure(1, minsize=80)
bgMiddle.columnconfigure(2, minsize=80)
bgMiddle.columnconfigure(3, minsize=80)
bgMiddle.columnconfigure(4, minsize=80)
label_indL.grid(row=0, column=0, sticky=E+N+W)
label_hb.grid(row=0, column=1, sticky=E+N+S+W)
label_park.grid(row=0, column=2, sticky=E+N+S+W)
label_batt.grid(row=0, column=3, sticky=E+N+S+W)
label_indR.grid(row=0, column=4, sticky=E+N+S+W)
# Left frame
bgLeft.rowconfigure(0, minsize=46, weight=1)
bgLeft.rowconfigure(1, minsize=46, weight=1)
bgLeft.rowconfigure(2, minsize=46, weight=1)
bgLeft.rowconfigure(3, minsize=46, weight=1)
bgLeft.rowconfigure(4, minsize=46, weight=1)
bgLeft.columnconfigure(0, minsize=100)
bgLeft.columnconfigure(1, minsize=100)
label_4hi.grid(row=0, column=0, sticky=E+N+S+W)
label_4lo.grid(row=0, column=1, sticky=E+N+S+W)
label_lock.grid(row=1, column=0, sticky=E+N+S+W)
label_pwrS.grid(row=1, column=1, sticky=E+N+S+W)
label_rFog.grid(row=2, column=0, sticky=E+N+S+W)
label_lowFuel.grid(row=2, column=1, sticky=E+N+S+W)
label_lowOil.grid(row=3, column=0, sticky=E+N+S+W)
label_temp.grid(row=3, column=1, sticky=E+N+S+W)
label_fuelF.grid(row=4, column=0, sticky=E+N+S+W)
label_glow.grid(row=4, column=1, sticky=E+N+S+W)
# Middle frame
speedo = helpers.Gauge()
speedo.makeGauge(bgMiddle, 150, "speed")
speedo.grid(row=1, columnspan=5, sticky=E+N+S+W)
#label_gauge.grid(row=1, columnspan=5, sticky=E+N+S+W)
# Right Frame
#oilPres = Gauge(bgRight, 150, "oilPres")
root.mainloop()
And here is the 'helpers.py' from helperThingys package.
from tkinter import Canvas
class Gauge(Canvas):
def __init__(self):
Canvas.__init__(self)
pass
def makeGauge(self, window, value, gaugeType):
if gaugeType == "speed":
baseCanvas = Canvas(window, bg="black", width=400, height=217,
highlightthickness=0)
baseCanvas.create_arc([10, 5, 390, 395], start=0, extent=180,
fill="white")
return baseCanvas
I'm using the canvases as the background for the gauges. The strange thing was that this 'helpers.py' worked and created the canvases to my GUI when it was not a class but a module:
def makeGauge(self, window, value, gaugeType):
if gaugeType == "speed":
baseCanvas = Canvas(window, bg="black", width=400, height=217,
highlightthickness=0)
baseCanvas.create_arc([10, 5, 390, 395], start=0, extent=180,
fill="white")
return baseCanvas
... and so on (the module was then in the same package as the GUI). That's why I know that the canvases work with the GUI. What am I doing wrong when using them in a class?
Thank you for your answers.
Your problem is that Gauge both is a subclass of Canvas and creates one or more other canvases (that are, oddly, a child of some other window).
When you call makeGauge, this creates the second canvas, and returns it. However, you don't save a reference and you never call pack, place or grid on this second canvas so it never shows up.
I don't know what you're intending to do with the two canvases, but I'm guessing you really only want one. I suggest making the class like this, where you pass all arguments in at the time you create the canvas, so that you can create the gauge in a single step:
class Gauge(Canvas):
def __init__(self, parent, value, gaugeType):
Canvas.__init__(self, parent)
self.makeGauge(value, gaugeType)
def makeGauge(self, value, gaugeType):
if gaugeType == "speed":
self.configure(bg="black", width=400, height=217,
highlightthickness=0)
self.create_arc([10, 5, 390, 395], start=0, extent=180,
fill="white")
elif gaugeType == "rpm":
...
speedo = Gauge(bgMiddle, 150, "speed")
speedo.grid(...)
If you want to keep both canvases, or you decide to make Gauge inherit from something else, you need to save the reference that is returned by makeGauge, and then add it to the display:
gauge = speedo.makeGauge(bgMiddle, 150, "speed")
gauge.grid(row=1, columnspan=5, sticky=E+N+S+W)