Append combobox values from textbox using a button - python

Using Python I have created a frame with empty ComboBox, TextBox and a Button. My ComboBox values are taken from List acitivity_list which initialy is empty. I am looking for a solution where user can insert a text into a TextBox and append the List activity_list so it appears in ComboBox by clicking the Button.
I failed implementing the append() function to update the List. My goal is to have a functionality where I write the name of activity in the TextBox, click the 'Add' Button and it appears in my ComboBox.
Thank you.
from tkinter import *
from tkinter import ttk
class Activity:
def __init__(self,root):
self.root=root
self.root.title("database")
self.root.geometry("1350x700+0+0")
title=Label(self.root, text="Daily Activities Database", font=("Calibri",40,"bold"))
title.pack(side=TOP)
#ComboBox
activity_list = []
Frame1=Frame(self.root,bd=4, relief=RIDGE)
Frame1.place(x=20, y=75, width=355, height=560 )
combo_activity=ttk.Combobox(Frame1, font=("Calibri",20))
combo_activity["values"]= activity_list
combo_activity.grid(row=10, column=1, padx=20, pady=10)
#Textbox
txt_act=Entry(Frame1, font=("Calibir",20))
txt_act.grid(row=11, column=1, padx=20, pady=20)
#Button
bt1 = ttk.Button(Frame1, text = "Add")
bt1.grid(row=12, column=1, padx=20, pady=20)
root=Tk()
ob=Activity(root)
root.mainloop()

Add an instance method which is triggered when Add is clicked. In the function, add the user input into activity_list and then update the values option of combo_activity.
However, you need to change some local variables to instance variables, otherwise they cannot be accessed inside the new function:
from tkinter import *
from tkinter import ttk
class Activity:
def __init__(self, root):
self.root = root
self.root.title("database")
self.root.geometry("1350x700+0+0")
title=Label(self.root, text="Daily Activities Database", font=("Calibri",40,"bold"))
title.pack(side=TOP)
Frame1 = Frame(self.root,bd=4, relief=RIDGE)
Frame1.place(x=20, y=75, width=355, height=560 )
#ComboBox
self.activity_list = []
self.combo_activity = ttk.Combobox(Frame1, font=("Calibri",20))
self.combo_activity["values"] = self.activity_list
self.combo_activity.grid(row=10, column=1, padx=20, pady=10)
#Textbox
self.txt_act = Entry(Frame1, font=("Calibir",20))
self.txt_act.grid(row=11, column=1, padx=20, pady=20)
#Button
bt1 = ttk.Button(Frame1, text="Add", command=self.add_activity) # added command option
bt1.grid(row=12, column=1, padx=20, pady=20)
def add_activity(self):
activity = self.txt_act.get().strip()
if activity:
self.activity_list.append(activity)
self.combo_activity["values"] = self.activity_list
root = Tk()
ob = Activity(root)
root.mainloop()

Thank you for help. I have adjusted the code like this and the button disappeared for the frame. Perhaps there is something wrong with indentation?
from tkinter import *
from tkinter import ttk
class Activity:
def __init__(self,root):
self.root=root
self.root.title("database")
self.root.geometry("1350x700+0+0")
title=Label(self.root, text="Daily Activities Database", font=("Calibri",40,"bold"))
title.pack(side=TOP)
#ComboBox
activity_list = []
Frame1=Frame(self.root,bd=4, relief=RIDGE)
Frame1.place(x=20, y=75, width=355, height=560 )
combo_activity=ttk.Combobox(Frame1, font=("Calibri",20))
combo_activity["values"]= activity_list
combo_activity.grid(row=10, column=1, padx=20, pady=10)
#Textbox
txt_act=Entry(Frame1, font=("Calibir",20))
txt_act.grid(row=11, column=1, padx=20, pady=20)
#Button
def add_task(self):
activity = txt_act.get()
activity_list.append(activity)
return activity_list
bt1 = ttk.Button(Frame1, text = "Add")
bt1.grid(row=12, column=1, padx=20, pady=20, command=add_task)
root=Tk()
ob=Activity(root)
root.mainloop()

Related

Display text live on Text widget while typing on another Text as input

Hi I am a beginner to Python. How to display text live in tkinter Text widget while i am typing on another Text or Entry widget? Can i use root.after to keep getting the contents?
from tkinter import *
root = Tk()
root.geometry('600x400')
def display():
tDisplay.config(text=tEnter.get(1.0, END))
root.after(1000, display)
tDisplay = Text(root, height=2, width=20, padx=10, pady=10)
tDisplay.grid(row=0, column=0, padx=5, pady=5)
tEnter = Text(root, height=2, width=20, padx=10, pady=10)
tEnter.grid(row=1, column=0, padx=5, pady=5)
display()
root.mainloop()
Yes you can also use after() to get the contents, at the same time you should also delete the current item inside the text box so as to not keep adding to the textbox:
def display():
tDisplay.delete('1.0','end')
tDisplay.config(text=tEnter.get('1.0', 'end-1c'))
root.after(1000, display)

What can I do to make the frame without widgets?

What I want the frame to do is that when I click on the 'clear' button, the frame is cleaned but it does not and when I enter a string that is not valid and then a valid one, it shows traces of the past and past action. I already tried changing the Label.grid () by a Label.pack (), but it is worse since the 'animation' looks like a stack without removing any element when the 'clear' button is pressed
This is basically what would make it change
from tkinter import *
import tkinter.ttk as ttk
def clear():
area.delete(0,END)
frame.config(bd=1, relief=SUNKEN)
frame.update()
status = Label(frame)
status.grid(row=0, column=0, sticky=NSEW)
def statusVal(value):
if not value == 0:
status = Label(frame, background="#ff4242", fg="#262626", text="Cadena invalida", anchor="center")
status.grid(row=0, column=0)
frame.config(bd=1, relief=SUNKEN, background="#ff4242")
frame.update()
else:
status = Label(frame, background="#56ed42", fg="#262626", text="Cadena valida", anchor="center")
status.grid(row=0, column=0)
frame.config(bd=1, relief=SUNKEN, background="#56ed42")
frame.update()
#Test
def validation():
capture = area.get()
if capture == '1':
return statusVal(0)
else:
return statusVal(1)
root = Tk()
root.geometry("300x150+300+300")
area = Entry(root)
area.grid(row=1, column=0, columnspan=2, sticky=E+W+S+N, padx=5)
frame = Frame(root, bd=1, relief=SUNKEN)
frame.grid(row=2, column=0, padx=5, pady=5, columnspan=2, sticky=W+E+S+N)
frame.columnconfigure(0,weight=5)
frame.rowconfigure(0,weight=5)
abtn = Button(root, text="Validate", command=validation)
abtn.grid(row=1, column=3)
cbtn = Button(root, text="Clear", command=clear)
cbtn.grid(row=2, column=3, pady=5)
root.mainloop()
See if this works better. The main change was to have the status Label always exist and hide or unhide it as desired — instead of creating a new one every time the validation() function was called. I also removed the code that was explicitly updating the frame which isn't necessary.
from tkinter import *
import tkinter.ttk as ttk
def clear():
area.delete(0,END)
status.grid_remove() # Hide. but remember grid options.
def statusVal(value):
if not value == 0:
status.config(background="#ff4242", fg="#262626", text="Cadena invalida",
anchor="center")
status.grid() # Unhide
else:
status.config(background="#56ed42", fg="#262626", text="Cadena valida",
anchor="center")
status.grid() # Unhide
#Test
def validation():
capture = area.get()
if capture == '1':
statusVal(0)
else:
statusVal(1)
# Main
root = Tk()
root.geometry("300x150+300+300")
area = Entry(root)
area.grid(row=1, column=0, columnspan=2, sticky=E+W+S+N, padx=5)
frame = Frame(root, bd=1, relief=SUNKEN)
frame.grid(row=2, column=0, padx=5, pady=5, columnspan=2, sticky=W+E+S+N)
frame.columnconfigure(0,weight=5)
frame.rowconfigure(0,weight=5)
# Initialize status Label.
status = Label(frame, anchor="center")
status.grid(row=0, column=0)
status.grid_remove() # Hide it.
abtn = Button(root, text="Validate", command=validation)
abtn.grid(row=1, column=3)
cbtn = Button(root, text="Clear", command=clear)
cbtn.grid(row=2, column=3, pady=5)
root.mainloop()

Tkinter Widgets next to each other and below

I'm putting widgets into a popup for my GUI. I'm putting the checkboxes along the top of the pop up and I want the label, entry and button to be in a row below them. Whatever I try the label, entry and button always go next to the check boxes. I haven't found a solution which uses pack(). I've tried anchor=but this also didn't do what I wanted.
This is my code:
import tkinter as tk
from tkinter import *
CheckVar1 = IntVar()
CheckVar2 = IntVar()
class PopUp(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
popup = tk.Toplevel(self, background='gray15')
popup.wm_title("EMAIL")
self.withdraw()
popup.tkraise(self)
self.c1 = tk.Checkbutton(popup, text="Current", variable=CheckVar1, onvalue =1, offvalue = 0, height=2, width=15)
self.c1.pack(side="left", fill="x")
self.c2 = tk.Checkbutton(popup, text="-1", variable=CheckVar2, onvalue =1, offvalue = 0, height=2, width=15)
self.c2.pack(side="left", fill="x")
label = tk.Label(popup, text="Please Enter Email Address", background='gray15', foreground='snow')
label.pack(side="left", fill="x", pady=10, padx=10)
self.entry = tk.Entry(popup, bd=5, width=35, background='gray30', foreground='snow')
self.entry.pack(side="left", fill="x")
self.button = tk.Button(popup, text="OK", command=self.on_button, background='gray15', foreground='snow')
self.button.pack(side="left", padx=10)
def on_button(self):
address = self.entry.get()
print(address)
time.sleep(10)
self.destroy()
app = PopUp()
app.mainloop
Is there something I can put into pack() so that I can put the widgets next to each other and then put the other below them?
Thanks in advance
Use the grid geometry manager to divide your window into two frames, then pack your widgets into the frames.
from tkinter import *
import time
class PopUp(Tk):
def __init__(self):
Tk.__init__(self)
CheckVar1 = IntVar()
CheckVar2 = IntVar()
popup = Toplevel(self, background='gray15')
popup.wm_title("EMAIL")
self.withdraw()
popup.tkraise(self)
topframe = Frame(popup)
topframe.grid(column=0, row=0)
bottomframe = Frame(popup)
bottomframe.grid(column=0, row=1)
self.c1 = Checkbutton(topframe, text="Current", variable=CheckVar1, onvalue=1, offvalue=0, height=2, width=15)
self.c1.pack(side="left", fill="x")
self.c2 = Checkbutton(topframe, text="-1", variable=CheckVar2, onvalue=1, offvalue=0, height=2, width=15)
self.c2.pack(side="left", fill="x")
label = Label(bottomframe, text="Please Enter Email Address", background='gray15', foreground='snow')
label.pack(side="left", fill="x", pady=10, padx=10)
self.entry = Entry(bottomframe, bd=5, width=35, background='gray30', foreground='snow')
self.entry.pack(side="left", fill="x")
self.button = Button(bottomframe, text="OK", command=self.on_button, background='gray15', foreground='snow')
self.button.pack(side="left", padx=10)
def on_button(self):
address = self.entry.get()
print(address)
time.sleep(10)
self.destroy()
app = PopUp()
app.mainloop()
A few notes:
There is no need to import Tkinter twice
Mainloop is a method, so it's app.mainloop()
CheckVar1 and CheckVar2 must be declared within your class
camel case (capitalising within words, e.g 'CheckVar') is not pythonic

Tkinter entry insert from another class

I am learning a bit of tkinter at the moment and have come across a problem I can't seem to solve.
I have 1 class (named 'GUI') in which I first declare an object of another class (named 'client') then create a simple tkinter GUI with an entry field in which the user enters an address.
I then have a button that when pressed, gets the address and passes it to a function of the client class. This function calls another function from a library, which goes out to an external source (the 'client') and gets the value of a boolean register at that address.
Up to here I have working.
I now would like to update another entry field in the tkinter GUI with the value of that Boolean register.
Here is a code sample:
class GUI:
def __init__(self, master):
device = client()
self.master = master
#Define size (x,y) and position (top left is 0,0) of window
master.geometry("800x400+300+300")
#Disable window resize
master.resizable(width=False, height=False)
#GUI Controls
lbl_read_discrete_output = Label(self.master, text="Read boolean register")
lbl_read_discrete_output_address = Label(self.master, text="Address:")
ent_read_discrete_output_address = Entry(self.master)
btn_read_discrete_output_address = Button(self.master, text='READ', command=lambda: device.read_discrete_output(int(ent_read_discrete_output_address.get())))
ent_read_discrete_output_value = Entry(self.master, state='disabled')
#GUI Layout
lbl_read_discrete_output.grid(column=0, row=6, padx=5, pady=5)
lbl_read_discrete_output_address.grid(column=0, row=7, padx=5, pady=5)
ent_read_discrete_output_address.grid(column=1, row=7, padx=5, pady=5)
btn_read_discrete_output_address.grid(column=2, row=7, padx=5, pady=5)
ent_read_discrete_output_value.grid(column=3, row=7, padx=5, pady=5)
class client:
def __init__(self):
pass
def read_discrete_output(self, address):
data = self._client.read_coils(address-1, 1).bits[0:1]
if not data[0]:
#Update entry field 'ent_read_discrete_output_value' with "FALSE"
else:
#Update entry field 'ent_read_discrete_output_value' with "TRUE"
def main():
#Create GUI object
root = Tk()
app = GUI(root)
root.mainloop()
if __name__ == '__main__':
main()
Any help would be greatly appreciated!
You can solve that problem, this way:
import tkinter as tk
from tkinter import *
from pymodbus.client.sync import ModbusTcpClient as ModbusClient
class GUI:
def __init__(self, master):
self.master = master
#GUI Controls
lbl_read_discrete_output = Label(self.master, text="Read boolean register")
lbl_read_discrete_output_address = Label(self.master, text="Address:")
self.ent_read_discrete_output_address = Entry(self.master)
btn_read_discrete_output_address = Button(self.master, text='READ', command=lambda: device.read_discrete_output(int(self.ent_read_discrete_output_address.get())))
self.ent_read_discrete_output_value = Entry(self.master, state='disabled')
#GUI Layout
lbl_read_discrete_output.grid(column=0, row=6, padx=5, pady=5)
lbl_read_discrete_output_address.grid(column=0, row=7, padx=5, pady=5)
self.ent_read_discrete_output_address.grid(column=1, row=7, padx=5, pady=5)
btn_read_discrete_output_address.grid(column=2, row=7, padx=5, pady=5)
self.ent_read_discrete_output_value.grid(column=3, row=7, padx=5, pady=5)
self.x=self.ent_read_discrete_output_address.get()
print(self.x)
device=clientx(self.ent_read_discrete_output_value,self.ent_read_discrete_output_address.get())
class clientx():
def __init__(self,ent,address):
self.address=address
self.ent=ent
def read_discrete_output(self, address):
with ModbusClient('127.0.0.1') as client:
data = self.client.read_coils(address-1, 1).bits[0:1]
if not data[0]:
self.ent.config(state="disabled")
else:
self.ent.config(state="disabled")
def main():
#Create GUI object
root = tk.Tk()
app = GUI(root)
root.mainloop()
if __name__ == '__main__':
main()
Let me know if this works.

why is nothing returned when I invoke .get()

Having trouble setting the file path that is selected by the user and setting to variable. I am able to retrieve the path and set it to display in the entry box but I would like to capture that path and import it into another script. Maybe my logic is flawed here? What am I doing wrong?
import Tkinter
import tkFileDialog
from Tkinter import *
from tkFileDialog import *
class GUI:
def __init__(self, master):
self.master = master
master.title("XML Compare Tool")
master.geometry('700x300')
path1 = StringVar()
path2 = StringVar()
self.bb1 = Button(master, text="Browse", command=lambda: path1.set(askopenfilename()))
self.bb1.grid(row=0, column=0, padx=5, pady=5)
self.bb2 = Button(master, text="Browse", command=lambda: path2.set(askopenfilename()))
self.bb2.grid(row=1, column=0, padx=5, pady=5)
self.confirm = Button(master, text="Confirm", command='')
self.confirm.grid(row=3, column=1, padx=5, pady=5, sticky='')
self.entry1 = Entry(master, width=75, textvariable=path1)
self.entry1.grid(row=0, column=1, columnspan=2, sticky=W)
print path1.get()
self.entry2 = Entry(master, width=75, textvariable=path2)
self.entry2.grid(row=1, column=1, sticky=W)
self.t_label = Label(master, text="Script Output")
self.t_label.grid(row=4, column=1, columnspan=1, sticky='')
self.t_frame = Frame(master, bg="white", height=150, width=600)
self.t_frame.grid(row=5, column=1, columnspan=1, sticky='')
self.t_text = Text(self.t_frame)
root = Tk()
my_gui = GUI(root)
root.mainloop()
You do not need to use a textvariable, you can just use variable = entry1.get(). A Tkinter textvariable is not like a traditional python variable, it is just used for setting the text in an entry.

Categories

Resources