How to grab Tkinter inputs and put into config - python

For example I want to get an input from tkinter and in the GUI it says "how much do you like cars from 1 - 10?" and then the victim inputs a number for example 8 how would I transfer my input to my settings.ini?
My Code:
root = Tk()
config = ConfigParser()
updater = ConfigUpdater()
path = os.path.dirname(os.path.abspath(__file__))
configPath = os.path.join(path, "settings.ini")
updater.read('settings.ini')
updater['Trading Settings']['maximum_value_gain'].value = "the input I want from tkinter user"
updater.update_file()
root.mainloop()

For your case, you can use OptionMenu for the rating input as below:
import os
import tkinter as tk
from configupdater import ConfigUpdater
appPath = os.path.dirname(os.path.abspath(__file__))
configPath = os.path.join(appPath, "settings.ini")
updater = ConfigUpdater()
updater.read(configPath) # settings.ini must exists, otherwise exception
root = tk.Tk()
tk.Label(root, text='How much do you like cars (from 1 - 10)?').grid(row=0, column=0)
rating = tk.StringVar()
rating_opt = tk.OptionMenu(root, rating, *range(1, 11)) # dropdown with values 1 to 10
rating_opt.config(width=5)
rating_opt.grid(row=0, column=1)
def update():
value = rating.get()
# update ini file only when user has selected a rating
if value:
updater['Trading Settings']['maximum_value_gain'].value = rating.get()
updater.update_file()
tk.Button(root, text='Update', command=update).grid(row=2, column=0, columnspan=2)
root.mainloop()

Related

Run a function on button command using tkinter

first of all, I'm a beginner. I have a basic script (get grades()) that takes a .csv file and specific class sections (min 1, max 3). I wrote this function to clean courses grades, and the output is a .txt containing only the student number, class section and grade. This text file is then ready to be upload to a system at my uni.
I'm trying to create a GUI for this script, but I'm stuck. Googling around, I managed to get a basic GUI, but even though I can enter the class sections and browse for a file, I cannot make it run my function. When I click on the button to the get the grades, the GUI crashes. Could you please point me in the right direction? Thank you in advance.
tkinter code
import tkinter as tk
from tkinter import ttk
from tkinter.messagebox import showinfo
import tkinter
from tkinter import *
from tkinter import filedialog as fd
from get_grades import get_grades
from functools import partial
# root window
root = tk.Tk()
root.geometry("500x450")
root.title('Grades')
# store sections
sections = tk.StringVar()
file_name = tk.StringVar()
def save_sections():
""" callback when the sections button clicked
"""
msg = f'You entered sections: {sections.get()}'
showinfo(
title='Information',
message=msg
)
# Sign in frame
signin = ttk.Frame(root)
signin.pack(padx=10, pady=10, fill='x', expand=True)
# sections
sections_label = ttk.Label(signin, text="sections:")
sections_label.pack(fill='x', expand=True)
sections_entry = ttk.Entry(signin, textvariable=sections)
sections_entry.pack(fill='x', expand=True)
sections_entry.focus()
# login button
section_button = ttk.Button(signin, text="save sections", command=save_sections)
section_button.pack(fill='x', expand=True, pady=10)
def get_file_name(file_entry):
file_name = fd.askopenfilename(title="Select file", filetypes=(("CSV Files", "*.csv"),))
file_entry.delete(0, END)
file_entry.insert(0, file_name)
entry_csv = Entry(root, text="", width=50)
entry_csv.pack(fill='x', expand=True)
file_label = ttk.Label(root, text="Input CSV")
file_button = ttk.Button(root, text="Browse...", width=10, command=lambda: get_file_name(entry_csv))
file_button.pack(fill='x', expand=True, pady=10)
grades_button = ttk.Button(root, text="Get grades", width=10, command=lambda: get_grades(entry_csv, sections))
grades_button.pack(fill='x', expand=True, pady=10)
# infinite loop
root.mainloop()
get_grades.py
import pandas as pd
from datetime import datetime
def get_grades(file, section1=True, section2=False, section3=False):
sections = []
if section1:
sections.append(section1)
if section2:
sections.append(section2)
if section3:
sections.append(section3)
else:
return "missing sections"
# get file
df = pd.read_csv(file)
# delete the first two rows
df = df.drop([df.index[0], df.index[1]])
# important columns are "SIS User ID", "Section", and the name of the test, which changes by course
# first, rename the assignment column
df = df.rename(columns={df.columns[5]: "Grade"})
df = df[df.Student != "Student, Test"]
# select columns
df = df[["SIS User ID", "Section", "Grade"]]
df = df[df['Section'].isin(sections)]
# cleaning
df = df.replace("0.0", "NVD")
df = df.fillna("NA")
# deleting decimal
df['SIS User ID'] = df['SIS User ID'].astype(str).apply(lambda x: x.replace('.0', ''))
# save to txt and csv
# file name
date_time = datetime.now().strftime("%Y_%m_%d-%I_%M_%S_%p")
filename = str(date_time) + "_" + str(sections)
df.to_csv(str(filename + ' .txt'), sep='\t', index=False)
print("done! file " + str(filename) + ".txt saved")
You are passing an Entry widget and a StringVar to your function. But your function expects string objects.
You have to get the values of your entry box and StringVar. Luckily, the method is called the same for both cases. It's the .get() method.
grades_button = ttk.Button(root, text="Get grades", width=10, command=lambda: get_grades(entry_csv.get(), sections.get()))
This should pass the correct values to get_grades(). But to be sure, you should print the values to console, just to check. This would also have hinted at the problem you had with your code.

How to close the empty tkinter window that pops up when I run my code

I am trying to create a tkinter gui that performs a certain calculation. I create a window to ask for input to do the calculations. However, each time I run my code 2 windows pop up instead of one. Is there a way to automatically close the blank window when I run my code such that the user would only see the window that asks for input.
For simplicity I changed all buttons to close the applications.
import numpy as np
import pandas as pd
from datetime import datetime
import tkinter as tk
import tkinter.ttk as ttk
import tkinter.messagebox
import blpapi
import pdblp
con = pdblp.BCon(timeout=5000)
con.start()
s= ttk.Style()
s.theme_use('xpnative')
root =tk.Tk()
root.title("Vega Requirement Application")
root.geometry("600x400")
ticker_var= tk.StringVar()
volume_var= tk.StringVar()
def close():
root.destroy()
def clear_all():
root.destroy()
def vega_calculation():
root.destroy()
ticker_label = ttk.Label(root, text='Bloomberg Ticker:',font=('calibre',10,'normal'))
ticker_entry = ttk.Entry(root, textvariable = ticker_var,font=('calibre',10,'normal'))
volume_label = ttk.Label(root, text='Volume:',font=('calibre',10,'normal'))
volume_entry = ttk.Entry(root, textvariable = volume_var,font=('calibre',10,'normal'))
run_btn = ttk.Button(root, text = 'Calculate', command = vega_calculation, width = 13)
close_btn = ttk.Button(root, text= 'Close App', command = close, width =13)
clear_btn = ttk.Button(root, text= 'Clear table', command = clear_all, width=13)
ticker_label.grid(row=0,column=0)
ticker_entry.grid(row=0,column=1)
volume_label.grid(row=1,column=0)
volume_entry.grid(row=1,column=1)
run_btn.grid(row=0,column=2)
close_btn.grid(row=1, column=2)
clear_btn.grid(row=0, column =4)
root.mainloop()
The following two lines will create an instance of Tk() because there is no instance of Tk() when they are executed:
s = ttk.Style() # create an instance of Tk() if there is none
s.theme_use('xpnative')
Move the two lines to after root = tk.Tk() so that it uses the already created instance of Tk():
root = tk.Tk()
s = ttk.Style() # use existing instance of Tk(), root
s.theme_use('xpnative')

Defining function or class to browse and list multiple directories with tkinter

I would like to create a function or class that has the proper formatting to create a text label, entry field, and button. The button would allow me to browse through my directory and populate the entry field with the chosen directory. The code I have allows me to do most of this, however the directory is always populated in the last entry field instead of the one the button refers to.
I am new to tkinter and GUIs so apologies if this is a simple solution, I assume the problem is with root.name.set referring to the function that was called last.
from tkinter import *
from tkinter import filedialog
def askdirectory():
dirname = filedialog.askdirectory()
root.name.set(dirname)
def dirField(root, label, rowNum):
text = StringVar()
text.set(label)
dirText = Label(root, textvariable = text, height =4)
dirText.grid(row = rowNum, column = 1)
dirBut = Button(root, text = 'Browse', command = askdirectory)
dirBut.grid(row = rowNum, column = 3)
root.name = StringVar()
adDir = Entry(root,textvariable = root.name, width = 100)
adDir.grid(row = rowNum, column = 2)
if __name__ == '__main__':
root = Tk()
root.geometry('1000x750')
adText = "Select directory of Ads"
userText = "Select directory of User credentials"
adField = dirField(root, adText, 1)
userField = dirField(root, userText, 2)
root.mainloop()
You should realise that you need to have each Entry have its own textvariable. Otherwise they will overlap. Have a look at my code, which should get you going.
from tkinter import *
from tkinter import filedialog
path = [None, None] # Fill it with the required number of filedialogs
def askdirectory(i):
dirname = filedialog.askdirectory()
path[i].set(dirname)
def dirField(root, label, rowNum, i):
dirText = Label(root, text=label)
dirText.grid(row=rowNum, column=0)
dirBut = Button(root, text='Browse', command=lambda: askdirectory(i))
dirBut.grid(row=rowNum, column=2)
path[i] = StringVar()
adDir = Entry(root, textvariable=path[i], width=50)
adDir.grid(row=rowNum, column=1)
if __name__ == '__main__':
root = Tk()
adText = "Select directory of Ads"
userText = "Select directory of User credentials"
adField = dirField(root, adText, 0, 0)
userField = dirField(root, userText, 1, 1)
root.mainloop()

How to use class and self here to get two different entries?

With my current code, it does not matter whether I click on "Input Folder" - Change or "JukeBox" change the result always gets displayed in "JukeBox" entry. This is incorrect, using class and self how can I change the code to display result from "Input Folder" - Change in "Input Folder" entry and the result from "Jukbox" - Change in "Jukebox" entry?
Also, how can I save the selected folders to a file so that it is there on app exit and re open?
My code:
import os
from tkinter import *
from tkinter import filedialog
inPut_dir = ''
jukeBox_dir = ''
def inPut():
opendir = filedialog.askdirectory(parent=root,initialdir="/",title='Input Folder')
inPut_dir = StringVar()
inPut_dir = os.path.abspath(opendir)
entry.delete(0, END)
entry.insert(0, inPut_dir)
def jukeBox():
opendir = filedialog.askdirectory(parent=root,initialdir="/",title='JukeBox')
jukeBox_dir = StringVar()
jukeBox_dir = os.path.abspath(opendir)
entry.delete(0, END)
entry.insert(0, jukeBox_dir)
root = Tk()
root.geometry("640x240")
root.title("Settings")
frametop = Frame(root)
framebottom = Frame(root)
frameright = Frame(framebottom)
text = Label(frametop, text="Input Folder").grid(row=5, column=2)
entry = Entry(frametop, width=50, textvariable=inPut_dir)
entry.grid(row=5,column=4,padx=2,pady=2,sticky='we',columnspan=20)
text = Label(frametop, text="JukeBox").grid(row=6, column=2)
entry = Entry(frametop, width=50, textvariable=jukeBox_dir)
entry.grid(row=6,column=4,padx=2,pady=2,sticky='we',columnspan=20)
ButtonA = Button(frametop, text="Change", command=inPut).grid(row=5, column=28)
ButtonB = Button(frametop, text="Change", command=jukeBox).grid(row=6, column=28)
ButtonC = Button(frameright, text="OK").grid(row=5, column=20, padx=10)
ButtonD = Button(frameright, text="Cancel").grid(row=5, column=15)
frametop.pack(side=TOP, fill=BOTH, expand=1)
framebottom.pack(side=BOTTOM, fill=BOTH, expand=1)
frameright.pack(side=RIGHT)
root.mainloop()
See attached image:enter image description here
Your code has both:
entry = Entry(frametop, width=50, textvariable=inPut_dir)
entry.grid(row=5,column=4,padx=2,pady=2,sticky='we',columnspan=20)
and
entry = Entry(frametop, width=50, textvariable=jukeBox_dir)
entry.grid(row=6,column=4,padx=2,pady=2,sticky='we',columnspan=20)
with jukeBox_dir/row 6 overriding inPut_dir/row 5
Therefore, in def input:
where you have:
entry.insert(0, inPut_dir)
You'll get the result in row 5 (jukebox_dir)

Can this be done more than once?

from tkinter import *
from tkinter import ttk
import webbrowser
import urllib
root = Tk()
w = Label(root, text="Where can I take you?")
w.pack()
url = 'http://sampdm.net/member.php?action=profile&uid=1'
def Openurl(url):
webbrowser.open_new(url)
button = Button(root, text = "Open Owners Profile #1", command = lambda:
Openurl(url))
button.pack()
root.mainloop()
Is there any way to make another button with another link like it?
I know there will be but I can't seem to figure out
From reading the comments it looks like you are not sure how to create multiple buttons inside your Tkinter window.
Its really easy and all you need to do is repeat the process that you used to create your first button.
I will provide 2 examples.
Here is how you can create each button manually for each website you wish to provide a button for.
from tkinter import *
import webbrowser
root = Tk()
url = 'http://sampdm.net/member.php?action=profile&uid=1'
url2 = 'www.google.com' # assign any variable name you want.
some_other_url = 'https://www.yahoo.com/'
def Openurl(url):
webbrowser.open_new(url)
w = Label(root, text="Where can I take you?")
w.pack()
# Here you can keep creating buttons using the same method as the first button.
# Just make sure you assign the correct url variable to the command.
button = Button(root, text = "Open Owners Profile #1", command = lambda: Openurl(url)).pack()
button2 = Button(root, text = "Open Google", command = lambda: Openurl(url2)).pack()
some_other_button = Button(root, text = "Open something else", command = lambda: Openurl(some_other_url)).pack()
root.mainloop()
Here is an example where your buttons are created from a list. This is a simple example but it should be enough to illustrate how it can be done.
from tkinter import *
import webbrowser
root = Tk()
# Here we create a list to use in button creation.
url_list = ['www.google.com', 'www.yahoo.com']
w = Label(root, text="Where can I take you?")
w.pack()
def Openurl(url):
webbrowser.open_new(url)
def create_buttons():
for url in url_list: # for each string in our url list
# creating buttons from our for loop values that will pack
# in the order they are created.
Button(root, text = url, command = lambda u = url: Openurl(u)).pack()
create_buttons()
root.mainloop()

Categories

Resources