Python run script when Tkinter button pressed - python

I am trying to make it so that the variable fpl is set when the button (command submit) is used. The problem is, it runs through the entire thing before the user has hit the button. How do i make it so the script beginning?
#Convert string to list
fpl = fpl.replace(" " , ".")
Is only run once the user has pressed the button? Rest of the code below.
import json
from tkinter import *
def submit():
fpl = entry.get()
window = Tk()
window.title ("Infinite FMS")
Label (window, text="Enter your flight plan
here:").grid(row=0,column=0,sticky=W)
entry = Entry(window, width = 75, bg = "light blue")
entry.grid(row=1,column=0,sticky=W)
Button (window, text="Submit",
command=submit).grid(row=2,column=0,sticky=W)
output = Text(window,width=75,height=6,background="light
blue")
output.grid(row=3,column=0,sticky=W)
#Convert string to list
fpl = fpl.replace(" " , ".")
"[" + fpl + "]"
fpllist = fpl.split(".")
#Length of fpllist
fpllen = len(fpllist)
#Loop through the flight plan missing first and last
entries
n = 1
Invalid = []
while n < fpllen - 1:
#Check for item in file
searchTerm = (fpllist[n])
searchTermF = "\'Name\': \'" + searchTerm + "\'"
searchTermV = "\'identifier\': \'" + searchTerm + "\'"
file = open('mydirectory', 'r')
data1 = json.load(file)
file.close()
file = open('mydirectory', 'r')
data2 = json.load(file)
file.close()
if searchTermF in str(data1):
Validity = "Your route is valid!"
n = n + 1
elif searchTermV in str(data2):
Validity = "Your route is valid!"
n = n + 1
else:
Validity = "Your route is invalid!\nInvalid
waypoints:"
Invalid.append(searchTerm)
n = n + 1
if len(Invalid) == 0:
print (Validity , ', '.join(Invalid))
else:
Validity = "Your route is invalid!\nInvalid
waypoints:"
print (Validity , ', '.join(Invalid))
output.delete(0.0, END)
output.insert(END, (Validity , ', '.join(Invalid)))

As PM 2Ring said if you put this
#Convert string to list
fpl = fpl.replace(" " , ".")
"[" + fpl + "]" #what is this supposed to do?
fpllist = fpl.split(".")
#Length of fpllist
fpllen = len(fpllist)
in your submit function it will be run when you click the button.
Also you don't need to replace the spaces with points fpllist = fpl.split() will give you the same result.
And you should really learn OOP(google it if you don't know what it is) it will make your program more readable and you can split diffrent parts of your program in diffrent functions.

Related

storing output text in a tkinter textbox

im looking to output a list of text to both a text file as well as a tkinter textbox. Currently I have it working to print to a text file being held in the same folder. I would like this same list to be printed on screen into the outputToScreen textbox
From my research I think I am meant to use .insert(index , text) but I can not get this method to work. I have also seen some old code using a .set function but when I tried this I came across an error saying that textbox's don't have that method
#file -> gui.py
# IMPORT tkinter for GUI creation and import scripts for functions
from tkinter import *
from tkinter.ttk import *
import scripts
import customtkinter
windowDim = str(750)+'x'+str(600)
window = customtkinter.CTk()
window.title("INFO GENERATOR")
window.geometry(windowDim)
window.resizable(True, True)
# Modes: system (default), light, dark
customtkinter.set_appearance_mode("dark")
# Themes: blue (default), dark-blue, green
customtkinter.set_default_color_theme("customTkinterTheme.json")
outputToScreen = customtkinter.CTkTextbox(window , width=400 , height=200)
outputToScreen.place(x=200, y=300)
def popupmsg(msg):
popup = customtkinter.CTk()
popup.title("!")
label = customtkinter.CTkLabel(popup, text=msg,)
label.pack(side="top", fill="x", pady=10)
B1 = customtkinter.CTkButton(popup, text="Okay", command=popup.destroy)
B1.pack()
popup.mainloop()
# create main window
# window specs are 700 x 350 and window is not able to be resizeable
# CREATING USER CONTROLS
# each button will print a list of items (number of items will be come from the entry userValue)
userEntry = customtkinter.CTkEntry(window)
# userValue = int(userValue)
userValue = ""
userEntry.place(x=325, y=200)
userEntry.insert(0, userValue)
userValueLabel = customtkinter.CTkLabel(
window, text="ENTER AMOUNT OF RECORDS YOU WOULD LIKE").place(x=275, y=170)
label = customtkinter.CTkLabel(window, text="INFOMATION GENERATOR by Noah Mackay "
).pack()
def outputEmails(userValue):
# function receives the amount of records the user wants to print
# function will be called when email button is clicked
# this function will clear the output file and then read open it
# will call the generateEmail function from scripts.py file
# outputs the amount of records based on the user input in the entry text box
userValue = int(userEntry.get())
outputFile = scripts.generateEmail(userValue)
file = open('output.txt', 'w').close()
file = open('output.txt', 'w')
file.write(str(outputFile))
outputToScreen.set(outputFile)
popupmsg("PRINTING WORKED")
def outputNames(userValue):
# function receives the amount of records the user wants to print
# function will be called when email button is clicked
# this function will clear the output file and then read open it
# will call the generateEmail function from scripts.py file
# outputs the amount of records based on the user input in the entry text box
userValue = int(userEntry.get())
outputFile = scripts.generateName(userValue)
file = open('output.txt', 'w').close()
file = open('output.txt', 'w')
file.write(str(outputFile))
outputToScreen.set(outputFile)
popupmsg("PRINTING COMPLETED")
def outputCost(userValue):
userValue = int(userEntry.get())
outputFile = scripts.generateCost(userValue)
file = open('output.txt', 'w').close()
file = open('output.txt', 'w')
file.write(str(outputFile))
outputToScreen.set(outputFile)
popupmsg("PRINTING COMPLETED")
def outputProduct(userValue):
userValue = int(userEntry.get())
outputFile = scripts.generateProduct(userValue)
file = open('output.txt', 'w').close()
file = open('output.txt', 'w')
file.write(str(outputFile))
outputToScreen.set(outputFile)
popupmsg("PRINTING COMPLETED")
def outputPhoneNumber(userValue):
userValue = int(userEntry.get())
outputFile = scripts.generatePhoneNumber(userValue)
file = open('output.txt', 'w').close()
file = open('output.txt', 'w')
file.write(str(outputFile))
outputToScreen.insert(0,outputFile)
popupmsg("PRINTING COMPLETED")
# creates 5 buttons each have their respective output function attached using command=
emailButton = customtkinter.CTkButton(window, text="EMAILS",
command=lambda: outputEmails(userValue)).place(x=5, y=40)
productButton = customtkinter.CTkButton(window, text="PRODUCTS",
command=lambda: outputProduct(userValue)).place(x=150, y=40)
phoneNumberButton = customtkinter.CTkButton(
window, text="PHONE NUMBERS" , command= lambda:outputPhoneNumber(userValue)).place(x=300, y=40)
costButton = customtkinter.CTkButton(window, text="PRICES",
command=lambda: outputCost(userValue)).place(x=450, y=40)
nameButton = customtkinter.CTkButton(
window, text="FIRST + LAST NAMES", command=lambda: outputNames(userValue)).place(x=600, y=40)
window.mainloop()
#file -> scripts.py
import random
def generateName(numberOfItemsNeed):
# opens 2 files. One containing first names and the other containing last names
firstNameFile = open('dataFiles\FirstNamesData.txt', 'r')
lastNameFile = open('dataFiles\LastNamesData.txt', 'r')
# builds values for the while statement and the return string
returnValue = ""
counter = 0
# builds the return string using a while loop and removing the newline character
# after each line from both files when being read
while counter < int(numberOfItemsNeed):
returnValue += str(firstNameFile.readline().strip("\n")
) + " " + str(lastNameFile.readline().strip("\n")) + "\n"
counter = counter + 1
# returns a list of "human" names in a single string divided by a newline character
return (returnValue)
def generateEmail(numberOfItemsNeed):
# opens a file containing a records of first names
firstNameFile = open('dataFiles\dictonary.txt', 'r')
counter = 0
# A list of commonly used email address suffixs
suffix = ['#gmail.com', '#gmail.ca', '#hotmail.com',
'#hotmail.ca', '#mail.com ', '#mail.ca', '#gov.ca']
returnValue = ""
while counter < int(numberOfItemsNeed):
returnValue += firstNameFile.readline().strip("\n") + \
str((random.randrange(0, 100))) + \
suffix[random.randrange(0, len(suffix))]+'\n'
counter = counter + 1
return (returnValue)
def generateCost(numberOfItemsNeed):
# generates a random item price in the inclusive range of 0.00$ to 1000.99$
counter = 0
cost = ""
while counter < int(numberOfItemsNeed):
cost += '$' + str(random.randrange(0, 1000)) + \
"." + str(random.randrange(0, 99)) + '\n'
counter = counter+1
return cost
def generateProduct(numberOfItemsNeed):
counter = 0
returnValue = ""
productList = open('dataFiles\itemData.txt', 'r')
while counter < int(numberOfItemsNeed):
returnValue += str(productList.readline()
).strip("\n") + str(generateCost(1))
counter = counter + 1
return (returnValue)
def generatePhoneNumber(numberOfItemsNeed):
counter = 0
returnValue = ""
while counter < int(numberOfItemsNeed):
firstNumber = str(random.randrange(100, 999))
secondNumber = str(random.randrange(1000, 9999))
thirdNumber = str(random.randrange(100, 999))
returnValue += firstNumber + "-" + secondNumber + "-" + thirdNumber + '\n'
counter = counter + 1
return (returnValue)
def shuffleFile(filePath):
lines = open(filePath).readlines()
random.shuffle(lines)
open(filePath, 'w').writelines(lines)
# shuffleFile('dataFiles\dictonary.txt')
Text widget indexes are strings of the form line.character with lines starting at 0 and characters starting at 1. So, to insert at the start you need to use the index "1.0", not 0. If you want to insert at the end you can use the special index "end". If the widget is empty, "1.0" and "end" yield identical results.
outputToScreen.insert("1.0", outputToFile)

Set specific words in ScrolledText red

i need to find and highlight with color OR bold specific words in string.
i thought on doing like this
word to put in red=is:
var="my string is that should is appear with the word flame is in red is"
varf=var.replace(" is ","\033[1;32;40m is ")
but this dont work on tkinter ScrolledText, just in terminal :s
is there a way to do this in a tkinter ScrolledText widget?
Word will appear in diferent places in string so its hard to do the config.tag because i have to specify the interval of characters in the string to color.
my code
def checkval(e, spec0, spec1, spec2, spec3, spec4, spec5):
e.widget.insert("1.0", PLACEHOLDER if e.widget.get("1.0", "end-1c") == "" else "")
reqlidst=(spec0, spec1, spec2, spec3, spec4, spec5)
textlabl=""
for x in reqlidst:
if len(x)>1:
#print("selected text: '%s'" % e.widget.get(SEL_FIRST, SEL_LAST))
if x.upper() in e.widget.get("1.0", "end-1c").upper():
if len(textlabl)>1:
textlabl = textlabl + "- " + x.replace(" ", "").upper() + " " + html.unescape('✔')+"\n\n"
else:
textlabl = "- " + x.replace(" ", "").upper() + " " + html.unescape('✔')+"\n\n"
else:
if len(textlabl) > 1:
textlabl =textlabl + "- " + x.replace(" ", "").lower() + " " + html.unescape('✘')+"\n\n"
else:
textlabl = "- " + x.replace(" ", "").lower() + " " + html.unescape('✘')+"\n\n"
e.widget.my_var_expected.set(textlabl)
reqlidst are the word to search for and show in red
How to change the color of certain words in the tkinter text widget? doesnt answer my question :/
There is a tag method in the Tkinter text. This allows you to mark certain parts. I have prepared a small example for you, where the Text-Widget dynamically recognizes the words Hello and Jonny.
In principle, you only really need to be familiar with the indexes.
from tkinter import Text, Button, Tk
root = Tk()
def output(event):
length = len("Hello")
val = len(txt.get("1.0", "end-1c"))
for x in range(len(txt.get("1.0", "end-1c"))):
if "Hello" in txt.get(f"1.{x}", "end-1c") or "Jonny" in txt.get(f"1.{x}", "end-1c") :
val = x
vals = str(val + length)
txt.tag_add("Hello", f"1.{str(val)}", f"1.{vals}")
txt.tag_config("Hello", background="red", foreground="white")
txt = Text(root)
txt.grid(columnspan=3)
root.bind("<Key>", output)
root.mainloop()
enter image description here
Please note that I did not write a whole program for each new line.
For example, to make it more dynamic, you could change the indexes. So you can implement that for each line.
My example is for the first line only.
greeting

How do i store a value in my txt file without it disappearing

import tkinter as tk
#The data does appear in the txt file. but after pressing the submitting button it doesnt stay there.
def submit():
outfile = open("text.txt", "w")
A = entry1.get()
B = entry2.get()
username = "UserName, "
password = "Password, "
C = username + A
D = password + B
outfile.write(C + " " + D)
entry1.delete(0, tk.END)
entry2.delete(0, tk.END)
#If i put a input and submit it will just be thr and not stored. how do i store the value in the txt file permently without it going away? Must i do a loop?
frame = tk.Tk()
tk.Label(text="Username").grid(row=1)
tk.Label(text="Password").grid(row=2)
entry1 = tk.Entry()
entry2 = tk.Entry()
entry1.grid(row=1 , column=1)
entry2.grid(row=2 , column=1)
tk.Button(frame, text="Submit" , command=submit).grid(row=3,column=0, pady=4)
frame.mainloop()
Your syntax is wrong. The correct way to write to a file is:
outfile.write(C + " " + D)
file.write is a function, not a variable.
So this
outfile.write = (C + " " + D)
should be
outfile.write(C + " " + D)
At the end, don't forget to close the file. Otherwise, it might not be saved.

Files won't be read in GUI program, only in shell [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
Hey guys so I have a lengthy code here I need help with,
specifically: my end process is an assignment creating a word cloud, But I haven't even start at that point yet. As of now, I've been able to create the function of creating a frequency accumulator and my first GUI platform.
When running the program, the gui asks the user to type in the file name of their program. However, you can type gibberish or even leave it blank, click the transform file button, and it still opens up Shell and prompts the user for the text file name and then the number of words they want in the list.
I don't even want the 2nd part (asking how many words) but I didn't know another way of doing it for my frequency counter.
from graphics import *
##Deals with Frequency Accumulator##
def byFreq(pair):
return pair[1]
##Function to allow user to upload their own text document##
def FileOpen(userPhrase):
filename = input("Enter File Name (followed by .txt): ")
text = open(filename, 'r').read()
text = text.lower()
for ch in ('!"#$%&()*+,-./:;<=>?#[\\]^_{}~'):
text = text.replace(ch, " ")
words = text.split()
counts = {}
for w in words:
counts[w] = counts.get(w,0) + 1
n = eval(input("Output how many words?"))
items = list(counts.items())
items.sort(key=byFreq, reverse=True)
for i in range(n):
word, count = items[i]
print("{0:<15}{1:>5}".format(word, count))
##This Function allows user to simply press button to see an example##
def Example():
win = GraphWin("Word Cloud", 600, 600)
file = open("econometrics.txt", "r", encoding = "utf-8")
text = file.read()
text = text.lower()
for ch in ('!"#$%&()*+,-./:;<=>?#[\\]^_{}~'):
text = text.replace(ch, " ")
words = text.split()
counts = {}
for w in words:
counts[w] = counts.get(w,0) + 1
n = eval(input("Output how many words?"))
items = list(counts.items())
items.sort(key=byFreq, reverse=True)
for i in range(n):
word, count = items[i]
print("{0:<15}{1:>5}".format(word, count))
#########################################################################
##Gold Boxes##
def boxes(gwin, pt1, pt2, words):
button = Rectangle(pt1, pt2)
button.setFill("gold")
button.draw(gwin)
#Middle of the box coordinates
labelx = (pt1.getX() + pt2.getX())/2.0
labely = (pt1.getY() + pt2.getY())/2.0
#Labels
label = Text(Point(labelx,labely),words)
label.setFill("black")
label.draw(gwin)
####GUI function#####
def main():
#Creates the actual GUI
win = GraphWin("Word Cloud Prompt", 600, 600)
#Box which user types into:
inputBox = Entry(Point(300,150),50)
inputBox.draw(win)
#Gold Boxes at Top
boxes(win, Point(220,300), Point(370,350), "Transform Text File")
boxes(win, Point(220,400), Point(370,450), "Example text file")
#Tells user what to do
prompt = Text(Point(300,25),"Welcome to the Word Cloud program!")
prompt.draw(win)
prompt = Text(Point(300,125),"Enter your textfile name")
prompt.draw(win)
prompt = Text(Point(300,180),"Want to see our own file into a Word Cloud? Click below")
prompt.draw(win)
#display answer
display = Text(Point(300, 500),"")
display.draw(win)
#User Clicks a box:
pt = win.getMouse()
#Store user info
userPhrase = inputBox.getText()
key = inputBox.getText()
#Incase a button isn't clicked
output = "No button was clicked, Please restart program"
#Clicking the Transform Text File Button
if pt.getY() >= 300 and pt.getY() <= 350:
if pt.getX() >= 220 and pt.getX() <= 370:
output = FileOpen(userPhrase)
#Clicking the Example Text File Button
if pt.getY() >= 400 and pt.getY() <= 450:
if pt.getX() >= 220 and pt.getX() <= 370:
output = Example()
#State Answer
display.setText(output)
display.setFill("purple3")
display.setStyle("bold")
prompt.setText("Thank You! Click anywhere to close!")
prompt.setFill("red")
#closing program
pt = win.getMouse()
win.close()
main()
(Editor's Note: I've modified some of the formatting for my ease of reading, but the function will be identical)
def FileOpen(userPhrase):
"""FileOpen allows users to upload their own text document."""
filename = input("Enter File Name (followed by .txt): ")
text = open(filename, 'r').read()
text = text.lower()
for ch in ('!"#$%&()*+,-./:;<=>?#[\\]^_{}~'):
text = text.replace(ch, " ")
words = text.split()
counts = {}
for w in words:
counts[w] = counts.get(w, 0) + 1
n = eval(input("Output how many words?"))
items = list(counts.items())
items.sort(key=byFreq, reverse=True)
for i in range(n):
word, count = items[i]
print("{0:<15}{1:>5}".format(word, count))
This is the function we're concerned with. You call it with an argument userPhrase that comes from a gui text entry field, but then you never use userPhrase anywhere in the function. Consider instead:
def file_open(userPhrase=None):
# file_open is lowercase and snake_case for PEP8
# userPhrase=None to make it an optional argument
filename = userPhrase if userPhrase is not None else \
input("Enter file name (including extension): ")
...
Then you'll have to call it differently if you want file_open to prompt for a filename if not given one.
def main():
...
if 300 <= pt.getY() <= 350 and 220 <= pt.getX() <= 370:
# you can chain conditionals as above. It makes it much easier to read!
# `a <= N <= b` is easily read as `N is between a and b`
userPhrase = inputBox.getText()
if userPhrase.strip(): # if there's something there
file_open(userPhrase)
else:
file_open()

Displaying numbers in tkMessageBox

I am trying to build a python script (on my Linux box with Python 2.7.6 ) in which I enter a company name, a contact name, their phone number and a comment. When I have entered the information I click a button which then opens a file for reading and iterates through it to see if either the company name or phone number are already in the file before appending the data I have entered to the file. If either or both have already previously been logged i want it to display this fact in a tkMessageBox showing, for example, that the phone number is logged 3 times.
It all works except that the number is completely wrong. If the real count is 3 it will show all sorts of numbers maybe 426 or 105 or any other number.below is the part of the code as I have it at present:
#!/usr/bin/env python
from Tkinter import *
import time
import tkMessageBox
from ScrolledText import *
titles = 'Company', 'Contact', 'Tel', 'Comments'
fields = 'e1', 'e2', 'e3', 'e4'
def show_entry_titles():
countname = IntVar
counttel = IntVar
filename = "callers.txt"
myfile = open(filename, 'r')
company= e1.get()
tel=e2.get()
for myline in myfile:
q = myline
if q.find(company):
countname += 1
if q.find(tel):
counttel += 1
myfile.close()
if countname + counttel > 0:
msg = "Company " + str(countname)
tkMessageBox.showinfo(countname)
localtime = time.asctime( time.localtime(time.time()) )
localtime = "Logged on: " + localtime + "\n"
company = "Company " + e1.get() + "\n"
contact = "Contact " + e2.get() + "\n"
tel = "Tel Num " + e3.get() + "\n"
comm = "Comments: " + e4.get('1.0', END+'-1c') + "\n"
filename = "callers.txt"
myfile = open(filename, 'a')
myfile.write(localtime)
myfile.write(company)
myfile.write(contact)
myfile.write(tel)
myfile.write(comm)
myfile.write("-----------------------------------\n")
myfile.close()
e1.delete(0,END)
e2.delete(0,END)
e3.delete(0,END)
e4.delete('0.0', 'end')
master = Tk()
for k in range(4):
Label(master, text=titles[k]).grid(row=k)
e1 = Entry(master)
e2 = Entry(master)
e3 = Entry(master)
e4 = ScrolledText(master, width=40, height=10)
e1.insert(20,"")
e2.insert(20,"")
e3.insert(20,"")
e1.grid(row=0, column=1)
e2.grid(row=1, column=1)
e3.grid(row=2, column=1)
e4.grid(row=3, column=1)
Button(master, text='Quit', command=master.quit).grid(row=k+1, column=0, sticky=W, pady=4)
Button(master, text='Show', command=show_entry_titles).grid(row=k+1, column=1, sticky=W, pady=4)
mainloop( )
As an example with the code as posted I know the particular phone number I entered was already in the file 7 times but the message was:
closed file 'callers.txt', mode 'r' at 0x7f870074c0c0
With the tkMessageBox line as:
tkMessageBox.showinfo(msg)
the message comes out as :
Company 174
I have spent hours searching for a solution but cannot find any reference to displaying a string and an int correctly and I must have tried at least 5 different syntax suggestions.
Can someone help me with this please?
I've never used Tkinter before, but a quick Google search shows us that IntVar is a class and when you instantiate classes in Python, you need to use parentheses, like so:
countname = IntVar()
counttel = IntVar()
When you want to set a value to the object, you use the set function, like so:
countname.set(0)
When you want to retrieve a value from the object, you use the get function, like so:
countname.get()
Also, you declare countname to be an IntVar(), but in the very next line, you set that object to a regular int, so it's no longer an IntVar().
Perhaps the following code will fix your problem:
countname = IntVar(0)
counttel = IntVar(0)
...
if q.find(company):
countname.set(countname.get() + 1)
if q.find(tel):
counttel.set(counttel.get() + 1)
...
msg = "Company " + str(countname.get())
tkMessageBox.showinfo(countname.get())
Sources:
Tkinter.IntVar
Tkinterbook: The Variable Classes
Your output is 186 instead of 7, because of these lines:
if q.find(company):
countname += 1
if q.find(tel):
counttel += 1
You should not use str.find in this way. find returns -1 if the string is not found, and the index of the start of the substring otherwise. bool(someInt) evaluates to True for any integer other than zero, so your countname and counttel will be incremented for every single line in your file, except ones that start with a company name or telephone number. If you want to check if a string is inside another string, I suggest the in operator.
if company in q:
countname += 1
if tel in q:
counttel += 1
As a simpler example, this is effectively what you're doing:
lines = [
"Hello, how are you today?",
"Today I went to Starbucks and bought a coffee.",
"It was delicious."
]
countname = 0
company = "Starbucks"
for line in lines:
if line.find(company):
countname += 1
print "We found the company name 'Starbucks' this many times: " + str(countname)
Result:
We found the company name 'Starbucks' this many times: 3
This is the incorrect result. 'Starbucks' only appears once, not three times. Let's try again using in.
lines = [
"Hello, how are you today?",
"Today I went to Starbucks and bought a coffee.",
"It was delicious."
]
countname = 0
company = "Starbucks"
for line in lines:
if company in line:
countname += 1
print "We found the company name 'Starbucks' this many times: " + str(countname)
Result:
We found the company name 'Starbucks' this many times: 1
This is the correct result.

Categories