Related
Good day everyone,
I am banging my head on this for what feels like eternity but cannot solve this issue. Hence I thought I may as well ask devs more experienced than me. My situation is this:
I have one python script that continuously identifies people's faces through a video stream and creates a dict object with the name and the time the preens was recognised - called recogniser_class.py. This one has a class with a method to retrieve the identified persons called returnIdentifiedFaces()
I have a second python (called tkapp.py) script that consists of a main script and two classes. The first one creates a screen with some information on it - mainly weather, clock and personalised news and calendar events. And the second one called recognizerAsync() Now these two last items, news and calendar events, should be personalised by the name of the user and that "user" shall of course be identified by this very first script by calling that method returnIdentifiedFaces()
This I tried to achieve by creating this second class recognizerAsync() within tkapp.py to instantiate recognizer_class class and have it run as a thread.
I can start both scripts alone and they work - obviously the tkapp without personalisation :-)
Now here is the code from within the script tkapp to instantiate the recogniser class and start the recognition process as a thread
class recognizerAsync(Thread):
def __init__(self):
super().__init__()
print("starting up recogizer from callRecognizerThread")
if (use_user == True):
#myRecognizer = recognizer(consoleLog, debugMsg, run_from_flask)
self.myRecognizer = the_recognizer.recognizer(True, True, True)
def run(self):
print("starting up recogizer from callRecognizerThread")
if (use_user == True):
#myRecognizer = recognizer(consoleLog, debugMsg, run_from_flask)
self.myRecognizer.faceRecognizer()
def getUser(self):
self.myRecognizer.printRecognizedFaces()
return(self.myRecognizer.returnRecognizedFaces())
As said, this code is within the tkapp.py script.
I changed this to using a queue so now the code looks like this, but it still does NOT execute correctly. The returnRecognizedFaces method from the external recogniser class is never executed. This is the new code:
class recognizerAsync(Thread):
def __init__(self):
super(recognizerAsync,self).__init__()
print("starting up recogizer from callRecognizerThread")
if (use_user == True):
#myRecognizer = recognizer(consoleLog, debugMsg, run_from_flask)
self.myRecognizer = the_recognizer.recognizer(True, True, True)
def run(self):
print("starting up recogizer from callRecognizerThread")
if (use_user == True):
self.myRecognizer.faceRecognizer()
while (True):
if ( not q.full() ):
fd = self.myRecognizer.returnRecognizedFaces()
print(f"PRODUCER: putting into queue {fd}")
q.put(fd)
else:
print("ERROR :: Queue q is full")
Once the tkapp.py is started it instantiates it's own GUI class and then starts the recogniser_class.py thread with this code snippet:
# start the gui
window = Tk()
window.title("Smart Mirror")
window.geometry('1024x768')
window.configure(background=gui_back_color)
window.bind("<Escape>", close_escape)
mirror = GUI(window)
mirror.setupGUI()
# update the news calling returnRecognizedFaces()
window.after(1000, mirror.updateNews)
face_thread = recognizerAsync()
face_thread.start()
window.mainloop()
This all works. So the GUI is created and the recognition of people is started (I assume as a thread)
The problem I have is that the moment this is executed, I can see in the log and console, that the recogniser_class.py is indeed identifying people, but I don't know how to query the result of the recognizer_class.
this is the code within tkapp.py that I thought should do the trick:
def updateNews(self):
# cola the method to query the recognised person dictionary from recognizer_class.py
self.user = recognizerAsync.getUser()
print(f"got user {self.user} from recognizer")
news_data = self.myNews.returnNews(self.user)
if (len(news_data) > 0):
GUI.news_today.configure(text=(f"Nachrichten für {self.user}"))
GUI.news_number1.insert(INSERT, (f"{news_data[0]['title']}"))
else:
GUI.news_title.configure(text="Keine Nachrichten verfügbar")
window.after(50000000, mirror.updateNews)
As said, this does not work and I really don't know how to do it right. This is the error I receive from this code:
File "./tkapp.py", line 271, in updateNews
self.user = recognizerAsync.getUser()
TypeError: getUser() missing 1 required positional argument: 'self'
starting face detection - press Ctrl C to stop
I understand of course, that the recognizerAsync class is instantiated from the main script and therefore not available within the GUI class within the tkapp.py script - but how do I solve this issue????
I hope someone can help me here,
Christian
Please find below the code of the tkapp.py
tkapp.py:
#!/usr/bin/env python3
# needed to source in the configuration from file config.py
from pathlib import Path
# time formatting for clock
import locale
locale.setlocale(locale.LC_TIME, 'de_DE.UTF-8')
import time
from time import strftime
from datetime import date, timedelta
# the TK Gui
from tkinter import *
import tkinter.font
import pandas as pd
# needed to run the recognizer in background
from threading import Thread
# need to show images from the web
from PIL import Image, ImageTk
from urllib.request import urlopen
from io import BytesIO
import Weather.weather_class as the_weather
import News.news_class as the_news
import Recognizer.recognizer_class as the_recognizer
# EVERY RUNTIME BEHAVIOUR IS SET IN THE CONFIG FILE config.py
config_file = 'config.py'
#
## THE GUI CLASS SETS UP THE LABLES AND INSTANTIATES THE NEWS AND WEATHER CLASS
## IT IS ALSO RESPONSIBLE FOR UPDATING THE SCREEN CONTENT
#
class GUI(Frame):
largeFont = ''
mediumFont = ''
normalplusFont = ''
normalFont = ''
lightFont = ''
identified_person = 'nil' # the dict we should get back from recognizer
user = 'nil' # a simple name string we pass to other functions
# module pathes etc.
weather_icons_path = ''
def __init__(self, master):
Frame.__init__(self, master)
self.largeFont = tkinter.font.Font(family=gui_font_large[0], size=gui_font_large[1])
self.mediumFont = tkinter.font.Font(family=gui_font_medium[0], size=gui_font_medium[1])
self.normalplusFont = tkinter.font.Font(family=gui_font_normalplus[0], size=gui_font_normalplus[1])
self.normalFont = tkinter.font.Font(family=gui_font_normal[0], size=gui_font_normal[1])
self.lightFont = tkinter.font.Font(family=gui_font_light[0], size=gui_font_light[1])
# instantiate news and weather class
if (show_weather == True):
self.myWeather = the_weather.weather()
if (show_news) == True:
self.myNews = the_news.news()
#if (use_user == True):
#myRecognizer = recognizer(consoleLog, debugMsg, run_from_flask)
#self.myRecognizer = the_recognizer.recognizer(True, True, True)
def setupGUI(self):
self.grid(row=0, column=0, padx=20, pady=20)
if (show_weather == True):
# Weather & news frame to contain weather/news info
today_weather_frame = Frame(self, width=400, height=500, bg=gui_back_color)
today_weather_frame.grid(row=0, column=0, sticky=W)
GUI.weather_headline = Label(today_weather_frame, text="Wetter...", fg=gui_fore_color, bg=gui_back_color,
font=self.mediumFont, justify=LEFT)
GUI.weather_headline.grid(row=0, column=0, sticky=NW)
GUI.weather_report = Label(today_weather_frame, text="Wetterbericht...", fg=gui_fore_color, bg=gui_back_color,
font=self.normalplusFont, justify=LEFT)
GUI.weather_report.grid(row=1, column=0, sticky=W)
today_weather_frame_details = Frame(self, width=400, height=500, bg=gui_back_color)
today_weather_frame_details.grid(row=1, column=0, sticky=W)
GUI.weather_temp = Label(today_weather_frame_details, text="Temperatur:", fg=gui_fore_color, bg=gui_back_color,
font=self.normalFont, justify=LEFT)
GUI.weather_temp.grid(row=2, column=0, sticky=W)
GUI.weather_temp_el = Label(today_weather_frame_details, text="...", fg=gui_fore_color, bg=gui_back_color,
font=self.normalFont, justify=LEFT)
GUI.weather_temp_el.grid(row=2, column=1, sticky=W)
GUI.weather_humidity = Label(today_weather_frame_details, text="Luftfeuchtigkeit:", fg=gui_fore_color, bg=gui_back_color,
font=self.normalFont, justify=LEFT)
GUI.weather_humidity.grid(row=3, column=0, sticky=W)
GUI.weather_humidity_el = Label(today_weather_frame_details, text="...", fg=gui_fore_color, bg=gui_back_color,
font=self.normalFont, justify=LEFT)
GUI.weather_humidity_el.grid(row=3, column=1, sticky=W)
GUI.weather_sunrise = Label(today_weather_frame_details, text="Sonnenaufgang:", fg=gui_fore_color, bg=gui_back_color,
font=self.normalFont, justify=LEFT)
GUI.weather_sunrise.grid(row=4, column=0, sticky=W)
GUI.weather_sunrise_el = Label(today_weather_frame_details, text="...", fg=gui_fore_color, bg=gui_back_color,
font=self.normalFont, justify=LEFT)
GUI.weather_sunrise_el.grid(row=4, column=1, sticky=W)
GUI.weather_sunset = Label(today_weather_frame_details, text="Sonnenuntergang:", fg=gui_fore_color, bg=gui_back_color,
font=self.normalFont, justify=LEFT)
GUI.weather_sunset.grid(row=5, column=0, sticky=W)
GUI.weather_sunset_el = Label(today_weather_frame_details, text="...", fg=gui_fore_color, bg=gui_back_color,
font=self.normalFont, justify=LEFT)
GUI.weather_sunset_el.grid(row=5, column=1, sticky=W)
# the initial weather icon
icon = PhotoImage(file=weather_icons_path+"partly-cloudy-day.gif")
icon = icon.subsample(10)
# Set up labels to hold weather icons
GUI.icon_label = Label(today_weather_frame, borderwidth=0, image=icon)
GUI.icon_label.photo = icon
GUI.icon_label.grid(row=0, column=1, sticky=W)
empty_frame = Frame(self, width=200, height=500, bg=gui_back_color)
empty_frame.grid(row=2, column=0, sticky=W)
if (show_news == True):
# Labels to hold news info
news_frame = Frame(self, width=400, height=500, bg=gui_back_color)
news_frame.grid(row=3, column=0, sticky=W)
GUI.news_today = Label(news_frame, text="\nNachrichten:", fg=gui_fore_color, bg=gui_back_color,
font=self.normalplusFont, justify=LEFT)
GUI.news_today.grid(row=0, column=0, sticky=W)
GUI.news_number1 = Text(news_frame, wrap=WORD, height=1, width=80,
fg=gui_fore_color, bg=gui_back_color, bd=0,
font=self.lightFont, highlightthickness=0)
GUI.news_number1.grid(row=1, column=0, sticky=W)
GUI.news_number2 = Text(news_frame, wrap=WORD, height=1, width=80,
fg=gui_fore_color, bg=gui_back_color, bd=0,
font=self.lightFont, highlightthickness=0)
GUI.news_number2.grid(row=2, column=0, sticky=W)
GUI.news_number3 = Text(news_frame, wrap=WORD, height=1, width=80,
fg=gui_fore_color, bg=gui_back_color, bd=0,
font=self.lightFont, highlightthickness=0)
GUI.news_number3.grid(row=3, column=0, sticky=W)
GUI.news_number4 = Text(news_frame, wrap=WORD, height=1, width=80,
fg=gui_fore_color, bg=gui_back_color, bd=0,
font=self.lightFont, highlightthickness=0)
GUI.news_number4.grid(row=4, column=0, sticky=W)
GUI.news_number5 = Text(news_frame, wrap=WORD, height=1, width=80,
fg=gui_fore_color, bg=gui_back_color, bd=0,
font=self.lightFont, highlightthickness=0)
GUI.news_number5.grid(row=5, column=0, sticky=W)
# Adjust this width for spacing
frame_placeholder = Frame(self, width=gui_width/4, height=10, bg=gui_back_color)
frame_placeholder.grid(row=0, column=1)
# Time frame to hold time & date in grid
if (show_clock == True):
time_frame = Frame(self, width=400, height=500, bg=gui_back_color)
time_frame.grid(row=0, column=2, sticky=NE)
GUI.time_label = Label(time_frame, text=strftime("%H:%M", time.localtime()), fg=gui_fore_color, bg=gui_back_color,
font=self.largeFont)
GUI.time_label.grid(row=0, column=0, sticky=NE)
GUI.date_label = Label(time_frame, text=strftime("%A, %d. %B", time.localtime()), fg=gui_fore_color, bg=gui_back_color,
font=self.normalFont)
GUI.date_label.grid(row=1, column=0, sticky=NE)
# Frame for calendar info
if (show_calendar == True):
calendar_frame = Frame(self, width=400, height=500, bg=gui_back_color)
calendar_frame.grid(row=1, column=2, sticky=NE)
GUI.calendar_header = Label(calendar_frame, text='\nUpcoming events:', fg=gui_fore_color, bg=gui_back_color,
font=self.mediumFont)
GUI.calendar_header.grid(row=0, column=0, sticky=NE)
GUI.calendar_event1 = Label(calendar_frame, text='Loading calendar events...', fg=gui_fore_color, bg=gui_back_color,
font=self.normalFont)
GUI.calendar_event1.grid(row=1, column=0, sticky=NE)
GUI.calendar_event2 = Label(calendar_frame, text='Loading calendar events...', fg=gui_fore_color, bg=gui_back_color,
font=self.normalFont)
GUI.calendar_event2.grid(row=2, column=0, sticky=NE)
GUI.calendar_event3 = Label(calendar_frame, text='Loading calendar events...', fg=gui_fore_color, bg=gui_back_color,
font=self.normalFont)
GUI.calendar_event3.grid(row=3, column=0, sticky=NE)
GUI.calendar_event4 = Label(calendar_frame, text='Loading calendar events...', fg=gui_fore_color, bg=gui_back_color,
font=self.normalFont)
GUI.calendar_event4.grid(row=4, column=0, sticky=NE)
GUI.calendar_event5 = Label(calendar_frame, text='Loading calendar events...', fg=gui_fore_color, bg=gui_back_color,
font=self.normalFont)
GUI.calendar_event5.grid(row=5, column=0, sticky=NE)
self.configure(background=gui_back_color)
def updateClock(self):
GUI.time_label.configure(text=strftime("%H:%M", time.localtime()))
GUI.date_label.configure(text=strftime("%A, %d. %B", time.localtime()))
window.after(1000, mirror.updateClock)
def updateWeather(self):
# Updates the weather information
weather_data = self.myWeather.returnWeather(self.user)
GUI.weather_headline.configure(text=(f"Das {weather_data['city']} Wetter"))
GUI.weather_report.configure(text=(f"{weather_data['weather_desc']}"))
GUI.weather_temp_el.configure(text=(f"{weather_data['temp']}°C (Gefühlt: {weather_data['feels_like']}°C)"))
GUI.weather_humidity_el.configure(text=(f"{weather_data['humidity']}%"))
GUI.weather_sunrise_el.configure(text=(f"{weather_data['sunrise']}"))
GUI.weather_sunset_el.configure(text=(f"{weather_data['sunset']}"))
window.after(50000000, mirror.updateWeather)
def updateNews(self):
if (use_user == True):
self.user = recognizerAsync.getUser()
print(f"got user {self.user} from recognizer")
news_data = self.myNews.returnNews(self.user)
#print("size: " + str(len(news_data)) + "\n / result: " + str(news_data))
if (len(news_data) > 0):
if self.user != 'nil' and self.user != "":
GUI.news_today.configure(text=(f"Nachrichten für {self.user}"))
else:
GUI.news_today.configure(text=(f"Aktuelle Nachrichten"))
GUI.news_number1.insert(INSERT, (f"{news_data[0]['title']}"))
GUI.news_number2.insert(INSERT, (f"{news_data[1]['title']}"))
GUI.news_number3.insert(INSERT, (f"{news_data[2]['title']}"))
GUI.news_number4.insert(INSERT, (f"{news_data[3]['title']}"))
GUI.news_number5.insert(INSERT, (f"{news_data[4]['title']}"))
else:
GUI.news_title.configure(text="Keine Nachrichten verfügbar")
window.after(50000000, mirror.updateNews)
def updateCalendar(self):
event_list = []
if not events:
print('No upcoming events found.')
for event in events:
event_str = ''
start = event['start'].get('dateTime', event['start'].get('date'))
start = start[0:10] # Remove unnecessary characters at end of string
year = start.find('-')
start_day = datetime.datetime.strptime(start, '%Y-%m-%d').strftime('%a %b %d')
event_date = start[year + 1:year + 6]
summary = event['summary'].encode('ascii', 'ignore').decode('ascii') # Remove emojis
event_str += summary + ' | ' + start_day
event_list.append(event_str)
window.after(500000000, mirror.updateCalendar)
def recognizer(self):
self.myRecognizer.faceRecognizer()
class recognizerAsync(Thread):
def __init__(self):
super().__init__()
print("starting up recogizer from callRecognizerThread")
if (use_user == True):
#myRecognizer = recognizer(consoleLog, debugMsg, run_from_flask)
self.myRecognizer = the_recognizer.recognizer(True, True, True)
def run(self):
print("starting up recogizer from callRecognizerThread")
if (use_user == True):
self.myRecognizer.faceRecognizer()
def getUser(self):
self.myRecognizer.printRecognizedFaces()
return(self.myRecognizer.returnRecognizedFaces())
#
## MAIN SCRIPT RUN FROM HERE
#
app_config={}
print("setting config file to " + str(config_file))
exec(Path(config_file).read_text(encoding="utf8"), {}, app_config)
use_user = (app_config["use_user"])
show_news = (app_config["show_news"])
show_weather = (app_config["show_weather"])
show_calendar = (app_config["show_calendar"])
show_clock = (app_config["show_clock"])
analog_clock = (app_config["analog_clock"])
# GUI controls
gui_width = (app_config["gui_width"])
gui_height = (app_config["gui_height"])
gui_fullscreen = (app_config["gui_fullscreen"])
gui_back_color = (app_config["gui_back_color"])
gui_fore_color = (app_config["gui_fore_color"])
gui_font_large = (app_config["gui_font_large"])
gui_font_medium = (app_config["gui_font_medium"])
gui_font_normalplus = (app_config["gui_font_normalplus"])
gui_font_normal = (app_config["gui_font_normal"])
gui_font_light = (app_config["gui_font_light"])
# module pathes etc.
weather_icons_path = (app_config["weather_icons_path"])
def close_escape(event=None):
print('Smart mirror closed')
window.destroy()
print(f"starting GUI with {gui_width}x{gui_height}")
# start the gui
window = Tk()
window.title("Smart Mirror")
window.geometry((F'{gui_width}x{gui_height}'))
window.configure(background=gui_back_color)
#Removes borders from GUI and implements quit via esc
window.overrideredirect(1)
window.overrideredirect(0)
window.attributes("-fullscreen", gui_fullscreen)
window.wm_attributes("-topmost", 1)
window.focus_set()
window.bind("<Escape>", close_escape)
mirror = GUI(window)
mirror.setupGUI()
if (show_clock == True):
window.after(1000, mirror.updateClock)
if (show_weather == True):
window.after(1000, mirror.updateWeather)
if (show_news == True):
window.after(1000, mirror.updateNews)
if (show_calendar == True):
window.after(1000, mirror.updateCalendar)
if (use_user == True):
face_thread = recognizerAsync()
face_thread.start()
window.mainloop()
Use a Queue, it is designed for inter-thread communication. Initialise a queue object before you split off the thread, and it will be available in both. When your recogniser thread finds a user, put it into the queue. In your update function, if the queue is not empty get the data and display it.
EDIT: Here is a minimal example:
from tkinter import Tk, Label
from threading import Thread
from queue import Queue
from time import sleep
queue = Queue()
class CountLabel(Label):
def __init__(self, master):
super().__init__(text="Waiting")
self.pack()
def update(self):
while not queue.empty():
count = queue.get()
self.configure(text=f"Count: {count}")
self.master.after(1000, self.update)
def produce(queue):
count = 0
while (True):
count += 1
queue.put(count)
sleep(1)
window = Tk()
label = CountLabel(window)
window.after(1000, label.update)
thread = Thread(target=produce, args=[queue]).start()
window.mainloop()
in my code I do not understand how radio buttons are working. My problem is, that the radio-buttons variables are not passed further.
from tkinter import *
class SimpleDialog(Frame):
def __init__(self):
super().__init__()
self.output1 = ""
self.output10 = ""
self.output11 = ""
self.output12 = ""
self.initUI()
def initUI(self):
self.master.title("New Input")
self.pack(fill=BOTH, expand=True)
frame1 = Frame(self)
frame1.pack(fill=X)
lbl1 = Label(frame1, text="Name:", width=20)
lbl1.pack(side=LEFT, padx=5, pady=10)
self.entry1 = Entry(frame1, textvariable=self.output1)
self.entry1.insert(0,"Your name")
self.entry1.pack(fill=X, padx=5, expand=True)
auswahl = IntVar()
auswahl.set(0)
frame10 = Frame(self)
frame10.pack(fill=X)
lbl10 = Label(frame10, text="Do you like tomatoes?", width=40)
lbl10.pack(side=LEFT, padx=5, pady=5)
self.entry10 = Radiobutton(frame10, text="No",variable=auswahl, padx = 0, value=0).pack(anchor=W)
self.entry11 = Radiobutton(frame10, text="Sometimes",variable=auswahl,padx = 0, value=1).pack(anchor=W)
self.entry12 = Radiobutton(frame10, text="Yes",variable=auswahl,padx = 0, value=2).pack(anchor=W)
frame3 = Frame(self)
frame3.pack(fill=X)
print(self.entry12)
btn = Button(frame3, text="New entry", command=self.onSubmit)
btn.pack(padx=5, pady=10)
def onSubmit(self):
# Input
self.output1 = self.entry1.get()
# Radio-Buttons
self.output10 = self.entry10
self.output11 = self.entry11
self.output12 = self.entry12
self.quit()
def main():
# This part triggers the dialog
root = Tk()
root.geometry("650x300+500+300")
app = SimpleDialog()
root.mainloop()
# Here we can act on the form components or
# better yet, copy the output to a new variable
user_input = (app.output1, app.output10, app.output11, app.output12)
try:
root.destroy()
except:
pass
return user_input
if __name__ == '__main__':
diaginput = main()
Can you help me to change the code, so that I can get the values of the radio buttons, e.g. print(diaginput).
I have problems to get the values of the radio buttons.
You should not try to access the radiobuttons but the variable you used to store the values.
But you should make the variable an attribute of the class of your dialog to access it from all methods:
self.auswahl = IntVar()
self.auswahl.set(0)
self.entry10 = Radiobutton(frame10, text="No",variable=self.auswahl, padx = 0, value=0).pack(anchor=W)
self.entry11 = Radiobutton(frame10, text="Sometimes",variable=self.auswahl,padx = 0, value=1).pack(anchor=W)
self.entry12 = Radiobutton(frame10, text="Yes",variable=self.auswahl,padx = 0, value=2).pack(anchor=W)
In the function on submit, you may then just get the value of the .auswahl attribute
# Radio-Buttons
self.output = self.auswahl.get()
The variable self.output will then hold an integer with a value between 0 and 2, depending on your selection.
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.
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.
This code works fine.
CalculateButton = tk.Button(self.root, text="Calculate", command=lambda: calc.GrandTotal()).grid(row=6, column=0, sticky=tk.W+tk.E)
But this code results in an error: "NameError: global name 'app' is not defined"
CalculateButton = tk.Button(self.root, text="Calculate", command=calc.GrandTotal()).grid(row=6, column=0, sticky=tk.W+tk.E)
So why is it that removing Lambda causes an error?
Source code itself is:
# -*- coding: cp1252 -*-
import Tkinter as tk
import tkMessageBox
# Classes
class Application(tk.Frame):
def __init__(self):
# Create G.U.I. Framework
self.root = tk.Tk()
tk.Frame.__init__(self)
self.root.title("Job Estimator")
self.root.geometry("290x152")
self.root.resizable(0,0)
# Create G.U.I. Widgets
tk.Label(self.root, text="Labour: " + unichr(163) + "40.00 x Hours") .grid(row=0, column=0, sticky=tk.W)
tk.Label(self.root, text="Travel: " + unichr(163) + "1.00 x Miles") .grid(row=1, column=0, sticky=tk.W)
tk.Label(self.root, text="Plastic: " + unichr(163) + "2.00 x Metres").grid(row=2, column=0, sticky=tk.W)
tk.Label(self.root, text="Copper: " + unichr(163) + "3.00 x Metres").grid(row=3, column=0, sticky=tk.W)
tk.Label(self.root, text="Chrome: " + unichr(163) + "4.00 x Metres") .grid(row=4, column=0, sticky=tk.W)
tk.Label(self.root, text="Total: " + unichr(163)) .grid(row=5, column=0, sticky=tk.W)
self.totalLabel = tk.Label(self.root, text="0.00")
self.totalLabel.grid(row=5, column=0, sticky=tk.W, padx=42, pady=0)
self.LabourInput = tk.Entry(self.root)
self.LabourInput.grid(row=0, column=1)
self.LabourInput.insert(0, "0")
self.TravelInput = tk.Entry(self.root)
self.TravelInput.grid(row=1, column=1)
self.TravelInput.insert(0, "0")
self.PlasticInput = tk.Entry(self.root)
self.PlasticInput.grid(row=2, column=1)
self.PlasticInput.insert(0, "0")
self.CopperInput = tk.Entry(self.root)
self.CopperInput.grid(row=3, column=1)
self.CopperInput.insert(0, "0")
self.ChromeInput = tk.Entry(self.root)
self.ChromeInput.grid(row=4, column=1)
self.ChromeInput.insert(0, "0")
CalculateButton = tk.Button(self.root, text="Calculate", command=calc.GrandTotal()).grid(row=6, column=0, sticky=tk.W+tk.E)
class Calculator():
def __init__(self):
pass
def Multiply(self, number, rate):
try:
NumFloat = float(number)
RateFloat = float(rate)
return NumFloat * RateFloat
except (ValueError):
raise tkMessageBox.showerror("Error", "One or more text fields contains non-numerical characters.")
def GrandTotal(self): # Adds each entry field to produce and return a grand total.
# Set Variables
self.LabourTotal = self.Multiply(app.LabourInput. get(), 40)
self.TravelTotal = self.Multiply(app.TravelInput. get(), 1)
self.PlasticTotal = self.Multiply(app.PlasticInput.get(), 2)
self.CopperTotal = self.Multiply(app.CopperInput. get(), 3)
self.ChromeTotal = self.Multiply(app.ChromeInput. get(), 4)
self.CompleteTotal = self.LabourTotal + self.TravelTotal + self.PlasticTotal + self.CopperTotal + self.ChromeTotal
return app.totalLabel.config(text=self.CompleteTotal) # Return the total value.
calc = Calculator()
app = Application()
app.mainloop()
Any ideas?
app is not defined until after the Application() instance is created, which means that Application.__init__ must have completed first.
By removing the lambda, you directly call the calc.GrandTotal() method, and that method relies on app already existing. It does not, as Application.__init__ is not done yet.
The whole point of the command argument however is to pass in something that will be called later. That's why the lambda works, it produces a function to call calc.GrantTotal() later on, when the Calculate button is pressed. By calling it directly you short-circuited this normal path.
You can pass in calc.GrantTotal without calling it, by removing the ():
CalculateButton = tk.Button(
self.root, text="Calculate", command=calc.GrandTotal)
CalculateButton.grid(row=6, column=0, sticky=tk.W+tk.E)
Note that I called the Button.grid() method in a separate expression. Button.grid() returns None; there is no point in storing that return value in a variable. Store the tk.Button() return value instead.
lambda is used to create a function that, when called (i.e., when you click the button), will call calc.GrandTotal. Without it, you are assigning the return value of an immediate call to GrantTotal instead as the callback.