How to respond to tkinter events? - python

I'm doing some work with GUI in python. I'm using the Tkinter library.
I need a button, which will open a .txt file and do this bit of processing:
frequencies = collections.defaultdict(int) # <-----------------------
with open("test.txt") as f_in:
for line in f_in:
for char in line:
frequencies[char] += 1
total = float(sum(frequencies.values())) #<-------------------------
I started with:
from Tkinter import *
import tkFileDialog,Tkconstants,collections
root = Tk()
root.title("TEST")
root.geometry("800x600")
button_opt = {'fill': Tkconstants.BOTH, 'padx': 66, 'pady': 5}
fileName = ''
def openFile():
fileName = tkFileDialog.askopenfile(parent=root,title="Open .txt file", filetypes=[("txt file",".txt"),("All files",".*")])
Button(root, text = 'Open .txt file', fg = 'black', command= openFile).pack(**button_opt)
frequencies = collections.defaultdict(int) # <-----------------------
with open("test.txt") as f_in:
for line in f_in:
for char in line:
frequencies[char] += 1
total = float(sum(frequencies.values())) #<-------------------------
root.mainloop()
Now I don't know how to assemble my code so it runs when the button is pressed.

The main problem was tkFileDialog.askopenfile() returns an open file rather than a file name. This following seemed to be more-or-less working for me:
from Tkinter import *
import tkFileDialog, Tkconstants,collections
root = Tk()
root.title("TEST")
root.geometry("800x600")
def openFile():
f_in = tkFileDialog.askopenfile(
parent=root,
title="Open .txt file",
filetypes=[("txt file",".txt"),("All files",".*")])
frequencies = collections.defaultdict(int)
for line in f_in:
for char in line:
frequencies[char] += 1
f_in.close()
total = float(sum(frequencies.values()))
print 'total:', total
button_opt = {'fill': Tkconstants.BOTH, 'padx': 66, 'pady': 5}
fileName = ''
Button(root, text = 'Open .txt file',
fg = 'black',
command= openFile).pack(**button_opt)
root.mainloop()
For quickly creating simple GUI programs I highly recommend EasyGUI, a fairly powerful yet simple Tk--based Python module for doing such things.

Try something laid out a bit like this:
class my_app():
def __init__():
self.hi_there = Tkinter.Button(frame, text="Hello", command=self.say_hi)
self.hi_there.pack(side=Tkinter.LEFT)
def say_hi():
# do stuff
You also may want to read:
This tutorial on Tkinter,
And this one.
EDIT: The OP wanted an example with his code (I think) so here it is:
from Tkinter import *
import tkFileDialog,Tkconstants,collections
class my_app:
def __init__(self, master):
frame = Tkinter.Frame(master)
frame.pack()
self.button_opt = {'fill': Tkconstants.BOTH, 'padx': 66, 'pady': 5}
self.button = Button(frame, text = 'Open .txt file', fg = 'black', command= self.openFile).pack(**button_opt)
self.calc_button = Button(frame, text = 'Calculate', fg = 'black', command= self.calculate).pack()
self.fileName = ''
def openFile():
fileName = tkFileDialog.askopenfile(parent=root,title="Open .txt file", filetypes=[("txt file",".txt"),("All files",".*")])
def calculate():
############################################### *See note
frequencies = collections.defaultdict(int) # <-----------------------
with open("test.txt") as f_in:
for line in f_in:
for char in line:
frequencies[char] += 1
total = float(sum(frequencies.values())) #<-------------------------
################################################
root = Tk()
app = App(root)
root.title("TEST")
root.geometry("800x600")
root.mainloop()
*Note: Nowhere in your code did I see where collections came from so I wasn't quite sure what to do with that block. In this example I have set it to run on the

In your openFile() function, just after you ask the user for a file name, put your code!

Related

Tkinter: Progressbar indicating the status of the uploaded file

Hi I'd like to have in my tkinter GUI a progress bar that gives visual cue about the status of the loading of a file. This is my code, but when I launch it the app just get stuck and does not work (I have to close it by force).
def start():
file = filedialog.askopenfilename(filetypes =(("Text File", "*.txt"),("All Files","*.*")), title = "Select")
filesize = os.path.getsize(file)
with open(file, "r", encoding='utf-8') as f:
for i in range(os.path.getsize(file)):
progressbar["value"] = 5
progressbar["maximum"] = filesize
label.config(text=str(progressbar["value"]) + "%")
root.update_idletasks()
time.sleep(1)
label = ttk.Label(root, text="00%")
label.pack()
button_prg = Button(root, text="progress", command=start)
button_prg.pack()
progressbar = ttk.Progressbar(root, orient="horizontal", length=100, mode='determinate')
progressbar.pack()
Also is there a way to resize the height of the bar? since I'd like to put it in the status bar at the bottom of my frame. Thank you all!
well what you want, i didn't understand clearly..
but here's what you shall have:
import time
import os
from tkinter import * #importing * is a very bad habit!
from tkinter import ttk
from tkinter import filedialog
def start():
file = filedialog.askopenfilename(filetypes =(("Text File", "*.txt"),("All Files","*.*")), title = "Select")
filesize = os.path.getsize(file)
with open(file, "r", encoding='utf-8') as f:
for i in range(os.path.getsize(file)):
progressbar["value"] = progressbar["value"]+1
progressbar["maximum"] = filesize
label.config(text=str(int(progressbar["value"]/os.path.getsize(file)*100)) + "%")
root.update_idletasks()
#time.sleep(1)
root = Tk()
label = ttk.Label(root, text="00%")
label.pack()
button_prg = Button(root, text="progress", command=start)
button_prg.pack()
progressbar = ttk.Progressbar(root, orient="horizontal", length=100, mode='determinate')
progressbar.pack()
root.mainloop()
btw, there's a limit in the file size.. that is 400kb.. i am just unable to load any of my files larger than 400kb in size!

Tkinter entry.get() only works every 2 button clicks

I was making a simple flashcard tkinter application and I've encountered a problem such that when I manage the subjects, only every second item is added to the file.
For example, say I went to the manage subject page and I wanted to add the subjects: subject1, subject2, subject3, subject4, ... subjectN.
The only subjects that would add to the file are the subjects with the odd endings, is there a fix for this?
The code responsible for this:
#subjects window
def managesubjectsF():
def addF():
f = open ('subjectlist.txt', 'a')
f.write(addsubjectE.get() + '\n')
f.close()
addsubjectE.delete('0', 'end')
subjectPage = Tk()
subjectPage.title('Add subject')
subjectPage.resizable(False, False)
subjectPage.configure(background = 'light blue')
subjectPage.geometry('260x70')
addsubjectE = Entry(subjectPage, width=23, font=('bold', 14))
addsubjectE.grid(column=1, row=1)
addS = Button(subjectPage, text='Add', font=('bold', 15), command = addF)
addS.grid(column=1, row=2, sticky = N)
Minimal example of implementation:
#modules
from tkinter import *
import os.path
#implementations
count=0
subjectlist = []
#main window details
root = Tk()
root.geometry('225x350')
#list of available subjects
choice = Listbox(root, font = ('bold', 15))
choice.grid(column=1, row=2)
if os.path.exists('./subjectlist.txt') == True:
with open('subjectlist.txt', 'r') as f:
for line in f:
count += 1
f.close()
f = open('subjectlist.txt', 'r')
for i in range(count):
choice.insert(END, (f.readline().strip()))
subjectlist.append(f.readline().strip())
f.close()
else:
f = open('subjectlist.txt', 'w')
f.close()
#subjects window
def managesubjectsF():
def addF():
f = open ('subjectlist.txt', 'a')
f.write(addsubjectE.get() + '\n')
f.close()
addsubjectE.delete('0', 'end')
subjectPage = Toplevel()
subjectPage.geometry('260x70')
addsubjectE = Entry(subjectPage, width=23, font=('bold', 14))
addsubjectE.grid(column=1, row=1)
addS = Button(subjectPage, text='Add', font=('bold', 15), command = addF)
addS.grid(column=1, row=2, sticky = N)
#buttons
addsubjectsB = Button(root, text = 'Manage subjects', font = ('bold', 15), command = managesubjectsF)
addsubjectsB.grid(column=1, row=3, sticky = N)
root.mainloop()
(moving comment to answer)
You are calling readline twice which is moving the file pointer and skipping subjects.
for i in range(count):
choice.insert(END, (f.readline().strip()))
subjectlist.append(f.readline().strip()) # reading next line
Try reading the value once then storing in both lists:
for i in range(count):
s = f.readline().strip() # read once
choice.insert(END, (s))
subjectlist.append(s)

string formatting is not working in tkinter

I have been trying to learn tkinter and have created something that post the results of a bunch of functions, and in the terminal the string formats works, but in the gui the string format does not work at all. I am super confused on why?
The code is below:
from tkinter import *
import ForFeesCovered
root = Tk()
root.title("Staff Fee Calculator")
root.geometry("375x400")
myLabel = Label(root,
text="Staff Fee Calculator")
e = Entry(root,
width=50,
borderwidth=5)
def output():
input_file = e.get()
f = ForFeesCovered.readfile(input_file)
file = ForFeesCovered.readfile(input_file)
staff = ForFeesCovered.getnamesofstaff(f)
staff.sort(reverse=False)
dic = ForFeesCovered.sort_dic(staff)
line_skip = 1
for lines in file:
line = lines.strip().split(",")
if line_skip != 1:
total = float("
{:.2f}".format(ForFeesCovered.getfeesforline(line)))
name = ForFeesCovered.get_name_of_staff(line, staff)
dic = ForFeesCovered.populating_dic(dic, name, total)
else:
line_skip += 1
string_dic = ""
result_file = open("result.txt", "w+")
for key in dic:
result_file.write("{} : {}\n".format(key, dic[key]))
string_dic = string_dic + "{:30} : {:>30}\n".format(key,
dic[key])
print(string_dic)
result_file.close()
output_dic = Label(root, text=string_dic, justify=LEFT)
output_dic.grid(row=2, column=0, pady=20)
submit = Button(root, text="Submit", command=output)
myLabel.grid(row=0, column=0)
e.grid(row=1, column=0,)
submit.grid(row=1, column=2)
root.mainloop()
The terminal is using a fixed-width font, the GUI is using a variable-width font.
If you are trying to line things up with spaces, you will need to used a fixed-width font.

Write and Read List, Python Pickle

I made a program with a List and this List is included in the Combobox. I want to write the List into a file in order to read the List again later, even after a restart of the program.
I tried this:
import tkinter as tk
from tkinter import ttk
import pickle
# window
win = tk.Tk()
win.title("menu")
List = []
newList = []
with open('data.txt', 'wb') as f:
pickle.dump(List, f)
with open('data.txt', 'rb') as f:
newList = pickle.load(f)
# button click event
def clickMe():
List.append(name.get())
numberChosen.configure(values=List)
# text box entry
ttk.Label(win, text="Eingabe:").grid(column=0, row=0)
name = tk.StringVar()
nameEntered = ttk.Entry(win, width=12, textvariable=name)
nameEntered.grid(column=0, row=1)
# button
action = ttk.Button(win, text="Enter", command=clickMe)
action.grid(column=2, row=1)
# drop down menu
ttk.Label(win, text="Auswahl:").grid(column=1, row=0)
number = tk.StringVar()
numberChosen = ttk.Combobox(win, width=12)
numberChosen['values'] = [List]
numberChosen.grid(column=1, row=1)
win.mainloop()
You just need to save the list to the file after mainloop, and load it at the start of the program.
with open('data.txt', 'rb') as file:
data = pickle.load(file)
...
win.mainloop()
with open('data.txt', 'wb') as file:
pickle.dump(data, file)
This will load the list at the start, and save it after the tk window closes.

How to make buttons call functions

After defining my word count method thanks to another member, I am now creating a GUI to go along with it. I have created three buttons, one for browsing for a file, one for counting the words and lines in a file, and one for exiting.
My question is, how do I make these buttons do things? I am trying to make the "Browse for a file" run the filename = fileopenbox() line, and the "Count" button run the word_count() method.
Here is what the code looks like:
from tkinter import *
from easygui import fileopenbox
root = Tk()
root.title("Word Counter")
root.geometry("500x500")
app = Frame(root)
app.grid()
button1 = Button(app, text = "Browse for a file")
button1.grid()
button2 = Button(app)
button2.grid()
button2.configure(text ="Count the file")
button3 = Button(app)
button3.grid()
button3["text"] = "Exit"
root.mainloop()
def word_count(filename):
filename = fileopenbox()
if not filename.endswith(('.txt', '.py', '.java')):
print('Are you trying to annoy me? How about giving me a TEXT or SOURCE CODE file, genius?')
return
with open(filename) as f:
n_lines = 0
n_words = 0
for line in f:
n_lines += 1
n_words += len(line.split())
print('Your file has {} lines, and {} words'.format(n_lines, n_words))
You have to pass the reference to the function you want to execute as the command option. Since you are divinding the task in two steps (one button to ask for the file name, and another one to count the lines and the words), I'd suggest you to create a class to wrap everything.
Besides, I suggest you to remove the dependency of easygui - since it is a project that is not longer maintained - and replace it with filedialog.askopenfilename, which is part of the standard library:
from tkinter import *
from tkinter.filedialog import askopenfilename
from tkinter.messagebox import showwarning, showinfo
class App(Frame):
def __init__(self, master):
Frame.__init__(self, master)
self.filename = None
button1 = Button(self, text="Browse for a file", command=self.askfilename)
button2 = Button(self, text ="Count the file", command=self.word_count)
button3 = Button(self, text="Exit", command=master.destroy)
button1.grid()
button2.grid()
button3.grid()
self.grid()
def askfilename(self):
filename = askopenfilename()
if not filename.endswith(('.txt', '.py', '.java')):
showwarning('Are you trying to annoy me?', 'How about giving me a TEXT or SOURCE CODE file, genius?')
else:
self.filename = filename
def word_count(self):
if self.filename:
with open(self.filename) as f:
n_lines = 0
n_words = 0
for line in f:
n_lines += 1
n_words += len(line.split())
showinfo('Result', 'Your file has {} lines, and {} words'.format(n_lines, n_words))
else:
showwarning('No file selected', 'Select a file first')
root = Tk()
root.title("Word Counter")
root.geometry("500x500")
app = App(root)
root.mainloop()

Categories

Resources