Add Checkbutton "remember my answer" to messagebox askokcancel - python-3.x

What's the easiest way (if any) of adding "Remember my answer" Checkbutton to askokcancel (tkinter messagebox) dialog? I see nothing short of making my own dialog (Toplevel window with the layout similar to askokcancel). I don't think it will be easy to conform the dialog's style. I may popup other dialog (instead of breaking the loop) to ask user if he wants that his answer was applies to all successive "error", but it looks to me no better.
if lg.name in db:
if askokcancel(message=f'"{args.db}" already has "{lg.name}", continue?'):
pass
else:
break
Using Python 3.9.2, Debian GNU/Linux 11 (bullseye)
UPDATE 2023-02-20
Not quite a solution, a workaround
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import textwrap
import tkinter as tk
from tkinter.simpledialog import Dialog
class AskOkCancel(Dialog):
def __init__(self, master, message=None, parent=None, title="askokcancel"):
self.message = message
self._parent = parent
self._title = title
super().__init__(master)
def body(self, master):
self.title(self._title)
master.rowconfigure(0, weight=1)
tk.Label(master, text=textwrap.fill(self.message, width=40), height=3,
relief=tk.SUNKEN).grid(column=0, columnspan=2, row=0)
self.chkvar = tk.IntVar()
self.chk = tk.Checkbutton(master, variable=self.chkvar,
text="Remember my answer")
self.chk.grid(column=0, row=1, columnspan=2, sticky=tk.EW)
self.lift(aboveThis=self._parent)
return self.chk # initial focus
def ok(self, event=None):
super().ok(event)
self.result = True, self.chkvar.get()
def cancel(self, event=None):
super().cancel(event)
self.result = False, self.chkvar.get()
I use it as below:
if lg.name in db and not (lg.name in confirmed):
_d = AskOkCancel(
lv, parent=lv, title='Duplicated record',
message=(f'"{args.db}" already has "{lg.name}", '
f'continue?'))
if _d.result[0]:
if _d.result[1]:
confirmed.add(lg.name)
else:
break
Where confirmed is a set()

I think you would like reading this:
https://stackoverflow.com/questions/69559208/tkinter-messagedialog-askyesno-with-a-checkbox```

Related

How to close current tkinter window and open a new tkinter window when the user inputs test into a tkinter Entry widget

I would like to close the current tkinter window, and open a new tkinter window when the user inputs text into an entry widget. That might sound confusing so let me explain.
First tkinter window:
When the user inputs text into the Entry widget, I would like this current window to close and the second window to open with the text the user entered displayed in a label widget.
Second window:
Here is my current code:
from tkinter import *
user_input = ''
class Startup_window:
def __init__(self, master):
self.master = master
master.title('Window 1')
def get_input(event):
global user_input
# Gets the user input from the Entry widget
user_input = self.input.get()
# Clears Entry widget
self.input.delete(0, END)
master.destroy()
self.label = Label(master, text='Input:')
self.label.grid(row=0, column=0)
self.input = Entry(master)
self.input.grid(row=0, column=1)
self.input.focus()
self.input.bind("<Return>", get_input)
class Main_window:
def __init__(self, master):
self.master = master
master.title('Window 2')
self.label = Label(master, text="You've entered (user_input)" + user_input)
self.label.pack()
root = Tk()
startup_window = Startup_window(root)
if user_input != '':
main_window = Main_window(root)
mainloop()
I am new to tkinter and object oriented programming so any help would be greatly appreciated!
This would work for you. As #CoolCloud mentioned, the if condition will be checked only once. Because mainloop() actually waits for events to be triggered (maybe through some buttons or whatever), NOT that it executes the blocks of code over and over again
import tkinter as tk
class MainApp():
def __init__(self, root):
self.root = root
self.inputBox = tk.Entry(self.root)
self.inputBox.pack()
self.inputBox.bind('<Return>', self.checkInput)
def checkInput(self, args):
if self.inputBox.get() != '':
userVal = self.inputBox.get()
self.root.destroy() # try root.quit if it doesn't work
newWindow = tk.Tk()
myLabel = tk.Label(newWindow, text='You entered: ' + userVal)
myLabel.pack()
win = tk.Tk()
MainApp(win)
win.mainloop()

how do i stop the tkinter window being not interactable while a "computation heavy" function is running

i have a tkinter window that does has some widgeds that the user can interact with and when a function that takes a little bit of time to run the whole window cant be interacted with.and i want to change that
i heard you can solve this problem by implementing multiprocessing to the function but i dont really understand how to implement it.
my code is something like this :
import tkinter as tk
from tkinter import *
def functionthattakessometime():
while True:
print("haa")
root=tk.Tk()
b=Button(root,text="print haha",command=functionthattakessometime)
a=Button(root,text="do nothing")
b.pack()
root.mainloop()
You cant press the "do nothing" window after you pressed the "print haha" button and i want to change that
so you can press the "do nothing" button even after you pressed the "print haha" button.
The threading library is what you want here.
Here is a simple example of how it would work with your code.
import tkinter as tk
import threading
root = tk.Tk()
allow_print = True
def function_that_takes_sometime():
while allow_print:
print("haha")
def start_thread():
global allow_print
allow_print = True
thread = threading.Thread(target=function_that_takes_sometime)
thread.start()
def stop_thread():
global allow_print
allow_print = False
tk.Button(root, text="print haha", command=start_thread).pack()
tk.Button(root, text="Stop print", command=stop_thread).pack()
root.mainloop()
That said I would change a few things.
First I would remove from tkinter import * as you should never import tkinter twice and it is better to just use import tkinter as tk because this prevents us from overwriting any methods on accident.
Second I would build this in a class so we can avoid global variables.
Here is an OOP version:
import tkinter as tk
import threading
class Main(tk.Tk):
def __init__(self):
super().__init__()
self.allow_print = True
tk.Button(self, text="print haha", command=self.start_thread).pack()
tk.Button(self, text="Stop print", command=self.stop_thread).pack()
def function_that_takes_sometime(self):
while self.allow_print:
print("haha")
def start_thread(self):
self.allow_print = True
thread = threading.Thread(target=self.function_that_takes_sometime)
thread.start()
def stop_thread(self):
self.allow_print = False
Main().mainloop()
And to simplify this further because often threading is overkill we can use the after() method to manage the loop and not affect the mainloop.
import tkinter as tk
class Main(tk.Tk):
def __init__(self):
super().__init__()
self.allow_print = True
tk.Button(self, text="print haha", command=self.function_that_takes_sometime).pack()
tk.Button(self, text="Stop print", command=self.stop_print).pack()
def function_that_takes_sometime(self):
if self.allow_print:
print("haha")
self.after(1000, self.function_that_takes_sometime)
def stop_print(self):
self.allow_print = False
Main().mainloop()

Accessing Children in LabelFrames using Tkinter and Python 3

I am working with tkinter and have set up a bare bones application of my project. My objective is to retrieve a value from tk.Entry() which lies within a tk.LabelFrame() (in this code referenced by the groupbox variable). The button finds the groupbox, and the code passes the compiler, too. I guess my question is: How do I access Widgets and their values in a LabelFrame?
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import tkinter as tk
class Application(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.master.title("Application Title")
# Introduce LabelFrame
self.groupbox = tk.LabelFrame(self, text="Parameters")
self.groupbox.grid(row=0, column=1, padx=5, pady=5)
# Test Label & Entry Widget
label = tk.Label(self.groupbox, text="label=")
label.grid(row=0, column=0, sticky="W")
entry = tk.Entry(self.groupbox)
entry.insert(0, default_value)
entry.grid(row = 0, column=1)
# Compile Button
button = tk.Button(self.groupbox, text="Compile", command=self.compile)
button.grid(row=1, column=1)
# Retrieve first Value (second Widget) from LabelFrame
def compile(self):
print(self.groupbox.entry.get(1))
if __name__ == '__main__':
figure = Application()
figure.pack()
figure.mainloop()
I am doing this because I want to perform some calculations based on the tk.Entry() values triggered by a button click which is contained in the same LabelFrame() as suggested by the code snippet above (in the original code there are a lot more widgets but that's essentially the gist of my current problem).
Change entry to self.entry.
class Application(tk.Frame):
def __init__(self, master=None):
....
self.entry = tk.Entry(self.groupbox)
self.entry.insert(0, "default_value")
self.entry.grid(row = 0, column=1)
...
# Retrieve first Value (second Widget) from LabelFrame
def compile(self):
print(self.entry.get())

Python3 tkinter - New window with class is blank + new window contents in original window

I am dabbling in tkinter's possibilities to make a simple application that shows a "Enter password" little window upon startup. But the weirdest behaviour started to happen...
mainWindow.py
import tkinter as tk
import password
class mainWindow(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.title("mainWindow")
self.geometry("{0}x{1}+20+20".format(50,50))
if __name__ == "__main__":
mainW = mainWindow()
passW = password.passwordWindow()
passW.resizable(False, False)
passW.attributes("-topmost", True)
passW.mainloop()
password.py
import tkinter as tk
import mainWindow
class passwordWindow(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.title("Password")
self.frame = tk.Frame(height=2, bd=1, relief=tk.SUNKEN)
self.frame.pack(fill=tk.X, padx=5, pady=5)
self.label = tk.Label(self.frame, text="This Label is packed\nin the Password's Frame.")
self.label.pack(fill=tk.BOTH, expand=1)
Result:
Needless to say, it's not the desired effect. The "Label" part should be on the password window! Any clue why am I getting this result? Thanks in advance!!
The 1st porblem I can see is you are using Tk() twice here. Instead of using Tk() for a new window use Toplevel() instead. Toplevel is meant to be used to create new windows after the main window has been generated.
Next we need to pass the root window to the password class so we can use it as the top level of the main windows instance.
So in short your code should look like this:
mainWindow.py
import tkinter as tk
import password
class mainWindow(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.title("mainWindow")
self.geometry("{0}x{1}+20+20".format(50,50))
if __name__ == "__main__":
mainW = mainWindow()
passW = password.passwordWindow(mainW)
passW.resizable(False, False)
passW.attributes("-topmost", True)
mainW.mainloop()
password.py
import tkinter as tk
import mainWindow
class passwordWindow(tk.Toplevel):
def __init__(self, controller):
tk.Toplevel.__init__(self, controller)
self.title("Password")
self.frame = tk.Frame(self, height=2, bd=1, relief=tk.SUNKEN)
self.frame.pack(fill=tk.X, padx=5, pady=5)
self.label = tk.Label(self, text="This Label is packed\nin the Password's Frame.")
self.label.pack(fill=tk.BOTH, expand=1)
Results:

Save and Load GUI-tkinter

I want to save and load my GUI.
I have made a GUI and I want that when I click on the save button.
It should save the GUI in some blob of data and when I click on load button then it will load the same GUI again.
My GUI has various text widgets, drop down Option Menu.
I am new to python, so someone can help me on this, please?
I have tried pickle module, too.
You can't do what you want to do without doing the work yourself. You'll need to write a function that gathers all the data you need in order to restore the GUI, and then you can save that to disk. Then, when the GUI starts up you can read the data and reconfigure the widgets to contain this data.
Tkinter gives you pretty much everything you need in order to accomplish it, but you have to do all the work yourself. Pickling the GUI won't work.
Here's a contrived example. Enter a few expressions in the window that pops up. Notice that they are added to the combobox. When you exit, the current expression, the saved expressions, and the current value are all saved. The next time you start the GUI, these values will be restored.
try:
import Tkinter as tk
import ttk
except ModuleNotFoundError:
import tkinter as tk
import tkinter.ttk as ttk
import pickle
FILENAME = "save.pickle"
class Example(tk.Frame):
def __init__(self, parent):
self.create_widgets(parent)
self.restore_state()
def create_widgets(self, parent):
tk.Frame.__init__(self, parent, borderwidth=9, relief="flat")
self.previous_values = []
l1 = tk.Label(self, text="Enter a mathematical expression:", anchor="w")
l2 = tk.Label(self, text="Result:", anchor="w")
self.expressionVar = tk.StringVar()
self.expressionEntry = ttk.Combobox(self, textvariable=self.expressionVar, values=("No recent values",))
self.resultLabel = tk.Label(self, borderwidth=2, relief="groove", width=1)
self.goButton = tk.Button(self, text="Calculate!", command=self.calculate)
l1.pack(side="top", fill="x")
self.expressionEntry.pack(side="top", fill="x", padx=(12, 0))
l2.pack(side="top", fill="x")
self.resultLabel.pack(side="top", fill="x", padx=(12, 0), pady=4)
self.goButton.pack(side="bottom", anchor="e", pady=4)
self.expressionEntry.bind("<Return>", self.calculate)
# this binding saves the state of the GUI, so it can be restored later
root.wm_protocol("WM_DELETE_WINDOW", self.save_state)
def calculate(self, event=None):
expression = self.expressionVar.get()
try:
result = "%s = %s" % (expression, eval(expression))
self.previous_values.append(expression)
self.previous_values = self.previous_values[-8:]
self.expressionVar.set("")
self.expressionEntry.configure(values=self.previous_values)
except:
result = "invalid expression"
self.resultLabel.configure(text=str(result))
def save_state(self):
try:
data = {
"previous": self.previous_values,
"expression": self.expressionVar.get(),
"result": self.resultLabel.cget("text"),
}
with open(FILENAME, "wb") as f:
pickle.dump(data, f)
except Exception as e:
print
"error saving state:", str(e)
root.destroy()
def restore_state(self):
try:
with open(FILENAME, "rb") as f:
data = pickle.load(f)
self.previous_values = data["previous"]
self.expressionEntry.configure(values=self.previous_values)
self.expressionVar.set(data["expression"])
self.resultLabel.configure(text=data["result"])
except Exception as e:
print
"error loading saved state:", str(e)
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack(fill="both", expand=True)
root.mainloop()

Resources