Hello i tried to do that in loop, but can't understand why only last created one is the only one restricted? I'd like to limit the 12 created widgets in loop to 4 signs. Can someone help me? :3
PS. Sorry if something uncleared, i ask question here for the first time.
from tkinter import *
import trace
import random
class Plansza:
def __init__(self, master):
self.frame = Frame(master, bg="brown")
self.frame.pack()
self.tab = [random.randint(1, 6),random.randint(1, 6),random.randint(1, 6),random.randint(1, 6)]
print(self.tab)
print(len(self.tab))
self.max_len = 4
self.wynik = StringVar()
self.wynik.set(self.tab)
self.goal = Entry(self.frame, width=6, font=50, fg="purple", justify=CENTER, textvariable=self.wynik, show="*")
self.goal.grid(row=0, column=1, padx=30, pady=30)
self.pokaz = Button(self.frame, text = "Pokaż", command=self.show)
self.pokaz.grid(row=0, column=2)
self.wiersz=1
print(self.wynik.get())
self.var = [1,1,1,1,1,1,1,1,1,1,1,1]
self.iter = 0
self.map()
self.sprawdz = Button(self.frame, text = "Sprawdź")
self.sprawdz.grid(row=self.wiersz+1, column=1, padx=50, pady=50)
def on_write(self, *arg):
s = self.var[self.iter].get()
if len(s) > self.max_len:
self.var[self.iter].set(s[:self.max_len])
def show(self):
self.goal.config(show="")
def map(self):
self.var[self.iter]=StringVar()
self.var[self.iter].trace_variable("w", self.on_write)
self.pole_na_odp = Entry(self.frame, width=6, font=50, fg="purple", justify=CENTER, textvariable=self.var[self.iter])
self.pole_na_odp.grid(row=self.wiersz, column=1, padx=20, pady=20)
self.wiersz+=1
self.var.append([])
self.iter+=1
if(self.wiersz<12):
self.map()
root = Tk()
b = Plansza(root)
root.mainloop()
[EDIT] I did a list but now I've got another error:
Whenever i wanna type something in my Entry widgets i got en error like this:
s = self.var[self.iter].get()
AttributeError: 'int' object has no attribute 'get'
And there are no more restrict number of sings even in last Entry widget.
(Answer to the question in your edit.)
In this line
s = self.var[self.iter].get()
it looks like you are trying to use get() to return an element of self.var. That is not how lists work. I'm pretty sure what you want is
s = self.var[self.iter]
Related
i am working on a GUI in Tkinter, and i have encountered a wierd issue that i have been struggling to solve.
The goal is to remove and add users from the interface. When a user is added, it is displayed, and when deleted the user should disappear from the GUI.
This is where my issue begins. When only adding and removing one user, everything works fine.
However when two or more users are added, the removal process fails. The removal works as expected on the first try, but when trying to remove any more, the interface does not update. The users get removed from the list as should, but the GUI never updates. Here is my code
#anden slet klik virker ikke
class Application(tk.Frame):
def __init__(self, master=None):
super().__init__(master)
self.entries = -1
self.people = []
self.names = []
self.id = []
self.tlf = []
self.frames = []
self.master = master
self.pack()
self.create_widgets()
#Create the first two rows of the application
def create_widgets(self):
# Row 0: Input boxes
self.inputName = tk.Entry(self, bd=4)
self.inputName.grid(row=0, column=0)
self.inputID = tk.Entry(self, bd=4)
self.inputID.grid(row=0, column=1)
self.inputTLF = tk.Entry(self, bd=4)
self.inputTLF.grid(row=0, column=2)
# Row 0: "Add" button
self.addButton = tk.Button(self, text="Add", command=self.AddMember)
self.addButton.grid(row=0, column=3)
# Row 1: Labels
tk.Label(self, text = "Navn", borderwidth = 4).grid(row=1, column=0)
tk.Label(self, text="ID", borderwidth=4).grid(row=1, column=1)
tk.Label(self, text="Tlf", borderwidth=4).grid(row=1, column=2, ipadx=30)
tk.Label(self, text=" ", borderwidth=4).grid(row=1, column=3)
# What the "add" button does
def AddMember(self):
self.people.append([self.inputName.get(), self.inputID.get(), self.inputTLF.get()]) #Add textbox-text to list
self.entries += 1
self.updateMembers()
def updateMembers(self): # Display new member
# This is declared to make sure that self.entries is assigned by value, and not by index
entry = self.entries
# Add the new name from 'people' to the list of name entries, and display
self.names.append(tk.Label(self, text=self.people[entry][0], borderwidth=4))
self.names[entry].grid(row=entry + 2, column=0)
# -//- but with ids
self.id.append(tk.Label(self, text=self.people[entry][1], borderwidth=4))
self.id[entry].grid(row=entry + 2, column=1)
# -//- but with phone numbers
self.tlf.append(tk.Label(self, text=self.people[entry][2], borderwidth=4))
self.tlf[entry].grid(row=entry + 2, column=2)
# Create a frame to but multiple buttons in one grid-cell
self.frames.append(tk.Frame(self))
self.frames[entry].grid(row=entry + 2, column=3)
#Create such buttons
removeButton = tk.Button(self.frames[entry], text="X", command=lambda: self.remove(entry))
msgButton = tk.Button(self.frames[entry], text="SMS", command=lambda: self.sendSMS(entry))
callButton = tk.Button(self.frames[entry], text="Ring", command=lambda: self.makeCall(entry))
#Display such buttons
removeButton.pack(side='top')
callButton.pack(side = 'right')
msgButton.pack(side='left')
def sendSMS(self, sender_id):
print("SMSMSMSM")
def makeCall(self, sender_id):
print("RINGRINGRING")
def remove(self, sender_id):
print("")
print(self.entries)
self.people.pop(sender_id) # Remove from the "People" list
if self.entries >= 0:
# Un-display the lowest entry
self.tlf[self.entries].destroy()
self.frames[self.entries].destroy()
self.id[self.entries].destroy()
self.names[self.entries].destroy()
for i in range(self.entries): # RE-display all current entries (deleted one excluded)
tk.Label(self, text=self.people[i][0], borderwidth=4).grid(row=i + 2, column=0)
tk.Label(self, text=self.people[i][1], borderwidth=4).grid(row=i + 2, column=1)
tk.Label(self, text=self.people[i][2], borderwidth=4).grid(row=i + 2, column=2)
# Remove deleted user's info in the display lists.
self.names.pop(sender_id)
self.id.pop(sender_id)
self.tlf.pop(sender_id)
self.frames.pop(sender_id)
self.entries -= 1 # Decrement size of people
print(self.entries)
#Actually start the program
root = tk.Tk()
app = Application(master=root)
app.mainloop()
I have been troubleshooting this for hours on end, and have not managed to solve this, so any help is appreciated :D
I'm making GUI the first time with tkinter(python), and I want to show the results in the same place, where they are at the beginning.
When I run this code the functions are fully working, but I cannot show the results in my label.
The button have to take data from Entries and give it to the function with data from drop-down list.
The results should overwrite the list as1, as2 = [0, 0] and then show the results on the label result_1, result_2
I've tried to add "master" parameter to the function - onclick, but then the GUI was running without clicking the button.
# coding=utf-8
from tkinter import *
def function_1(h, eta_bet):
print(h, eta_bet)
return h, eta_bet
def calculated_value_concrete(class_concrete): # could be 20/25
eta_bet = class_concrete
return eta_bet
class Menu:
def __init__(self, master):
container = Label(master, bg="#003366")
container.pack()
menu_bg = Label(container, bg="#003366", fg="white", pady=15)
countings_bg = Label(container)
self.button1 = Button(menu_bg, text="Zbrojenie symetryczne", command=lambda: self.onclick(1, countings_bg),
width=20)
menu_bg.pack(side=LEFT, fill=Y)
self.button1.pack()
def onclick(self, args, countings_bg):
if args == 1:
countings_bg.pack()
ZbrojenieSymetryczne(countings_bg)
class ZbrojenieSymetryczne:
def __init__(self, master):
self.desc_1 = Label(master, text="Wysokość przekroju h [cm]")
self.desc_7 = Label(master, text="Wybór betonu")
self.data_1 = Entry(master, width=6)
var = StringVar()
var.set("Klasa")
self.data_7 = OptionMenu(master, var, "1", "2", command=self.option_menu)
self.data_7.config(width=10)
self.desc_1.grid(row=1, sticky=E)
self.desc_7.grid(row=7, sticky=E)
self.data_1.grid(row=1, column=1)
self.data_7.grid(row=7, column=1, stick="ew")
self.button5 = Button(master, text="Count", command=self.onclick)
self.button5.grid(row=9, columnspan=2, pady=10)
as1, as2 = [0, 0]
self.result_1 = Label(master, text=f"A_s1 = {as1} [cm^2]")
self.result_1.grid(row=12, sticky=E)
self.result_2 = Label(master, text=f"A_s2 = {as2} [cm^2]")
self.result_2.grid(row=13, sticky=E)
def option_menu(self, selection):
self.eta_bet = calculated_value_concrete(selection)
print(self.eta_bet)
def onclick(self):
h = float(self.data_1.get().replace(',', '.')) * 10 ** -2
as1, as2 = function_1(h, self.eta_bet)
self.result_1 = Label(master, text=f"A_s1 = {as1} [cm^2]")
self.result_1.grid(row=12, sticky=E)
self.result_2 = Label(master, text=f"A_s2 = {as2} [cm^2]")
self.result_2.grid(row=13, sticky=E)
root = Tk()
root.title("Obliczanie zbrojenia")
Menu(root)
root.mainloop()
I want the results in the same label as it is in the beginning (under the button)
If you want to update the text of an existing label there are many ways to do this but perhaps consider doing this inside your onclick function rather than creating new buttons.
def onclick(self):
h = float(self.data_1.get().replace(',', '.')) * 10 ** -2
as1, as2 = function_1(h, self.eta_bet)
self.result_1['text'] = f"A_s1 = {as1} [cm^2]"
self.result_2['text'] = f"A_s2 = {as2} [cm^2]"
This should set the text of result_1 and result_2 as per the f-string.
I am trying to make my first GUI script based on the answers of 2 questions. I'll show an example of the non GUI script
while True:
ammount = input("What is your debt")
if ammount.isdigit() == True:
break
else:
print("Please try typing in a number")
while True:
month = input("In which month did the debt originate?")
if month not in ["January", "February"]:
print("Try again")
else:
break
The point of this script is that it is scalable with all the questions one may add, I want to understand it in the same way in Tkinter. I'll show what I've tried:
from tkinter import *
def click():
while True:
entered_text = text_entry.get()
if entered_text .isdigit() == False:
error = Label(window, text="Try again", bg = "black", fg="red", font="none 11").grid(row = 3, column = 2, sticky= W).pack()
else:
break
return True
window = Tk()
window.title("Tax calculator")
window.configure(background="black")
monto = Label(window, text="¿What is your debt?", bg="black", fg="white", font="none 12 bold")
monto.grid(row = 1, column = 0, sticky= W)
text_entry = Entry(window, width = 20, bg="white")
text_entry.grid(row = 2, column=2, sticky=W)
output = Button(window, text = "Enter", width = 6, command = click)
output.grid(row = 3, column = 0, sticky = W)
The thing is, I can't add a Label() method in the if/else of the click() method, because I would like to ask a new question once the condition is met. I can't also can't get True from click once the condition is met, because the input comes from Button() method. Thanks in advance
You don't actually need any loops here, a simple if statement would be enough to do the trick. Also, there is no need to recreate the label every time, you can just configure() its text. And, note that indexing starts from 0 - so, in your grid, actual first row (and column) needs to be numbered 0, not 1. Besides that, I suggest you get rid of import *, since you don't know what names that imports. It can replace names you imported earlier, and it makes it very difficult to see where names in your program are supposed to come from. You might want to read what PEP8 says about spaces around keyword arguments, as well:
import tkinter as tk
def click():
entered_text = text_entry.get()
if not entered_text.isdigit():
status_label.configure(text='Please try again')
text_entry.delete(0, tk.END)
else:
status_label.configure(text='Your tax is ' + entered_text)
text_entry.delete(0, tk.END)
root = tk.Tk()
root.title('Tax calculator')
root.configure(background='black')
monto = tk.Label(root, text='¿What is your debt?', bg='black', fg='white', font='none 12 bold')
monto.grid(row=0, column=0, padx=10, pady=(10,0))
text_entry = tk.Entry(root, width=20, bg='white')
text_entry.grid(row=1, column=0, pady=(10,0))
status_label = tk.Label(root, text='', bg='black', fg='red', font='none 11')
status_label.grid(row=2, column=0)
button = tk.Button(root, text='Enter', width=17, command=click)
button.grid(row=3, column=0, pady=(0,7))
root.mainloop()
I forgot to mention, if your application gets bigger, you might be better off using a class.
l would like to create a control system for administrator on Tkinter and some functions (add, delete, update and load) are main part of control system but when l run the code , these functions do not work and there is no error message. But ,l could not figure out where the problem is. My code is still not completed yet. İf l solve it, then l will move to another step.
import tkinter
from tkinter import *
userlist = [
['Meyers', '12356'],
['Smith','abcde'],
['Jones','123abc34'],
['Barnhart','12//348'],
['Nelson','1234'],
["Prefect",'1345'],
["Zigler",'8910'],
['Smith','1298']]
def domain():
def whichSelected () :
print ("At %s of %d" % (select.curselection(), len(userlist)))
return int(select.curselection()[0])
def addEntry():
userlist.append ([nameVar.get(), passwordVar.get()])
setSelect()
def updateEntry():
userlist[whichSelected()] = [nameVar.get(), passwordVar.get()]
setSelect()
def deleteEntry():
del userlist[whichSelected()]
setSelect()
def loadEntry():
name, password = userlist[whichSelected()]
nameVar.set(name)
passwordVar.set(password)
def makeWindow():
win=Tk()
global nameVar, passwordVar, select
frame1 = Frame(win)
frame1.pack()
Label(frame1, text="Name").grid(row=0, column=0, sticky=W)
nameVar = StringVar()
name = Entry(frame1, textvariable=nameVar)
name.grid(row=0, column=1, sticky=W)
Label(frame1, text="Password").grid(row=1, column=0, sticky=W)
passwordVar= StringVar()
password= Entry(frame1, textvariable=passwordVar)
password.grid(row=1, column=1, sticky=W)
frame2 = Frame(win) # Row of buttons
frame2.pack()
b1 = Button(frame2,text=" Add ",command=addEntry)
b2 = Button(frame2,text="Update",command=updateEntry)
b3 = Button(frame2,text="Delete",command=deleteEntry)
b4 = Button(frame2,text=" Load ",command=loadEntry)
b1.pack(side=LEFT); b2.pack(side=LEFT)
b3.pack(side=LEFT); b4.pack(side=LEFT)
frame3 = Frame(win) # select of names
frame3.pack()
scroll = Scrollbar(frame3, orient=VERTICAL)
select = Listbox(frame3, yscrollcommand=scroll.set, height=6)
scroll.config (command=select.yview)
scroll.pack(side=RIGHT, fill=Y)
select.pack(side=LEFT, fill=BOTH, expand=1)
return win
def setSelect():
userlist.sort()
select.delete(0,END)
for name in userlist:
select.insert(END,name)
win=makeWindow()
setSelect()
win.mainloop()
page1=Tk()
but1=Button(page1,text="Domain",command=domain).pack()
It is bad practice to define your functions in a function and makes debugging pretty difficult. I would start by using an object to create this GUI. Object variables:
passwordVar and nameVar,
select
userlist
win
There's a lot going wrong for your code.
For instance, you don't need to import tkinter twice. Your casing of the variable names doesn't follow PEP8. You could benefit from an OOP approach.
I would suggest finding a good IDE to code in that can highlight your formatting and errors.
Take a look at the provided code:
import tkinter as tk
user_list = [
['Meyers', '12356'],
['Smith','abcde'],
['Jones','123abc34'],
['Barnhart','12//348'],
['Nelson','1234'],
["Prefect",'1345'],
["Zigler",'8910'],
['Smith','1298']]
class Domain(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.parent = parent
self.name_var = tk.StringVar()
self.password_var = tk.StringVar()
self.make_window()
def which_selected(self):
print("At %s of %d" % (self.select.curselection(), len(user_list)))
return int(self.select.curselection()[0])
def add_entry(self):
user_list.append([self.name_var.get(), self.password_var.get()])
self.set_select()
def update_entry(self):
user_list[self.which_selected()] = [
self.name_var.get(), self.password_var.get()]
self.set_select()
def delete_entry(self):
del user_list[self.which_selected()]
self.set_select()
def load_entry(self):
name, password = user_list[self.which_selected()]
self.name_var.set(name)
self.password_var.set(password)
def make_window(self):
frame1 = tk.Frame(self.parent)
frame1.pack()
tk.Label(frame1, text="Name").grid(row=0, column=0, sticky=tk.W)
name = tk.Entry(frame1, textvariable=self.name_var)
name.grid(row=0, column=1, sticky=tk.W)
tk.Label(frame1, text="Password").grid(row=1, column=0, sticky=tk.W)
password = tk.Entry(frame1, textvariable=self.password_var)
password.grid(row=1, column=1, sticky=tk.W)
frame2 = tk.Frame(self.parent) # Row of buttons
frame2.pack()
b1 = tk.Button(frame2, text=" Add ", command=self.add_entry)
b2 = tk.Button(frame2, text="Update", command=self.update_entry)
b3 = tk.Button(frame2, text="Delete", command=self.delete_entry)
b4 = tk.Button(frame2, text=" Load ", command=self.load_entry)
b1.pack(side=tk.LEFT)
b2.pack(side=tk.LEFT)
b3.pack(side=tk.LEFT)
b4.pack(side=tk.LEFT)
frame3 = tk.Frame(self.parent) # select of names
frame3.pack()
scroll = tk.Scrollbar(frame3, orient=tk.VERTICAL)
self.select = tk.Listbox(frame3, yscrollcommand=scroll.set, height=6)
scroll.config(command=self.select.yview)
scroll.pack(side=tk.RIGHT, fill=tk.Y)
self.select.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)
def set_select(self):
user_list.sort()
self.select.delete(0, tk.END)
for name in user_list:
self.select.insert(tk.END, name)
if __name__ == '__main__':
root = tk.Tk()
Domain(root)
root.mainloop()
Note:
There's still errors here, but I don't exactly know what you're trying to do so I've just restructured it here so you can start on a better path.
I'm doing a large project at the moment to help me learn my first programming language (Python) and I've run into some unknown territory. I am aware that it's generally bad to use global variables and there are better solutions, but I can't figure it out for my situation.
I've made the code below as a simple example of what I want to achieve. What's the best way to do this instead of using the global variable?
Also, are there any general errors I've made in my code below?
Thanks in advance
from tkinter import *
root = Tk()
display_number = 5
class NumberBox():
def __init__(self):
global display_number
self.number_label = Label(root, text=display_number)
self.number_label.pack()
self.engine()
def engine(self):
self.number_label.config(text=display_number)
root.after(10, self.engine)
def change_number(operation):
global display_number
if operation == "add":
display_number += 1
if operation == "subtract":
display_number -= 1
Button(root, text="Add Class", command=lambda: NumberBox()).pack()
Button(root, text="Number UP", command=lambda: change_number("add")).pack()
Button(root, text="Number DOWN", command=lambda: change_number("subtract")).pack()
for _ in range(5):
NumberBox()
root.mainloop()
I made several changes:
Create a new class NumberBoxesList to avoid global variables and make program's logic more visible
Remove root.after method: this method should not be used for updates immediately following user's actions
Use import tkinter as tk : import * is bad practice
Result:
import tkinter as tk
class NumberBox():
def __init__(self, root, display_number):
self.number_label = tk.Label(root, text=display_number)
self.number_label.pack()
def changeNumber(self, display_number):
self.number_label.config(text=display_number)
class NumberBoxesList():
def __init__(self, root, start_number = 5):
self.number = start_number
self.root = root
self.boxes = []
tk.Button(root, text="Add Class", command= self.addBox).pack()
tk.Button(root, text="Number UP", command=lambda: self.change_number("add")).pack()
tk.Button(root, text="Number DOWN", command=lambda: self.change_number("subtract")).pack()
def addBox(self):
self.boxes.append(NumberBox(self.root, self.number))
def change_number(self, operation):
if operation == "add":
self.number += 1
if operation == "subtract":
self.number -= 1
for box in self.boxes:
box.changeNumber(self.number)
root = tk.Tk()
boxList = NumberBoxesList(root)
for _ in range(5):
boxList.addBox()
root.mainloop()
like this:
from tkinter import *
root = Tk()
class NumberBox():
display_number = 5
def __init__(self):
self.number_label = Label(root, text=self.display_number)
self.number_label.pack()
self.engine()
def engine(self):
self.number_label.config(text=self.display_number)
root.after(10, self.engine)
def change_number(operation):
if operation == "add":
NumberBox.display_number += 1
if operation == "subtract":
NumberBox.display_number -= 1
Button(root, text="Add Class", command=lambda: NumberBox()).pack()
Button(root, text="Number UP", command=lambda: change_number("add")).pack()
Button(root, text="Number DOWN", command=lambda: change_number("subtract")).pack()
for _ in range(5):
NumberBox()
root.mainloop()
by defining the variable in the class (but outside the __init__ it becomes owned by all instances of the class as a single variable, so changing it in one affects all instances