Python tkinter cannot update a window in a while loop - python

I am trying to create a main screen that changes to a homepage after user logged in. If I change while loop it never prints or opens login page. Now I changed it but whenever i logged in the login def returns true but main.py keeps it as False.
main.py:
from tkinter import *
from login import LoginNP
class NP:
def __init__(self, root):
self.root = root
self.root.geometry("1350x700+0+0")
self.root.title("New Project")
self.buton = Button(text="Giriş yap", command=self.loginPage).pack(anchor=NE)
self.title_frame = Frame(borderwidth=5,height=150,width=300, relief=RIDGE)
self.title_frame.pack(anchor=N)
self.welcome_label = Label(self.title_frame, text="Hello", height=10, width=10).pack(padx=10, pady=5)
while True:
root.update_idletasks()
root.update()
if not self.checkLogin():
break
else:
pass
def checkLogin(self):
if LoginNP.loginMessage:
print("A")
return True
else:
print("B")
return False
def loginPage(self):
self.new_win = Toplevel(self.root)
self.new_obj = LoginNP(self.new_win)
self.new_win.attributes('-topmost', True)
class HomePage:
def __init__(self, root):
self.root = root
self.root.geometry("1350x700+0+0")
self.root.title("Homepage")
self.title_frame = Frame(self.root, height=500, width=300)
self.title_frame.pack(anchor=CENTER, padx=10, pady=5)
self.welcome_label = Label(self.title_frame, text="Homepage", height=10, width=10).pack(padx=10, pady=5)
if __name__ =="__main__":
root=Tk()
obj=NP(root)
root.mainloop()
I want to update my NP window with Homepage window but in while loop program not getting result from login.py
login.py:
from tkinter import *
import sqlite3
from tkinter import messagebox
con = sqlite3.connect("npdb.db")
cur = con.cursor()
class LoginNP:
def __init__(self, root):
self.root = root
self.root.geometry("350x240")
self.root.title("Login Page")
#vars
self.username_var = StringVar()
self.password_var = StringVar()
#frames
self.upper_frame = Frame(self.root, height=70)
self.upper_frame.pack(anchor=N, fill=X, padx=10, pady=5)
self.middle_frame = Frame(self.root, height=70)
self.middle_frame.pack(anchor=CENTER, fill=X, padx=10, pady=5)
self.lower_frame = Frame(self.root, height=70)
self.lower_frame.pack(anchor=S, fill=X, padx=10, pady=5)
#label&entry
self.username_label = Label(self.upper_frame, text="Username: ").pack(anchor=W, padx=10, pady=5)
self.username_entry = Entry(self.upper_frame, textvariable=self.username_var).pack(anchor=W, padx=10, pady=5, fill=X)
self.password_label = Label(self.middle_frame, text="Password: ").pack(anchor=W, padx=10, pady=5)
self.password_entry = Entry(self.middle_frame, textvariable=self.password_var, show="*").pack(anchor=W, padx=10, pady=5, fill=X)
self.login_btn = Button(self.lower_frame, text="Login", command=self.loginMessage).grid(column=0, row=0, padx=10, pady=5)
self.register_btn = Button(self.lower_frame, text="Register",command=self.register).grid(column=1, row=0, padx=205, pady=5)
#property
def login(self):
with con:
cur.execute("SELECT * FROM user_database WHERE username=:username", {'username': self.username_var.get()})
if cur.fetchone() == None:
return False
else:
cur.execute("SELECT password FROM user_database WHERE username=:username", {'username': self.username_var.get()})
`enter code here` row = cur.fetchone()
return row[0] == self.password_var.get()
def loginMessage(self):
if self.login:
messagebox.showerror(title="Approve!", message="Giriş Başarılı!")
else:
messagebox.showerror(title="Deny!", message="Kullanıcı adı veya şifre hatalı!")
self.root.destroy()
return self.login
def search(self):
with con:
cur.execute("SELECT * FROM user_database WHERE username=:username", {'username': self.username_var.get()})
return len(cur.fetchall()) < 1
def register(self):
if self.username_var.get().strip() == "" or self.password_var.get().strip() == "":
messagebox.showerror(title='Hata!', message="Lütfen boşluk bırakmayınız!")
else:
if not self.search():
messagebox.showerror(title='Hata!', message="Kullanıcı adı zaten kayıtlı.\nLütfen başka bir kullanıcı adı alınız.")
else:
cur.execute("""INSERT INTO user_database VALUES (?, ?)""", (self.username_var.get(), self.password_var.get()))
con.commit()
if __name__ =="__main__":
root=Tk()
obj=LoginNP(root)
root.mainloop()

I suspect that if LoginNP.loginMessage: in checkLogin doesn't do what you think it does.
You have imported the LoginNP class, and loginMessage is a method of this class.
So, if LoginNP.loginMessage: basically means "does the class LoginNP have a method loginMessage". To which the answer is True.
But you are not instantiating an object of type LoginNP nor calling a method on that instance.
Check this example:
In [1]: class Foo:
...: def __init__():
...: pass
...: def bar():
...: print("calling 'bar'")
...:
In [2]: if Foo.bar:
...: print(True)
...:
True
And note the absence of the printed message calling 'bar'.

Related

Pandas DataFrame from pyodbc missing 1 row in result

Community!
While using pyodbc with pandas, I discovered something that is, at least to me, strange.
When running the program, everything works out as intended, however I seem to be missing one row for the resulting DataFrame.
I ran the exact same query in SSMS, and the result should show 2 rows.
Printing the DataFrame to console, I see that it only shows the latter of the resulting rows.
What am I not seeing? Any settings in pd.set_option-part I've done wrong? I've tried to change these, without luck so far.
import tkinter as tk
from tkinter import Tk, W, E
from tkinter.ttk import Frame, Button, Entry, Style, Radiobutton, Label
from tkinter import filedialog as fd
import os
class Application(Frame):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
#------------------------------#
# Functions #
#------------------------------#
def SQL_Query(query_string):
import pyodbc as p # MIT Lisence. OK
import itertools
import pandas as pd # BSD Lisence. OK
pd.set_option("display.max_rows", None)
pd.set_option("display.max_columns", None)
pd.set_option("display.width", 1000)
databaseName = '***'
username = '***'
password = '***'
server = '***'
driver = '***'
CONNECTION_STRING = 'DRIVER='+driver+';SERVER='+server+';DATABASE='+databaseName+';UID='+username+';PWD='+ password
conn = p.connect(CONNECTION_STRING)
cursor = conn.cursor()
cursor.execute(query_string)
row = cursor.fetchone()
desc = cursor.description
column_names = [col[0] for col in desc]
data = [dict(zip(column_names, row))
for row in cursor.fetchall()]
conn.close()
df = pd.DataFrame(data)
if df.empty == False:
qty_total = str(df['InitialQuantity'].sum())
qty_RT = str(df['RT'].sum())
print('Number of units found with criteria: ' + qty_total)
print('Numbe rof units with RT: ' + qty_RT + '\n')
print(df)
def btnRun():
line = var.get()
mat = varMaterial.get()
if line == "('1', '6', '8', '18')":
query = f"""QueryStringIsHere"""
SQL_Query(query)
elif line == "('3', '10')":
query = f"""QueryStringIsHere"""
SQL_Query(query)
#------------------------------#
# Program title and attributes #
#------------------------------#
self.master.title("Production Orders")
Style().configure("TButton", padding=(0, 5, 0, 5),
font='serif 10')
self.columnconfigure(0, pad=3)
self.columnconfigure(1, pad=3)
self.columnconfigure(2, pad=3)
self.columnconfigure(3, pad=3)
self.rowconfigure(0, pad=3)
self.rowconfigure(1, pad=3)
#------------------------------#
# UI Elements #
#------------------------------#
var = tk.StringVar() #variable to hold radio button values
varMaterial = tk.StringVar()
rad12 = Radiobutton(self,text="x", variable=var, value = "('1', '6', '8', '18')").grid(row=0, column=0, sticky=W)
rad36 = Radiobutton(self,text="y", variable=var, value = "('3', '10')").grid(row=1, column=0, sticky=W)
entry = Entry(self, textvariable=varMaterial).grid(row=2, column=1, columnspan=4, sticky=W+E)
lblEntry = Label(self, text="Material Number:").grid(row=2, column=0,columnspan=1, sticky=W+E)
#------------------------------#
# Command buttons #
#------------------------------#
btnSelect = Button(self, text="Run Query", command = btnRun).grid(row=3, column=0)
btnClear = Button(self, text="Clear text", command = '').grid(row=3, column=1)
btnQuit = Button(self, text="Quit", command = self.master.destroy).grid(row=3, column=4)
#------------------------------#
# Packing #
#------------------------------#
self.pack()
def main():
root = Tk()
app = Application()
root.mainloop()
if __name__ == '__main__':
main()
The solution to this problem was found with guidance from comments on original post. As I was doing a .fetchone() first, and then populating the DataFrame with .fetchall(), data did not include the first resulting row.
import tkinter as tk
from tkinter import Tk, W, E
from tkinter.ttk import Frame, Button, Entry, Style, Radiobutton, Label
from tkinter import filedialog as fd
import os
class Application(Frame):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
#------------------------------#
# Functions #
#------------------------------#
def SQL_Query(query_string):
import pyodbc as p # MIT Lisence. OK
import itertools
import pandas as pd # BSD Lisence. OK
pd.set_option("display.max_rows", None)
pd.set_option("display.max_columns", None)
pd.set_option("display.width", 1000)
databaseName = '***'
username = '***'
password = '***'
server = '***'
driver = '***'
CONNECTION_STRING = 'DRIVER='+driver+';SERVER='+server+';DATABASE='+databaseName+';UID='+username+';PWD='+ password
conn = p.connect(CONNECTION_STRING)
cursor = conn.cursor()
cursor.execute(query_string)
desc = cursor.description
column_names = [col[0] for col in desc]
data = [dict(zip(column_names, row))
for row in cursor.fetchall()]
conn.close()
df = pd.DataFrame(data)
if df.empty == False:
qty_total = str(df['InitialQuantity'].sum())
qty_RT = str(df['RT'].sum())
print('Number of units found with criteria: ' + qty_total)
print('Numbe rof units with RT: ' + qty_RT + '\n')
print(df)
def btnRun():
line = var.get()
mat = varMaterial.get()
if line == "('1', '6', '8', '18')":
query = f"""QueryStringIsHere"""
SQL_Query(query)
elif line == "('3', '10')":
query = f"""QueryStringIsHere"""
SQL_Query(query)
#------------------------------#
# Program title and attributes #
#------------------------------#
self.master.title("Production Orders")
Style().configure("TButton", padding=(0, 5, 0, 5),
font='serif 10')
self.columnconfigure(0, pad=3)
self.columnconfigure(1, pad=3)
self.columnconfigure(2, pad=3)
self.columnconfigure(3, pad=3)
self.rowconfigure(0, pad=3)
self.rowconfigure(1, pad=3)
#------------------------------#
# UI Elements #
#------------------------------#
var = tk.StringVar() #variable to hold radio button values
varMaterial = tk.StringVar()
rad12 = Radiobutton(self,text="x", variable=var, value = "('1', '6', '8', '18')").grid(row=0, column=0, sticky=W)
rad36 = Radiobutton(self,text="y", variable=var, value = "('3', '10')").grid(row=1, column=0, sticky=W)
entry = Entry(self, textvariable=varMaterial).grid(row=2, column=1, columnspan=4, sticky=W+E)
lblEntry = Label(self, text="Material Number:").grid(row=2, column=0,columnspan=1, sticky=W+E)
#------------------------------#
# Command buttons #
#------------------------------#
btnSelect = Button(self, text="Run Query", command = btnRun).grid(row=3, column=0)
btnClear = Button(self, text="Clear text", command = '').grid(row=3, column=1)
btnQuit = Button(self, text="Quit", command = self.master.destroy).grid(row=3, column=4)
#------------------------------#
# Packing #
#------------------------------#
self.pack()
def main():
root = Tk()
app = Application()
root.mainloop()
if __name__ == '__main__':
main()

Tkinter: setting entry to readonly not working

I have a window with an Entry for QR Codes. The idea is the user will read the QR code with an QR Scanner, the Entry turns readonly to avoid another input from user while application do some processing. After the conclusion the Entry is editable again and the user can read another QR Code.
I created a variable status that controls when the Entry show be readonly or not, it works fine when the user read an QR Code and another, and another.
The problem is when I try to show a message when the user hits enter and QR code is empty or when the user reads the same QR Code in sequence. The message is shown but the Entry continues editable. In the real code various message windows are opened in this situation.
Here is my code:
import tkinter as tk
from tkinter import ttk
from tkinter import *
def main():
root = Tk()
root.title("Test")
root.geometry("850x140+10+450")
root.resizable(0,0)
MyFrame()
root.mainloop()
class MyFrame(Frame):
def __init__(self):
super().__init__()
self.qrcode = StringVar()
self.qrcodeEntry = None
self.lastQrcode = ""
# Status da tela
# 0 - Enabled
# 1 - Disable (Processing)
self.status=0
self.initUI()
def initUI(self):
self.status=0
root = self.master
mainframe = ttk.Frame(root, padding="3 3 12 12")
mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)
self.qrcodeEntry = ttk.Entry(mainframe, width=20, textvariable=self.qrcode)
self.qrcodeEntry.grid(column=2, row=1, sticky=(W, E))
self.qrcodeEntry.focus()
root.bind('<Return>', self.execute)
def execute(self, *argss):
#This call is not working
self.qrcodeEntry.configure(state='readonly')
# Executes if status is 0
if self.status == 1:
return
# Reset Status
self.status=1
# Check if QR is empty
if (not self.qrcode.get()):
self.showCriticalError("Message", "QR is empty")
return
# Check if QR is equals last QR
if (self.qrcode.get()==self.lastQrcode):
self.update_idletasks()
self.showCriticalError("Message", "QR is the same")
# DO SOMETHING
# Makes lastQrCode equals current QR
self.lastQrcode = self.qrcode.get()
self.master.after(3000, self.clear)
def clear(self):
self.status=0
self.qrcodeEntry.configure(state='normal')
self.qrcode.set('')
self.master.lift()
self.qrcodeEntry.focus()
def showCriticalError(self, title, message):
self.master.lift()
top = Toplevel(self.master)
top.grab_set()
top.title(title)
top.geometry("650x240+10+10")
top.resizable(0,0)
top.transient(self.master)
rows = 0
while rows < 10:
top.rowconfigure(rows, weight=1)
top.columnconfigure(rows, weight=1)
rows += 1
Message(top, text=message, width = 500).grid(row=0,column=2, rowspan=8, columnspan=7,sticky='W')
okButton = Button(top, text ="OK", command = top.destroy, width = 10)
okButton.grid(row=9,column=4, columnspan=2)
top.after(7000, top.destroy)
self.clear()
if __name__ == '__main__':
main()
The problem was in the last line of the method showCriticalError : self.clear() this line was returning the Entry to normal state. So I removed this line and changed the top.after(7000, top.destroy) to top.after(7000, lambda: self.clear() or top.destroy() ) and I did the same in the command of okButton
import tkinter as tk
from tkinter import ttk
from tkinter import *
def main():
root = Tk()
root.title("Test")
root.geometry("850x140+10+450")
root.resizable(0,0)
MyFrame()
root.mainloop()
class MyFrame(Frame):
def __init__(self):
super().__init__()
self.qrcode = StringVar()
self.qrcodeEntry = None
self.lastQrcode = ""
# Status da tela
# 0 - Enabled
# 1 - Disable (Processing)
self.status=0
self.initUI()
def initUI(self):
self.status=0
root = self.master
mainframe = ttk.Frame(root, padding="3 3 12 12")
mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)
self.qrcodeEntry = ttk.Entry(mainframe, width=20, textvariable=self.qrcode)
self.qrcodeEntry.grid(column=2, row=1, sticky=(W, E))
self.qrcodeEntry.focus()
root.bind('<Return>', self.execute)
def execute(self, *argss):
#This call is not working
self.qrcodeEntry.configure(state='readonly')
# Executes if status is 0
if self.status == 1:
return
# Reset Status
self.status=1
# Check if QR is empty
if (not self.qrcode.get()):
self.showCriticalError("Message", "QR is empty")
return
# Check if QR is equals last QR
if (self.qrcode.get()==self.lastQrcode):
self.update_idletasks()
self.showCriticalError("Message", "QR is the same")
# DO SOMETHING
# Makes lastQrCode equals current QR
self.lastQrcode = self.qrcode.get()
self.master.after(3000, self.clear)
def clear(self):
self.status=0
self.qrcodeEntry.configure(state='normal')
self.qrcode.set('')
self.master.lift()
self.qrcodeEntry.focus()
def showCriticalError(self, title, message):
self.master.lift()
top = Toplevel(self.master)
top.grab_set()
top.title(title)
top.geometry("650x240+10+10")
top.resizable(0,0)
top.transient(self.master)
rows = 0
while rows < 10:
top.rowconfigure(rows, weight=1)
top.columnconfigure(rows, weight=1)
rows += 1
Message(top, text=message, width = 500).grid(row=0,column=2, rowspan=8, columnspan=7,sticky='W')
okButton = Button(top, text ="OK", command = lambda: self.clear() or top.destroy(), width = 10)
okButton.grid(row=9,column=4, columnspan=2)
top.after(7000, lambda: self.clear() or top.destroy() )
if __name__ == '__main__':
main()
You disable the entry inside the execute() function. You need to call it.
Here is what I think you need:
import tkinter as tk
from tkinter import ttk
from tkinter import *
def main():
root = Tk()
root.title("Test")
root.geometry("850x140+10+450")
root.resizable(0,0)
MyFrame().execute()
root.mainloop()
class MyFrame(Frame):
def __init__(self):
super().__init__()
self.qrcode = StringVar()
self.qrcodeEntry = None
self.lastQrcode = ""
# Status da tela
# 0 - Enabled
# 1 - Disable (Processing)
self.status=0
self.initUI()
def initUI(self):
self.status=0
root = self.master
mainframe = ttk.Frame(root, padding="3 3 12 12")
mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)
self.qrcodeEntry = ttk.Entry(mainframe, width=20, textvariable=self.qrcode)
self.qrcodeEntry.grid(column=2, row=1, sticky=(W, E))
self.qrcodeEntry.focus()
root.bind('<Return>', self.execute)
def execute(self, *argss):
#This call is not working
self.qrcodeEntry.configure(state='disabled')
# Executes if status is 0
if self.status == 1:
return
# Reset Status
self.status=1
# Check if QR is empty
if (not self.qrcode.get()):
self.showCriticalError("Message", "QR is empty")
return
# Check if QR is equals last QR
if (self.qrcode.get()==self.lastQrcode):
self.update_idletasks()
self.showCriticalError("Message", "QR is the same")
# DO SOMETHING
# Makes lastQrCode equals current QR
self.lastQrcode = self.qrcode.get()
self.master.after(3000, self.clear)
def clear(self):
self.status=0
self.qrcodeEntry.configure(state='normal')
self.qrcode.set('')
self.master.lift()
self.qrcodeEntry.focus()
def showCriticalError(self, title, message):
self.master.lift()
top = Toplevel(self.master)
top.grab_set()
top.title(title)
top.geometry("650x240+10+10")
top.resizable(0,0)
top.transient(self.master)
rows = 0
while rows < 10:
top.rowconfigure(rows, weight=1)
top.columnconfigure(rows, weight=1)
rows += 1
Message(top, text=message, width = 500).grid(row=0,column=2, rowspan=8, columnspan=7,sticky='W')
okButton = Button(top, text ="OK", command = top.destroy, width = 10)
okButton.grid(row=9,column=4, columnspan=2)
top.after(7000, top.destroy)
self.clear()
if __name__ == '__main__':
main()

How to return entry value from another class?

I am trying to return a value from an Entry widget from another class.
My idea is, when the user has logged in successfully, the welcome screen will show the username that has just logged in.
I have tried using this:
self.userLogged = Label(main, text = self.entry_username.get())
self.userLogged.pack()
i tried linking >self.entry.entry_username.get() from the login class. But here is the error code:
AttributeError: 'App' object has no attribute 'entry_username'
Where I'm I going wrong?
Here is the full code:
from tkinter import *
import tkinter.ttk as ttk
class App():
def __init__(self,master):
notebook = ttk.Notebook(master)
notebook.pack(expand = 1, fill = "both")
#Frames
main = ttk.Frame(notebook)
notebook.add(main, text='Welcome Screen')
self.userLogged = Label(main, text = self.entry_username.get())
self.userLogged.pack()
###################################################################################################################################
##USERS##
###################################################################################################################################
class login(Frame):
def __init__(self, master):
super().__init__(master)
self.label_username = Label(self, text="Username: ",font=("bold",16))
self.label_password = Label(self, text="Password: ",font=("bold",16))
self.entry_username = Entry(self, font = ("bold", 14))
self.entry_password = Entry(self, show="*", font = ("bold", 14))
self.label_username.grid(row=0, sticky=E)
self.label_password.grid(row=1, sticky=E)
self.entry_username.grid(row=0, column=1)
self.entry_password.grid(row=1, column=1)
self.logbtn = Button(self, text="Login", font = ("bold", 10), command=self._login_btn_clicked)
self.logbtn.grid(columnspan=2)
self.pack()
def _login_btn_clicked(self):
# print("Clicked")
username = self.entry_username.get()
password = self.entry_password.get()
# print(username, password)
account_list = [line.split(":", maxsplit=1) for line in open("passwords.txt")]
# list of 2-tuples. Usersnames with colons inside not supported.
accounts = {key: value.rstrip() for key, value in account_list}
# Convert to dict[username] = password, and slices off the line ending.
# Does not support passwords ending in whitespace.
if accounts[username] == password:
self.label_username.grid_forget()
self.label_password.grid_forget()
self.entry_username.grid_forget()
self.entry_password.grid_forget()
self.logbtn.grid_forget()
self.pack_forget()
app = App(root)
else:
print("error")
root = Tk()
root.minsize(950, 450)
root.title("test")
lf = login(root)
root.mainloop()
When working with multiple classes in tkinter it is often a good idea to use class inherancy for the main window and frames. This allows us to use self.master to interact between classes.
That said you have a few things to change. You are using self where it is not needed and you should be doing import tkinter as tk to prevent overwriting of methods.
I have added a class to your code so we use one class for the root window. Then use one class for the login screen and then use one class for the frame after login.
import tkinter as tk
import tkinter.ttk as ttk
class NotebookFrame(tk.Frame):
def __init__(self, username):
super().__init__()
notebook = ttk.Notebook(self)
notebook.pack(expand=1, fill="both")
main = ttk.Frame(notebook)
notebook.add(main, text='Welcome Screen')
tk.Label(main, text=username).pack()
class Login(tk.Frame):
def __init__(self):
super().__init__()
tk.Label(self, text="Username: ", font=("bold", 16)).grid(row=0, sticky='e')
tk.Label(self, text="Password: ", font=("bold", 16)).grid(row=1, sticky='e')
self.entry_username = tk.Entry(self, font=("bold", 14))
self.entry_password = tk.Entry(self, show="*", font=("bold", 14))
self.entry_username.grid(row=0, column=1)
self.entry_password.grid(row=1, column=1)
tk.Button(self, text="Login", font=("bold", 10), command=self.master._login_btn_clicked).grid(columnspan=2)
class App(tk.Tk):
def __init__(self):
super().__init__()
self.title("test")
self.minsize(950, 450)
self.login_frame = Login()
self.login_frame.pack()
def _login_btn_clicked(self):
username = self.login_frame.entry_username.get()
password = self.login_frame.entry_password.get()
account_list = [line.split(":", maxsplit=1) for line in open("passwords.txt")]
accounts = {key: value.rstrip() for key, value in account_list}
if accounts[username] == password:
self.login_frame.destroy()
NoteFrame = NotebookFrame(username)
NoteFrame.pack()
else:
print("error")
if __name__ == "__main__":
App().mainloop()
Firstly, you should change class name from class login(Frame) to class Login(Frame).
Before fixing it, you called the login function from App, but you need to call Login class and use it.
class App:
def __init__(self, master):
notebook = ttk.Notebook(master)
notebook.pack(expand=1, fill="both")
# Frames
main = ttk.Frame(notebook)
notebook.add(main, text='Welcome Screen')
# `entry_username.get()` method is owned by the Login class,
# so you need to call from not `self(App class)` but `login(Login class)`.
login = Login(master) # Call Login class
self.userLogged = Label(main, text=login.entry_username.get())
self.userLogged.pack()
With this fix, I could call the Welcome screen.

How to replace an existing image instead of adding additional images?

This is my first time here, and I would really appreciate some help with this.
So I have some code which runs a Tkinter tab and shows 2 buttons. If you click the first one, a picture of a cat appears.
However, if you click the button again, the same picture appears again at the bottom, making there 2.
If I click the other button, titled N/A, a different picture appears. But if you click the button again, the picture duplicates.
I want to make it so that when each button is pressed, the image is replaced, not duplicated.
Here is what I have so far.
from tkinter import *
root = Tk()
class HomeClass(object):
def __init__(self, master):
frame = Frame(master)
frame.pack()
self.WelcomeLabel = Label(root, text="Welcome to the game!",
bg="Black", fg="White")
self.WelcomeLabel.pack(fill=X)
self.FirstButton = Button(root, text="Start", bg="RED", fg="White",
command=self.FirstClick)
self.FirstButton.pack(side=LEFT, fill=X)
self.SecondButton = Button(root, text="N/A", bg="Blue", fg="White",
command=self.SecondClick)
self.SecondButton.pack(side=LEFT, fill=X)
def FirstClick(self):
FirstPhoto = PhotoImage(file="keyboardcat.gif")
FiLabel = Label(root, image=FirstPhoto)
FiLabel.img = FirstPhoto
FiLabel.pack()
def SecondClick(self):
FirstPhoto = PhotoImage(file="donald.gif")
FiLabel = Label(root, image=FirstPhoto)
FiLabel.img = FirstPhoto
FiLabel.pack()
k = HomeClass(root)
root.mainloop()
That's becouse every time you click a button, you're calling FirstClick method which in turn creates new instance of PhotoImage class. I think it would be better to store FirstPhoto and in every FirstClick method call check if it is already has value or not.
class HomeClass(object):
def __init__(self, master):
frame = Frame(master)
frame.pack()
self.WelcomeLabel = Label(root, text="Welcome to the game!",
bg="Black", fg="White")
self.WelcomeLabel.pack(fill=X)
self.FirstButton = Button(root, text="Start", bg="RED", fg="White",
command=self.FirstClick)
self.FirstButton.pack(side=LEFT, fill=X)
self.SecondButton = Button(root, text="N/A", bg="Blue", fg="White",
command=self.SecondClick)
self.SecondButton.pack(side=LEFT, fill=X)
self.FirstPhoto = None
def FirstClick(self):
if self.FirstPhoto is None:
self.FirstPhoto = PhotoImage(file="ksiazka.png")
self.FiLabel = Label(root, image=self.FirstPhoto)
self.FiLabel.img = self.FirstPhoto
self.FiLabel.pack()
Try this to change SecondPhoto
def SecondClick(self):
if self.SecondPhoto is None:
self.SecondPhoto = PhotoImage(file="ksiazka.png")
self.SecondPhotoLabel = Label(root, image=self.FirstPhoto)
self.SecondPhotoLabel.img = self.SecondPhoto
self.SecondPhotoLabel.pack()
Else:
self.SecondPhotoLabel.config(image='newimage')
self.SecondPhotoLabel.update()
Note - you can declare the newImage before as you have to read it with PhotoImage and then just put the image name in the .config
In this example you have two methods FirstClick, SecondClick to display an image and two methods to clear an first and second image accordingly: clearFirstImage, clearSecondImage. You just have to add two buttons to trigger those clear methods :)
from tkinter import *
from tkFileDialog import askopenfilename
root = Tk()
class HomeClass(object):
def __init__(self, master):
self.master = master
self.frame = Frame(master)
self.WelcomeLabel = Label(root, text="Welcome to the game!",
bg="Black", fg="White")
self.WelcomeLabel.pack(fill=X)
self.FirstButton = Button(root, text="Start", bg="RED", fg="White",
command=self.FirstClick)
self.FirstButton.pack(side=LEFT, fill=X)
self.SecondButton = Button(root, text="N/A", bg="Blue", fg="White",
command=self.SecondClick)
self.SecondButton.pack(side=LEFT, fill=X)
self.ToggleButtonText = "Show image"
self.ToggleButton = Button(root, text=self.ToggleButtonText, bg="Grey", fg="White",
command=self.ToggleClick)
self.ToggleButton.pack(side=LEFT, fill=X)
self.FirstPhoto = None
self.FiLabel = None
self.SecondPhoto = None
self.SecondPhotoLabel = None
self.ToggleButtonPhoto = None
self.ToggleButtonPhotoLabel = None
self.frame.pack()
def FirstClick(self):
if self.FirstPhoto is None:
self.FirstPhoto = PhotoImage(file="ksiazka.png")
self.FiLabel = Label(root, image=self.FirstPhoto)
self.FiLabel.img = self.FirstPhoto
self.FiLabel.pack()
def ToggleClick(self):
if self.ToggleButtonPhoto is None:
self.ToggleButtonPhoto = PhotoImage(file="ksiazka.png")
self.ToggleButtonPhotoLabel = Label(self.frame, image=self.ToggleButtonPhoto)
self.ToggleButtonPhotoLabel.img = self.ToggleButtonPhoto
self.ToggleButtonPhotoLabel.pack()
# and set label
self.ToggleButton.config(text="Hide image")
else:
self.ToggleButton.config(text="Show image")
self.ToggleButtonPhotoLabel.destroy()
self.ToggleButtonPhotoLabel.img = None
self.ToggleButtonPhotoLabel = None
self.ToggleButtonPhoto = None
self.frame.pack()
def SecondClick(self):
filename = askopenfilename()
allowed_extensions = ['jpg', 'png']
if len(filename) > 0 and filename.split('.')[-1] in allowed_extensions:
self.SecondPhoto = PhotoImage(file=filename)
self.SecondPhotoLabel = Label(root, image=self.SecondPhoto)
self.SecondPhotoLabel.img = self.SecondPhoto
self.SecondPhotoLabel.pack()
def clearFirstImage(self):
self.FirstPhoto = None
self.FiLabel = None
def clearSecondImage(self):
self.SecondPhoto = None
self.SecondPhotoLabel = None
k = HomeClass(root)
root.mainloop()
If you want to replace an existing image, first create the label the image is displayed in, and simply reconfigure only its image option with each click. Below is an example that does that:
try: # In order to be able to import tkinter for
import tkinter as tk # either in python 2 or in python 3
except ImportError:
import Tkinter as tk
def download_images():
# In order to fetch the image online
try:
import urllib.request as url
except ImportError:
import urllib as url
url.urlretrieve("https://i.stack.imgur.com/57uJJ.gif", "13.gif")
url.urlretrieve("https://i.stack.imgur.com/8LThi.gif", "8.gif")
class ImageFrame(tk.Frame):
def __init__(self, master, *args, **kwargs):
tk.Frame.__init__(self, master, *args, **kwargs)
self._create_widgets()
self._display_widgets()
def _create_widgets(self):
def __create_image_label():
def ___load_images():
self.label.images = list()
self.label.images.append(tk.PhotoImage(file="8.gif"))
self.label.images.append(tk.PhotoImage(file="13.gif"))
self.label = tk.Label(self)
___load_images()
def __create_buttons():
self.buttons = list()
for i in range(2):
self.buttons.append(tk.Button(self, text=i,
command=lambda i=i: self.replace_image(i)))
__create_image_label()
__create_buttons()
def replace_image(self, button_index):
"""
Replaces the image in label attribute based on the index of the
button pressed.
"""
self.label['image'] = self.label.images[button_index]
def _display_widgets(self):
self.label.pack()
for i in range(2):
self.buttons[i].pack(fill='x', expand=True)
if __name__ == '__main__':
#download_images() # comment out after initial run
root = tk.Tk()
frame = ImageFrame(root)
frame.pack()
tk.mainloop()

calling function from another class in button command

I want to call the showallrecords1 function from the car class when I push a button in the "gett" class.
I get the error
'gett' object has no attribute 'car'
Here is the related part of my code
from tkinter import *
import tkinter as tk
import sqlite3
conn = sqlite3.connect('jadval.db')
c = conn.cursor()
class App:
def __init__(self,master):
frame = Frame(master)
frame.pack()
## bottomframe = Frame(master)
## bottomframe.pack( side = BOTTOM )
self.master=master
a= StringVar()
b= StringVar()
a1= StringVar()
b1= StringVar()
c= StringVar()
self.button = Button(frame,text="memory", command=self.ouvrir)
self.button.pack(side=LEFT)
self.button2 = Button(frame,text="report", command=self.tabluh)
self.button2.pack(side=LEFT)
self.button3 = Button(frame,text="setting", command=self.fermer)
self.button3.pack(side=LEFT)
self.button20 = Button(frame,text="calibration", command=self.cal)
self.button20.pack(side=LEFT)
self.button30 = Button(frame,text="empty weight", command=self.weighing)
self.button30.pack(side=LEFT)
def ouvrir(self):
root3=Toplevel(self.master)
mygui=records(root3)
def tabluh(self):
root4=Toplevel(self.master)
mygui2=report(root4)
def fermer(self):
root5=Toplevel(self.master)
mygui3=settting(root5)
def cal(self):
root8=Toplevel(self.master)
mygui8=cal(root8)
def weighing(self):
root9=Toplevel(self.master)
mygui9=gett(root9)
class car():#################################################### trunck manage
def __init__(self,master):
##super(car,self).__init__()
## tk.Frame.__init__(self, master)
self.master=master
## self.master.geometry('250x200+100+200')
self.master.geometry('400x300')
self.master.title('Report')
self.button28 = Button(self.master,text="create", command=self.tabluh1)
self.button28.grid(row=0, column=0)
self.button29 = Button(self.master,text="insert rec", command=self.insertar1)
self.button29.grid(row=3, column=2)
self.tyLabel1 = Label(self.master,text="driver name")
self.tyLabel1.grid(row=1, column=0)
self.disLabel1 = Label(self.master,text="trunck type")
self.disLabel1.grid(row=2, column=0)
self.pelLabel1 = Label(self.master,text="pelack")
self.pelLabel1.grid(row=3, column=0)
self.d = Entry(self.master)
self.d.grid(row=1, column=1)
self.e = Entry(self.master)
self.e.grid(row=2, column=1)
self.f = Entry(self.master)
self.f.grid(row=3, column=1)
self.connection = sqlite3.connect('jadval.db')
self.cur = self.connection.cursor()
self.dateLabel1 = Label(self.master, text="driver name", width=10)
self.dateLabel1.grid(row=4, column=0)
self.BMILabel1 = Label(self.master, text="trunck type", width=10)
self.BMILabel1.grid(row=4, column=1)
self.stateLabel1 = Label(self.master, text="pelack", width=10)
self.stateLabel1.grid(row=4, column=2)
self.showallrecords1()
def showallrecords1(self):
data1 = self.readfromdatabase1()
for index1, dat1 in enumerate(data1):
Label(self.master, text=dat1[0]).grid(row=index1+5, column=0)
Label(self.master, text=dat1[1]).grid(row=index1+5, column=1)
Label(self.master, text=dat1[2]).grid(row=index1+5, column=2)
def tabluh1(self):
c.execute('''CREATE TABLE trunmanage(id1 INTEGER,firs1 stringvar(10),las1 stringvar(10))''')
def insertar1(self):
d1=self.d.get()
e1=self.e.get()
f1=int(self.f.get())
c.execute("INSERT INTO trunmanage (id1, firs1,las1 ) VALUES (?, ?, ?)",(f1, d1, e1))
conn.commit()
self.showallrecords1()
def readfromdatabase1(self):
self.cur.execute("SELECT * FROM trunmanage")
return self.cur.fetchall()
class gett():########################################### class selecting trunck from empty weight window
def __init__(self,master):
##super(gett,self).__init__()
## tk.Frame.__init__(self, master)
self.master=master
## self.master.geometry('250x200+100+200')
self.master.geometry('200x120')
self.master.title('gett')
## obj2 = car()
## b1 = Button(master,text="button 1",command=obj2.showallrecords1)
## b1.pack()
## self.button32 = Button(text='select', command=self.master.showallrecords1)
## self.button32.pack()
self.button32 = Button(self.master,text="select trunck", command=self.car.showallrecords1);
self.button32.pack(side=LEFT)
root = Tk()
root.title("Dbase")
root.geometry('500x120')
app=App(root)
root.mainloop()
The gett class has no member called "car". You have to define it somewhere inside the class definition. I. e.:
self.car = car(master)

Categories