So, I'm working on a timer using Python and Tkinter's GUI. To do so, I intend to convert the minutes into seconds (as seen in my code) and use Python's time.sleep command to count down (not yet implemented).
from tkinter import *
import time
countdown = Tk()
countdown.geometry('500x300')
minute = Text(countdown, height = 0.01, width = 5)
minute.place(x=100, y=100)
minlabel = Label(text = "Input Minutes", font = ("MS Sans Serif", 10), bg = 'Light Blue')
minlabel.place(x=85, y = 80)
def go(event):
minseconds = int(minute.get("1.0", END))*60
print(int(minseconds))
countdown.bind('<Return>', go)
countdown.mainloop()
However, when I convert it to minutes, it works the first time (I.E, when I input 3, 180 returns), but any time after that I get this:
ValueError: invalid literal for int() with base 10: '3\n3\n\n'
Any idea what could be causing this? And why it works the first time but then stops working? Thanks :)
The problem is every time Enter is pressed a newline character is entered into the Text widget named minute and they mess up the conversion to int.
The simplest way I can think of to avoid that would be to just clear the widget in the event handler function:
def go(event):
minseconds = int(minute.get("1.0", END))*60
print(int(minseconds))
minute.delete('1.0', END) # <---- ADDED.
so actually the error is quite simple. You created a Text widget, which is just adding lines when you press Enter (corresponding to the \n characters). Just make your text widget bigger (instead of height = 0.01 maybe 2) and you will see it.
To do it more elegantly, you might try Entry() instead of Text(). See the example.
import time
import tkinter as tk
def go(event):
minseconds = int(min_entry.get())
seconds = minseconds*60
print(int(seconds))
countdown = tk.Tk()
countdown.geometry('500x300')
minlabel = tk.Label(text = "Input Minutes", font = ("MS Sans Serif", 10), bg = 'Light Blue')
minlabel.place(x=85, y = 80)
min_entry = tk.Entry()
min_entry.place(x=100, y=100)
countdown.bind('<Return>', go)
countdown.mainloop()
Furthermore try to put your functions always on top of your code, as they have to be defined before you call them. This might be causing trouble as you code gets bigger.
Hope you get a better understanding from tkinter by this :)
Check this update function. Import the module at top
import messagebox as msg
def go(event):
try:
minseconds = int(minute.get("1.0", END))*60
print(int(minseconds))
minute.delete("1.0", END)
except Exception:
msg.showerror("Error","invalid input provided.")
minute.delete("1.0", END)
But I would suggest to go with Entry With a StringVar()
from tkinter import *
from tkinter import messagebox as msg
countdown = Tk()
countdown.geometry('500x300')
minute=StringVar()
minut = Entry(countdown,textvariable=minute, width = 5)
minut.place(x=100, y=100)
minlabel = Label(text = "Input Minutes", font = ("MS Sans Serif", 10), bg = 'Light Blue')
minlabel.place(x=85, y = 80)
def go(event):
try:
minseconds = int(minute.get())*60
print(int(minseconds))
minute.set("")
except ValueError:
msg.showerror("Error","Invalid input provided.")
countdown.bind('<Return>', go)
countdown.mainloop()
Related
i've red a lot of post here and i couldn't find a clue on my problem even if it was repeated a lot, it doesn't really apply to my case.
My code is simple. I have a string, i want to create the wordcloud of this string, but i also created a function that gets in entry an integer, and returns the wordcloud with the number of words in the variable. My code works well alone, my function is called "test_wordcloud". If i enter "test_wordcloud(4)" for example, it will return the wordcloud with the 4 most present words in the string.
def test_wordcloud(n):
if type(n) == "int":
wordcloud = WordCloud(width=900, height=400, background_color="white", max_font_size=125,
min_font_size=20, max_words=n).generate(string)
fig = plt.figure(figsize = (10, 10))
plt.axis("off")
plt.imshow(wordcloud)
fig.savefig("Test Tkinter.jpg", bbox_inches='tight', dpi=150)
source_path = "C:\\Users\\f002722\\Stage NLP\\Test Tkinter.jpg"
destination_path = "C:\\Users\\f002722\\Desktop\\NLP4DTV 2.0\\results\\data\\Test Tkinter.jpg"
shutil.move(source_path, destination_path)
return "DONE"
Now i want to make a Tkinter interface where the user enter the number of words he wants, then the wordcloud in format jpg is created in the folder up there and he can see it. But it doesn't work. So far i've done like this.
import tkinter as tk
from tkinter import ttk
from tkinter.messagebox import showinfo
root = tk.Tk()
root.title("WordCloud configuration")
title = root.title()
window_width = 300
window_height = 300
# Center the window
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
center_x = int(screen_width/2 - window_width / 2)
center_y = int(screen_height/2 - window_height / 2)
root.geometry(f'{window_width}x{window_height}+{center_x}+{center_y}')
wordnumber = tk.StringVar()
wordnumberlabel = ttk.Label(root, text = "Number of words").pack()
entry = ttk.Entry(root, textvariable = wordnumber)
entry.pack()
ttk.Button(root, text = "Ok", command = test_wordcloud(entry.get())).pack()
root.mainloop()
I really don't see where i'm wrong, my command on the button is "test_wordcloud(entry.get())" which should guarantee my code to run this function with the entry, but when i do so, nothing happens. The window opens with the button and the place where to right the variable but when i press "ok" nothing happens.
I woudl really appreciate help her because i keep looking for answer on google but i feel stuck, thx in advance
So I'm writing some code to check VAT-IDs using a web API. Since some files have quite a large amount of API-calls it sometimes takes quite a while to complete and I want to show a progressbar so other users know that the program hasn't crashed yet. I found an example and modified it slightly so that it fits my needs. This code shows a window with a progressbar and once the for loop is finished the window closes.
import tkinter as tk
from tkinter import ttk
import time
def wrap():
MAX = 30000
root = tk.Tk()
root.geometry('{}x{}'.format(400, 100))
progress_var = tk.IntVar() #here you have ints but when calc. %'s usually floats
theLabel = tk.Label(root, text="Sample text to show")
theLabel.pack()
progressbar = ttk.Progressbar(root, variable=progress_var, maximum=MAX)
progressbar.pack(fill=tk.X, expand=1)
def loop_function():
k = 0
for k in range(MAX):
### some work to be done
progress_var.set(k)
time.sleep(0.002)
root.update()
root.destroy()
root.after(100, loop_function)
root.mainloop()
wrap()
Now I wanted to implement this into my tool:
import pandas as pd
import re
import pyvat
from tkinter import ttk
import tkinter as tk
def vatchecker(dataframe):
#initialise progressbar
root = tk.Tk()
root.geometry('{}x{}'.format(400, 100))
progress_var = tk.DoubleVar() #here you have ints but when calc. %'s usually floats
theLabel = tk.Label(root, text="Calling VAT Api")
theLabel.pack()
maxval = len(dataframe['Vat-ID'])
progressbar = ttk.Progressbar(root, variable=progress_var, maximum=maxval)
progressbar.pack(fill=tk.X, expand=1)
checked =[]
def loop_function():
for row in range(len(dataframe['Vat-ID'])):
print("Vatcheck: " + str(round(row/maxval * 100, 2)) + " %")
if pd.isna(dataframe['Vat-ID'][row]):
checked.append('No Vat Number')
else:
#check if vat id contains country code
groups = re.match(r'[A-Z][A-Z]', dataframe['Vat-ID'][row])
if groups != None:
querystring = dataframe['Vat-ID'][row][:-2]
country = dataframe['Vat-ID'][row][-2:]
#else get VAT-ID from Country ISO
else:
querystring = dataframe['Vat-ID'][row]
country = dataframe['Land-ISO2'][row]
try:
result = pyvat.check_vat_number(str(querystring), str(country))
checked.append(result.is_valid)
except:
checked.append('Query Error')
progress_var.set(row)
root.update()
root.destroy()
root.quit()
root.after(100, loop_function)
root.mainloop()
dataframe['Vat-ID-check'] = checked
return dataframe
This function gets called by the main script. Here the progressbar window is shown yet the bar doesn't fill up.
With print("Vatcheck: " + str(round(row/maxval * 100, 2)) + " %") I can still track the progress but it's slightly ugly.
Earlier in the main script the user already interacts with a Tkinter GUI but afterwards I close those windows and loops with root.destroy()' and 'root.quit() so I think it should be fine to run another Tkinter instance like this?
Any help or hints would be greatly appreciated.
as #jasonharper mentioned above changing progress_var = tk.DoubleVar() to progress_var = tk.DoubleVar(root) works
I am trying to create a harmless prank joke on my friends, and I want the background of a python tkinter window(not canvas) to change to a random colour every second, then, after ten rounds, it will destroy itself. The problem is that when root.config(background=random_colour)is called, it will not change it's background colour. The entire code is below:
from tkinter import *
import pyglet
import time
import random
root = Tk()
text = Label( padx = 1000, pady = 999, text = 'VIRUS!' )
text.pack()
text.config(font=('Courier', 44))
root.attributes("-fullscreen", True)
root.update()
I'm cutting this bit out because it's just a list of all the named colours in python(It's called COLOURS).
for x in range(0, 9):
colours_length = len(COLOURS)
number = random.randint(0, colours_length)
random_colour = COLOURS[number]
root.config(background=random_colour)
time.sleep(1)
root.update()
root.destroy()
I've took acw1668's advice from the comments section, and it works now. Turns out that the label was covering the entire root window, and that was why it wasn't working.
I am fairly new to python and am currently working on a school project, my aim is to create a search bar that can be used to search a data file, however I am struggling to get the search bar to work correctly. I am using the tkinter entry widget.
When I call .get(), the string in the entry widget is not printed. Here is my code...
from tkinter import *
def searchButton():
text = searched.get()
print (text)
def drawStatWindow():
global searched
statWindow = Tk()
statWindow.title("View Statistics")
statWindow.config(bg = "grey")
statWindow.geometry('800x900')
searched = StringVar()
searchBox = Entry(statWindow, textvariable = searched)
searchBox.place(x= 450, y=50, width = 200, height = 24)
enterButton = tkinter.Button(statWindow, text ="Enter", command =searchButton)
enterButton.config(height = 1, width = 4)
enterButton.place(x=652, y=50)
drawStatWindow()
When I type a string into the entry widget and press the enter button, nothing happens.
Like I say I am not very experienced and this is my first project, but after reading about the tkinter entry widgets I can't understand why this won't work.
I am using python V3.4.0
Thanks.
Your code lacks a call to mainloop(). You could try adding it to the end of the drawStatWindow() function:
statWindow.mainloop()
You might want to restructure your code into a class. This allows you to avoid using global variables and generally provides better organisation for your application:
from tkinter import *
class App:
def __init__(self, statWindow):
statWindow.title("View Statistics")
statWindow.config(bg = "grey")
statWindow.geometry('800x900')
self.searched = StringVar()
searchBox = Entry(statWindow, textvariable=self.searched)
searchBox.place(x= 450, y=50, width = 200, height = 24)
enterButton = Button(statWindow, text ="Enter", command=self.searchButton)
enterButton.config(height = 1, width = 4)
enterButton.place(x=652, y=50)
def searchButton(self):
text = self.searched.get()
print(text)
root = Tk()
app = App(root)
root.mainloop()
You have to add mainloop() because tkinter needs it to run.
If you run code in IDLE which use tkinter then IDLE runs own mainloop() and code can work but normally you have to add mainloop() at the end.
And you have to remove tkinter in tkinter.Button.
from tkinter import *
def searchButton():
text = searched.get()
print(text)
def drawStatWindow():
global searched
statWindow = Tk()
statWindow.title("View Statistics")
statWindow.config(bg="grey")
statWindow.geometry('800x900')
searched = StringVar()
searchBox = Entry(statWindow, textvariable=searched)
searchBox.place(x= 450, y=50, width=200, height=24)
# remove `tkinter` in `tkinter.Button`
enterButton = Button(statWindow, text="Enter", command=searchButton)
enterButton.config(height=1, width=4)
enterButton.place(x=652, y=50)
# add `mainloop()`
statWindow.mainloop()
drawStatWindow()
No need to use textvariable, you should use this:
searchBox = Entry(statWindow)
searchBox.focus_set()
searchBox.place(x= 450, y=50, width = 200, height = 24)
then you will be able to use searchBox.get(), that will be a string.
I have a window containing a label w whose text can be any of a given variety (in this case "Hello World! " once, twice and thrice):
from Tkinter import *
import time
root = Tk()
text = "Hello, World! "
w = Label(root)
for i in range(1, 4):
w["text"] = text*i
w.update_idletasks()
w.grid()
w.update_idletasks()
time.sleep(1)
root.mainloop()
I would like to set the size of the window to a fixed width. This width should be the one which is required for the longest text that w can get. How can I do this most easily? Do I have to cycle through all possible texts, read the respective window width and set the final width to the maximum of these values? If this is the best way, how can I do this without the window appearing on the screen?
How can you know the size of the largest text if you don't cycle through them ? The only possibility would be knowing the size of each one earlier, but then you would have solved the problem already. Therefore all you have to do is set the label and check the required width for the window, then you check whether this width is larger than the current maximum and update it if needed. If the window happens to show during this process, you can call withdraw, do everything you need, and then call deiconify.
import time
import random
import Tkinter
root = Tkinter.Tk()
root.withdraw()
text = "Hello, World! "
w = Tkinter.Label()
w.grid()
maxwidth = 0
for _ in range(10):
i = random.randint(1, 5)
w["text"] = text*i
print i
w.update_idletasks()
maxwidth = max(maxwidth, root.winfo_reqwidth())
root.wm_minsize(maxwidth, root.winfo_reqheight())
root.wm_maxsize(maxwidth, int(1e6))
root.deiconify()
root.mainloop()
You can set a fixed width for the label, and wrap the text using the textwrap module. textwrap.wrap(text, width) will split text into lines no longer than width characters. It also has options for breaking long words or hyphens, but see the documentation for that.
from Tkinter import *
import time
import textwrap
root = Tk()
text = "Hello, World! "
w = Label(root, width=35)
w.grid()
for i in range(1, 4):
w.update()
s = text*i
s = "\n".join(textwrap.wrap(s, 21))
w["text"] = s
time.sleep(1)
root.mainloop()