How do I fix this strange exception : Exception in Tkinter callback - python

I am working on a YouTube downloader project that takes a link and then puts the information about the video quality and sound quality of the link in the Combobox.
But when I try to put audio and video information in the Combobox, it gives this exception:
This is my code :
import tkinter
import tkinter.ttk
from tkinter import *
from tkinter import filedialog
from os import path
import pafy
from pafy import *
class Youtube():
def __init__(self):
self.label()
self.entry()
self.button()
self.combobox()
self.data=[]
def label(self):
Label(window, text='URL', font='bold').grid(row=0, column=0, padx=100)
Label(window, text='Destination', font='bold').grid(row=2, column=0, padx=100)
Label(window, text='File Name', font='bold').grid(row=4, column=0, padx=100)
Label(window, text='Video Quality', font='bold').grid(row=6, column=0, pady=20)
Label(window, text='Audio Quality', font='bold').grid(row=7, column=0, pady=5)
Label(window, text='Download Type', font='bold').grid(row=8, column=0, pady=15)
Label(window, text='Combine AV', font='bold').grid(row=8, column=1)
def entry(self):
global een
global en
en=Entry(window, width=35, borderwidth=10)
en.grid(row=1, column=0, padx=100, pady=5)
een=Entry(window, width=35, borderwidth=10)
een.grid(row=3, column=0, padx=100, pady=5)
Entry(window, width=35, borderwidth=10).grid(row=5, column=0, padx=100, pady=5)
def button(self):
Button(window, text='i', height=1, width=3, command=self.information).grid(row=1, column=1)
Button(window, text='d', height=1, width=3, command=self.destination).grid(row=3, column=1)
Button(window, text='Download', font='bold').grid(row=12, column=0, padx=150, pady=10, columnspan=3)
def combobox(self):
tkinter.ttk.Combobox(window, width=15).grid(row=6, column=1)
tkinter.ttk.Combobox(window, width=15).grid(row=7, column=1, pady=5)
tkinter.ttk.Combobox(window, values=['Audio only', 'Vido only', 'Audio and vido'],
width=15).grid(row=9, column=0)
tkinter.ttk.Combobox(window, values=['Yes', 'No'], width=15).grid(row=9, column=1, pady=20)
tkinter.ttk.Progressbar(window, orient=HORIZONTAL, length=300,
mode='determinate').grid(row=11, column=0, padx=200, pady=10, columnspan=3)
def destination(self):
path = str(filedialog.askdirectory())
een.insert(tkinter.END, path)
def information(self):
global link
link = en.get()
self.video()
self.audio()
def video(self):
video_quality_list = []
self.data = pafy.new(link)
video_streams = self.data.videostreams
for video_quality in video_streams:
video_quality_list.append(video_quality)
tkinter.ttk.Combobox(window, values=video_quality_list, width=15).grid(row=6, column=1, pady=5)
def audio(self):
audio_quality_list = []
self.data = pafy.new(link)
audio_streams = self.data.audiostreams
for audio_quality in audio_streams:
audio_quality_list.append(audio_quality)
tkinter.ttk.Combobox(window, values=audio_quality_list, width=15).grid(row=7, column=1)
window = Tk()
mywin = Youtube()
window.title('Youtube Downloader')
window.geometry("700x600+10+10")
window.mainloop()
I would be very grateful if anyone could help me to fix it.
Thanks!

Related

Python Tkinter, How to pass Variable into mutltiple Functions

EDIT: Thanks to #Osadhi Virochana Jayasinghe Si! Using global "vars" inside the buildwindow() function, makes them readable in the called button function. I also had to fix how to get the Values of the Checkbox and text Widget.
Full Fixed code:
import tkinter as tk
import tkinter.scrolledtext as tkst
from PyQt5.QtWidgets import QApplication # need to install PyQt5 or remove center() Function
def main_window():
window = tk.Tk()
window.title("New Entry")
build_window(window)
center(window) # https://stackoverflow.com/questions/3352918/how-to-center-a-window-on-the-screen-in-tkinter
window.mainloop() # Main Loop, nothing runs after here on Gui
def center(toplevel):
toplevel.update_idletasks()
app = QApplication([])
screen_width = app.desktop().screenGeometry().width()
screen_height = app.desktop().screenGeometry().height()
size = tuple(int(_) for _ in toplevel.geometry().split('+')[0].split('x'))
x = screen_width/2 - size[0]/2
y = screen_height/2 - size[1]/2
toplevel.geometry("+%d+%d" % (x, y))
def build_window(window):
global entry_name, entry_link, entry_xpath, chbox_active, entry_comment, box_var
label_title = tk.Label(window, text="NEW ENTRY")
label_name = tk.Label(window, text="Name:")
entry_name = tk.Entry(window)
label_link = tk.Label(window, text="Link:")
entry_link = tk.Entry(window)
label_xpath = tk.Label(window, text="XPath:")
entry_xpath = tk.Entry(window)
label_active = tk.Label(window, text="Active:")
box_var = tk.IntVar()
chbox_active = tk.Checkbutton(window, variable=box_var, text="Active")
label_comment = tk.Label(window, text="Comment:")
entry_comment = tkst.ScrolledText(window, width=40, height=4, font=("roboto", 8))
botton_cancel = tk.Button(window, text="Done", command=lambda: close_window(window))
button_go = tk.Button(window, text="Run", command=lambda: write_dict(window))
label_title.grid (row=0, column=1, sticky="nwse", padx=2, pady=2)
label_name.grid (row=1, column=0, sticky="e", padx=2, pady=2)
entry_name.grid (row=1, column=1, sticky="nwse", padx=2, pady=2)
label_link.grid (row=2, column=0, sticky="e", padx=2, pady=2)
entry_link.grid (row=2, column=1, sticky="nwse", padx=2, pady=2)
label_xpath.grid (row=3, column=0, sticky="e", padx=2, pady=2)
entry_xpath.grid (row=3, column=1, sticky="nwse", padx=2, pady=2)
label_active.grid (row=4, column=0, sticky="e", padx=2, pady=2)
chbox_active.grid (row=4, column=1, sticky="w", padx=2, pady=2)
label_comment.grid (row=5, column=0, sticky="e", padx=2, pady=2)
entry_comment.grid (row=5, column=1, sticky="w", padx=2, pady=2)
window.grid_rowconfigure(6, minsize=20) # Empty?
botton_cancel.grid(row=7, column=0, sticky="w", padx=2, pady=2) # Cancel Button
button_go.grid(row=7, column=1, sticky="e", padx=2, pady=2) # Write Dict Button
def close_window(window):
window.destroy()
def write_dict(window):
i_dict = {}
i_dict["name"] = entry_name.get()
i_dict["link"] = entry_link.get()
i_dict["xpath"] = entry_xpath.get()
i_dict["active"] = box_var.get()
i_dict["comment"] = entry_comment.get('1.0', tk.END)
print(i_dict)
pass
main_window()
I am trying to make a simple GUI do enter Data into a Dictionary. Most things i find online write the Tkinter straight into the .py, but i want to use a Function to Draw the Window, and another Function to do its stuff once a Button is pressed.
Shorted code:
def main_window():
window = tk.Tk()
build_window(window)
window.mainloop()
def build_window(window):
entry_name = tk.Entry(window)
button_go = tk.Button(window, text="Run", command=lambda: write_dict())
button_go.grid(row=7, column=1, sticky="e", padx=2, pady=2)
def write_dict():
i_dict = {}
i_dict["name"] = entry_name.get()
main_window()
And i am getting AttributeError: module 'tkinter' has no attribute 'entry_name'. I tried various ways to get window into write_dict(), but i could never use .get() to read the values inside the Entry Box.
how would i do this?
Full code:
import tkinter as tk
import tkinter.scrolledtext as tkst
from PyQt5.QtWidgets import QApplication
d_list = []
def main_window():
window = tk.Tk()
window.title("New Entry")
build_window(window)
window.mainloop() # Main Loop, nothing runs after here on Gui
def build_window(window):
label_title = tk.Label(window, text="NEW ENTRY")
label_name = tk.Label(window, text="Name:")
entry_name = tk.Entry(window)
label_link = tk.Label(window, text="Link:")
entry_link = tk.Entry(window)
label_xpath = tk.Label(window, text="XPath:")
entry_xpath = tk.Entry(window)
label_active = tk.Label(window, text="Active:")
chbox_active = tk.Checkbutton(window, variable=1, text="Active")
label_comment = tk.Label(window, text="Comment:")
entry_comment = tkst.ScrolledText(window, width=40, height=4, font=("roboto", 8))
botton_cancel = tk.Button(window, text="Done", command=lambda: close_window(window))
button_go = tk.Button(window, text="Run", command=lambda: write_dict())
label_title.grid (row=0, column=1, sticky="nwse", padx=2, pady=2)
label_name.grid (row=1, column=0, sticky="e", padx=2, pady=2)
entry_name.grid (row=1, column=1, sticky="nwse", padx=2, pady=2)
label_link.grid (row=2, column=0, sticky="e", padx=2, pady=2)
entry_link.grid (row=2, column=1, sticky="nwse", padx=2, pady=2)
label_xpath.grid (row=3, column=0, sticky="e", padx=2, pady=2)
entry_xpath.grid (row=3, column=1, sticky="nwse", padx=2, pady=2)
label_active.grid (row=4, column=0, sticky="e", padx=2, pady=2)
chbox_active.grid (row=4, column=1, sticky="w", padx=2, pady=2)
label_comment.grid (row=5, column=0, sticky="e", padx=2, pady=2)
entry_comment.grid (row=5, column=1, sticky="w", padx=2, pady=2)
window.grid_rowconfigure(6, minsize=20) # Empty?
botton_cancel.grid(row=7, column=0, sticky="w", padx=2, pady=2) # Cancel Button
button_go.grid(row=7, column=1, sticky="e", padx=2, pady=2) # Write Dict Button
def close_window(window):
window.destroy()
def write_dict():
global d_list
i_dict = {}
i_dict["name"] = entry_name.get()
i_dict["link"] = entry_link.get()
i_dict["xpath"] = entry_xpath.get()
i_dict["active"] = chbox_active.get()
i_dict["comment"] = entry_comment.get()
print(i_dict)
pass
main_window()
EDIT:
The Full Errors are these 2, the first one is with the currently posted code, the second is with passing ´window´ into the button.
Traceback (most recent call last):
File "C:\Python\Python38\lib\tkinter\__init__.py", line 1883, in __call__
return self.func(*args)
File "C:/Users/Chris/Google Drive/Python/html_new_entry.py", line 50, in <lambda>
button_go = tk.Button(window, text="Run", command=lambda: write_dict())
File "C:/Users/Chris/Google Drive/Python/html_new_entry.py", line 78, in write_dict
i_dict["name"] = entry_name.get()
NameError: name 'entry_name' is not defined
Traceback (most recent call last):
File "C:\Python\Python38\lib\tkinter\__init__.py", line 1883, in __call__
return self.func(*args)
File "C:/Users/Chris/Google Drive/Python/html_new_entry.py", line 50, in <lambda>
button_go = tk.Button(window, text="Run", command=lambda: write_dict(window))
File "C:/Users/Chris/Google Drive/Python/html_new_entry.py", line 78, in write_dict
i_dict["name"] = window.entry_name.get()
File "C:\Python\Python38\lib\tkinter\__init__.py", line 2345, in __getattr__
return getattr(self.tk, attr)
AttributeError: '_tkinter.tkapp' object has no attribute 'entry_name'
Add global entry_name,entry_link,entry_xpath,chbox_active,entry_comment under the def build_window(window): It will fix Variable error.
And I fixed all of the issues
Here is the Code:
import tkinter as tk
import tkinter.scrolledtext as tkst
#from PyQt5.QtWidgets import QApplication
d_list = []
def main_window():
window = tk.Tk()
window.title("New Entry")
build_window(window)
window.mainloop() # Main Loop, nothing runs after here on Gui
def build_window(window):
global entry_name,entry_link,entry_xpath,chbox_active,entry_comment,var
var = tk.IntVar()
label_title = tk.Label(window, text="NEW ENTRY")
label_name = tk.Label(window, text="Name:")
entry_name = tk.Entry(window)
label_link = tk.Label(window, text="Link:")
entry_link = tk.Entry(window)
label_xpath = tk.Label(window, text="XPath:")
entry_xpath = tk.Entry(window)
label_active = tk.Label(window, text="Active:")
chbox_active = tk.Checkbutton(window, variable=var, text="Active")
label_comment = tk.Label(window, text="Comment:")
entry_comment = tkst.ScrolledText(window, width=40, height=4, font=("roboto", 8))
botton_cancel = tk.Button(window, text="Done", command=lambda: close_window(window))
button_go = tk.Button(window, text="Run", command=lambda: write_dict())
label_title.grid (row=0, column=1, sticky="nwse", padx=2, pady=2)
label_name.grid (row=1, column=0, sticky="e", padx=2, pady=2)
entry_name.grid (row=1, column=1, sticky="nwse", padx=2, pady=2)
label_link.grid (row=2, column=0, sticky="e", padx=2, pady=2)
entry_link.grid (row=2, column=1, sticky="nwse", padx=2, pady=2)
label_xpath.grid (row=3, column=0, sticky="e", padx=2, pady=2)
entry_xpath.grid (row=3, column=1, sticky="nwse", padx=2, pady=2)
label_active.grid (row=4, column=0, sticky="e", padx=2, pady=2)
chbox_active.grid (row=4, column=1, sticky="w", padx=2, pady=2)
label_comment.grid (row=5, column=0, sticky="e", padx=2, pady=2)
entry_comment.grid (row=5, column=1, sticky="w", padx=2, pady=2)
window.grid_rowconfigure(6, minsize=20) # Empty?
botton_cancel.grid(row=7, column=0, sticky="w", padx=2, pady=2) # Cancel Button
button_go.grid(row=7, column=1, sticky="e", padx=2, pady=2) # Write Dict Button
def close_window(window):
window.destroy()
def write_dict():
global d_list
i_dict = {}
v = ""
i_dict["name"] = entry_name.get()
i_dict["link"] = entry_link.get()
i_dict["xpath"] = entry_xpath.get()
i_dict["active"] = var.get()
i_dict["comment"] = entry_comment.get('1.0', 'end-1c')
print(i_dict)
pass
main_window()
Now you can get checkbox status and comment box status too.

TKINTER QUIZ GAME

I am a beginner in programming and in Python. I am trying to build a quiz game with tkinter in which I call a csv file that has 6 columns, (QUESTION, ANSWERA, ANSWERB, ANSWERC, ANSWERD, CORRECTANSWER) in a python file. I have an entry box(for the questions) and 4 buttons(for the answers).
My question: How do I interate through the list created for the csv file through the command in the buttons?
When I click on the button, with the right or wrong answer, I want it to change the text at the buttons and take the values from the next row in the list.
My code:
from tkinter import*
import pygame
import sys
pygame.init()
root = Tk()
root.title("ΜΑΘΕ ΠΑΙΖΟΝΤΑΣ")
root.geometry('1352x652+0+0')
root.configure(background = 'blue')
#=================CONNECT TO DATABASE csv=========================
import csv
import unicodedata
with open('questiondb.csv',newline='',encoding="utf8")as csvfile:
csvreader=csv.reader(csvfile,delimiter=',',quotechar='|')
rows=list(csvreader)
for i in range(1,3):
print(rows[i])
#=================functions=============
def correct_answer_funcA():
if answerA==correctanswer:
print ("right!!!")
else:
print("wrong!!")
def correct_answer_funcB():
if answerB==correctanswer:
print ("right!!!")
else:
print("wrong!!")
def correct_answer_funcC():
if answerC==correctanswer:
print ("right!!!")
else:
print("wrong!!")
def correct_answer_funcD():
if answerD==correctanswer:
print ("right!!!")
else:
print("wrong!!")
#===============TEXT,LABELS,BUTTON=======================
i=1
questions=rows[i][1]
answerA=rows[i][2]
answerB=rows[i][3]
answerC=rows[i][4]
answerD=rows[i][5]
correctanswer=rows[i][6]
txtQuestion = Entry(ABC1c, font=('arial', 18,'bold'),bg='red', fg='white', bd=1, width=44,justify=CENTER)
txtQuestion.grid(row=0, column=0, columnspan=4, pady=4)
txtQuestion.insert(INSERT,questions)
lblQuestA = Label(ABC1c, font=('arial', 14,'bold'),text="A: ",bg='black', fg='white', bd=1, justify=CENTER)
lblQuestA.grid(row=1, column=0, pady=4, sticky=W)
txtQuestion1 = Button(ABC1c, font=('arial', 14,'bold'),bg='blue', fg='white', bd=1, width=17, height=2,justify=CENTER, text=answerA, command=correct_answer_funcA)
txtQuestion1.grid(row=1, column=1, pady=4)
lblQuestB = Label(ABC1c, font=('arial', 14,'bold'),text="B: ",bg='black', fg='white', bd=1,justify=LEFT)
lblQuestB.grid(row=1, column=2, pady=4, sticky=W)
txtQuestion2 = Button(ABC1c, font=('arial', 14,'bold'),bg='blue', fg='white', bd=1, width=17, height=2,justify=CENTER, text = answerB, command=correct_answer_funcB)
txtQuestion2.grid(row=1, column=3, pady=4)
lblQuestC = Label(ABC1c, font=('arial', 14,'bold'),text="C: ",bg='black', fg='white', bd=1, justify=CENTER)
lblQuestC.grid(row=2, column=0, pady=4, sticky=W)
txtQuestion3 = Button(ABC1c, font=('arial', 14,'bold'),bg='blue', fg='white', bd=1, width=17, height=2,justify=CENTER, text = answerC, command=correct_answer_funcC)
txtQuestion3.grid(row=2, column=1, pady=4)
lblQuestD = Label(ABC1c, font=('arial', 14,'bold'),text="B: ",bg='black', fg='white', bd=1,justify=LEFT)
lblQuestD.grid(row=2, column=2, pady=4, sticky=W)
txtQuestion4 = Button(ABC1c, font=('arial', 14,'bold'),bg='blue', fg='white', bd=1, width=17, height=2,justify=CENTER, text = answerD, command=correct_answer_funcD)
txtQuestion4.grid(row=2, column=3, pady=4)

Tkinter won't close correctly and launch new file

I made a little login screen. After I put in the credentials I want the Tkinter to be closed and open a new python file. If you execute the code below it will give me the error NameError: name ttk is not defined. In the other file I imported everything and gave it the correct name.
The file I use for the login:
from tkinter import *
import tkinter.messagebox as tm
class LoginFrame(Frame):
def __init__(self, master):
super().__init__(master)
self.label_username = Label(self, text="Username")
self.label_password = Label(self, text="Password")
self.photo = PhotoImage(file="sbshreg.png")
self.label_image = Label(root, image=self.photo)
self.label_image.image = self.photo
self.entry_username = Entry(self)
self.entry_password = Entry(self, show="*")
self.label_username.grid(row=0, sticky=E)
self.label_password.grid(row=1, sticky=E)
self.label_image.grid(row=3, column=2, rowspan=2, columnspan=2, sticky=W, padx=10)
self.entry_username.grid(row=0, column=1, sticky=E)
self.entry_password.grid(row=1, column=1, sticky=E)
self.logbtn = Button(self, text="Login", command=self._login_btn_clicked)
self.logbtn.grid(columnspan=2, column=1, row=2, sticky=S+E+N+W)
self.grid()
def _login_btn_clicked(self):
username = self.entry_username.get()
password = self.entry_password.get()
if username == "123" and password == "123":
tm.showinfo("SBSHREG", "Welcome 123")
#The sweet spot where all goes wrong...
self.destroy()
exec(open("./BatchFrame.py").read())
else:
tm.showerror("SBSHREG", "Incorrect username")
root = Tk()
root.title("SBSHREG")
root.geometry("235x120")
lf = LoginFrame(root)
root.mainloop()
In the other file I got this: from tkinter import ttk as ttk which should prevent the error in the other file from happening.
from tkinter import *
import tkinter.messagebox as tm
from tkinter import ttk as ttk
class BatchFrame(Frame):
def __init__(self, master):
super().__init__(master)
self.photo = PhotoImage(file="sbshreg.png")
self.label_photo = Label(root, image=self.photo)
self.label_photo.image = self.photo
self.label_photo.grid(row=0, column=2, sticky=N, padx=10, pady=10)
#Add frame starting here
frame = LabelFrame(self.master, text='Voeg batch toe')
frame.grid (row=0, column=0, padx=10)
self.label_batch = Label(frame, text="Batchnummer")
self.label_employee = Label(frame, text="Medewerker")
self.label_material = Label(frame, text="Materiaalsoort")
self.label_weight = Label(frame, text="Gewicht")
self.entry_batch = Entry(frame)
self.entry_employee = Entry(frame)
self.entry_material= Entry(frame)
self.entry_weight = Entry(frame)
self.label_batch.grid(row=0, column=0, sticky=S+E+N+W, columnspan=2, padx=10)
self.label_employee.grid(row=2, column=0, sticky=S+E+N+W, columnspan=2, padx=10)
self.label_material.grid(row=4, column=0, sticky=S+E+N+W, columnspan=2, padx=10)
self.label_weight.grid(row=6, column=0, sticky=S+E+N+W, columnspan=2, padx=10)
self.entry_batch.grid(row=1, column=0, sticky=S+E+N+W, columnspan=2, padx=10)
self.entry_employee.grid(row=3, column=0, sticky=S+E+N+W, columnspan=2, padx=10)
self.entry_material.grid(row=5, column=0, sticky=S+E+N+W, columnspan=2, padx=10)
self.entry_weight.grid(row=7, column=0, sticky=S+E+N+W, columnspan=2, padx=10)
self.btnadd = Button(frame, text='Voeg toe', command=self._btn_add_clicked)
self.btnadd.grid(column=0, row=8, pady=10)
#Search frame starting here
framesearch = LabelFrame(self.master, text='Zoek')
framesearch.grid(row=0, column=1, sticky=N)
self.label_batch = Label(framesearch, text="Batchnummer")
self.label_employee = Label(framesearch, text="Medewerker")
self.entry_batch = Entry(framesearch)
self.entry_employee = Entry(framesearch)
self.label_batch.grid(row=0, column=0, sticky=S, columnspan=2, padx=10)
self.label_employee.grid(row=2, column=0, sticky=S, columnspan=2, padx=10)
self.entry_batch.grid(row=1, column=0, sticky=S + E + N + W, columnspan=2, padx=10, pady=10)
self.entry_employee.grid(row=3, column=0, sticky=S + E + N + W, columnspan=2, padx=10, pady=10)
self.btnbatch = Button(framesearch, text="Zoek", command=self._btn_batch_clicked)
self.btnemployee = Button(framesearch, text="Zoek", command=self._btn_employee_clicked)
self.btnbatch.grid(columnspan=1, column=2, row=1, sticky=W, padx=10)
self.btnemployee.grid(columnspan=1, column=2, row=3, sticky=W, padx=10)
#This is the viewingarea for the data
self.tree = ttk.Treeview (height=10, columns=("Batchnummer", "Medewerker", "Materiaalsoort", "Gewicht"))
self.tree.grid (row=9, columnspan=10, padx=10, pady=10)
self.tree.heading('#1', text='Batchnummer', anchor=W)
self.tree.heading('#2', text='Medewerker', anchor=W)
self.tree.heading('#3', text='Materiaalsoort', anchor=W)
self.tree.heading('#4', text='Gewicht', anchor=W)
self.tree.column('#0', stretch=NO, minwidth=0, width=0)
self.tree.column('#1', stretch=NO, minwidth=0, width=100)
self.tree.column('#2', stretch=NO, minwidth=0, width=100)
self.tree.column('#3', stretch=NO, minwidth=0, width=100)
self.tree.column('#4', stretch=NO, minwidth=0, width=100)
self.grid()
def _btn_add_clicked(self):
batch = self.entry_batch.get()
def _btn_batch_clicked(self):
batch = self.entry_batch.get()
def _btn_employee_clicked(self):
batch = self.entry_employee.get()
root = Tk()
root.title("SBSHREG")
root.geometry("432x480")
lf = BatchFrame(root)
root.mainloop()
If I change self.destroy() to root.destroy() I get the following error: _tkinter.TclError: can't invoke "label" command: application has been destroyed. In the second file the functions are not done yet because I'm still working on the file, but this shouldn't have any impact on the error.
I searched everywhere and tried a lot and I still got no clue whatsoever...
Consider initializing frames in a top level class, GUI, that handles opening of both frames where LoginFrame calls its parent's open_batch() (now lambda implemented) method. Below assumes LoginFrame.py and BatchFrame.py resides in same folder as GUI_App script.
In this way, scripts run as standalone modules on one Tk() instance.
GUIApp (calls child frames, LoginFrame, and BatchFrame)
from tkinter import *
import LoginFrame as LF
import BatchFrame as BF
class GUI():
def __init__(self):
self.root = Tk()
self.root.title("SBSHREG")
self.root.geometry("235x120")
self.root.open_batch = self.open_batch
lf = LF.LoginFrame(self.root)
self.root.mainloop()
def open_batch(self):
bf = BF.BatchFrame(self.root)
app = GUI()
LoginFrame
from tkinter import *
import tkinter.messagebox as tm
class LoginFrame(Frame):
def __init__(self, master):
super().__init__(master)
self.label_username = Label(self, text="Username")
self.label_password = Label(self, text="Password")
self.photo = PhotoImage(file="sbshreg.png")
self.label_image = Label(self, image=self.photo)
self.label_image.image = self.photo
self.entry_username = Entry(self)
self.entry_password = Entry(self, show="*")
self.label_image.grid(row=0, column=2, rowspan=2, columnspan=2, sticky=W, padx=10)
self.label_username.grid(row=2, sticky=E)
self.label_password.grid(row=3, sticky=E)
self.entry_username.grid(row=2, column=1, sticky=E)
self.entry_password.grid(row=3, column=1, sticky=E)
self.logbtn = Button(self, text="Login", command=lambda: self._login_btn_clicked(master))
self.logbtn.grid(row=4, column=1, columnspan=2, sticky=S+E+N+W)
self.grid()
def _login_btn_clicked(self, controller):
username = self.entry_username.get()
password = self.entry_password.get()
if username == "123" and password == "123":
tm.showinfo("SBSHREG", "Welcome 123")
self.destroy()
controller.open_batch()
else:
tm.showerror("SBSHREG", "Incorrect username")
BatchFrame
from tkinter import *
import tkinter.messagebox as tm
from tkinter import ttk as ttk
class BatchFrame(Frame):
def __init__(self, master):
super().__init__(master)
self.photo = PhotoImage(file="sbshreg.png")
self.label_photo = Label(master, image=self.photo)
self.label_photo.image = self.photo
self.label_photo.grid(row=0, column=2, sticky=N, padx=10, pady=10)
#Add frame starting here
frame = LabelFrame(master, text='Voeg batch toe')
frame.grid (row=0, column=0, padx=10)
self.label_batch = Label(frame, text="Batchnummer")
self.label_employee = Label(frame, text="Medewerker")
self.label_material = Label(frame, text="Materiaalsoort")
self.label_weight = Label(frame, text="Gewicht")
self.entry_batch = Entry(frame)
self.entry_employee = Entry(frame)
self.entry_material= Entry(frame)
self.entry_weight = Entry(frame)
self.label_batch.grid(row=0, column=0, sticky=S+E+N+W, columnspan=2, padx=10)
self.label_employee.grid(row=2, column=0, sticky=S+E+N+W, columnspan=2, padx=10)
self.label_material.grid(row=4, column=0, sticky=S+E+N+W, columnspan=2, padx=10)
self.label_weight.grid(row=6, column=0, sticky=S+E+N+W, columnspan=2, padx=10)
self.entry_batch.grid(row=1, column=0, sticky=S+E+N+W, columnspan=2, padx=10)
self.entry_employee.grid(row=3, column=0, sticky=S+E+N+W, columnspan=2, padx=10)
self.entry_material.grid(row=5, column=0, sticky=S+E+N+W, columnspan=2, padx=10)
self.entry_weight.grid(row=7, column=0, sticky=S+E+N+W, columnspan=2, padx=10)
self.btnadd = Button(frame, text='Voeg toe', command=self._btn_add_clicked)
self.btnadd.grid(column=0, row=8, pady=10)
#Search frame starting here
framesearch = LabelFrame(master, text='Zoek')
framesearch.grid(row=0, column=1, sticky=N)
self.label_batch = Label(framesearch, text="Batchnummer")
self.label_employee = Label(framesearch, text="Medewerker")
self.entry_batch = Entry(framesearch)
self.entry_employee = Entry(framesearch)
self.label_batch.grid(row=0, column=0, sticky=S, columnspan=2, padx=10)
self.label_employee.grid(row=2, column=0, sticky=S, columnspan=2, padx=10)
self.entry_batch.grid(row=1, column=0, sticky=S + E + N + W, columnspan=2, padx=10, pady=10)
self.entry_employee.grid(row=3, column=0, sticky=S + E + N + W, columnspan=2, padx=10, pady=10)
self.btnbatch = Button(framesearch, text="Zoek", command=self._btn_batch_clicked)
self.btnemployee = Button(framesearch, text="Zoek", command=self._btn_employee_clicked)
self.btnbatch.grid(columnspan=1, column=2, row=1, sticky=W, padx=10)
self.btnemployee.grid(columnspan=1, column=2, row=3, sticky=W, padx=10)
#This is the viewingarea for the data
self.tree = ttk.Treeview (height=10, columns=("Batchnummer", "Medewerker", "Materiaalsoort", "Gewicht"))
self.tree.grid (row=9, columnspan=10, padx=10, pady=10)
self.tree.heading('#1', text='Batchnummer', anchor=W)
self.tree.heading('#2', text='Medewerker', anchor=W)
self.tree.heading('#3', text='Materiaalsoort', anchor=W)
self.tree.heading('#4', text='Gewicht', anchor=W)
self.tree.column('#0', stretch=NO, minwidth=0, width=0)
self.tree.column('#1', stretch=NO, minwidth=0, width=100)
self.tree.column('#2', stretch=NO, minwidth=0, width=100)
self.tree.column('#3', stretch=NO, minwidth=0, width=100)
self.tree.column('#4', stretch=NO, minwidth=0, width=100)
self.grid()
def _btn_add_clicked(self):
batch = self.entry_batch.get()
def _btn_batch_clicked(self):
batch = self.entry_batch.get()
def _btn_employee_clicked(self):
batch = self.entry_employee.get()
I do not agree with the method of how you are invoking your 2nd python file.
You really dont need to use exec here.
However if you really want to you need to add import tkinter.ttk as ttk to your first page for it to work right.
Your best option is to import the 2nd file on the 1st file and invoke it by calling the class name.
so for you imports on the first page you need to add import BatchFrame.
Then call it in your code.
Replace:
exec(open("./test2.py").read())
with:
BatchFrame.BatchFrame(root)
I do see one mistake in your BatchFrame class thought.
change this:
self.label_photo = Label(root, image=self.photo)
to this:
self.label_photo = Label(master, image=self.photo)
UPDATE:
To address your issue from the comment make these changes:
1: Add this to your BatchFrame Class:
class BatchFrame(Frame):
def __init__(self, master):
super().__init__(master)
self.master = master # add this
self.master.title("SBSHREG") # and this
self.master.geometry("432x480") # and this
2: Remove this from your BatchFrame file:
root = Tk()
root.title("SBSHREG")
root.geometry("432x480")
lf = BatchFrame(root)
root.mainloop()
3: Add this to your LoginFrame class:
class LoginFrame(Frame):
def __init__(self, master):
super().__init__(master)
self.master = master # add this
4: In the LoginFrame class change this:
BatchFrame.BatchFrame(root)
to this:
BatchFrame.BatchFrame(self.master)
I recommend importing batchframe instead of executing it.
from tkinter import *
import tkinter.messagebox as tm
from tkinter import ttk as ttk
from batchframe import BatchFrame
class LoginFrame(Frame):
def __init__(self, master):
super().__init__(master)
self.master = master
self.label_username = Label(self, text="Username")
self.label_password = Label(self, text="Password")
self.photo = PhotoImage(file="icon.png")
self.label_image = Label(root, image=self.photo)
self.label_image.image = self.photo
self.entry_username = Entry(self)
self.entry_password = Entry(self, show="*")
self.label_username.grid(row=0, sticky=E)
self.label_password.grid(row=1, sticky=E)
self.label_image.grid(row=3, column=2, rowspan=2, columnspan=2, sticky=W, padx=10)
self.entry_username.grid(row=0, column=1, sticky=E)
self.entry_password.grid(row=1, column=1, sticky=E)
self.logbtn = Button(self, text="Login", command=self._login_btn_clicked)
self.logbtn.grid(columnspan=2, column=1, row=2, sticky=S+E+N+W)
self.grid()
def _login_btn_clicked(self):
username = self.entry_username.get()
password = self.entry_password.get()
if username == "123" and password == "123":
tm.showinfo("SBSHREG", "Welcome 123")
#The sweet spot where all goes wrong...
self.destroy()
# Create the instance of the BatchFrame class, passing in self.master
self.batchframe = BatchFrame(self.master)
else:
tm.showerror("SBSHREG", "Incorrect username")
Then in batchframe.py change variable reference from root to master

Python big space between Button columns

I want to set my buttons in my Tk window close to each other, but there is too much space between them. They actually have to sit very close to each other, but i can't change their position.
Code:
from tkinter import *
from tkinter import ttk
def Page():
Profile = Tk()
TreeSearchbar = Text(Profile, width=30, height=1, font="Arial 15")
TreeSearchbar.grid(row=0, column=0, sticky=W, pady=5, columnspan=2)
TreeSearchButton = ttk.Button(Profile, text="Search").grid(row=0, column=1, sticky=W, columnspan=2)
Tree = ttk.Treeview(Profile, height=20)
Tree["columns"] = ("value1", "value2", "value3", "value4", "value5", "value6")
Tree.column("#0", width=170)
Tree.column("#1", width=180)
Tree.column("#2", width=0)
Tree.heading("#0", text="1")
Tree.heading("#1", text="2")
Tree.grid(row=1, column=0, sticky="nw", columnspan=2)
Button1 = ttk.Button(Profile, text="Delete").grid(row=2, column=0, sticky=W, pady=12, padx=(20, 0))
Button2 = ttk.Button(Profile, text="Update").grid(row=2, column=1, sticky=W)
Button3 = ttk.Button(Profile, text="Edit").grid(row=2, column=2, sticky=W)
Profile.mainloop()
Page()
Using frames inside your grid cells you will be able to pack controls. That will give you more flexibility in the layout, like this:
from tkinter import *
from tkinter import ttk
def Page():
Profile = Tk()
TreeSearchbar = Text(Profile, width=30, height=1, font="Arial 15")
TreeSearchbar.grid(row=0, column=0, sticky=W, pady=5, columnspan=2)
TreeSearchButton = ttk.Button(Profile, text="Search").grid(row=0, column=1, sticky=W, columnspan=2)
Tree = ttk.Treeview(Profile, height=20)
Tree["columns"] = ("value1", "value2", "value3", "value4", "value5", "value6")
Tree.column("#0", width=170)
Tree.column("#1", width=180)
Tree.column("#2", width=0)
Tree.heading("#0", text="1")
Tree.heading("#1", text="2")
Tree.grid(row=1, column=0, sticky="nw", columnspan=2)
ButtonFrame = ttk.Frame(Profile)
Button1 = ttk.Button(ButtonFrame,
text="Delete").pack(side=LEFT, padx=5, pady=5)
Button2 = ttk.Button(ButtonFrame,
text="Update").pack(side=LEFT, padx=5, pady=5)
Button3 = ttk.Button(ButtonFrame,
text="Edit").pack(side=LEFT, padx=5, pady=5)
ButtonFrame.grid(row=2, column=0)
Profile.mainloop()
Page()
You should grid your areas in the UI and probably apply this principle in each of them, using either grid again, or packer, inside them (although you can use placer it is usually not recommended, to be able to adjust to window size...)

Python tkinter, clearing an Entry widget from a class

This is the class I'm calling and the function from a different file
class CalcFunc:
def clearScreen(self):
self.log("CLEAR (CE)")
ent.delete(0, END)
This is the Entry Box
ent = Entry(root, textvariable=clc.getBtn, justify=RIGHT, font=10, relief=RIDGE, bd=2, width=15)
ent.grid(row=0, columnspan=3, pady=10)
This is the button I'm clicking to clear the Entry Box
buttonCC = Button(root, text="CLEAR (CE)", height=1, width=20, bg='orange', command=clc.clearScreen)
I'm not sure what the syntax is to be able to to clear an Entry widget from a class basically. That code worked when I had it in the same file but my project requires it to be in a separate file. It's a class project for a calculator and the "clear" button clears the Entry widget. I can post my entire code if that helps. Thank you.
----EDIT----
My Class
import time
class CalcFunc:
def log(self, val):
myFile = open(r".\log.dat", "a")
myFile.write("%s\n" % val)
myFile.close()
def onScreen(self, iVal):
self.log(iVal)
currentTxt = self.getBtn.get()
updateEnt = self.getBtn.set(currentTxt + iVal)
def clearScreen(self):
self.log("CLEAR (CE)")
ent.delete(0, END)
def evaL(self):
self.log("=")
self.getBtn.set(str(eval(self.getBtn.get())))
self.log(self.getBtn.get())
def logLbl(self):
myFile = open(r".\log.dat", "a")
myFile.write("\n==================================\n")
myFile.write("Date: " + str(time.strftime("%m/%d/%Y")) + " -- Time: " + str(time.strftime("%I:%M:%S")))
myFile.write("\n==================================\n")
myFile.close()
My Program
from tkinter import *
import time
import clcClass
root = Tk()
root.title('skClc v1')
clc = clcClass.CalcFunc()
clc.logLbl()
clc.getBtn = StringVar()
ent = Entry(root, textvariable=clc.getBtn, justify=RIGHT, font=10, relief=RIDGE, bd=2, width=15)
ent.grid(row=0, columnspan=3, pady=10)
button1 = Button(root, text="1", height=1, width=5, bg='light blue', command=lambda:clc.onScreen('1'))
button2 = Button(root, text="2", height=1, width=5, bg='light blue', command=lambda:clc.onScreen('2'))
button3 = Button(root, text="3", height=1, width=5, bg='light blue', command=lambda:clc.onScreen('3'))
button4 = Button(root, text="4", height=1, width=5, bg='light blue', command=lambda:clc.onScreen('4'))
button5 = Button(root, text="5", height=1, width=5, bg='light blue', command=lambda:clc.onScreen('5'))
button6 = Button(root, text="6", height=1, width=5, bg='light blue', command=lambda:clc.onScreen('6'))
button7 = Button(root, text="7", height=1, width=5, bg='light blue', command=lambda:clc.onScreen('7'))
button8 = Button(root, text="8", height=1, width=5, bg='light blue', command=lambda:clc.onScreen('8'))
button9 = Button(root, text="9", height=1, width=5, bg='light blue', command=lambda:clc.onScreen('9'))
button0 = Button(root, text="0", height=1, width=5, bg='light blue', command=lambda:onScreen('0'))
buttonP = Button(root, text="+", height=1, width=5, bg='gray', command=lambda:clc.onScreen('+'))
buttonM = Button(root, text="-", height=1, width=5, bg='gray', command=lambda:clc.onScreen('-'))
buttonMM = Button(root, text="x", height=1, width=5, bg='gray', command=lambda:clc.onScreen('*'))
buttonDD = Button(root, text="÷", height=1, width=5, bg='gray', command=lambda:clc.onScreen('/'))
buttonEE = Button(root, text="=", height=1, width=5, bg='light green', command=clc.evaL)
buttonCC = Button(root, text="CLEAR (CE)", height=1, width=20, bg='orange', command=clc.clearScreen)
button1.grid(row=1, column=0, pady=5)
button2.grid(row=1, column=1, pady=5)
button3.grid(row=1, column=2, pady=5)
button4.grid(row=2, column=0, pady=5)
button5.grid(row=2, column=1, pady=5)
button6.grid(row=2, column=2, pady=5)
button7.grid(row=3, column=0, pady=5)
button8.grid(row=3, column=1, pady=5)
button9.grid(row=3, column=2, pady=5)
button0.grid(row=4, column=0, pady=5)
buttonP.grid(row=4, column=1, pady=5)
buttonM.grid(row=4, column=2, pady=5)
buttonEE.grid(row=5, column=0, pady=5)
buttonDD.grid(row=5, column=1, pady=5)
buttonMM.grid(row=5, column=2, pady=5)
buttonCC.grid(row=6, column=0, pady=5, columnspan=3)
root.maxsize(140,245);
root.minsize(140,245);
root.mainloop()
ent = Entry(root, ....)
clc = clcClass.CalcFunc(ent)
class CalcFunc:
def __init__(self, entry):
self.entry = entry
def clearScreen(self):
self.log("CLEAR (CE)")
self.entry.delete(0, END)
Here's an abbreviated example:
#my_entry.py
from tkinter import END
import time
class EntryWithLogger:
def __init__(self, entry):
self.entry = entry
def log(self, val):
with open("log.dat", "a") as my_file: #Automatically closes the file--even if an exception occurs, which is not the case with my_file.close().
my_file.write("%s\n" % val)
def onScreen(self, i_val):
self.log(i_val)
self.entry.insert(END, i_val)
def clearScreen(self):
self.log("CLEAR (CE)")
self.entry.delete(0, END)
Note that I didn't use a StringVar(), which doesn't appear to be necessary. If you need it, you can always pass it as an argument to __init__(), then store it on self.
import my_entry as me
import tkinter as tk
root = tk.Tk()
root.title("Calculator")
root.geometry("+100+50") #("300x500+200+10") dimension, position
entry = tk.Entry(root, justify=tk.RIGHT, font=10, relief=tk.RIDGE, bd=2, width=15)
entry.grid(row=0, columnspan=3, pady=10)
entry_with_logger = me.EntryWithLogger(entry)
#Create the buttons in a loop:
for i in range(10):
row_num, col_num = divmod(i, 3) #divmod(7, 2) => (3, 1), divmod(0, 3) => (0, 0), divmod(4, 3) => (1, 1)
row_num += 1
button_text = str(i)
tk.Button(root, text=button_text,
height=1,
width=5,
bg='light blue',
command=lambda x=button_text: entry_with_logger.onScreen(x)
).grid(row=row_num, column=col_num, pady=5)
#Put the clear button at the bottom of the grid:
tk.Button(root, text="CLEAR (CE)",
height=1,
width=20,
bg='orange',
command=entry_with_logger.clearScreen
).grid(row=row_num+1, columnspan=3) #columnspan tells grid() to use 3 cells for the button,
#and the button will be centered by default.
root.mainloop()
Or, you could do it like this:
#my_entry.py
from tkinter import Entry, END
import time
class EntryWithLogger(Entry):
#Because __init__() is not implemented, the parent class's __init__() gets
#called, so you create an EntryWithLogger just like you would an Entry.
def log(self, val):
with open("log.dat", "a") as my_file: #Automatically closes the file--even if there is an exception, which is not the case with my_file.close().
my_file.write("%s\n" % val)
def onScreen(self, i_val):
self.log(i_val)
self.insert(END, i_val)
def clearScreen(self):
self.log("CLEAR (CE)")
self.delete(0, END)
import my_entry as me
import tkinter as tk
root = tk.Tk()
root.title("Calculator")
root.geometry("+100+50") #("300x500+200+10") dimension, position
entry = me.EntryWithLogger(root, justify=tk.RIGHT, font=10, relief=tk.RIDGE, bd=2, width=15)
entry.grid(row=0, columnspan=3, pady=10)
#Create the buttons in a loop:
for i in range(10):
row_num, col_num = divmod(i, 3) #divmod(7, 2) => (3, 1), divmod(0, 3) => (0, 0), divmod(4, 3) => (1, 1)
row_num += 1
button_text = str(i)
tk.Button(root, text=button_text,
height=1,
width=5,
bg='LightBlue',
command=lambda x=button_text: entry.onScreen(x)
).grid(row=row_num, column=col_num, pady=5)
#Put the clear button at the bottom of the grid:
tk.Button(root, text="CLEAR (CE)",
height=1,
width=20,
bg='orange',
command=entry.clearScreen
).grid(row=row_num+1, columnspan=3) #columnspan tells grid() to use 3 cells for the button,
#and the button will be centered by default.
root.mainloop()

Categories