I'm struggling again to figure out a way to update my tkinter listbox from a combobox selection.
What I want to happen is the user imports an excel file, the file is then read and all the sheets available on that workbook is displayed for the user to select (this part works - Combobox), once its selected it suppose to display all the headers in that excel sheet in a listbox so the user can select multiple headers. The headers changes depending on the sheet selected, so the listbox would have to update and display the new headers.
I figured out how to display it as a ComboBox and it'll update as different sheets are selected, but I need the ability to select multiple headers - hence why I'm trying to use a listbox.
I've pasted what I've got right now.
import pandas as pd
import os
import xlrd
from tkinter import *
from tkinter.filedialog import askopenfilename, asksaveasfilename
from tkinter.ttk import Combobox
import tkinter as tk
import re
import numpy as np
class myApp:
importedSheets = []
headers = []
reports = ['A','B','C','D']
# rb_select = IntVar()
def UploadAction(self):
self.filename = askopenfilename()
def SaveAction(self):
self.savelocation = asksaveasfilename()
def sheetnames(self):
self.xlssheets = xlrd.open_workbook(self.filename,on_demand=True)
importedSheets = self.xlssheets.sheet_names()
self.cbox_sheets.config(value=importedSheets) #updating the value of the combobox
return importedSheets
def headernames(self):
if self.reporttype.get(self.reporttype.curselection()) == self.reports[0]:
self.df = pd.read_excel(self.filename,sheet_name = self.cbox_sheets.get(),header = 1, index_col=0)
headers = list(self.df.columns)
self.headerselectors.config(values=headers)
def __init__(self,master):
self.filename = None
self.master = master
#---------------------------------------------------------------------#
# Creating Basic Frame Structure
#---------------------------------------------------------------------#
self.frame1 = Frame(master=master,relief=RAISED,borderwidth=1)
self.frame1.pack(padx=10,pady=10)
self.frame2 = Frame(master=master,relief=RAISED,borderwidth=1)
self.frame2.pack(padx=10,pady=10)
self.frame3 = Frame(master=master,relief=RAISED,borderwidth=1)
self.frame3.pack(padx=10,pady=10)
#---------------------------------------------------------------------#
# Frame 2 - Selecting Sheet and Header To Work with
#---------------------------------------------------------------------#
self.frame2a = Frame(master = self.frame2)
self.frame2b = Frame(master = self.frame2)
self.frame2r = Frame(master = self.frame2)
self.frame2a.pack(side=TOP)
self.frame2b.pack(side=LEFT)
self.frame2r.pack(side=RIGHT)
self.uploadLabel = Label(master = self.frame2a,text = '1) Select the file you want to import',font=(None,12,)).pack()
self.uploadButton = Button(master = self.frame2a,text = 'Import', command =lambda:self.UploadAction()).pack(padx=5,pady=5)
self.reporttype = Listbox(master=self.frame2a,height=4,selectmode=SINGLE,exportselection = False)
for x,reports in enumerate(self.reports):
self.reporttype.insert(x,reports)
self.reporttype.pack(padx=5,pady=5)
#---------------------------------------------------------------------#
# Selecting Sheets to work with:
#---------------------------------------------------------------------#
self.sheetLabel = Label(master = self.frame2b,text = '2) Select the sheet to extract',font=(None,12)).pack(padx=15)
self.cbox_sheets = Combobox(master = self.frame2b,values = self.importedSheets,postcommand = self.sheetnames)
self.cbox_sheets.pack(padx=5,pady=5)
#---------------------------------------------------------------------#
# Selecting Headers to Work with:
#---------------------------------------------------------------------#
self.headerLabel = Label(master = self.frame2r,text = '3) Select the header with data',font=(None,12)).pack(padx=15)
self.headerselectors = Combobox(master = self.frame2r,values = self.headers,postcommand = self.headernames)
self.headerselectors.pack(padx=5,pady=5)
if __name__ == '__main__':
root = Tk()
my_gui = myApp(root)
root.mainloop()
EDIT: The section that needs to be worked on is in: Selecting Headers to Work with (I don't know how to highlight on stackoverflow)
To create a dynamic listbox I had to bind it to a button:
self.headerLabel = Label(master = self.frame2r,
text = '3) Select the header with data',
font=(None,12)).pack(padx=15)
self.headers_button = Button(master = self.frame2r, text = 'Show Headers',command = self.headernames).pack()
self.headers_select = Listbox (master = self.frame2r,exportselection = False,selectmode=MULTIPLE)
self.headers_select.pack()
Once I created the basic listbox and button I added to my function def headernames(self):
def headernames(self):
if self.reporttype.get(self.reporttype.curselection()) == self.reports[0]:
self.df = pd.read_excel(self.filename,sheet_name = self.cbox_sheets.get(),header = 1, index_col=0)
headers = list(self.df.columns)
self.headers_select.delete(0,'end')
for x,header in enumerate(headers):
self.headers_select.insert(x,header)
Now everytime I click on the button "Show Headers" it'll clear the list and then add the new headers for the selected sheet.
Related
I would like to know if anyone could help me with this problem. Im a beginner at Python, and im trying to create a program. The problem is that i want to search for a person in a stats database, and then get the result of the 5 most similar players based on stats. Now i only get one name, and cannot figure out what I am doing wrong.
This is the code that i have used, but it only displays 1 player, instead of the 5 players that are most similar.
import tkinter as tk
import pandas as pd
import os
from tkinter import filedialog
from tkinter import messagebox
from tkinter import ttk
def compare_players(player_name, data):
player = data[data['Player'] == player_name]
player_stats = player.select_dtypes(include=['float64'])
player_stats = (player_stats - player_stats.mean()) / player_stats.std()
data_stats = data.select_dtypes(include=['float64'])
data_stats = (data_stats - data_stats.mean()) / data_stats.std()
similarity = data_stats.dot(player_stats.T)
top_5 = data.iloc[similarity.iloc[0,:].sort_values(ascending=False).index[:5]]
return top_5
def run_search(folder_path, player_name, data):
result = compare_players(player_name, data)
for i, row in result[['Player', 'Team', 'Age']].iterrows():
tree.insert("", "end", values=(row['Player'], row['Team'], row['Age']))
def on_search():
player_name = entry.get()
run_search(folder_path, player_name, data)
def load_data():
global data
data = pd.DataFrame()
for file in os.listdir(folder_path):
if file.endswith(".xlsx"):
file_path = os.path.join(folder_path, file)
temp_data = pd.read_excel(file_path)
data = pd.concat([data, temp_data], axis=0)
root = tk.Tk()
root.withdraw()
folder_path = filedialog.askdirectory(initialdir = *Here i put the folder which contains many excel files*,
title = "Select folder")
load_data()
root = tk.Tk()
root.title("Player Comparison")
root.geometry("600x400")
label = tk.Label(root, text="Enter player name:")
entry = tk.Entry(root)
search_button = tk.Button(root, text="Search", command=on_search)
label.pack()
entry.pack()
search_button.pack()
tree = ttk.Treeview(root, columns=("Player", "Team", "Age"), show="headings")
tree.heading("Player", text="Player Name")
tree.heading("Team", text="Team")
tree.heading("Age", text="Age")
tree.pack(side="left", fill="y")
root.mainloop()
The code is most likely all over the place, but i try :D
Thanks for all answers in advance.
Good day folks,
I created a simple GUI that let's the user browse through their files with tkinter's filedialog.
After picking one, python reads the data from the (excel) file, and with that creates a new .txt file.
Now after doing that, I would like python to make that .txt file pop up, so that the user gets to see the result.
How do I do this?
Edit for the bot-moderator- he wanted code examples:
File1.py
from contextlib import nullcontext
import File2 as tp
import tkinter as tk
from tkinter import StringVar, messagebox
from tkinter import filedialog
filename = None
def pickFile():
global filename
filename = filedialog.askopenfilename()
#Creating main window
master = tk.Tk()
masterWidth = 350
masterHeight = 250
master.iconbitmap('C:\...')#directory
master.title('Title')
# get the screen dimension
screen_width = master.winfo_screenwidth()
screen_height = master.winfo_screenheight()
# find the center point
center_x = int(screen_width/2 - masterWidth / 2)
center_y = int(screen_height/2 - masterHeight / 2)-100
# set the position of the window to the center of the screen
master.geometry(f'{masterWidth}x{masterHeight}+{center_x}+{center_y}')
#Creating startbutton
startButton = tk.Button (master, text="Start", height=1, width=3, command=lambda: tp.readFile(filename))
#Creating bladerknop
browseButton = tk.Button (master, text='browse...', command=pickFile)
browseLabel = tk.Label(master, text='Choose a file')
startButton.place(x=175,y=200)
browseButton.place(x=210,y=50)
browseLabel.place (x=110,y=52)
master.mainloop()
File2.py
import pandas as pd
import tkinter as tk
from tkinter import messagebox
#declaring variables for later use
data = None
def missingValues(path):
if path is not None:
data = pd.read_excel(path, header=None)
return data
else:
messagebox.showinfo('No file chosen', 'Choose a file first.')
def readFile(path):
data = missingValues(path)
with open("C:\...\newFile.txt", 'w') as newTxt:
count = 0
for index, row in data.iterrows():
code = data.loc[count,0]
price = toEightBits(data.loc[count,1])
newTxt.write(str(code))
newTxt.write(str(price))
newTxt.write("\n")
count += 1
newTxt.close()
I have spent many hours all over the internet and this site trying to determine what is going on. All I'm trying to do is, using tkinter, have 1 button (Browse Files) that runs the first function (get_file_name) and opens a window to browse for a files location (.csv to be exact). It then displays that file location on the open window. I'm trying to retrieve that displayed location and pass that to the 2nd function (Analyze), so that it can retrieve and analyze the .csv file with a press of the second button (Analyze)
So far, the window opens as expected, there are 3 buttons that all read correctly. I can open a file explorer window and select the file I'm looking for, and it displays that file path in the window. I've also verified that my 2nd function works correctly to analyze and output a new .csv file.
What I can't figure out is how to get the file name/location from the first function into the second function. As you can see I did create a class at one point, but was unsuccessful in getting it to work so it currently just reads pass under def __init__.
Any help would be much appreciated, I'm sure that there is a simple solution that I'm just missing here.
# import all components
# from the tkinter library
from ast import Return
from pyclbr import Class
from tkinter import *
# import filedialog module
from tkinter import filedialog
import os
# Function for opening the
# file explorer window
# Create the root window
window = Tk()
# Set window title
window.title('Log Peruser 9000')
# Set window size
window.geometry("500x300")
#Set window background color
window.config(background = "white")
# Create a File Explorer label
label_file_explorer = Label(window,
text = "Select the Desired Log File",
width = 70, height = 4,
fg = "blue")
#Class Creation
class Log:
def __init__(self, file):
pass
#Get File Location
def get_file_name():
filename = filedialog.askopenfilename(initialdir = "/",
title = "Select a File",
filetypes = (("CSV", "*.csv*"),
("all files",
"*.*")))
# Change label contents
label_file_explorer.configure(text="Log File Selected: "+filename)
file = filename
return file
def Analyze():
#Import CSV
import csv
TCLoggerFile = open(file)
TCLoggerReader = csv.reader(TCLoggerFile)
#Create Dictionary
fields = [' Row #', ' Priority', ' Message Text']
data = []
# extracting each data row one by one
for rows in TCLoggerReader:
for row in rows:
position_error = 'position error","FSS_Control/controller_fss_master.c:'
if position_error in row:
data.append('Row #' + str(TCLoggerReader.line_num) + ', ' + 'Priority 3' + ', ' + row)
#data.append(row)
tfs = 'TFS passed -> Set ROTC speed NORMAL'
if tfs in row:
data.append('Row #' + str(TCLoggerReader.line_num) + ', ' + 'Priority 1' + ', ' + row)
#Export CSV File
outputFile = open('Analyzed_TCLogger.csv', 'w', newline='')
outputWriter = csv.writer(outputFile)
outputWriter.writerow(fields)
for row in data:
outputWriter.writerow([row])
outputFile.close()
button_explore = Button(window,
text = "Browse Files",
command = get_file_name)
button_analyze = Button(window,
text = "Analyze",
command = Analyze)
button_exit = Button(window,
text = "Exit",
command = exit)
# Grid method is chosen for placing
# the widgets at respective positions
# in a table like structure by
# specifying rows and columns
label_file_explorer.place(x=0, y=0)
button_explore.place(x=150, y=100)
button_analyze.place(x=240, y=100)
button_exit.place(x=305, y=100)
# Let the window wait for any events
window.mainloop()
Goal:
I am trying to have the script look through a directory named 'data' that is in the working directory of the script for excel workbooks. The script will then have a options menu of the different workbooks to choose from which will then give a selection of column names to choose from in a combo box above.
Results:
I was able to get it to read the default excel workbook upon start up but when I choose a different workbook the combo box does not update the column names.
I've tried to incorporate some sort of update function but I keep having trouble even running it because one or more things don't really line up. I am still new to python and tkinter so I would like some advice and suggestions to solve this problem.
import tkinter
from tkinter import ttk
from tkinter import *
import pandas as pd
def _quit():
root.quit()
root.destroy()
root = Tk()
root.title('BLURG')
root.geometry("1280x720")
path = os.chdir('Data')
filenames = os.listdir(path)
data_as_list = []
for filename in filenames:
if filename.endswith('.xlsx') or filename.endswith('.xls'):
data_as_list.append(filename)
clicked = StringVar()
options = data_as_list
clicked.set(options[0])
drop = OptionMenu(root, clicked, *options)
drop.pack(side="right")
data = pd.read_excel(clicked.get())
df = pd.DataFrame(data)
col_name = list(df.columns)
labelx = tkinter.Label(root, text="x-axis: ")
combox = ttk.Combobox(root, values=col_name)
labelx.pack(side="top")
combox.pack(side="top")
button = tkinter.Button(master=root, text="Quit", command=_quit)
button.pack(side=tkinter.BOTTOM)
root.mainloop()
Using an update function with a postcommand fixed the problem.
...
def update_list():
data = pd.read_excel(clicked.get())
df = pd.DataFrame(data)
col_name = list(df.columns)
combox['values'] = col_name
labelx = tkinter.Label(root, text="x-axis: ")
combox = ttk.Combobox(root, postcommand=update_list)
...
I've got an Excel spreadsheet I'm pulling info from. This will probably be changed to a database at some point but for now its fine for testing. It has two columns with data and looks like:
Key | ProgramName | Path
0 | Calculator | C:\Windows\System32\calc.exe
1 | Notepad | C:\Windows\System32\notepad.exe
I've built a pretty basic GUI using Python Tkinter and use the xlrd library to extract data from the spreadsheet into a list that contains dictionary entries.
https://pypi.python.org/pypi/xlrd
This gives me a list with dictionary entries:
[{'Path':'C:\Windows\System32\notepad.exe', 'Program':'Notepad', 'Key':0.0}, {'Path':'C:\Windows\System32\calc.exe', 'Program':'Calculator', 'Key':1.0}]
I can get the radio buttons working decently but I'm having an issue pulling the path data and re-using it, since I will (hopefully) use subprocess.Popen to actually open the program selected.
Heres the code so far:
from Tkinter import *
from xlrd import open_workbook
import os
import subprocess
class App:
def __init__(self, master):
frame = Frame(master)
frame.pack()
bottomframe= Frame(master)
bottomframe.pack(side = BOTTOM)
book = open_workbook('programlist.xls')
sheet = book.sheet_by_index(0)
# read header values into the list
keys = [sheet.cell(0, col_index).value for col_index in xrange(sheet.ncols)]
global dict_list
dict_list = []
for row_index in xrange(1, sheet.nrows):
d = {keys[col_index]: sheet.cell(row_index, col_index).value
for col_index in xrange(sheet.ncols)}
dict_list.append(d)
self.w = StringVar()
self.w.set(dict_list[0]['Key']) # initialize
for eachprogram in dict_list:
self.c = Radiobutton(master, text=eachprogram['Program'], variable=self.w, value=eachprogram['Key'])
self.c.pack(anchor=W)
self.quitButton = Button(
bottomframe, text="QUIT" , fg="red", command=frame.quit
)
self.quitButton.pack(side=LEFT, anchor=S)
self.programRun = Button(bottomframe, text="Run", command=self.programRun)
self.programRun.pack(side=LEFT, anchor=S)
def programRun(self):
???
root = Tk()
app = App(root)
root.mainloop()
root.destroy()
Not sure what I need to do so that when the programRun button is pressed, correct path is pulled so I can put it into a "subprocess.Popen" command.
Do I need to create another variable? Can I pull this info using a dictionary key?
Any suggestions are greatly appreciated.
It's not a hard task to pull path from your example and here're even two options to choose from. And you don't need to create an another variable.
According to Docs:
The variable option must be set to a control variable, either an IntVar or a StringVar. All the radiobuttons in a functional group must share the same control variable.
Set the value option of each radiobutton in the group to a different value. Whenever the user sets a radiobutton, the variable will be set to the value option of that radiobutton, and all the other radiobuttons that share the group will be cleared.
As you see - you don't need to use a StringVar, but DoubleVar since your value parameters (and keys) are floats. Downside here - you need to iterate over list to check each dictionary for Key.
try:
import tkinter as tk
except ImportError:
import Tkinter as tk
class App(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.frame = tk.Frame(self)
self.frame.pack()
self.bottomframe = tk.Frame(self)
self.bottomframe.pack(side=tk.BOTTOM)
# book = open_workbook('programlist.xls')
# sheet = book.sheet_by_index(0)
# read header values into the list
# keys = [sheet.cell(0, col_index).value for col_index in xrange(sheet.ncols)]
self.keys = ['Key', 'ProgramName', 'Path']
self.dict_list = [{'Path': r'C:\Windows\System32\notepad.exe', 'Program': 'Notepad', 'Key': 0.0},
{'Path': r'C:\Windows\System32\calc.exe', 'Program': 'Calculator', 'Key': 1.0}]
# global dict_list
# dict_list = []
# for row_index in xrange(1, sheet.nrows):
# d = {keys[col_index]: sheet.cell(row_index, col_index).value
# for col_index in xrange(sheet.ncols)}
# dict_list.append(d)
self.w = tk.DoubleVar()
self.w.set(self.dict_list[0]['Key']) # initialize
for each_program in self.dict_list:
self.c = tk.Radiobutton(self.master, text=each_program['Program'], variable=self.w, value=each_program['Key'])
self.c.pack(anchor=tk.W)
self.quitButton = tk.Button(
self.bottomframe, text="QUIT", fg="red", command=self.frame.quit
)
self.quitButton.pack(side=tk.LEFT, anchor=tk.S)
self.programRun = tk.Button(self.bottomframe, text="Run", command=self.programRun)
self.programRun.pack(side=tk.LEFT, anchor=tk.S)
def programRun(self):
print('Pulled path: %s' % self.search_list_dict())
def search_list_dict(self):
try:
return [item for item in self.dict_list if item['Key'] == self.w.get()][0]['Path']
except IndexError:
return ''
app = App()
app.mainloop()
As an alternative - you can use a StringVar and Path item as a value parameter! Just change some lines:
try:
import tkinter as tk
except ImportError:
import Tkinter as tk
class App(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
...
self.w = tk.StringVar()
self.w.set(self.dict_list[0]['Path']) # initialize
for each_program in self.dict_list:
self.c = tk.Radiobutton(self.master, text=each_program['Program'], variable=self.w, value=each_program['Path'])
self.c.pack(anchor=tk.W)
...
def programRun(self):
print('Pulled path: %s' % self.w.get())
app = App()
app.mainloop()