Check OptionMenu selection and update GUI - validation

I'm working on a class project and I'm trying to take it beyond the requirements a little here (I'm doing my own homework, just need help improving it!) so I want to update the GUI based on certain selections the user makes instead of just having all irrelevent options available all the time (requirements are to just present the options).
I'm still new to Python and even more new to Tkinter so my only attempt has been the following:
#Step Type
ttk.Label(mainframe, text = "Step Type").grid(column = 1, row = 16)
type_entry = OptionMenu(mainframe, StepType, "Kill", "Explore" , "Conversation")
type_entry.grid(column = 2, row = 16, sticky = (E))
#Step Goal
if StepType.get() == "Kill":
ttk.Label(mainframe, text = "Required Kills").grid(column = 1, row = 17)
goal_entry = ttk.Entry(mainframe, width = 20, textvariable = StepGoal)
goal_entry.grid(column = 2, row = 17, sticky = (E))
elif StepType.get() == "Explore":
ttk.Label(mainframe, text = "Location ID").grid(column = 1, row = 17)
goal_entry = ttk.Entry(mainframe, width = 20, textvariable = StepGoal)
goal_entry.grid(column = 2, row = 17, sticky = (E))
elif StepType.get() == "Conversation":
ttk.Label(mainframe, text = "NPC ID").grid(column = 1, row = 17)
goal_entry = ttk.Entry(mainframe, width = 20, textvariable = StepGoal)
goal_entry.grid(column = 2, row = 17, sticky = (E))
Obviously what I want to do here is when the user selects one of the options from the menu, to display the corresponding entry box and label instead of having all 3 all the time.
Also looking for the same situation for CheckButton

Full working example: tested od 2.7.5 and 3.3.2
It use command= in OptionMenu to call function when user changed option.
import tkinter as ttk
#----------------------------------------------------------------------
def on_option_change(event):
selected = step_type.get()
if selected == "Kill":
goal_label['text'] = "Required Kills"
elif selected == "Explore":
goal_label['text'] = "Location ID"
elif selected == "Conversation":
goal_label['text'] = "NPC ID"
# show label and entry
#goal_label.grid(column=1, row=17)
#goal_entry.grid(column=2, row=17, sticky='E')
#----------------------------------------------------------------------
mainframe = ttk.Tk()
# Step Type
step_type = ttk.StringVar() # there is the rule: variable name lowercase with _
ttk.Label(mainframe, text="Step Type").grid(column=1, row=16)
type_entry = ttk.OptionMenu(mainframe, step_type, "Kill", "Explore" , "Conversation", command=on_option_change)
type_entry.grid(column=2, row=16, sticky='E')
step_type.set("Kill")
# Step Goal
step_goal = ttk.StringVar()
goal_label = ttk.Label(mainframe, text="Required Kills")
goal_label.grid(column=1, row=17)
goal_entry = ttk.Entry(mainframe, width=20, textvariable=step_goal)
goal_entry.grid(column=2, row=17, sticky='E')
# hide label and entry
#goal_label.grid_forget()
#goal_entry.grid_forget()
# --- star the engine ---
mainframe.mainloop()
BTW: you can use grid() and grid_forget() to show and hide elements.
EDIT: example with Radiobutton using trace on StringVar
import tkinter as ttk
#----------------------------------------------------------------------
def on_variable_change(a,b,c): # `trace` send 3 argument to `on_variable_change`
#print(a, b, c)
selected = step_type.get()
if selected == "Kill":
goal_label['text'] = "Required Kills"
elif selected == "Explore":
goal_label['text'] = "Location ID"
elif selected == "Conversation":
goal_label['text'] = "NPC ID"
#----------------------------------------------------------------------
mainframe = ttk.Tk()
# Step Type
step_type = ttk.StringVar() # there is the rule: variable name lowercase with _
ttk.Label(mainframe, text="Step Type").grid(column=1, row=16)
ttk.Radiobutton(mainframe, text="Kill", value="Kill", variable=step_type).grid(column=2, row=16, sticky='E')
ttk.Radiobutton(mainframe, text="Explore", value="Explore", variable=step_type).grid(column=3, row=16, sticky='E')
ttk.Radiobutton(mainframe, text="Conversation", value="Conversation", variable=step_type).grid(column=4, row=16, sticky='E')
step_type.set("Kill")
# use `trace` after `set` because `on_variable_change` use `goal_label` which is not created yet.
step_type.trace("w", on_variable_change)
# Step Goal
step_goal = ttk.StringVar()
goal_label = ttk.Label(mainframe, text="Required Kills")
goal_label.grid(column=1, row=17)
goal_entry = ttk.Entry(mainframe, width=20, textvariable=step_goal)
goal_entry.grid(column=2, row=17, sticky='E')
# --- star the engine ---
mainframe.mainloop()

Related

how to add symbols to the multiple stock data

#i have scraped data below is my code, now i want to add a column of symbols to the respective company data, plz guide me how the symbol can be added to the respective firm data
#code below
from time import sleep
import pandas as pd
import os
import numpy as np
from bs4 import BeautifulSoup
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
browser = webdriver.Chrome(ChromeDriverManager().install())
symbols =['FATIMA',
'SSGC',
'FCCL',
'ISL',
'KEL',
'NCL',
'DGKC',
'SNGP',
'NML',
'ENGRO',
'HUMNL',
'CHCC',
'ATRL',
'HUBC',
'ASTL',
'PIBTL',
'OGDC',
'EFERT',
'FFC',
'NCPL',
'KTML',
'PSO',
'LUCK',
'SEARL',
'KOHC',
'ABOT',
'AICL',
'HASCOL',
'PTC',
'KAPCO',
'PIOC',
'POL',
'SHEL',
'GHGL',
'HCAR',
'DCR',
'BWCL',
'MTL',
'GLAXO',
'PKGS',
'SHFA','MARI',
'ICI',
'ACPL',
'PSMC',
'SPWL',
'THALL',
'BNWM',
'EFUG',
'GADT',
'AABS']
company = 1
for ThisSymbol in symbols :
# Get first symbol from the above python list
company = 2
# In the URL, make symbol as variable
url = 'http://www.scstrade.com/stockscreening/SS_CompanySnapShotYF.aspx?symbol=' + ThisSymbol
browser.get(url)
sleep(2)
# The below command will get all the contents from the url
html = browser.execute_script("return document.documentElement.outerHTML")
# So we will supply the contents to beautiful soup and we tell to consider this text as a html, with the following command
soup = BeautifulSoup (html, "html.parser")
for rn in range(0,9) :
plist = []
r = soup.find_all('tr')[rn]
# Condition: if first row, then th, otherwise td
if (rn==0) :
celltag = 'th'
else :
celltag = 'td'
# Now use the celltag instead of using fixed td or th
col = r.find_all(celltag)
print()
if col[i] == 0:
print ("")
else:
for i in range(0,4) :
cell = col[i].text
clean = cell.replace('\xa0 ', '')
clean = clean.replace (' ', '')
plist.append(clean)
# If first row, create df, otherwise add to it
if (rn == 0) :
df = pd.DataFrame(plist)
else :
df2 = pd.DataFrame(plist)
colname = 'y' + str(2019-rn)
df[colname] = df2
if (company == 1):
dft = df.T
# Get header Column
head = dft.iloc[0]
# Exclude first row from the data
dft = dft[1:]
dft.columns = head
dft = dft.reset_index()
# Assign Headers
dft = dft.drop(['index'], axis = 'columns')
else:
dft2 = df.T
# Get header Column
head = dft2.iloc[0]
# Exclude first row from the data
dft2 = dft2[1:]
dft2.columns = head
dft2 = dft2.reset_index()
# Assign Headers
dft2 = dft2.drop(['index'], axis = 'columns')
dft['Symbol'] = ThisSymbol
dft = dft.append(dft2, sort=['Year','Symbol'])
company = company +1
dft
my output looks this, i want to have a symbol column to each respective firm data
Symbol,i have added
dft['Symbol'] = ThisSymbol
but it add just first company from the list to all companies data
enter image description here

Adding Textfield in Tkinter

I want to programm a simple 'calculator'.. Some Input fields, then some calculations with those inputs in the background and then I want to see output.
In a simple form it looks like that:
a-e: are input fields.
f-h: output fields.
The calculations in the background and the showing of output goes well.
Now I want to have a line between e and f that says: Output
Without any entry field or sth.. just a textfield.
Can someone help me, how to insert a textfield on a specific place ?
This is the code:
fields = ('a', 'b', 'c', 'd', 'e',
'f (in EUR)', 'g (days per year)', 'h in %')
def initUI(self):
self.master.title("Calculator")
self.pack(fill=BOTH, expand=1)
Style().configure("TFrame", background="#111")
bardejov = ImageTk.PhotoImage(bard)
label1 = Label(self, image=bardejov)
label1.image = bardejov
label1.place(x=20, y=20)
def total_assets(entries):
# period rate:
a = (float(entries['a'].get()))
b = (float(entries['b'].get()))
c = (float(entries['c'].get()))
d = (float(entries['d'].get()))
e = (float(entries['e'].get()))
entries['f'].insert(0, calc1 )
entries['g'].insert(0, np.round( calc2 ) )
entries['h'].insert(0, calc3 )
#calc1,cal2,calc3 are some calculations with the input fields
def makeform(root, fields):
entries = {}
for field in fields:
print(field)
row = tk.Frame(root)
lab = tk.Label(row, width=50, text=field+": ", anchor='w')
ent = tk.Entry(row)
ent.insert(0, "0")
row.pack(side=tk.TOP,
fill=tk.X,
padx=5,
pady=5)
lab.pack(side=tk.LEFT)
ent.pack(side=tk.RIGHT,
expand=tk.YES,
fill=tk.X)
entries[field] = ent
ent.config(background="gray")
return entries
if __name__ == '__main__':
root = tk.Tk()
root.title("hello")
root.columnconfigure(1, weight=1)
#root.geometry("1000x300") #Width x Height
#root.grid_columnconfigure("50")
ents = makeform(root, fields)
b1 = tk.Button(root, text='do',
command=(lambda e=ents: total_assets(e)))
#ents.place(x=10, y=115, height=30, width=200)
b1.pack(side=tk.LEFT, padx=5, pady=5)
b2 = tk.Button(root, text = "reset",
command=(lambda e=ents: restart_program(e)))
b2.pack(side=tk.LEFT, padx=5, pady=5)
root.mainloop()
You can use below code to create a separator with text:
def create_separator(parent, text=None):
frame = tk.Frame(parent)
frame.columnconfigure(0, weight=1)
ttk.Separator(frame, orient=tk.HORIZONTAL).grid(row=0, column=0, sticky='ew')
if text:
tk.Label(frame, text=text).grid(row=0, column=0, padx=10, sticky='w')
return frame
Then inside the for loop of makeform():
for field in fields:
...
ent.config(background="gray")
if field == 'e':
# add a separator
sep = create_separator(root, 'Output')
sep.pack(side=tk.TOP, fill=tk.X, padx=5, pady=5)

tk.Entry validate command doesn't restore previous value when False returned

I have carefully reviewed answers to Interactively validating Entry widget content in tkinter, but my script fails to restore previous value if the validate command returns False. I captured %P and %s and print them out...They both show the same value.
import tkinter as tk
class Controller :
def __init__(self) :
i=10
j=20
# list comprehension
self.entry_widgets = [[None for col in range(j)] for row in range(i)]
#print(self.entry_widgets)
self.values = [["string"+str(row) + str(col) for col in range(10)] for row in range(20)]
#print(self.values)
class EnterBox(tk.Entry):
def __init__(self,*args,**kwargs):
#print (args)
self._modified = False
self._save = 0
self._raise = 1
self._lower = 2
frame, i,j, *newargs = args
self._content = tk.StringVar()
# tk.Entry.__init__(self,frame,*newargs,
# validate = 'focusout',
# validatecommand = vcmd,
# **kwargs)
tk.Entry.__init__(self,frame,*newargs,**kwargs)
vcmd = (self.register(self._revert), '%P', '%s')
ct.entry_widgets[i][j] = self
self.config(textvariable=self._content)
self.config(validate = "focusout")
self.config(validatecommand = vcmd )
x=(ct.values[i][j])
self.insert(0,x)
#self._content.set(x)
self.bind("<Return>",lambda event, x=self._save : self._action(event,x) )
self.bind("<Button-2>",lambda event, x=self._save : self._action(event,x) )
self.bind("<FocusIn>", lambda event, x=self._raise : self._action(event,x))
self.bind("<FocusOut>", lambda event, x=self._lower : self._action(event,x))
self.bind('<Button-3>', lambda event, x=self._lower : self._action(event,x))
self.grid(column=i+1,row=j+2)
def _revert(self,P,s):
print ("Hi There")
print(P)
print(s)
return False
def _action(self,event,action):
print(str(action)+' ' + str(event))
if action == self._save :
ct.values[i][j] = self._content.get()
self.config(bg='lightskyblue2')
self._modified = True
elif action == self._raise :
self.config(bg = 'light pink')
elif action == self._lower :
self.config(bg = 'gray80')
self._modified = False
else :
print('action value is bad action =>' + str(action))
if "__main__" == __name__ :
root = tk.Tk()
frame = tk.Frame()
i=j=0
ct = Controller()
root.grid()
frame.grid()
check = EnterBox(frame,i,j,width = 24)
check2 = EnterBox(frame,i+1,j,width = 24)
root.mainloop()
I have tried removing all other bindings, to no avail.
Interestingly, but a separate issue, If I use StringVar. set instead of self.insert, (see commented out line) the validate command runs once, and never again despite several focus changes. Using Python 3.8
The validation isn't designed to restore anything if the validation happens on focusout. The validation can only prevent characters from being added at the time they are added. You will have to add code to restore the previous value.

Struggleing to validate a user entry in tkinter

Here is part of some code i create for a project in tkinter using sqlite3 as a database in python. Im trying to make it so that when a user enters their values into the entry fields it only accepts integer values, and tried to implement this into the validation function. Ive tried using the try and except method, but this still seems to allow all values to be added to the table. How else could i attempt to make this work?
def validation (self):
try:
int(self.inc.get()) and int(self.out.get()) == True
except ValueError:
self.message['text'] = 'Value must be a number!'
def adding (self):
if self.validation:
query = 'INSERT INTO data VALUES (?,?)'
parameters = (self.inc.get(), self.out.get())
self.run_query (query, parameters)
self.message ['text'] = 'Record [] added' .format (self.inc.get ())
self.inc.delete (0, END)
self.out.delete (0, END)
else:
self.message['text'] = 'Income or outgoing field is empty'
self.viewing_records()
def deleting (self):
self.message ['text'] = ''
try:
self.tree.item(self.tree.selection ()) ['values'][0]
except IndexError as e:
self.message['text'] = 'Please, select record!'
return
self.message['text'] = ''
Income = self.tree.item (self.tree.selection ()) ['text']
query = 'DELETE FROM data WHERE totalinc = ?'
self.run_query (query, (Income, ))
self.message['text'] = 'Record [] deleted.'.format(Income)
self.viewing_records()
def editing (self):
self.message['text'] = ''
try:
self.tree.item (self.tree.selection ())['values'][0]
except IndexError as e:
self.message['text'] = 'Please select record'
return
name = self.tree.item (self.tree.selection ())['text']
old_out = self.tree.item (self.tree.selection ())['values'][0]
self.edit_wind = Toplevel ()
self.edit_wind.title ("Editing")
Label (self.edit_wind, text = 'Old income:').grid (row = 0, column = 1)
Entry (self.edit_wind, textvariable = StringVar(self.edit_wind, value = name), state = 'readonly').grid(row = 0, column = 2)
Label (self.edit_wind, text = 'New income:').grid(row = 1, column = 1)
new_inc = Entry (self.edit_wind)
new_inc.grid (row = 1, column = 2)
Label (self.edit_wind, text = 'Old outgoing:').grid (row = 2, column = 1)
Entry (self.edit_wind, textvariable = StringVar(self.edit_wind, value = old_out), state = 'readonly').grid(row = 2, column = 2)
Label (self.edit_wind, text = 'New outgoing: ').grid(row = 3, column = 1)
new_out = Entry (self.edit_wind)
new_out.grid (row = 3, column = 2)
Button (self.edit_wind, text = 'Save changes', command = lambda: self.edit_records (new_inc.get(), name, new_out.get(), old_out)).grid (row = 4, column = 2, sticky = W)
self.edit_wind.mainloop()
def edit_records (self, new_inc, name, new_out, old_out):
query = "UPDATE data SET totalinc = ?, totalout = ? WHERE totalinc = ? AND totalout = ?"
parameters = (new_inc, new_out, name, old_out)
self.run_query (query, parameters)
self.edit_wind.destroy()
self.message['text'] = 'Record [] changed.' .format (name)
self.viewing_records()
if __name__ == '__main__':
wind = Tk()
application = Product (wind)
wind.mainloop()
str = '8'
if str.isdigit():
print(str)
I suggest taking a look at is isdigit().

GTK how to create 3 different filter for 1 Liststore

In GTK/Python, I'm trying to build an interface with nodes.
This is photo of my interface
I create one liststore and I want to filter different things. The user has to do two actions, first, he has to choose in the combobox the type of filter that he wants to use, if he wants to filter by node's type, node's beginning name or others.
Then in the text entry, he decides what information that he wants to see. Take the exemple of nodes type. There are like 3 different types of nodes, node type 1, node type 2 and node type 3. As an user I want to see only node type 1, so I write 1 in the node entry. Actually I have a problem, it is my filter does not work.
I first create 2 liststores:
def create_liststore(self):
if len(self.FdessinCarto.pos) != 0:
for i,node in enumerate(self.FdessinCarto.pos):
self.node_liststore.append([str(node.title),self.controller.model.string_from_numdate(int(node.start_time)),self.controller.model.string_from_numdate(int(node.end_time)),str(node.node_group),str(node.description),str(node.attachment_list)])
self.edgelist = self.controller.get_edge_list()
if len(self.edgelist) !=0:
for i in self.edgelist:
edge_prop=self.controller.edge_data(i[0],i[1])
self.edge_liststore.append([edge_prop['label'],str(i[0].title),str(i[1].title),edge_prop['description'],edge_prop['attachment_list']])
#creating the treeview for Node, making it use the filter as a model, and adding the columns
self.treeviewNode = Gtk.TreeView.new_with_model(self.node_liststore)
for i, column_title in enumerate(["Name", "Beginning date", "End date", "Type of node", "Description of node","files"]):
self.Noderenderer = Gtk.CellRendererText()
self.Noderenderer.set_property("editable", True)
column = Gtk.TreeViewColumn(column_title, self.Noderenderer, text=i)
column.set_sort_column_id(0)
self.treeviewNode.append_column(column)
#creating the treeview for edge
self.treeviewEdge = Gtk.TreeView.new_with_model(self.edge_liststore)
for i, column_title in enumerate(["Name", "Node 1", "Node 2", "Description of edge","file"]):
self.Edgerenderer = Gtk.CellRendererText()
self.Edgerenderer.set_property("editable", True)
column = Gtk.TreeViewColumn(column_title, self.Edgerenderer, text=i)
column.set_sort_column_id(0)
self.treeviewEdge.append_column(column)
self.SWViewListStore.add(self.treeviewNode)
self.SWEdgeStore.add(self.treeviewEdge)
self.SWViewListStore.show_all()
self.SWEdgeStore.show_all()
There are my 3 different filters:
#creating the filtre
self.node_beginning_date_filter = self.node_liststore.filter_new()
self.node_end_date_filter = self.node_liststore.filter_new()
self.node_type_filter = self.node_liststore.filter_new()
#setting the filter function, note that we're not using the
self.node_end_date_filter.set_visible_func(self.node_end_date_filter_func)
self.node_beginning_date_filter.set_visible_func(self.node_beginning_date_filter_func)
self.node_type_filter.set_visible_func(self.node_type_filter_func)
Once I change my combo-box, it would activate my function, it took the type of combofilter then also the text of combobox :
def on_entryComboBox_changed(self,widget):
textComboFilter = self.View.combo_filter.get_active_text()
print("textComboFilter %s" %textComboFilter)
if textComboFilter == "Filter by node's beginning date":
#print("%s language selected!" % textComboFilter)
self.View.current_filter = textComboFilter
self.View.node_beginning_date_filter.refilter()
if textComboFilter == "Filter by node's end date":
#print("%s language selected!" % textComboFilter)
self.View.current_filter = textComboFilter
self.View.node_end_date_filter.refilter()
if textComboFilter == "Filter by type of node":
#print("%s language selected!" % textComboFilter)
self.View.current_filter = textComboFilter
self.View.node_type_filter.refilter()
And it does not work.
Finally,
I manage to answer it on my own.
You should build one filter rather than three. For people who have the same problem, this is a very good example which helps me to solve my problem.
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
#list of tuples for each software, containing the software name, initial release, and main programming languages used
software_list = [("Firefox", 2002, "C++"),
("Eclipse", 2004, "Java" ),
("Pitivi", 2004, "Python"),
("Netbeans", 1996, "Java"),
("Chrome", 2008, "C++"),
("Filezilla", 2001, "C++"),
("Bazaar", 2005, "Python"),
("Git", 2005, "C"),
("Linux Kernel", 1991, "C"),
("GCC", 1987, "C"),
("Frostwire", 2004, "Java")]
class TreeViewFilterWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Treeview Filter Demo")
self.set_border_width(10)
#Setting up the self.grid in which the elements are to be positionned
self.grid = Gtk.Grid()
self.grid.set_column_homogeneous(True)
self.grid.set_row_homogeneous(True)
self.add(self.grid)
#Creating the ListStore model
self.software_liststore = Gtk.ListStore(str, int, str)
for software_ref in software_list:
self.software_liststore.append(list(software_ref))
self.current_filter_language = None
#Creating the filter, feeding it with the liststore model
self.language_filter = self.software_liststore.filter_new()
#setting the filter function, note that we're not using the
self.language_filter.set_visible_func(self.language_filter_func)
#creating the treeview, making it use the filter as a model, and adding the columns
self.treeview = Gtk.TreeView.new_with_model(self.language_filter)
for i, column_title in enumerate(["Software", "Release Year", "Programming Language"]):
renderer = Gtk.CellRendererText()
column = Gtk.TreeViewColumn(column_title, renderer, text=i)
self.treeview.append_column(column)
#creating buttons to filter by programming language, and setting up their events
self.buttons = list()
for prog_language in ["Java", "C", "C++", "Python", "None"]:
button = Gtk.Button(prog_language)
self.buttons.append(button)
button.connect("clicked", self.on_selection_button_clicked)
#setting up the layout, putting the treeview in a scrollwindow, and the buttons in a row
self.scrollable_treelist = Gtk.ScrolledWindow()
self.scrollable_treelist.set_vexpand(True)
self.grid.attach(self.scrollable_treelist, 0, 0, 8, 10)
self.grid.attach_next_to(self.buttons[0], self.scrollable_treelist, Gtk.PositionType.BOTTOM, 1, 1)
for i, button in enumerate(self.buttons[1:]):
self.grid.attach_next_to(button, self.buttons[i], Gtk.PositionType.RIGHT, 1, 1)
self.scrollable_treelist.add(self.treeview)
self.show_all()
def language_filter_func(self, model, iter, data):
"""Tests if the language in the row is the one in the filter"""
if self.current_filter_language is None or self.current_filter_language == "None":
return True
else:
return model[iter][2] == self.current_filter_language
def on_selection_button_clicked(self, widget):
"""Called on any of the button clicks"""
#we set the current language filter to the button's label
self.current_filter_language = widget.get_label()
print("%s language selected!" % self.current_filter_language)
#we update the filter, which updates in turn the view
self.language_filter.refilter()
win = TreeViewFilterWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()

Resources