Using a conditional statement to link a button press - python-3.x

The idea is that if one presses one of the buttons the labeled text is inputted in the top left entry box. My initial plan was to use an if statement when the button is pressed and then insert the text according.
However, I am not sure what syntax to use that would allow me to make this one line conditional statement that recognizes the button being pressed. Is this actually possible or do I need to make a separate function?
from tkinter import *
from tkinter import ttk
class GUI():
def __init__(self, master):
self.master = master
master.resizable(True, True)
master.title('Conversion Calculator')
self.tabControl = ttk.Notebook(master)
self.tab1 = ttk.Frame(self.tabControl) # tab set up
self.tabControl.add(self.tab1, text='Builder')
self.tabControl.pack(expand=1, fill="both")
self.builder_entrybox = ttk.Entry(self.tab1, width=24) # entry box set up
self.builder_entrybox.grid(column=0, row=0)
self.builder_outputbox = ttk.Entry(self.tab1, width=24) # output box set up
self.builder_outputbox.grid(column=0, row=1)
self.builder_outputbox.config(state='NORMAL')
self.builder_outputbox.config(state='readonly')
self.CH3_Button = ttk.Button(self.tab1, text='CH3', command=self.builder) # CH3 button
self.CH3_Button.grid(column=1, row=0)
self.CH2_Button = ttk.Button(self.tab1, text='CH2', command=self.builder) # CH2 button
self.CH2_Button.grid(column=2, row=0)
self.OH_Button = ttk.Button(self.tab1, text='OH', command=self.builder) # OH button
self.OH_Button.grid(column=1, row=1)
self.O_Button = ttk.Button(self.tab1, text='O', command=self.builder) # O button
self.O_Button.grid(column=2, row=1)
self.H_Button = ttk.Button(self.tab1, text='H', command=self.builder) # H button
self.H_Button.grid(column=3, row=1)
self.COOH_Button = ttk.Button(self.tab1, text='COOH', command=self.builder) # COOH button
self.COOH_Button.grid(column=3, row=0)
class Logic(GUI):
def builder (self): # adding button text to entry box (tab1)
self.builder_entrybox.insert(0, 'CH3')
if __name__ == "__main__":
root = Tk()
test = Logic(root)

Yes, you would make a new function for every button:
class GUI():
def __init__(self, master):
# ...
self.CH3_Button = ttk.Button(self.tab1, text='CH3', command=self.CH3_builder) # CH3 button
self.CH3_Button.grid(column=1, row=0)
def CH3_builder(self):
self.builder_entrybox.insert('end', 'CH3')
Python can make functions on the fly, either with functools.partial (early binding) or lambda (late binding). Using that you could write the same thing like this:
from functools import partial
class GUI():
def __init__(self, master):
# ...
self.CH3_Button = ttk.Button(self.tab1, text='CH3', command=partial(self.builder_entrybox.insert, 'end', 'CH3')) # CH3 button
self.CH3_Button.grid(column=1, row=0)
But it would be better if you make a small subclass to handle all this for you, which makes your code very reusable and therefore neat:
from tkinter import ttk
import tkinter as tk
class Copa(ttk.Button):
"""A new type of Button that moves the text into a Entry when clicked"""
def __init__(self, master=None, **kwargs):
ttk.Button.__init__(self, master, command=self.builder, **kwargs)
def builder(self):
self.master.builder_entrybox.insert('end', self['text'])
class BuilderFrame(tk.Frame):
def __init__(self, master=None, **kwargs):
tk.Frame.__init__(self, master, **kwargs)
self.builder_entrybox = ttk.Entry(self, width=24) # entry box set up
self.builder_entrybox.grid(column=0, row=0)
self.builder_outputbox = ttk.Entry(self, width=24) # output box set up
self.builder_outputbox.grid(column=0, row=1)
self.builder_outputbox.config(state='NORMAL')
self.builder_outputbox.config(state='readonly')
self.CH3_Button = Copa(self, text='CH3') # CH3 button
self.CH3_Button.grid(column=1, row=0)
self.CH2_Button = Copa(self, text='CH2') # CH2 button
self.CH2_Button.grid(column=2, row=0)
self.OH_Button = Copa(self, text='OH') # OH button
self.OH_Button.grid(column=1, row=1)
self.O_Button = Copa(self, text='O') # O button
self.O_Button.grid(column=2, row=1)
self.H_Button = Copa(self, text='H') # H button
self.H_Button.grid(column=3, row=1)
self.COOH_Button = Copa(self, text='COOH') # COOH button
self.COOH_Button.grid(column=3, row=0)
class GUI():
def __init__(self, master):
self.master = master
master.resizable(True, True)
master.title('Conversion Calculator')
self.tabControl = ttk.Notebook(master)
self.tab1 = BuilderFrame(self.tabControl) # tab set up
self.tabControl.add(self.tab1, text='Builder')
self.tabControl.pack(expand=1, fill="both")
if __name__ == "__main__":
root = tk.Tk()
test = GUI(root)
root.mainloop()

Related

Tkinter background color change alone

i'm doing a tkinter application, and i have this problem:
I have a Frame with this code:
class SelectFrame(customtkinter.CTkFrame):
def __init__(self, master, back):
super(SelectFrame, self).__init__(master)
self.configure(width=120, height=60, border_width=2,)
self.master = master
self.menu = ""
self.input = ""
self.back = back
self.create_widgets()
def create_widgets(self):
def segmented_button_callback(value):
if value == "Menu":
import menu_frame
self.menu = menu_frame.MenuFrame(self.master, self.back).place(x=25, y=125)
if value == "Inputs":
import input_frame
self.input = input_frame.InputFrame(self.master, self.back).place(x=25, y=125)
segemented_button = customtkinter.CTkSegmentedButton(master=self,
values=["Menu", "Inputs"],
command=segmented_button_callback,
width=100,
height=40,
selected_hover_color="blue",
font=("Helvetica", 14))
segemented_button.place(x=10, y=10)
The idea its that, when you click on Menu it creates a Menu Frame, and the same with the Input Frame.
The problem is that when i click on Input Frame, the background becomes white.
Here's the input frame code:
class InputFrame(customtkinter.CTkFrame):
# CONSTRUCTOR FOR THE CLASS
def __init__(self, master, back):
super(InputFrame, self).__init__(master)
self.master = master
self.configure(width=850, height=350)
self.table = ttk.Treeview(self, columns=("c1", "c2"), show='headings')
self.lbl_error = customtkinter.CTkLabel(master=self.master, text="", text_color="red")
self.style()
self.back = back
self.createWidgets()
# METHOD TO CHANGE THE STYLE OF THE TREEVIEW
def style(self):
# STYLE FOR TABLE
style = ttk.Style()
style.configure("Treeview",
background="#2a2d2e",
foreground="white",
fieldbackground="#343638",
bordercolor="#343638",
rowheight=35,
borderwidth=0,
font=(None, 16))
style.map('Treeview', background=[('selected', '#22559b')])
style.configure("Treeview.Heading",
background="#565b5e",
foreground="white",
font=(None, 16))
style.map("Treeview.Heading",
background=[('active', '#3484F0')])
# METHOD TO CREATE THE WIDGETS
def createWidgets(self):
"""logging.basicConfig(format='%(asctime)s.%(msecs)03d %(levelname)s {%(module)s} [%(funcName)s] %(message)s',
datefmt='%Y-%m-%d,%H:%M:%S', level=logging.DEBUG)
logging.info("start")"""
# TITLE FOR MOD 2
lbl_mod2 = customtkinter.CTkLabel(master=self, text="INPUTS INFO", font=("Helvetica", 16))
lbl_mod2.place(x=380, y=10)
# CREATING TABLE TO VIEW INPUT'S DATA
self.table['columns'] = ('input', 'pulses')
# DEFINITION OF COLUMNS
self.table.column("input", width=300, anchor="center")
self.table.column("pulses", width=500, anchor="center")
# HEADERS
self.table.heading("input", text="INPUT")
self.table.heading("pulses", text="NÂș PULSES")
self.updateData()
self.table.place(x=225, y=60)
# LABEL FOR ERROR
self.lbl_error.place(x=180, y=430)
# METHOD TO UPDATE ALL THE DATA EVERY SECOND, AND WHEN PRESS REFRESH BUTTON
def updateData(self):
self.table.delete(*self.table.get_children())
pulses = []
try:
pulses = self.back.get_pulses()
self.lbl_error.configure(text="")
except:
self.lbl_error.configure(text="ERROR: Cannot get info from device")
self.after(1000, lambda: self.updateData())
for i in range(8):
self.table.insert(parent='', index='end',
values=('INPUT ' + str(i + 1), pulses[i])) #
self.after(1000, lambda: self.updateData())
I really don't have any idea of why is this happening, because i made so many changes on the app, and it wasn't working wrong after this new structure hahahaha
Thank u all :)

Tkinter - label doesn't update

This morning I started to work on a little app so I can understand better TkInter.
I didn't get too far because I can't make the label to update after I press a button.
It seems like after I create an instance of the Label object I can't work on it anymore because of the mainloop() I guess? I tried to use .update() and other ways to make this work but I can't figure it out. If I add () to file_explorer method, the label updates but I can't open the file explorer anymore and it also starts the file explorer without pressing the button so it's pointless. Found something here on StackOverflow but still nothing.
from tkinter import *
from tkinter import filedialog as fd
import os
# Main_window
App = Tk()
App.geometry("300x300")
App.resizable(0, 0)
filename = "empty"
class Btn:
def __init__(self, master, pos_x, pos_y, label):
frame = Frame(master)
frame.pack()
self.Button = Button(master, text=label, command=self.file_explorer)
self.Button.place(x=pos_x, y=pos_y)
def file_explorer(self):
global filename
filename = fd.askopenfilename(filetypes=(('text files', '*.txt'), ('All files', '*.*')))
filename = os.path.basename(filename)
class FileLabel:
def __init__(self, master, pos_x, pos_y):
global filename
frame = Frame(master)
frame.pack()
self.label1 = Label(master, text=filename)
self.label1.place(x=pos_x, y=pos_y)
e = Btn(App, 10, 10, "Browse file")
f = FileLabel(App, 90, 12)
App.mainloop()
Updating filename will not update the label automatically. However, you can use StringVar instead of normal string and textvariable option of Label to achieve the goal:
...
filename = StringVar(value="empty")
class Btn:
def __init__(self, master, pos_x, pos_y, label):
frame = Frame(master)
frame.pack()
self.Button = Button(master, text=label, command=self.file_explorer)
self.Button.place(x=pos_x, y=pos_y)
def file_explorer(self):
fname = fd.askopenfilename(filetypes=(('text files', '*.txt'), ('All files', '*.*')))
# update filename
filename.set(os.path.basename(fname))
class FileLabel:
def __init__(self, master, pos_x, pos_y):
frame = Frame(master)
frame.pack()
self.label1 = Label(master, textvariable=filename) # used textvariable instead
self.label1.place(x=pos_x, y=pos_y)
...

How to check if the mouse button is released outside the button? Python

I am trying to assign some behaviors to the buttons, some I have already achieved like:
Change the color of the button if the mouse is positioned over it.
Restore the default button color.
Save the last button pressed in green.
Today I realized that when I press a button without releasing the click, and I move the mouse pointer off the button and release the click, it turns green, but without having executed the linked function, I would like the button not to change color . I am trying to eliminate this behavior, but I have no ideas. The code is executable, it works with python 3.7. Thanks.
from tkinter import *
class TypeButton(Button):
def __init__(self, parent, *args, **kwargs):
kwargs = {'font':('Calibri',9,'bold'), 'bg': '#11161d', 'fg':'white',
'width':10, 'bd':0, 'activebackground':'#bdfe04', **kwargs}
super().__init__(parent, *args, **kwargs)
class Example(Frame):
def __init__(self,parent, *args, **kwargs):
super().__init__(parent, *args, **kwargs)
self.frame = Frame(self, bg='#11161d')
self.frame .grid(padx=(10,10), pady=(6,6))
self.container1 = None
self.creator_buttons()
#????????????????
self.bind_all("<B1-Motion>", self.callback)
def creator_buttons(self):
mobiles = [['Frog', 'Fox', 'Boomer', 'Ice', 'J.d', 'Grub', 'Lightning', 'Aduka', 'Knight', 'Kalsiddon', 'Mage'],
['Randomizer', 'Jolteon', 'Turtle', 'Armor', 'A.sate', 'Raon', 'Trico', 'Nak', 'Bigfoot', 'Barney', 'Dragon']]
self.mobiles2 = ['Fox','Knight','Jolteon','Barney','Dragon']
self.buttons22 = []
for index1, mobil in enumerate(mobiles):
for index2, texto in enumerate(mobil):
number = 11 if index1 == 1 else 0
btn = B1ButtonCls (self.frame_1, text=texto, command= self.callback)
n1 = 5 if index2 == 0 else 0
n2 = 5 if index2 == 10 else 0
btn .grid(column=index2 , row=index1 , pady=3, padx=(n1,n2))
btn.bind("<Enter>", self.enter_mouse)
btn.bind("<Leave>", self.leave_mouse)
btn.bind("<Button-1>", self.clic_mouse)
if texto in self.mobiles2: btn.config(fg='yellow')
self.buttons22.append(btn)
def enter_mouse(self, event):
widget1 = event.widget
if not widget1 .cget('bg') == '#bdfe04':
widget1 .config(bg="#24364a")
def leave_mouse(self, event):
if not event.widget .cget('bg') == '#bdfe04':
event.widget.config(bg='#11161d')
def clic_mouse(self, event):
widget1 = event.widget
widget1.config(bg='#bdfe04', fg='black')
if self.container1 is not None and self.container1 != widget1:
if self.container1 .cget('text') in self.mobiles2:
self.container1 .config (bg='#11161d', fg='yellow')
else:
self.container1 .config (bg='#11161d', fg='white')
self.container1 = widget1
def callback(self):
print('Closed')
root = Tk()
app = Example(root).pack()
root.mainloop()
You can use the winfo_containing method to know which widget is under the mouse when you release a button. You can then compare the result of that function call to the widget that was clicked on.
Here's an example that displays one of two text messages depending on whether or not you released the mouse button over the same widget that was clicked on.
import tkinter as tk
def _button_press(event):
label.configure(text="")
def _button_release(event):
widget_under_cursor = event.widget.winfo_containing(event.x_root, event.y_root)
if widget_under_cursor == event.widget:
label.configure(text="you released over the button")
else:
label.configure(text="you did not release over the button")
root = tk.Tk()
label = tk.Label(root, width=40)
label.pack(side="top", fill="x")
for i in range(10):
button = tk.Button(root, text=f"Button #{i+1}")
button.pack()
button.bind("<ButtonPress-1>", _button_press)
button.bind("<ButtonRelease-1>", _button_release)
root.mainloop()

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 to open a second ptinker Window separately rather than as a tab

I am trying to open a second window in tkinter but it always appears as a tab rather than separately. Code showing the problem is as follows:
import tkinter as tk
class MainWindow:
def __init__(self, master):
self.master = master
frame = tk.Frame(self.master)
button = tk.Button(frame, text = 'New Window', width = 25, command = self.new_window)
button.pack()
frame.pack()
def new_window(self):
newWindow = tk.Toplevel(self.master)
SecondWindow(newWindow)
class SecondWindow:
def __init__(self, master):
frame = tk.Frame(master)
quitButton = tk.Label(frame, text = 'Second Window')
quitButton.pack()
frame.pack()
def main():
root = tk.Tk()
app = MainWindow(root)
root.mainloop()
if __name__ == '__main__':
main()
When I run this I get the following output:
Clicking the button gives:
(Ignoring the secondary issue of the size) if we expand it we get the following:
I can get a separate window by dragging the tab. How to I code this so that I get the window displaying as a separate window when I click the button ?

Resources