This question already has answers here:
Tkinter: AttributeError: NoneType object has no attribute <attribute name>
(4 answers)
Closed last year.
I'm making a log/chat system in my program (just Tkinter default looks) and i came across a problem where I can't add or change a listbox. Here is what I'm trying to do:
import tkinter
from tkinter import *
from tkinter import messagebox
import random
window = tkinter.Tk()
window.geometry("250x195")
window.title(" ")
window.iconbitmap("icon.ico")
global loglength, log
log = []
loglength = len(log)
inventorylist = []
def sendmessage(event):
chatstring = chatentry.get()
log.append(chatstring)
print(log, loglength)
checknew() #dont worry abt this it works
serverlog = tkinter.Listbox(
width=20,
height=11,
bg="darkgray",
listvariable=log
).place(x=128,y=-2)
I want to add items to the listbox. Here is an image of my program:
When I press enter (the key bound to the function to add the string to the listbox) this happens:
is Listbox like a program u want?
if u want a program that will make u program list in tkinder this is the code :
from tkinter import *
a= Tk()
a.geometry("400x400")
a.title("test")
Lb1 = Listbox(a,bg = "pink", bd = 10, fg = "black",\
font = "Castellar", cursor = "target")
Lb1.insert(1, "lion")
Lb1.insert(2, "tiger")
Lb1.insert(3, "zebra")
Lb1.insert(4, "elephant")
Lb1.insert(5, "deer")
Lb1.insert(6, "fox")
Lb1.insert(7, "Wolf")
Lb1.insert(8, "Gorilla")
Lb1.insert(9, "Jackal")
Lb1.insert(10, "Otter")
Lb1.pack()
a.mainloop()
hope that i helped u.
Related
This question already has answers here:
Tkinter: AttributeError: NoneType object has no attribute <attribute name>
(4 answers)
Closed 4 days ago.
if __name__ == "__main__":
import tkinter as tk
from tkinter import ttk
window = tk.Tk()
def clear():
for btn in toClear.copy():
btn.destroy()
toClear.remove(btn)
def readFilefunction():
clear()
def enter():
path = ent_Filepath.get()
readFile(path)
#window.geometry("250x75+250+75")
ent_Filepath = tk.Entry(window, width=15).pack()
btn_Enter = tk.Button(window,command=enter,text="Enter").pack()#place(x=30,y=20)
def searchFilefunction():
txt_Model = ttk.Entry(window)
txt_Size = ttk.Entry(window)
print('searchFile')
def addRecordfunction():
print('addRecord')
def modQuantityfunction():
print('modQuantity')
functions = {
"readFile": readFilefunction,
"searchFile": searchFilefunction,
"addRecord": addRecordfunction,
"modQuantity": modQuantityfunction
}
toClear = []
title = tk.Label(text= "Please choose a function")
title.pack()
toClear.append(title)
for text, fu1 in functions.items():
frame = tk.Frame(master=window)
frame.pack(side=tk.LEFT)
button = tk.Button(
master=frame,
text=text,
width=10,
height=2,
command=fu1
)
button.pack()
toClear.append(button)
window.mainloop()
the .get function gets the error
Cannot access member "get" for type "None" Pylance(reportGeneralTypeIssues)[Ln 42, Col 33]
Member "get" is unknown
and i'm not sure why
it was working but i changed something but cant remember what sorry. im not sure how to fix it from here. please dont hesitate to ask for any further details
The issue is caused because ent_Filepath is None. If you look at line 15 of the included code, you will see ent_Filepath = tk.Entry(window, width=15).pack(). pack() does not return a value, so you get None. What you should be doing instead is
ent_Filepath = tk.Entry(window, width=15)
ent_Filepath.pack()
This question already has answers here:
Python Tkinter: OptionMenu modify dropdown list width
(6 answers)
Closed 1 year ago.
I want to create a dropdown menu in tkinter of custom width and height and certain styling options like fore background etc. but when I am running my this code it is giving AttributeError: 'NoneType' object has no attribute 'config' and when I run my code without config it gives 'TypeError: 'dict_keys' object is not subscriptable
These are my both two codes please help me in this problem.
from tkinter import *
from tkinter import ttk
import tkinter
root=Tk()
root.geometry('500x500')
seletion=StringVar()
def show():
label=Label(root,text=seletion.get()).pack(pady=10)
drop=OptionMenu(root,seletion,'one','two','three',width=10).pack(pady=10)
button=Button(root,text='show',command=show).pack(pady=10)
root.mainloop()
Second code:
from tkinter import *
from tkinter import ttk
import tkinter
root=Tk()
root.geometry('500x500')
seletion=StringVar()
def show():
label=Label(root,text=seletion.get()).pack(pady=10)
pass
drop=OptionMenu(root,seletion,'one','two','three').pack(pady=10)
button=Button(root,text='show',command=show).pack(pady=10)
drop.config(width=10)
root.mainloop()
It is possible to alter OptionMenu attributes including width and height as well as color, font and menu position.
It would probably be better to use ttk.ComboBox however to answer your question I will post this code.
Included is a function called find that will extract all attributes and their values from tkinter objects and display them in a human friendly way.
You can also display an image or bitmap so I've imported filedialog to assist with image selection.
This is your program with errors removed and extra code for attribute testing.
def find( obj ):
name = f"{type(obj).__name__}:\n "
try:
return name + "\n ".join( [ f"{x} = '{obj.cget(x)}'" for x in obj.keys() if x not in ['bg', 'fg', 'bd']] )
except:
return f"'{obj}' has no keys attribute"
import tkinter as tk
from tkinter import filedialog as fido
root = tk.Tk()
root.geometry('500x500')
selection = tk.StringVar()
def show():
label["text"] = selection.get()
label = tk.Label(root,text = selection.get())
label.pack()
drop = tk.OptionMenu(root,selection,'one','two','three')
drop.pack(pady = 10)
# Extra controls
image = fido.askopenfilename(title = "Choose a Picture")
if image:
photo = tk.PhotoImage(file = image)
photo_wide = photo.width()
photo_high = photo.height()
drop.config(height = photo_high, width = photo_wide,
takefocus = 1, image = photo, compound = "center")
else:
drop["height"] = '2'
drop['width'] = '10'
drop["direction"] = ["above", "below", "flush", "left", "right"][2]
drop["anchor"] = ["n", "ne", "e", "se", "s", "sw", "w", "nw", "center"][0]
drop["justify"] = ["left", "right", "center"][1]
# drop["bitmap"] = "warning"
drop["background" ] = "cyan"
drop["activebackground" ] = "cyan"
drop["highlightbackground"] = "red"
drop["font"] = 'TkDefaultFont 14'
drop["menu"]["background"] = "red"
drop["menu"]["foreground"] = "yellow"
drop["menu"]["font"] = "TkDefaultFont 15"
drop["menu"]["selectcolor"] = "green"
drop["menu"]["activeborderwidth"] = '4'
button = tk.Button(root, text = 'show', command = show)
button.pack(pady = 10)
print(find( drop ))
print(find( drop[ "menu" ] ))
root.mainloop()
This question already has answers here:
Why is my Button's command executed immediately when I create the Button, and not when I click it? [duplicate]
(5 answers)
Closed 3 years ago.
I'm playing around with TKinter trying to make a number generator.
I can't figure out why a new number doesn't get generated when I use this code:
roll = Button(window, text = 'Roll!', command = num())
But it works if I remove the brackets:
roll = Button(window, text = 'Roll!', command = num)
Thanks guys!
Rest of the code:
from tkinter import *
import random
def num():
number = random.randint(1, 6)
num1.configure(text = number)
return
window = Tk()
window.geometry('300x200')
window.title('Dice')
num1 = Label(window, text = 0)
num1.grid(column = 0, row = 0)
roll = Button(window, text = 'Roll!', command = num)
roll.grid(column = 0, row = 1)
window.mainloop()
When you write num() with the parentheses, you're calling the function immediately, and passing its return value as the argument to Button. When you just name the function, you're passing the function object itself as the argument to Button, and it will call the function later (when the button is clicked).
I'm new to Python and Tkinter and was trying to create an interface to search & plot data. I created a very simple toplevel window to get the values from a combobox that would be selected from users. However, I find the script would only print the first item in the list if comboxlist2.current(0) was set or it would print nothing, no matter which one is selected in the box. I created a sample script to test this. If I click on the "search & create", then the return values can change according to the user selection in comboxlist1, while it would all return "1" no matter what the user selected in comboxlist2. So may I ask where is the issue and how to solve?
Thanks in advance for the potential suggestions or solutions!
import tkinter as tk
from tkinter import ttk
from tkinter import *
def root_print():
reg_in = comboxlist1.get()
print(reg_in) #print the value selected
def on_click():
tl = Toplevel()
comvalue2 = tk.StringVar()
comboxlist2 = ttk.Combobox(tl,textvariable=comvalue2)
comboxlist2["values"] = ("1","2","3")
comboxlist2.grid()
comboxlist2.current(0) #select the first one as default
#mm = comboxlist2.get()
#print(mm) #print directly
go(comboxlist2,tl)
tl.wait_window()
return
def go(comboxlist2,tl):
mm = comboxlist2.get()
Button(tl,text='go', command=lambda:test(mm)).grid()
def test(mm):
print(mm) #do the same thing for the comboxlist2
root = Tk()
root.title('search') #create an interface
root.geometry('+400+200') #size and position
Label(text='region ').grid(row=2,column=0)
comvalue1 = tk.StringVar()
comboxlist1=ttk.Combobox(root,textvariable=comvalue1)
comboxlist1["values"]=("all","africa","asia","australia","canada","europe","mexico","southamerica","usa")
comboxlist1.grid(row=2,column=1)
comboxlist1.current(0)
Button(text='search & create', command=root_print).grid(row=0,column=4)
Button(text='click', command=on_click).grid(row=1, column=4)
loop = mainloop()#go!
Here is the working code, which should take care of your needs. I have removed the imports and some code snippets which are not useful.
import tkinter as tk
from tkinter import ttk
def root_print():
reg_in = comboxlist1.get()
print(reg_in)
def on_click():
tl = tk.Toplevel()
comvalue2 = tk.StringVar()
comboxlist2 = ttk.Combobox(tl,textvariable=comvalue2)
comboxlist2["values"] = ("1","2","3")
comboxlist2.grid()
comboxlist2.current(0) #select the first one as default
tk.Button(tl,text='go', command=lambda: test(comboxlist2.get())).grid()
tl.wait_window()
def test(mm):
print(mm)
root = tk.Tk()
root.title('search') #create an interface
root.geometry('+400+200') #size and position
tk.Label(text='region ').grid(row=2,column=0)
comvalue1 = tk.StringVar()
comboxlist1=ttk.Combobox(root,textvariable=comvalue1)
comboxlist1["values"]=("all","africa","asia","australia","canada","europe","mexico","southamerica","usa")
comboxlist1.grid(row=2,column=1)
comboxlist1.current(0)
tk.Button(text='search & create', command=root_print).grid(row=0,column=4)
tk.Button(text='click', command=on_click).grid(row=1, column=4)
root.mainloop()
I need my program to spawn multiple message boxes.
They have to be spawned in cascade at once.
(think of it as mimicry of malicious activity)
I tried do this using Tkinter:
import Tkinter
import tkMessageBox
for i in range(0,5):
tkMessageBox.showerror("", "oops")
but it seems program waits for user interaction with each message before showing next which is not quite what I need
and optional there is an empty form at top left corner. any idea to get rid of it?
The solutions might be to use TopLevel() here. This will allow all windows to pop up and you will be able to set a customer messagebox style as well.
Here is a simple example that will open all the windows at once while also hiding the root window. The below will stack all the windows on top of each other and you can move them. You can also provide some tracked variables to open each windows in a different location if you like.
#For python 3 imports:
import tkinter as tk
from tkinter import ttk
# for python 2 imports:
# import Tkinter as tk
# import ttk
root = tk.Tk()
root.withdraw()
for i in range(0,5):
x = tk.Toplevel(root)
x.title("Error Box!")
x.geometry("150x75+0+0")
x.resizable(False, False)
ttk.Label(x, text = "oops").pack()
ttk.Button(x, text = " OK ", command = x.destroy).pack(side=tk.BOTTOM)
root.mainloop()
In response to your comment on using a counter see below code:
#For python 3 imports:
import tkinter as tk
from tkinter import ttk
# for python 2 imports:
# import Tkinter as tk
# import ttk
root = tk.Tk()
root.withdraw()
counter = 0
def close_window(top_window):
global counter
top_window.destroy()
counter -= 1
if counter == 0:
print("destroying root window")
root.destroy()
for i in range(0,5):
counter += 1
x = tk.Toplevel(root)
x.title("Error Box!")
x.geometry("150x75+0+0")
x.resizable(False, False)
ttk.Label(x, text="oops").pack()
ttk.Button(x, text=" OK ", command=lambda tw=x: close_window(tw)).pack(side=tk.BOTTOM)
# this protocol() method is used to re-rout the window close event to a customer function.
# this will allow us to keep our counter and close windows as needed.
x.protocol("WM_DELETE_WINDOW", lambda tw=x: close_window(tw))
root.mainloop()
Better yet here is an example that places the items inside of a list so we do not need a counter.
#For python 3 imports:
import tkinter as tk
from tkinter import ttk
# for python 2 imports:
# import Tkinter as tk
# import ttk
root = tk.Tk()
root.withdraw()
list_of_windows = []
def close_window(tw):
i = list_of_windows.index(tw)
list_of_windows[i].destroy()
del list_of_windows[i]
if len(list_of_windows) == 0:
root.destroy()
print("root destroyed!")
for i in range(0,5):
x = tk.Toplevel(root)
x.title("Error Box!")
x.geometry("150x75+0+0")
x.resizable(False, False)
ttk.Label(x, text="oops").pack()
ttk.Button(x, text=" OK ", command=lambda tw=x: close_window(tw)).pack(side=tk.BOTTOM)
x.protocol("WM_DELETE_WINDOW", lambda tw=x: close_window(tw))
list_of_windows.append(x)
root.mainloop()
My conclusion:
Using tk message boxes wasn't best approach to the task,
because message boxes are modal, and there is no direct way to change that.
So instead I've just got a form shaped like a message box and spawned them with desirable quantity.
Ended up with following code:
from Tkinter import *
di = {}
for i in range(5):
di[i] = Tk()
offset = 300 + i*10
di[i].geometry('150x50+'+str(offset)+'+'+str(offset))
di[i].title('')
di[i].resizable(False, False)
la = Label(di[i],text = 'oops').pack()
button = Button(di[i], text = 'OK', command=di[i].destroy).pack()
di[0].mainloop()
And it serves my needs well. Thanks to Nae and Vasilis G. for their kind responses leading me to a working code.