This question already has answers here:
Tkinter: AttributeError: NoneType object has no attribute <attribute name>
(4 answers)
Closed 9 months ago.
What's the difference between packing a frame "in line" versus ='ing it to a variable and .pack'ing it on the next line?
So I saw how to do grid and pack at the same time (see here), but after playing around with it, I ran into something weird. If you change line 16/17 from:
f5 = Frame(mainF, bg = "yellow", height=100, width = 60)
f5.pack(side=BOTTOM,fill=NONE)
to:
f5 = Frame(mainF, bg = "yellow", height=100, width = 60).pack(side=BOTTOM,fill=NONE)
At the end of the code where the buttons get put into the grid within a pack within a frame within a frame within a dream... My once error-free code now gives the error:
TclError: cannot use geometry manager grid inside .164287488 which already has slaves managed by pack
How? Wha-huh? Why?
My full code here:
from tkinter import Tk, Frame, Label, Entry, LEFT, TOP, YES, NONE, BOTH, RIGHT, BOTTOM,SE, Button,W,E,N,S
root = Tk()
mainF = Frame(root, bg = "green", height=100, width = 1060).pack(side=BOTTOM,fill=NONE)
f4 = Frame(mainF, bg = "blue", width = 300).pack(side=BOTTOM,fill=BOTH)
f = Frame(f4, bg = "orange", width = 500, height = 500).pack(side=LEFT, expand = 1)
f3 = Frame(f, bg = "red", width = 500)
f3.pack(side=LEFT, expand = 1, pady = 10, padx = 50)
f2 = Frame(f4, bg = "black", height=100, width = 100).pack(side=LEFT, fill = BOTH)
f5 = Frame(mainF, bg = "yellow", height=100, width = 60)
f5.pack(side=BOTTOM,fill=NONE)
#f7 = Frame(f5, bg = "green", height=100, width = 160).pack(side=BOTTOM,fill=BOTH)
#f6 = Frame(f7, bg = "green", height=100, width = 360).pack(side=BOTTOM,fill=BOTH)
b = Button(f2, text = "test")
b.pack()
Button(f3, text = "1").grid(row=0, column=0)
Button(f3, text = "2").grid(row=1, column=1)
Button(f3, text = "3").grid(row=2, column=2)
Button(f5, text = "1").grid(row=0, column=0)
Button(f5, text = "2").grid(row=1, column=1)
Button(f5, text = "3").grid(row=2, column=2)
root.mainloop()
I'm using Spyder2 within ipython within anaconda 64 within python 3.4.1 64 within Windows 7 64...
That many dreams within dreams is too unstable!
In the second example:
f5 = Frame(mainF, bg = "yellow", height=100, width = 60).pack(side=BOTTOM,fill=NONE)
f5 is None. This is not the case in the first example:
f5 = Frame(mainF, bg = "yellow", height=100, width = 60)
f5.pack(side=BOTTOM,fill=NONE)
In short terms, the "in line" method is not-recommended. It is one of the most common mistakes and causes of headache for new users of tkinter in python.
The reason for None is very simple: pack() and grid() return None.
In your full code example, mainF, f4, f, f2 are all None. So for exmaple, you think you are passing a reference to mainF frame as master to f4 , but in fact you are passing None.
Related
I am trying to code a CPS test for fun but I ran into a problem:
I defined a function at the beginning of the code and than I defined a tkinter button which has this function as command and the button should disappear in this function. When I do it like this it says that the variable of the button isn't defined yet but when I defined it vice versa so first the button and then the function it says that the function is not defined yet.
Can anyone help me?
(Sorry for my bad English)
import tkinter as tk
root = tk.Tk()
root.title("CPS test")
root.geometry("1000x1000")
root.configure(bg='white')
def getstring():
duration = entry.get()
entry.delete(0)
entry.place_forget()
okbutton.place_forget
lab1 = tk.Label(text = "How long should the CPS test last? 2,5 or 10 seconds?(Answer with 2,5,10)", font = "Ariel 20", bg = "#FFFFFF")
button = tk.Button(root, text = "Click me!", font = "Ariel 50", bg = "#FFFFFF", fg = "#000000")
entry = tk.Entry(root, font=('Arieal 20'), bd = 2)
okbutton = tk.Button(root, text = "OK", font = "Ariel 20", bg = "#FFFFFF", fg = "#000000", bd = 2, command = getstring())
lab1.place(x = 45,y = 250)
entry.place(x = 344, y = 350)
entry.insert(0, "Enter your answer here!")
okbutton.place(x = 465, y = 400)
root.mainloop()
I think the error is on the button name.
def getstring():
duration = entry.get()
entry.delete(0)
entry.place_forget()
button.place_forget
Just replace "okbutton" by "button" and it should work.
Else just declared the "okbutton" before the function
This question already has answers here:
Tkinter: AttributeError: NoneType object has no attribute <attribute name>
(4 answers)
Closed 3 years ago.
I recently started coding in python 3.6 with tkinter and tried creating my own project on repl.it. The project is a simple interactive to-do list, however I am stuck and cant get the function to work. The function is just simply getting the entry and adding it to a list box, but when I try adding the function it returns
'NoneType' object has no attribute 'get'
Here is the code:
from tkinter import *
root = Tk()
#giving the window its colour
root.configure(bg = '#40e0d0')
#changing the size of the window
root.geometry('200x500')
#creating an empty List
tasks = []
#creating the functions
def uplistbox():
# clearing the current list
clear_listbox()
# populating the Listbox
for task in tasks:
lb.insert('end', task)
def addingtask():
#getting the task
tasks = ti.get()
#adding the task to the Listbox
tasks.append(task)
#updating the listbox
uplistbox()
#creating the title and adding the display below it
lbl1 = Label(root, text='To-Do-List', bg = 'red').pack()
display = Label(root, text='', bg = 'yellow').pack()
ti = Entry(root, width = 15).pack()
# adding buttons
btn1 = Button(root, text = 'Add task', bg = 'yellow', command = addingtask).pack()
btn2 = Button(root, text = 'Delete All', bg = 'yellow').pack()
btn3 = Button(root, text = 'Delete', bg = 'yellow').pack()
btn4 = Button(root, text = 'Sort(asc)', bg = 'yellow').pack()
btn5 = Button(root, text = 'Sort(desc)', bg = 'yellow').pack()
btn6 = Button(root, text = 'Choose random', bg = 'yellow').pack()
btn7 = Button(root, text = 'Number of tasks', bg = 'yellow').pack()
btn8 = Button(root, text = 'exit', bg = 'yellow').pack()
lb = Listbox(root, bg = 'white').pack()
root.mainloop()
Can anyone tell me what I'm doing wrong?
The error indicates that the object instantiation on the following line has returned None instead of an instance of Entry:
ti = Entry(root, width = 15).pack()
Therefore
tasks = ti.get()
fails because ti is of type None instead of type Entry.
The following should do the trick:
def addingtask():
# getting the task
ti = Entry(root, width = 15)
ti.pack()
tasks = ti.get()
# adding the task to the Listbox
tasks.append(task)
# updating the listbox
uplistbox()
You should replace the following:
ti = Entry(root, width = 15).pack()
To:
ti = Entry(root, width = 15)
ti.pack()
Because Entry.pack returns nothing, which assigns your ti to None.
I am trying to create a pop up help window for a tool. I managed to add the scrollbar to a frame that contains canvas and label widget. However that Scrollbar does not shows the img_canvas_3 that I added.
Here is my code:
from tkinter import *
import tkinter.filedialog
from tkinter.filedialog import askopenfilename
from tkinter.filedialog import askdirectory
import PIL
from PIL import Image, ImageTk
help_window = tkinter.Tk()
help_window.title("Help")
help_window.geometry("400x800")
#frame.grid(row=0,column=0)
canvas=Canvas(help_window,bg='red',width=300,height=800,scrollregion=(0,0,500,500))
scroll_y = Scrollbar(help_window, orient="vertical", command = canvas.yview)
frame=Frame(canvas,width=300,height=800, bg="green")
description_label = Label(frame, text = "\n\tMy Tool\n",anchor = "w").pack(side = TOP, fill = "both")
introduction = "This tool provides a basic workflow"
introduction_text = Label(frame, text = introduction, anchor = "w", font = "Verdana 10", bg="yellow").pack(fill = "both")
label_1 = Label(frame, text = "Input Data 1", anchor = "w", font = "Verdana 10", justify=CENTER).pack(fill = "both")
img_canvas_1 = Canvas(frame, bg = "black", height = 300, width = 300)
img_canvas_1.pack(side = TOP)
label_2 = Label(frame, text = "Input Data 2", anchor = "w", font = "Verdana 10", justify = CENTER).pack(fill = "both")
img_canvas_2 = Canvas(frame, bg = "black", height = 300, width = 300)
img_canvas_2.pack(side = TOP)
label_3 = Label(frame, text = "Input Data 3", anchor = "w", font = "Verdana 10", justify = CENTER).pack(fill = "both")
img_canvas_3 = Canvas(frame, bg = "black", height = 300, width = 300)
img_canvas_3.pack(side = TOP)
canvas.create_window(0, 0, anchor = 'nw', window = frame)
canvas.update_idletasks
canvas.configure(scrollregion=canvas.bbox('all'),
yscrollcommand = scroll_y.set)
canvas.pack(fill = 'both', expand = TRUE, side = 'left')
scroll_y.pack(fill = 'y', side = 'right')
help_window.mainloop()
I expected to have the scroll bar working, basically showing all the widgets and elements in the frame as I am adding more and more. That is only true for the untill img_canvas_2
Does anyone have an idea why this is not the case with my code? I tried by playing around with the scrollregion parameter in the canvas variable, but it did not work.
Thanks in advance.
from tkinter import *
from tkinter import font
root = Tk()
root.title("Wills Gui")
root.geometry('1400x700')
#root.configure(background='black')
def P1C():
if B1(fg) :
B1.fg(fg = red)
B1["text"] = "Pin 2 Active"
B1["fg"] = "green"
else:
B1.fg(fg = green)
B1["text"] = "Pin 2 Inactive"
B1["fg"] = "red"
B1 = Button(root, height = 8, width = 15, font="Times 12 bold",
wraplength=80, command = P1C, text="| Q | B1 Inactive", bg="black",
fg="yellow").grid(row =0,column =0)
root.mainloop()
I have simplified the code i just need it to change the colour of the button text from green to red, etc every time it is pressed.
The error is right there in the trace
in P1C if B1(fg) : NameError: name 'fg' is not defined
The variable fg in the function is not defined prior to use.
I'm trying to learn coding with python 3.4. I built this mini GUI and I'm having trouble getting it to work. It prints out 2 every time even though I press the button 1 . All I want to do is to get 1 printed out in the label when I click the button on and 2 with button two with an if statement.
from tkinter import *
root = Tk()
root.geometry("500x500")
root.title("Test")
def button_press():
if one:
x = 1
display.configure(text=x)
if two:
x = 2
display.configure(text=x)
display = LabelFrame(root, bg="red", width="462", height="60")
display.pack()
one = Button(root, text="1", width="15", height="5",command=button_press)
one.pack(side="left")
two = Button(root, text="2", width="15", height="5", command=button_press)
two.pack(side="left")
root.mainloop()
You have two ways:
Or using a different function for each button
Or pass a lambda with one parameter.
bt … command = fct1
bt … command = fct2
Or use a lambda…
from tkinter import *
root = Tk()
root.geometry("500x500")
root.title("Test")
def button_press(var):
display.configure(text=var)
display = LabelFrame(root, bg="red", width="462", height="60")
display.pack()
one = Button(root, text="1", width="15", height="5",command=lambda : button_press(1))
one.pack(side="left")
two = Button(root, text="2", width="15", height="5", command=lambda : button_press(2))
two.pack(side="left")
root.mainloop()
I haven't done any Tkinter to be honest. That said the code snippet below
if one:
x = 1
display.configure(text=x)
if two:
x = 2
display.configure(text=x)
looks like a weird thing to do. Basically you are checking if one and than two are equal or not to None. This doesn't make sense since an if VARIABLE is always True for VARIABLE that is unequal 0, False or None.
Well, they are most certainly not equal to None, False or 0 since both variables represent an instance of a Button. So what you are doing is:
Check if one != None
Set label if 1. is True - this happens and you set the label to "1" but then...
Check if two != None
Set label if 3. is True - this also happens and it also overwrites the previous value of the label set by 2 which was "1" to "2". All this happens instantly so you are unable to see the transition and are left with the impression that only "2" is displayed.
We can go further and rewrite your code in order to expose this error:
def button_press():
if one:
x = 1
display.configure(text=x)
elif two:
x = 2
display.configure(text=x)
or even
def button_press():
if one:
x = 1
display.configure(text=x)
else:
x = 2
display.configure(text=x)
In both of the above cases the first statement will be executed and you will get 1 all the time and never 2. Once you check for the first logical expression in your if-else block and it is True, you go in there and then leave the whole block not touching the elif or else at all.
There are various ways how to fix this. You can assign a name to the button (so that you can distinguish each button based on its name) in case you still want to handle both buttons with a single function and then do a comparison whether the name of the object that called your event handling function is == "one" or == "two". However in most (all?) UI frameworks it is a common practice to have a separate function for each UI component that handles an event that the component supports (multiple functions if the component supports multiple event).
one = Button(root, text="1", width="15", height="5",command=button_press1)
one.pack(side="left")
two = Button(root, text="1", width="15", height="5",command=button_press2)
two.pack(side="left")
This solution is similar to #Clodion's but without the lambdas since I'm not sure if you are familiar with the concept and throwing that in might be a bit confusing.
I would suggest following some basic principles when working with an UI. If your component has support for - let's say - value changes, resized, clicked, pressed down, pressed up etc. (don't know the name of these in Tkinter but I would guess it supports at at least some of them) - you will create a separate function for each event. This not only makes your code more readable but also forces you to learn a way of doing things that is de facto standard no matter if you write your UI with Tkinter, Qt, .NET, Swing, AngularJS and so on.
This is what you want. May be new syntax but its the kinda thing you will get used to seeing. Dont be daunted.
from tkinter import *
root = Tk()
class BuildGui():
def __init__(self, parent):
self.parent = parent
self.parent.geometry("500x500")
self.parent.title("Building a Gui")
self.parent.configure(background="steel blue")
self.parent.resizable(0,0)
self.parent.grid()
self.CreateFrames()
self.AddButtons()
def CreateFrames(self):
"""Create The Frames"""
self.Frm = Frame(self.parent, bg = "steel blue")
self.Frm.grid(row = 0, column = 0)
def AddButtons(self):
self.Btn1 = Button(self.Frm, text = "Button1", height = 2, width = 10, fg = "black", activebackground = "yellow", bg = "light blue", command = self.Button1Pressed)
self.Btn2 = Button(self.Frm, text = "Button2", height = 2, width = 10, fg = "black", activebackground = "yellow", bg = "light blue", command = self.Button2Pressed)
self.Btn1.grid(row = 0, column = 0, padx = 40, pady = 40)
self.Btn2.grid(row = 0, column = 1, padx = 40, pady = 40)
def Button1Pressed(self):
self.Lbl1 = Label(self.Frm, text = "Button1pressed!", font = ("Calibri", 12))
self.Lbl1.grid(row = 1, column = 0, padx = 20, pady = 20)
def Button2Pressed(self):
self.Lbl2 = Label(self.Frm, text = "Button2pressed!", font = ("Calibri", 12))
self.Lbl2.grid(row = 1, column = 1, padx = 20, pady = 20)
buildgui = BuildGui(root)
root.mainloop()