Tkinter: setting entry to readonly not working - python

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()

Related

mainloop() getting stuck on GUI on pyamaze library

I have a code made with pyamaze library which I perform 4 different types of search on maze and I want to display it with GUI (to make the user choose the type of search they want)
but the problem when I run the code the GUI gets stuck
from pyamaze import maze, COLOR, agent,textLabel
#Depth first search
def DFS(m1):
start=(m1.rows,m1.cols)
explored=[start]
frontier=[start]
dfsPath={}
while len(frontier)>0:
currCell=frontier.pop()
if currCell==(1,1):
break
for d in 'ESNW':
if m1.maze_map[currCell][d]==True:
if d=='E':
childCell=(currCell[0],currCell[1]+1)
elif d=='W':
childCell=(currCell[0],currCell[1]-1)
elif d=='S':
childCell=(currCell[0]+1,currCell[1])
elif d=='N':
childCell=(currCell[0]-1,currCell[1])
if childCell in explored:
continue
explored.append(childCell)
frontier.append(childCell)
dfsPath[childCell]=currCell
fwdPath={}
cell=(1,1)
while cell!=start:
fwdPath[dfsPath[cell]]=cell
cell=dfsPath[cell]
return fwdPath
#Breadth first search
def BFS(m2):
start=(m2.rows,m2.cols)
frontier=[start]
explored=[start]
bfsPath={}
while len(frontier)>0:
currCell=frontier.pop(0)
if currCell==(1,1):
break
for d in 'ESNW':
if m2.maze_map[currCell][d]==True:
if d=='E':
childCell=(currCell[0],currCell[1]+1)
elif d=='W':
childCell=(currCell[0],currCell[1]-1)
elif d=='N':
childCell=(currCell[0]-1,currCell[1])
elif d=='S':
childCell=(currCell[0]+1,currCell[1])
if childCell in explored:
continue
frontier.append(childCell)
explored.append(childCell)
bfsPath[childCell]=currCell
fwdPath={}
cell=(1,1)
while cell!=start:
fwdPath[bfsPath[cell]]=cell
cell=bfsPath[cell]
return fwdPath
# A-star search
from queue import PriorityQueue
def h(cell1,cell2):
x1,y1=cell1
x2,y2=cell2
return abs(x1-x2)+abs(y1-y2)
def aStar(m3):
start=(m3.rows,m3.cols)
g_score={cell:float('inf') for cell in m3.grid}
g_score[start]=0
f_score={cell:float('inf') for cell in m3.grid}
f_score[start]=h(start,(1,1))
open=PriorityQueue()
open.put((h(start,(1,1)),h(start,(1,1)),start))
aPath={}
while not open.empty():
currCell=open.get()[2]
if currCell==(1,1):
break
for d in 'ESNW':
if m3.maze_map[currCell][d]==True:
if d=='E':
childCell=(currCell[0],currCell[1]+1)
if d=='W':
childCell=(currCell[0],currCell[1]-1)
if d=='N':
childCell=(currCell[0]-1,currCell[1])
if d=='S':
childCell=(currCell[0]+1,currCell[1])
temp_g_score=g_score[currCell]+1
temp_f_score=temp_g_score+h(childCell,(1,1))
if temp_f_score < f_score[childCell]:
g_score[childCell]=temp_g_score
f_score[childCell]=temp_f_score
open.put((temp_f_score,h(childCell,(1,1)),childCell))
aPath[childCell]=currCell
fwdPath={}
cell=(1,1)
while cell!=start:
fwdPath[aPath[cell]]=cell
cell=aPath[cell]
return fwdPath
#uniform cost search.
def UCS(m,*h,start=None):
if start is None:
start=(m.rows,m.cols)
hurdles=[(i.position,i.cost) for i in h]
unvisited={n:float('inf') for n in m.grid}
unvisited[start]=0
visited={}
revPath={}
while unvisited:
currCell=min(unvisited,key=unvisited.get)
visited[currCell]=unvisited[currCell]
if currCell==m._goal:
break
for d in 'EWNS':
if m.maze_map[currCell][d]==True:
if d=='E':
childCell=(currCell[0],currCell[1]+1)
elif d=='W':
childCell=(currCell[0],currCell[1]-1)
elif d=='S':
childCell=(currCell[0]+1,currCell[1])
elif d=='N':
childCell=(currCell[0]-1,currCell[1])
if childCell in visited:
continue
tempDist= unvisited[currCell]+1
for hurdle in hurdles:
if hurdle[0]==currCell:
tempDist+=hurdle[1]
if tempDist < unvisited[childCell]:
unvisited[childCell]=tempDist
revPath[childCell]=currCell
unvisited.pop(currCell)
fwdPath={}
cell=m._goal
while cell!=start:
fwdPath[revPath[cell]]=cell
cell=revPath[cell]
return fwdPath,visited[m._goal]
from timeit import timeit
from tkinter import *
from tkinter import ttk
from tkinter import messagebox
import tkinter as tk
class MazeGUI:
def __init__(self, master):
self.master = master
self.master.title("Maze GUI")
self.master.geometry("700x500")
self.master.resizable(True, True)
self.master.configure(background='white')
self.create_widgets()
self.master.mainloop()
def create_widgets(self):
self.frame = tk.Frame(self.master, bg='black')
self.frame.pack(fill=tk.BOTH, expand=True)
self.frame.grid_rowconfigure(0, weight=1)
self.frame.grid_columnconfigure(0, weight=1)
self.frame.grid_propagate(False)
self.button1 = tk.Button(self.frame, text="BFS", command=self.bfs)
self.button1.grid(row=1, column=1, sticky="nsew", padx=10, pady=10)
self.button1.place(x=50,y=50)
self.button2 = tk.Button(self.frame, text="A*", command=self.aStar)
self.button2.grid(row=2, column=1, sticky="nsew", padx=10, pady=10)
self.button3 = tk.Button(self.frame, text="UCS", command=self.UCS)
self.button3.grid(row=3, column=1, sticky="nsew", padx=10, pady=10)
self.button4 = tk.Button(self.frame, text="DFS", command=self.dfs)
self.button4.grid(row=4, column=1, sticky="nsew", padx=10, pady=10)
self.button5 = tk.Button(self.frame, text="Exit", command=self.exit)
self.button5.grid(row=5, column=1, sticky="nsew", padx=10, pady=10)
def bfs(self):
m2=maze()
m2.CreateMaze()
path=BFS(m2)
b=agent(m2,footprints=True,filled=True)
m2.tracePath({b:path})
l2=textLabel(m2,'Length of Shortest Path',len(path)+1)
m2.mainloop()
def aStar(self):
m3=maze()
m3.CreateMaze()
path=aStar(m3)
c=agent(m3,footprints=True)
m3.tracePath({c:path})
l3=textLabel(m3,"A Star Path Length",len(path)+1)
m3.mainloop()
def UCS(self):
m4=maze(10,10)
m4.CreateMaze()
path,c=UCS(m4)
textLabel(m4,'Total Cost',c)
a=agent(m4,color=COLOR.cyan,filled=True,footprints=True,)
m4.tracePath({a:path},delay=100)
t1=timeit(stmt='UCS(m4)',number=100,globals=globals())
textLabel(m4,'UCS Time',t1)
m4.run()
m4.mainloop()
def dfs(self):
m1=maze()
m1.CreateMaze()
path=DFS(m1)
a=agent(m1,footprints=True)
m1.tracePath({a:path})
l1=textLabel(m1,'Length of Shortest Path',len(path)+1)
m1.mainloop()
def exit(self):
self.master.destroy()
if __name__ == '__main__':
root = tk.Tk()
app = MazeGUI(root)
I want to be displayed correctly and As it meant to be so if a press a button the search starts and agent moves.

Tkinter: drag and drop app only drop if the dragged text is selected in not under the cursor and show error for all widget instead of one

I'm working on a tkinter drag and drop app, my code is working just fine but only at one condition:
that the dragged text widget, when selected to be moved, is not under the cursor (so if the text widget is dragged by a word it doesn't work).
I've tried to fix the issue by adding some negative value to the y axis to make the selection always a little bit above, but it kinda create a weird distance if the text widget is dragged by the bottom.
So I was wondering if there is a better way to add some space.
Also I'd like to show the "Not empty" error only when the text is dragged in the self.dad_text
and is not empty, while right now it appear for every text widget. Is there a way to fix that?
This is my code
class MainApplication(tk.Frame):
def __init__(self, parent, *args, **kwargs):
tk.Frame.__init__(self, parent, *args, **kwargs)
self.first_list = ["11:00", "03:43", "22:04", "17:21", "22:35", "07:01", "16:11", "09:00"]
self.second_list = ["morning\nmorning\nmorning", "afternoon\nafternoon\nafternoon", "evening\nevening\nevening", "nigth\nnight\nnight"]
self.w_list = []
self.first_frame = tk.Frame(root)
self.first_frame.pack(padx=15, pady=15, fill="both", expand="true", side="left", anchor="w")
self.second_frame = tk.Frame(root)
self.second_frame.pack(padx=15, pady=15, fill="both", expand="true", side="left")
self.up()
def up(self):
for n, hour in enumerate(self.first_list):
self.list_one_frame = tk.LabelFrame(self.first_frame)
self.list_one_frame.grid(row=n, column=0, padx=10, pady=10)
self.one_text = tk.Text(self.list_one_frame, width=10, height=2)
self.one_text.grid(row=0, column=0,padx=10, pady=10)
self.one_text.insert("end", hour)
self.one_text.config(state="disabled")
self.dad_text = tk.Text(self.list_one_frame, width=20, height=1)
self.dad_text.grid(row=0, column=1, padx=10, pady=10, ipady=7)
for n, day in enumerate(self.second_list):
self.second_text = tk.Text(self.second_frame, width=9, height=3)
self.second_text.grid(row=n, column=1, pady=10, padx=10)
self.second_text.insert("end", day)
self.second_text.bind('<Button-1>', self.click)
self.second_text.bind('<B1-Motion>',self.drag)
self.second_text.bind('<ButtonRelease-1>',self.release)
def click(self, event):
self.widget_check = event.widget
self.text = event.widget.get("1.0",'end-1c')
root.clipboard_clear()
root.clipboard_append(self.text)
self.top = tk.Toplevel(root)
self.top.attributes('-alpha', 0.7)
self.top.overrideredirect(True)
self.top._offsetx = event.x
self.top._offsety = event.y
x = self.top.winfo_pointerx() - self.top._offsetx
y = self.top.winfo_pointery() - self.top._offsety - 50
self.top.geometry('+{x}+{y}'.format(x=x,y=y))
label = tk.Label(self.top, text=self.text)
label.grid(row=0, column=0)
def drag(self,event):
widget = event.widget.winfo_containing(event.x_root, event.y_root)
x = self.top.winfo_pointerx() - self.top._offsetx
y = self.top.winfo_pointery() - self.top._offsety - 50
self.top.geometry(f"+{x}+{y}")
def release(self, event):
widget = event.widget.winfo_containing(event.x_root, event.y_root)
try:
if widget.get('1.0', 'end-1c') != "":
messagebox.showerror("Error", "Not empty")
else:
reference_clipboard = root.clipboard_get()
widget.config(state="normal")
widget.insert("end", f"{reference_clipboard}")
widget.config(state="disabled")
self.top.destroy()
except:
self.top.destroy()
if __name__ == "__main__":
root = tk.Tk()
MainApplication(root).pack(side="top", fill="both", expand=True)
root.mainloop()
Thank you!

Why do my grid weights not affect the layout of window

I am writing some code for a program with a GUI, and part of this is this code:
self.chatbox = Text(self.chatframe)
self.messagebox = Entry(self.sendframe, textvariable=self.message)
self.sendbutton = Button(self.sendframe, text="Send", font=self.font(12))
self.chatframe.grid_rowconfigure(0, weight=1)
self.sendframe.grid_columnconfigure(0, weight=19)
self.sendframe.grid_columnconfigure(1, weight=1)
self.chatbox.grid(row=0, column=0)
self.messagebox.grid(row=0, column=0)
self.sendbutton.grid(row=0, column=1)
self.sendframe.grid(row=1, column=0)
self.mainframe.grid_columnconfigure(0, weight=1)
self.mainframe.grid_columnconfigure(1, weight=9)
self.mainframe.grid_rowconfigure(0, weight=1)
self.menu.grid(row=0, column=0)
self.chatframe.grid(row=0, column=1)
However when I run it, it always ends up only taking up some space and not filling the screen as I would expect. Any help appreciated.
Full Code:
from tkinter import *
import tkinter.messagebox
import os
class ServerInfo():
def __init__(self):
self.network = ""
self.host = False
self.name = StringVar()
self.name.set("")
class App(Frame):
def __init__(self, master=None):
super().__init__(master)
self.master = master
self.master.state("zoomed")
#self.master.minsize(1200, 600)
self.master.title("Chatroom App")
self.serverinfo = ServerInfo()
self.buffer_length = 2048
self.message = StringVar()
self.message.set("")
self.mainmenu = Frame(self.master)
self.localframe = Frame(self.master)
self.publicframe = Frame(self.master)
self.mainframe = Frame(self.master)
self.chatframe = Frame(self.mainframe)
self.sendframe = Frame(self.chatframe)
self.choiceframe = Frame(self.master)
self.inputframe = Frame(self.master)
self.create_widgets()
def font(self, size):
return ("Alef", size)
def create_widgets(self):
self.title = Label(self.mainmenu, text="The Chatroom App", font=self.font(40))
self.localbutton = Button(self.mainmenu, text="Local Chatrooms", font=self.font(16), command=self.go_to_local)
self.publicbutton = Button(self.mainmenu, text="Public Chatrooms", font=self.font(16), command=self.go_to_public)
self.exitbutton = Button(self.mainmenu, text="Exit", font=self.font(16), command=self.master.destroy)
self.title.pack(fill=BOTH)
self.localbutton.pack(pady=20, fill=BOTH)
self.publicbutton.pack(pady=20, fill=BOTH)
self.exitbutton.pack(side=BOTTOM, fill=BOTH)
self.instruction = Label(self.choiceframe, text="Would you like to host a server or search for available servers", font=self.font(26))
self.hostbutton = Button(self.choiceframe, text="Host server", font=self.font(32), command=self.host_input)
self.joinbutton = Button(self.choiceframe, text="Join server", font=self.font(32), command=self.join_input)
self.backbutton = Button(self.choiceframe, text="Back", font=self.font(32), command=self.back_from_choice)
self.instruction.pack(pady=20, fill=BOTH)
self.hostbutton.pack(pady=10, fill=BOTH)
self.joinbutton.pack(pady=10, fill=BOTH)
self.backbutton.pack(pady=20, fill=BOTH)
self.instruction2 = Label(self.inputframe, text="", font=self.font(18))
self.server_input = Entry(self.inputframe, textvariable=self.serverinfo.name)
self.continuebutton = Button(self.inputframe, text="", font=self.font(28), command=self.take_input)
self.backbutton2 = Button(self.inputframe, text="Back", font=self.font(28), command=self.back_from_input)
self.instruction2.pack(pady=10, fill=BOTH)
self.server_input.pack(pady=40, fill=BOTH)
self.continuebutton.pack(pady=10, fill=BOTH)
self.backbutton2.pack(pady=20, fill=BOTH)
self.menu = Canvas(self.mainframe, bg="Black")
self.chatbox = Text(self.chatframe)
self.messagebox = Entry(self.sendframe, textvariable=self.message)
self.sendbutton = Button(self.sendframe, text="Send", font=self.font(12))
self.chatframe.grid_rowconfigure(0, weight=1)
self.sendframe.grid_columnconfigure(0, weight=19)
self.sendframe.grid_columnconfigure(1, weight=1)
self.chatbox.grid(row=0, column=0)
self.messagebox.grid(row=0, column=0)
self.sendbutton.grid(row=0, column=1)
self.sendframe.grid(row=1, column=0)
self.mainframe.grid_columnconfigure(0, weight=1)
self.mainframe.grid_columnconfigure(1, weight=9)
self.mainframe.grid_rowconfigure(0, weight=1)
self.menu.grid(row=0, column=0)
self.chatframe.grid(row=0, column=1)
self.mainmenu.pack()
def back_from_choice(self):
self.choiceframe.forget()
self.mainmenu.pack()
window.update()
def back_from_input(self):
self.inputframe.forget()
self.choiceframe.pack()
def take_input(self):
self.inputframe.forget()
self.mainframe.pack(fill=BOTH)
def go_to_local(self):
self.serverinfo.network = "local"
self.mainmenu.forget()
self.choiceframe.pack()
window.update()
def go_to_public(self):
self.serverinfo.network = "public"
tkinter.messagebox.showinfo("Message from the developer", "This feature is still under development")
def host_input(self):
self.serverinfo.host = True
self.instruction2.config(text="Type in the name of your server. When the server is created, a server ID will show in the top left. Share this to people who want to join the server")
self.continuebutton.config(text="Host Server")
self.choiceframe.forget()
self.inputframe.pack()
def join_input(self):
self.serverinfo.host = False
self.instruction2.config(text="Type in the server ID of the server you want to join")
self.continuebutton.config(text="Join Server")
self.choiceframe.forget()
self.inputframe.pack()
def host_server(self):
pass
def join_server(self):
pass
def write_message_to_screen(self, data):
print(data)
def encode_id(self, server_id):
return server_id
def decode_id(self, server_id):
return server_id
Weights only affect how grid allocates extra space once everything has been laid out, it doesn't describe the overall relative size of widgets.
You also don't seem to be using the sticky attribute, so space may be allocated to widgets but you aren't requesting that they stretch to fill the space given to them.

Need to Add a Scroll Toolbar to FGCs LabelFrame (Tkinter)

Working on an internal app and trying to get a scrollbar to "FGCs" labelFrame only, in addition, I need to scale the frame to the app size.
I'll be happy if anyone could assist me in refactoring this and create the scrollbar.
I know that I need to create a canvas or something, but do not know how.
This is a first time for me with Tkinter.
from tkinter import *
import os, subprocess
from tkinter import ttk
managment = ["MAIN","NAV","OUTPUT","OUTPUTSPARE","GATEWAY","Sync1","Sync2"]
servers = ["recon01","recon02","recon03","recon04","recon05","recon06","recon07","recon08","recon09","recon10","recon11","recon12","render01","render02","storinator"]
FGCs =["fgc01","fgc02","fgc03","fgc04","fgc05","fgc06","fgc07","fgc08","fgc09","fgc10","fgc11","fgc12","fgc13","fgc14","fgc15","fgc16","fgc17","fgc18","fgc19","fgc20","fgc21","fgc22","fgc23","fgc24","fgc25","fgc26","fgc27","fgc28","fgc29","fgc30","fgc31","fgc32","fgc33","fgc34","fgc35","fgc36","fgc37","fgc38","fgcspare1","fgcspare2","fgcspare3","fgcspare4"]
tests = ["Network", "GPU", "Time", "Gidel", "Snapshot", "Disks"]
testbuttons = []
serverbuttons = []
managebuttons = []
fgcbuttons = []
class mainwindow:
global test
global testbuttons
global managment
global managebuttons
global FGCs
def __init__(self,master):
self.master = master
master.title("System Report Tool")
master.geometry("1000x500")
self.Tests = ttk.LabelFrame(root, text="Tests")
self.Tests.pack(expand="no",anchor=W,pady=20)
for test in tests:
testcheck = ttk.Checkbutton(self.Tests, text=test)
testcheck.pack(side=LEFT, anchor="n")
testbuttons.append(testcheck)
def select_tests():
for test in testbuttons:
test.invoke()
selecttests = ttk.Checkbutton(root, text="Select All",command=select_tests)
selecttests.place(x=260,y=16)
self.Managment = ttk.LabelFrame(root, text="Managment")
self.Managment.configure(width=10, height=20)
self.Managment.pack(expand="no",anchor=W)
for manage in managment:
managecheck = ttk.Checkbutton(self.Managment, text=manage)
managecheck.pack(side=TOP, anchor="w")
managebuttons.append(managecheck)
def select_manage():
for manage in managebuttons:
manage.invoke()
selectmanage = ttk.Checkbutton(self.Managment, text="Select All",command=select_manage)
selectmanage.pack()
self.FGCs = ttk.LabelFrame(root, text="FGCs")
self.FGCs.configure(width=10, height=20)
self.FGCs.place(x=120,y=80)
for fgc in FGCs:
fgccheck = ttk.Checkbutton(self.FGCs, text=fgc)
fgccheck.pack(side=TOP, anchor="w")
fgcbuttons.append(fgccheck)
def select_fgc():
for fgc in fgcbuttons:
fgc.invoke()
selectfgc = ttk.Checkbutton(self.FGCs, text="Select All",command=select_fgc)
selectfgc.pack()
root = Tk()
Window = mainwindow(root)
root.mainloop()
Thanks in advance.
Copy code with class ScrolledFrame from scrolled-frame-canvas
Create ScrolledFrame inside LabelFrame self.FGCs
self.sf = ScrolledFrame(self.FGCs)
self.sf.pack()
And then put widgets in inner element in ScrolledFrame instead of putting them in self.FGCs like
fgccheck = ttk.Checkbutton(self.sf.inner, text=fgc)
Working code
import os
import subprocess
import tkinter as tk
from tkinter import *
from tkinter import ttk
class ScrolledFrame(tk.Frame):
def __init__(self, parent, vertical=True, horizontal=False):
super().__init__(parent)
# canvas for inner frame
self._canvas = tk.Canvas(self)
self._canvas.grid(row=0, column=0, sticky='news') # changed
# create right scrollbar and connect to canvas Y
self._vertical_bar = tk.Scrollbar(self, orient='vertical', command=self._canvas.yview)
if vertical:
self._vertical_bar.grid(row=0, column=1, sticky='ns')
self._canvas.configure(yscrollcommand=self._vertical_bar.set)
# create bottom scrollbar and connect to canvas X
self._horizontal_bar = tk.Scrollbar(self, orient='horizontal', command=self._canvas.xview)
if horizontal:
self._horizontal_bar.grid(row=1, column=0, sticky='we')
self._canvas.configure(xscrollcommand=self._horizontal_bar.set)
# inner frame for widgets
self.inner = tk.Frame(self._canvas)
self._window = self._canvas.create_window((0, 0), window=self.inner, anchor='nw')
# autoresize inner frame
self.columnconfigure(0, weight=1) # changed
self.rowconfigure(0, weight=1) # changed
# resize when configure changed
self.inner.bind('<Configure>', self.resize)
# resize inner frame to canvas size
self.resize_width = False
self.resize_height = False
self._canvas.bind('<Configure>', self.inner_resize)
def resize(self, event=None):
self._canvas.configure(scrollregion=self._canvas.bbox('all'))
def inner_resize(self, event):
# resize inner frame to canvas size
if self.resize_width:
self._canvas.itemconfig(self._window, width=event.width)
if self.resize_height:
self._canvas.itemconfig(self._window, height=event.height)
managment = ["MAIN","NAV","OUTPUT","OUTPUTSPARE","GATEWAY","Sync1","Sync2"]
servers = ["recon01","recon02","recon03","recon04","recon05","recon06","recon07","recon08","recon09","recon10","recon11","recon12","render01","render02","storinator"]
FGCs =["fgc01","fgc02","fgc03","fgc04","fgc05","fgc06","fgc07","fgc08","fgc09","fgc10","fgc11","fgc12","fgc13","fgc14","fgc15","fgc16","fgc17","fgc18","fgc19","fgc20","fgc21","fgc22","fgc23","fgc24","fgc25","fgc26","fgc27","fgc28","fgc29","fgc30","fgc31","fgc32","fgc33","fgc34","fgc35","fgc36","fgc37","fgc38","fgcspare1","fgcspare2","fgcspare3","fgcspare4"]
tests = ["Network", "GPU", "Time", "Gidel", "Snapshot", "Disks"]
testbuttons = []
serverbuttons = []
managebuttons = []
fgcbuttons = []
class mainwindow:
global test
global testbuttons
global managment
global managebuttons
global FGCs
def __init__(self,master):
self.master = master
master.title("System Report Tool")
master.geometry("1000x500")
self.Tests = ttk.LabelFrame(root, text="Tests")
self.Tests.pack(expand="no", anchor=W, pady=20)
for test in tests:
testcheck = ttk.Checkbutton(self.Tests, text=test)
testcheck.pack(side=LEFT, anchor="n")
testbuttons.append(testcheck)
def select_tests():
for test in testbuttons:
test.invoke()
selecttests = ttk.Checkbutton(root, text="Select All",command=select_tests)
selecttests.place(x=260,y=16)
self.Managment = ttk.LabelFrame(root, text="Managment")
self.Managment.configure(width=10, height=20)
self.Managment.pack(expand="no",anchor=W)
for manage in managment:
managecheck = ttk.Checkbutton(self.Managment, text=manage)
managecheck.pack(side=TOP, anchor="w")
managebuttons.append(managecheck)
def select_manage():
for manage in managebuttons:
manage.invoke()
selectmanage = ttk.Checkbutton(self.Managment, text="Select All",command=select_manage)
selectmanage.pack()
self.FGCs = ttk.LabelFrame(root, text="FGCs")
self.FGCs.configure(width=10, height=20)
self.FGCs.place(x=120, y=80)
self.sf = ScrolledFrame(self.FGCs)
self.sf.pack()
for fgc in FGCs:
fgccheck = ttk.Checkbutton(self.sf.inner, text=fgc)
fgccheck.pack(side=TOP, anchor="w")
fgcbuttons.append(fgccheck)
def select_fgc():
for fgc in fgcbuttons:
fgc.invoke()
selectfgc = ttk.Checkbutton(self.sf.inner, text="Select All",command=select_fgc)
selectfgc.pack()
root = Tk()
Window = mainwindow(root)
root.mainloop()
EDIT: This code uses pack() with some options to resize widgets when window is resized
import os
import subprocess
import tkinter as tk
from tkinter import *
from tkinter import ttk
class ScrolledFrame(tk.Frame):
def __init__(self, parent, vertical=True, horizontal=False):
super().__init__(parent)
# canvas for inner frame
self._canvas = tk.Canvas(self)
self._canvas.grid(row=0, column=0, sticky='news') # changed
# create right scrollbar and connect to canvas Y
self._vertical_bar = tk.Scrollbar(self, orient='vertical', command=self._canvas.yview)
if vertical:
self._vertical_bar.grid(row=0, column=1, sticky='ns')
self._canvas.configure(yscrollcommand=self._vertical_bar.set)
# create bottom scrollbar and connect to canvas X
self._horizontal_bar = tk.Scrollbar(self, orient='horizontal', command=self._canvas.xview)
if horizontal:
self._horizontal_bar.grid(row=1, column=0, sticky='we')
self._canvas.configure(xscrollcommand=self._horizontal_bar.set)
# inner frame for widgets
self.inner = tk.Frame(self._canvas)
self._window = self._canvas.create_window((0, 0), window=self.inner, anchor='nw')
# autoresize inner frame
self.columnconfigure(0, weight=1) # changed
self.rowconfigure(0, weight=1) # changed
# resize when configure changed
self.inner.bind('<Configure>', self.resize)
# resize inner frame to canvas size
self.resize_width = False
self.resize_height = False
self._canvas.bind('<Configure>', self.inner_resize)
def resize(self, event=None):
self._canvas.configure(scrollregion=self._canvas.bbox('all'))
def inner_resize(self, event):
# resize inner frame to canvas size
if self.resize_width:
self._canvas.itemconfig(self._window, width=event.width)
if self.resize_height:
self._canvas.itemconfig(self._window, height=event.height)
managment = ["MAIN","NAV","OUTPUT","OUTPUTSPARE","GATEWAY","Sync1","Sync2"]
servers = ["recon01","recon02","recon03","recon04","recon05","recon06","recon07","recon08","recon09","recon10","recon11","recon12","render01","render02","storinator"]
FGCs =["fgc01","fgc02","fgc03","fgc04","fgc05","fgc06","fgc07","fgc08","fgc09","fgc10","fgc11","fgc12","fgc13","fgc14","fgc15","fgc16","fgc17","fgc18","fgc19","fgc20","fgc21","fgc22","fgc23","fgc24","fgc25","fgc26","fgc27","fgc28","fgc29","fgc30","fgc31","fgc32","fgc33","fgc34","fgc35","fgc36","fgc37","fgc38","fgcspare1","fgcspare2","fgcspare3","fgcspare4"]
tests = ["Network", "GPU", "Time", "Gidel", "Snapshot", "Disks"]
testbuttons = []
serverbuttons = []
managebuttons = []
fgcbuttons = []
class mainwindow:
global test
global testbuttons
global managment
global managebuttons
global FGCs
def __init__(self,master):
self.master = master
master.title("System Report Tool")
master.geometry("1000x500")
# --- top ---
self.Tests = ttk.LabelFrame(root, text="Tests")
self.Tests.pack(anchor='w', pady=20)
for test in tests:
testcheck = ttk.Checkbutton(self.Tests, text=test)
testcheck.pack(side='left', anchor="n")
testbuttons.append(testcheck)
def select_tests():
for test in testbuttons:
test.invoke()
selecttests = ttk.Checkbutton(root, text="Select All",command=select_tests)
selecttests.place(x=260,y=16)
# --- middle ---
self.Managment = ttk.LabelFrame(root, text="Managment")
self.Managment.configure(width=10, height=20)
self.Managment.pack(anchor='nw', side='left')
for manage in managment:
managecheck = ttk.Checkbutton(self.Managment, text=manage)
managecheck.pack(anchor="w")
managebuttons.append(managecheck)
def select_manage():
for manage in managebuttons:
manage.invoke()
selectmanage = ttk.Checkbutton(self.Managment, text="Select All",command=select_manage)
selectmanage.pack()
self.FGCs = ttk.LabelFrame(root, text="FGCs")
self.FGCs.configure(width=10, height=20)
self.FGCs.pack(fill='y', expand=True, side='left', anchor='w')
self.sf = ScrolledFrame(self.FGCs)
self.sf.pack(fill='y', expand=True)
for fgc in FGCs:
fgccheck = ttk.Checkbutton(self.sf.inner, text=fgc)
fgccheck.pack(anchor="w")
fgcbuttons.append(fgccheck)
def select_fgc():
for fgc in fgcbuttons:
fgc.invoke()
selectfgc = ttk.Checkbutton(self.sf.inner, text="Select All", command=select_fgc)
selectfgc.pack()
root = Tk()
Window = mainwindow(root)
root.mainloop()

Tkinter does not show one frame

I am trying to make a GUI for my program but I have changed my code a lot and I saw that GUI misses one frame but it was fine before.
Could anyone help me and tell why a frame with a button does not appear on the bottom?
Whole "button_part" object does not appear.
from tkinter import *
import tkinter as tk
import os
import glob
BOUNDS = ["Last week", "Last 2 weeks", "Last 3 weeks"]
class settings_part:
path_to_copy = 0
def __init__(self, master, update_func):
path_to_copy = StringVar()
settings_frame = Frame(master, background="")
settings_frame.pack(side=TOP, fill=X)
date_bound = StringVar()
date_bound.set(BOUNDS[1])
date_option = OptionMenu(settings_frame, date_bound, *BOUNDS, command=update_func)
date_option.config(background="#732c30")
date_option.config(foreground="white")
date_option.config(bd=0)
date_option.pack(side=LEFT, padx=5, pady=5)
path_to_copy.set("~/Python/usun")
box_with_path = Entry(settings_frame, textvariable=path_to_copy)
box_with_path.pack(side=RIGHT, padx=5, pady=5)
# s = path_to_copy.get()
class songs_part:
def __init__(self, master, root):
self.songs_frame = Frame(master)
self.update_songs(root.list_of_songs)
self.songs_frame.pack()
def update_songs(self, l):
for song in l:
c = Checkbutton(self.songs_frame, text=song[0], variable=song[1])
c.pack()
class button_part:
def __init__(self, master, copyFunc):
self.button_frame = Frame(master)
btn_image = PhotoImage(file="copybtn.png")
self.copy_button = Button(self.button_frame, command=copyFunc, text="Copy",
image=btn_image, highlightthickness=0, bd=0, activebackground="#732c30")
self.copy_button.pack()
class App:
def __init__(self):
root = Tk()
root.title("Copying songs")
root.geometry("500x500")
root.option_add("*Font", "Calibra")
back_image = PhotoImage(file="back.png")
self.window = Label(root, image=back_image)
self.window.pack(fill="both", expand="yes")
self.list_of_songs = list()
self.make_list_of_songs()
self.set_part = settings_part(self.window, self.update_list)
self.son_part = songs_part(self.window, self)
self.but_part = button_part(self.window, self.copy_songs)
root.mainloop()
def make_list_of_songs(self):
owd = os.getcwd()
os.chdir("/home/stanek/Music/usun")
for file in glob.glob("*.mp3"):
self.list_of_songs.append([file, tk.IntVar()])
os.chdir(owd)
def copy_songs(self):
for s in self.list_of_songs:
print(s)
def update_list(self, arg):
print("updating list with songs from " + arg)
self.son_part = songs_part(self.window, self)
if __name__ == '__main__':
App()
You never pack the button frame.

Categories