Tkinter using append to print to a label - python

I have been trying to return the fuction printLabel to print "Hello
world!", but I am not too sure how to progress further:
I would like to use lambda in order to print my append strings in the label when the button is clicked but this displays without the button being clicked. My
code is as follows:
from tkinter import *
class Example(Frame):
def printLabel(self):
self.hello = []
self.hello.append('Hello\n')
self.hello.append('World!')
print(self.hello)
return(self.hello)
def __init__(self, root):
Frame.__init__(self, root)
self.buttonA()
self.viewingPanel()
def buttonA(self):
self.firstPage = Button(self, text="Print Text", bd=1, anchor=CENTER, height = 13, width = 13, command=lambda: self.printLabel())
self.firstPage.place(x=0, y=0)
def viewingPanel(self):
self.panelA = Label(self, bg='white', width=65, height=13, padx=3, pady=3, anchor=CENTER, text="{}".format(self.printLabel()))
self.panelA.place(x=100, y=0)
def main():
root = Tk()
root.title("Tk")
root.geometry('565x205')
app = Example(root)
app.pack(expand=True, fill=BOTH)
root.mainloop()
if __name__ == '__main__':
main()

I made a few modifications to your code, and it should work the way you want:
from tkinter import *
class Example(Frame):
def printLabel(self):
self.hello.append('Hello\n')
self.hello.append('World!')
return(self.hello)
# Added 'updatePanel' method which updates the label in every button press.
def updatePanel(self):
self.panelA.config(text=str(self.printLabel()))
# Added 'hello' list and 'panelA' label in the constructor.
def __init__(self, root):
self.hello = []
self.panelA = None
Frame.__init__(self, root)
self.buttonA()
self.viewingPanel()
# Changed the method to be executed on button press to 'self.updatePanel()'.
def buttonA(self):
self.firstPage = Button(self, text="Print Text", bd=1, anchor=CENTER, height = 13, width = 13, command=lambda: self.updatePanel())
self.firstPage.place(x=0, y=0)
# Changed text string to be empty.
def viewingPanel(self):
self.panelA = Label(self, bg='white', width=65, height=13, padx=3, pady=3, anchor=CENTER, text="")
self.panelA.place(x=100, y=0)
def main():
root = Tk()
root.title("Tk")
root.geometry('565x205')
app = Example(root)
app.pack(expand=True, fill=BOTH)
root.mainloop()
if __name__ == '__main__':
main()

Related

How to use 2nd Tkinter window to change image in 1st?

Quick summary: The green button is supposed to change when an image is selected, but it doesn't:
I have a Tkinter window-A with a button that when pressed will use a separate Python file to create a new window-B. Window-B has two buttons: new screen-snip or select image from folder. The method used for this is supposed to then change self.image_selected so that it can be used to update the button in window-A to have this new image.
I've tried both lines of code below, and neither are working. I'm not getting any errors either:
self.button.configure(image = img.image_selected) # first try
self.button['image'] = img.image_selected # second try
Here is my code (simplified for clarity):
import tkinter as tk
import get_image_or_snip
class ButtonImg:
def __init__(self, master):
self.newWindow = None
self.master = master
self.title = "My Minimum Reproducible Example"
self.fontA = ("arial", 20, "bold")
self.canvas = tk.Canvas(height = 5)
self.canvas.pack()
self.button = tk.Button(bg="#93d9cc", height = 5, text = "Select Image",
font = self.fontA, command = self.changeImage)
self.button.pack(fill="both")
def changeImage(self):
self.newWindow = tk.Toplevel(self.master)
img = get_image_or_snip.AcquireImage(self.newWindow)
self.button.configure(image = img.image_selected)
#self.button['image'] = img.image_selected
root = tk.Tk()
app = ButtonImg(root)
root.mainloop()
Here is the aforementioned get_image_or_snip.py code:
import tkinter as tk
from tkinter import filedialog
from PIL import ImageTk, Image
import snipping_tool
class AcquireImage:
def __init__(self, master):
self.master = master
self.fontA = ("arial", 20, "bold")
self.frame = tk.Frame(master, bg="#1B2631")
self.frame.pack(fill="both", expand=True)
self.button1 = tk.Button(self.frame, text="Select Image File", padx=10, pady=10, bg="#d9a193",
font = self.fontA, command =lambda: self.show_dialogs(1))
self.button1.grid(row=0, column=0, sticky="nsew")
self.button2 = tk.Button(self.frame, text="Get Screen Snip", padx=10, pady=10, bg="#d9a193",
font = self.fontA, command=lambda: self.show_dialogs(2))
self.button2.grid(row=0, column=1, sticky="nsew")
self.image_selected = None
self.master.mainloop()
def show_dialogs(self, method):
if method == 1:
ret = filedialog.askopenfilename()
load_img = Image.open(ret)
self.image_selected = ImageTk.PhotoImage(load_img)
if method == 2:
ret = snipping_tool.get_snip()
self.image_selected = ret
def main():
root = tk.Tk()
AcquireImage(root)
root.mainloop()
if __name__ == '__main__':
main()
If you add print() before and after get_image_or_snip.AcquireImage(self.newWindow) in changeImage() then you should see only first text because you run second mainloop() and it never ends this loop and never go back to changeImage() and never runs self.button.configure(image=img.image_selected)
You should use only one mainloop() and eventually use
root.wait_window(self.newWindow)
to wait until you close second window and then it will run self.button.configure(image=img.image_selected)
But there are other problems.
It removes image from memory memory when second windows is destroyed so you have to assign it to variable in first window.
Button use height in chars when you sent text but when you assign image then it use height in pixels and you have to change it from 5 to image.height()`
All code in one file
import tkinter as tk
from tkinter import filedialog
from PIL import ImageTk
class AcquireImage:
def __init__(self, master):
self.master = master
self.fontA = ("arial", 20, "bold")
self.frame = tk.Frame(master, bg="#1B2631")
self.frame.pack(fill="both", expand=True)
self.button1 = tk.Button(self.frame, text="Select Image File", padx=10, pady=10, bg="#d9a193",
font=self.fontA, command=lambda:self.show_dialogs(1))
self.button1.grid(row=0, column=0, sticky="nsew")
self.button2 = tk.Button(self.frame, text="Get Screen Snip", padx=10, pady=10, bg="#d9a193",
font=self.fontA, command=lambda:self.show_dialogs(2))
self.button2.grid(row=0, column=1, sticky="nsew")
self.image_selected = None
def show_dialogs(self, method):
if method == 1:
ret = filedialog.askopenfilename(initialdir='/home/user/images/')
if ret:
self.image_selected = ImageTk.PhotoImage(file=ret)
self.master.destroy()
elif method == 2:
self.image_selected = snipping_tool.get_snip()
class ButtonImg:
def __init__(self, master):
self.newWindow = None
self.master = master
self.title = "My Minimum Reproducible Example"
self.fontA = ("arial", 20, "bold")
self.canvas = tk.Canvas(height=5)
self.canvas.pack()
self.button = tk.Button(bg="#93d9cc", height=5, text="Select Image",
font=self.fontA, command=self.changeImage)
self.button.pack(fill="both")
def changeImage(self):
print('open second window')
self.newWindow = tk.Toplevel(self.master)
img = AcquireImage(self.newWindow)
self.master.wait_window(self.newWindow)
print('close second window')
if img.image_selected: # check if image was selected
self.image = img.image_selected
self.button.configure(image=self.image, height=self.image.height())
root = tk.Tk()
app = ButtonImg(root)
root.mainloop()
BTW: If you want to change image without closing second window then you should send first window (or button from first window) as argument to second window and change image in show_dialogs()
import tkinter as tk
from tkinter import filedialog
from PIL import ImageTk
class AcquireImage:
def __init__(self, master, first_window):
self.master = master
self.first_window = first_window
self.fontA = ("arial", 20, "bold")
self.frame = tk.Frame(master, bg="#1B2631")
self.frame.pack(fill="both", expand=True)
self.button1 = tk.Button(self.frame, text="Select Image File", padx=10, pady=10, bg="#d9a193",
font=self.fontA, command=lambda:self.show_dialogs(1))
self.button1.grid(row=0, column=0, sticky="nsew")
self.button2 = tk.Button(self.frame, text="Get Screen Snip", padx=10, pady=10, bg="#d9a193",
font=self.fontA, command=lambda:self.show_dialogs(2))
self.button2.grid(row=0, column=1, sticky="nsew")
self.image_selected = None
def show_dialogs(self, method):
if method == 1:
ret = filedialog.askopenfilename(initialdir='/home/user/images/')
if ret:
self.image_selected = ImageTk.PhotoImage(file=ret)
self.first_window.image = self.image_selected
self.first_window.button.configure(image=self.first_window.image, height=self.first_window.image.height())
elif method == 2:
self.image_selected = snipping_tool.get_snip()
class ButtonImg:
def __init__(self, master):
self.newWindow = None
self.master = master
self.title = "My Minimum Reproducible Example"
self.fontA = ("arial", 20, "bold")
self.canvas = tk.Canvas(height=5)
self.canvas.pack()
self.button = tk.Button(bg="#93d9cc", height=5, text="Select Image",
font=self.fontA, command=self.changeImage)
self.button.pack(fill="both")
def changeImage(self):
self.newWindow = tk.Toplevel(self.master)
img = AcquireImage(self.newWindow, self) # first window as `self` but you can send `self.button`
root = tk.Tk()
app = ButtonImg(root)
root.mainloop()
EDIT: Doc about creating Dialog Windows

Passing values between classes for Tkinter

I'm working on a small GUI to query information from our CMDB to display for users. The trouble I am having is after an event in one class occurs(button), I want to update a combobox in another class. I thought I should use tk.StringVar() to pass the list, but the combobox only shows a 'PC_VAR#' value and doesn't update. Could anyone offer any assistance please?
#!/usr/bin/python
import Tkinter as tk
import ttk
import signal
class LoginUI:
def __init__(self, frame):
self.frame = frame
# Set default list entry
self.dc_list = tk.StringVar()
self.dc_list.set(['Login first'])
# Add a button to log in
self.button = tk.Button(self.frame, text='Login', command=self.change_combobox)
self.button.grid(column=0, row=0, pady=5)
def change_combobox(self):
# Change combobox values
dc_list = ['Site_1', 'Site_2', 'Site_3']
self.dc_list.set(dc_list)
class QueryUI:
def __init__(self, frame, dc_list):
self.frame = frame
self.dc = tk.StringVar()
self.dc_list = tk.StringVar()
self.dc_list.set(dc_list)
# Create site combobox
tk.Label(self.frame, text='Site:').grid(column=0, row=0, sticky="w")
self.dc_combobox = ttk.Combobox(
self.frame,
textvariable=self.dc,
width=20,
state='readonly'
)
self.dc_combobox['values'] = self.dc_list.get()
self.dc_combobox.grid(column=1, row=0, sticky="w")
class App:
def __init__(self, root):
self.root = root
self.root.title('Logging Handler')
self.root.columnconfigure(0, weight=1)
self.root.rowconfigure(0, weight=1)
# Create the left frame panels
left_frame = tk.Frame(self.root, padx=5, pady=5)
login_frame = tk.LabelFrame(left_frame, text="Login", borderwidth=2, relief="groove", padx=5, pady=5)
query_frame = tk.LabelFrame(left_frame, text="Query", borderwidth=2, relief="groove", padx=5, pady=5)
# Align frames
left_frame.grid(row=0, column=0, sticky="nw")
login_frame.grid(row=0, column=0, pady=5, sticky="nw")
query_frame.grid(row=1, column=0, pady=5, sticky="nw")
# Initialize all frames
self.login = LoginUI(login_frame)
self.query = QueryUI(query_frame, self.login.dc_list)
self.root.protocol('WM_DELETE_WINDOW', self.quit)
self.root.bind('<Control-q>', self.quit)
signal.signal(signal.SIGINT, self.quit)
def quit(self, *args):
self.root.destroy()
def main():
root = tk.Tk()
app = App(root)
app.root.mainloop()
if __name__ == '__main__':
main()
What I would do here is pass the controlling class (app) to the class needed to update the combobox. This way we can interact with it later if need be. By passing self of App to LoginUI we can then interact with the class attributes and methods of App from within LoginUI. This makes it a simple matter to update the combobox.
That said you really don't Need all the StringVars. Just past the list as a list and you will be good to go.
import Tkinter as tk
import ttk
import signal
class LoginUI:
def __init__(self, controller, frame):
self.controller = controller
self.frame = frame
self.dc_list = ['Login first']
self.button = tk.Button(self.frame, text='Login', command=self.change_combobox)
self.button.grid(column=0, row=0, pady=5)
def change_combobox(self):
self.controller.query.dc_combobox['values'] = ['Site_1', 'Site_2', 'Site_3']
self.controller.query.dc.set('Site_1')
class QueryUI:
def __init__(self, frame, dc_list):
self.frame = frame
self.dc = tk.StringVar()
tk.Label(self.frame, text='Site:').grid(column=0, row=0, sticky="w")
self.dc_combobox = ttk.Combobox(self.frame, textvariable=self.dc, width=20, state='readonly')
self.dc_combobox['values'] = dc_list
self.dc_combobox.grid(column=1, row=0, sticky="w")
class App:
def __init__(self, root):
self.root = root
self.root.title('Logging Handler')
self.root.columnconfigure(0, weight=1)
self.root.rowconfigure(0, weight=1)
left_frame = tk.Frame(self.root, padx=5, pady=5)
login_frame = tk.LabelFrame(left_frame, text="Login", borderwidth=2, relief="groove", padx=5, pady=5)
query_frame = tk.LabelFrame(left_frame, text="Query", borderwidth=2, relief="groove", padx=5, pady=5)
left_frame.grid(row=0, column=0, sticky="nw")
login_frame.grid(row=0, column=0, pady=5, sticky="nw")
query_frame.grid(row=1, column=0, pady=5, sticky="nw")
self.login = LoginUI(self, login_frame)
self.query = QueryUI(query_frame, self.login.dc_list)
self.root.protocol('WM_DELETE_WINDOW', self.quit)
self.root.bind('<Control-q>', self.quit)
signal.signal(signal.SIGINT, self.quit)
def quit(self, *args):
self.root.destroy()
if __name__ == '__main__':
root = tk.Tk()
app = App(root)
app.root.mainloop()

How to save text from textbox to file (Tkinter)

Whenever the function save() runs I get an error saying that the variable that holds the Text() function does not exist. I want the GUI to save whatever is inputted at the point when the Activate button is pressed.
from tkinter.ttk import *
class Example(Frame):
def __init__(self, parent= None):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("TL;DR")
self.style = Style()
self.style.theme_use("default")
self.pack(fill=BOTH, expand=1)
self.columnconfigure(1, weight=1)
self.columnconfigure(3, pad=7)
self.rowconfigure(3, weight=1)
self.rowconfigure(5, pad=7)
lbl = Label(self, text="Enter Text")
lbl.grid(sticky=W, pady=4, padx=5)
area = Text(self)
area.grid(row=1, column=0, columnspan=2, rowspan=4,
padx=5, sticky=E+W+S+N)
abtn = Button(self, text="Activate", command= self.save)
abtn.grid(row=1, column=3)
cbtn = Button(self, text="Close", command = self.client_exit)
cbtn.grid(row=2, column=3, pady=4)
hbtn = Button(self, text="Help", command= self.help1)
hbtn.grid(row=5, column=0, padx=5)
def save(self):
text = self.area.get("1.0",'end-1c')
with open("filepy.txt", "a") as outf:
outf.write(text)
def help1(self):
messagebox.showinfo('Help')
def client_exit(self):
exit()
def main():
root = Tk()
root.geometry("400x300+300+300")
app = Example(root)
if __name__ == '__main__':
main()
My question is: how do I save any text in the TextBox when the activate button is pressed?
In save() method, you are trying to access self.area but you did not created it.
area = Text(self) # class variable
self.area = Text(self)# instance variable
To be able to use self to access area you should change your code:
...
self.area = Text(self)
self.area.grid(row=1, column=0, columnspan=2, rowspan=4,
padx=5, sticky=E+W+S+N)
...

Tkinter custom frame not working

I'm trying to create a custom frame in tkinter, Python v2.7. I have done this just fine once (a frame with a scrollbar), but my second attempt isn't working. I compare it to the Frame that does work, and I can't understand what I have done differently.
What I want is a frame that has a little separator line underneath it, so I'm creating a "normal" frame, a thin frame to use as a separator under it, and a bigFrame to hold it.
Everything I create in the class works, except the frame itself. Hopefully my comments explain what is and isn't showing.
from Tkinter import *
class FunFrame(Frame):
def __init__(self, master, lbl, **kwargs):
self.bigFrame = Frame(master)
Frame.__init__(self, self.bigFrame, width=280, height=200, bg="red", **kwargs)
self.grid(row=0, column=0, pady=3) #this is in bigFrame, and doesn't display
#however the padding is still respected
self.separator = Frame(self.bigFrame, height=2, bd=1, width=280, relief = SUNKEN)
self.separator.grid(row=1, column=0) #this is in bigFrame, and displays
self.l = Label(self, text=lbl) #this is in self and doesn't display
self.l.grid(row=0, column=0)
def grid(self, **kwargs):
self.bigFrame.grid(**kwargs)
if __name__ == "__main__":
root=Tk()
Frame1=FunFrame(root, "hello")
Frame2=FunFrame(root, "world")
Frame1.grid(row=0, column=0)
Frame2.grid(row=1, column=0)
root.mainloop()
If you call self.grid in __init__, it calls your own grid, not Tkinter's version.
Try following (renamed grid to grid_):
from Tkinter import *
class FunFrame(Frame):
def __init__(self, master, lbl, **kwargs):
self.bigFrame = Frame(master)
Frame.__init__(self, self.bigFrame, width=280, height=200, bg="red", **kwargs)
self.grid(row=0, column=0, pady=3)
self.separator = Frame(self.bigFrame, height=2, bd=1, width=280, relief=SUNKEN)
self.separator.grid(row=1, column=0)
self.l = Label(self, text=lbl)
self.l.grid(row=0, column=0)
def grid_(self, **kwargs): ######## grid -> grid_
self.bigFrame.grid(**kwargs)
if __name__ == "__main__":
root=Tk()
Frame1 = FunFrame(root, "hello")
Frame2 = FunFrame(root, "world")
Frame1.grid_(row=0, column=0) ######## grid -> grid_
Frame2.grid_(row=1, column=0) ######## grid -> grid_
root.mainloop()
I'd rather code as follow (if '....' was used to represent hierarchy visually):
from Tkinter import *
class FunFrame(Frame):
def __init__(self, master, lbl, **kwargs):
Frame.__init__(self, master)
if 'inside outer frame (self)':
innerFrame = Frame(self, width=280, height=200, bg="red", **kwargs)
innerFrame.grid(row=0, column=0, pady=3)
if 'inside inner frame':
self.l = Label(innerFrame, text=lbl)
self.l.grid(row=0, column=0)
separator = Frame(self, height=2, bd=1, width=280, relief=SUNKEN)
separator.grid(row=1, column=0)
if __name__ == "__main__":
root = Tk()
Frame1 = FunFrame(root, "hello")
Frame2 = FunFrame(root, "world")
Frame1.grid(row=0, column=0)
Frame2.grid(row=1, column=0)
root.mainloop()

Why am I getting a blank Tkinter box when typing it this code in Python?

Most of this code was provided by my professor, and I have to make changes to his format. However, his original code is not even providing ANYTHING in the tk box when I run the program. I made some changes, but nothing is quite working. Any advice??
This is my main code:
from Tkinter import *
import todo
master = Tk()
class todoApp():
def __init__(self, master):
self.master = master
self.frame = Frame(master)
self.frame.grid()
self.todo = todo.todoList()
self.saveButton = Button(self.frame, text="Save", command=self.save)
self.saveButton.grid()
self.restoreButton = Button(self.frame, text="Restore", command = self.restore)
self.restoreButton.grid(row=1, column=1)
self.addButton = Button(self.frame, text="Add", command=self.add)
self.addButton.grid(row=0,column=2)
self.doneButton = Button(self.frame, text="Done", command=self.done)
self.doneButton.grid(row=0,column=3)
self.button = Button(self.frame, text="Quit", command=self.quit)
self.button.grid(row=0, column=4)
label = Label(self.frame, text="New Task: ")
label.grid()
self.entry = Entry(self.frame)
self.entry.grid(row=1, column=1, columnspan=4)
frame1 = LabelFrame(self.frame, text="Tasks")
frame1.grid(columnspan=5, sticky=E+W)
frame1.columnconfigure(0,weight=1)
self.tasks = Listbox(frame1)
self.tasks.grid(sticky=E+W)
frame2 = LabelFrame(self.frame, text="Completed")
frame2.grid(columnspan=5, sticky=E+W)
frame2.columnconfigure(0,weight=1)
self.completed = Listbox(frame2)
self.completed.grid(sticky=E+W)
def save(self):
self.todo.saveList("tasks.txt")
def restore(self):
self.todo.restoreList("tasks.txt")
items = self.todo.getTasks()
self.tasks.delete(0,END)
for item in [ "study", "grocery shop", "cram for finals!", "sleep", "build a gingerbread house" ]:
self.tasks.insert(END,item)
items = self.todo.getCompleted()
self.completed.delete(0,END)
for item in items:
self.completed.insert(END,item)
def add(self):
task = self.entry.get()
self.todo.addTask(task)
self.tasks.insert(END,task)
def done(self):
selection = self.tasks.curselection()
if len(selection) == 0:
return
task = self.tasks.get(selection[0])
self.todo.completeTask(task)
self.tasks.delete(selction[0])
self.completed.insert(END,task)
def quit(self):
self.frame.quit()
self.master.destroy()
master.mainloop()
The todo import is:
class todoList:
def __init__(self):
self.todo = []
self.done = []
def addTask(self,task):
self.todo.append(task)
def completeTask(self,task):
if self.todo.count(task) > 0:
self.todo.remove(task)
self.done.append(task)
def getTasks(self):
return self.todo
def getCompleted(self):
return self.done
You havent created an instance of the class todoApp,
add this line here:
def quit(self):
self.frame.quit()
self.master.destroy()
a = todoApp(master)
master.mainloop()
You do need to mess around with the positioning though, when I ran it, it looked a bit messy.
edit:
is this exactly what you're looking for?
from Tkinter import *
import todo
master = Tk()
class todoApp():
def __init__(self, master):
self.master = master
self.frame = Frame(master)
self.frame.grid()
self.todo = todo.todoList()
self.buttonframe = LabelFrame(self.frame, text='controls')
self.buttonframe.grid(row=0, column=0, columnspan=2)
self.saveButton = Button(self.buttonframe, text="Save", command=self.save)
self.saveButton.grid()
self.restoreButton = Button(self.buttonframe, text="Restore", command = self.restore)
self.restoreButton.grid(row=0, column=1)
self.addButton = Button(self.buttonframe, text="Add", command=self.add)
self.addButton.grid(row=0,column=2)
self.doneButton = Button(self.buttonframe, text="Done", command=self.done)
self.doneButton.grid(row=0,column=3)
self.button = Button(self.buttonframe, text="Quit", command=self.quit)
self.button.grid(row=0, column=4)
label = Label(self.frame, text="New Task: ")
label.grid(row=1, column=0)
self.entry = Entry(self.frame)
self.entry.grid(row=1, column=1)
frame1 = LabelFrame(self.frame, text="Tasks")
frame1.grid(columnspan=5, sticky=E+W)
frame1.columnconfigure(0,weight=1)
self.tasks = Listbox(frame1)
self.tasks.grid(sticky=E+W)
frame2 = LabelFrame(self.frame, text="Completed")
frame2.grid(columnspan=5, sticky=E+W)
frame2.columnconfigure(0,weight=1)
self.completed = Listbox(frame2)
self.completed.grid(sticky=E+W)
def save(self):
self.todo.saveList("tasks.txt")
def restore(self):
self.todo.restoreList("tasks.txt")
items = self.todo.getTasks()
self.tasks.delete(0,END)
for item in [ "study", "grocery shop", "cram for finals!", "sleep", "build a gingerbread house" ]:
self.tasks.insert(END,item)
items = self.todo.getCompleted()
self.completed.delete(0,END)
for item in items:
self.completed.insert(END,item)
def add(self):
task = self.entry.get()
self.todo.addTask(task)
self.tasks.insert(END,task)
def done(self):
selection = self.tasks.curselection()
if len(selection) == 0:
return
task = self.tasks.get(selection[0])
self.todo.completeTask(task)
self.tasks.delete(selection[0])
self.completed.insert(END,task)
def quit(self):
self.frame.quit()
self.master.destroy()
a = todoApp(master)
master.mainloop()
It seems to me like you haven't created an instance of your class.
In the bottom of your file, add this:
myApp = todoApp(master)
master.mainloop()
It could be that they must be in reverse order (I'm at work so I can't try it out right now).

Categories