I was trying to create a QRcode generating app in python with tkinter that you enter color and then text and it generates a QRcode but it closes instantly upon startup. (the problem did not happen when I didn't have the color part), (in the future I'm also planning to add a save QR as png button)
here's what I have:
from tkinter import *
from tkinter import messagebox
import pyqrcode
from tkinter import colorchooser
import re
def choose_color():
x = 0
# variable to store hexadecimal code of color
color_code = colorchooser.askcolor(title ="Choose color")
print(color_code)
x = 1
root = Tk()
button = Button(root, text = "Select color",
command = choose_color)
button.pack()
if 'x' == 1:
str = 'color_code' # Your Hex
match = re.search(r'^#(?:[0-9a-fA-F]{3}){1,2}$', str)
if match:
print('Hex is valid')
ws = Tk()
ws.title("PythonGuides")
ws.config(bg='color_code')
def generate_QR():
if len(user_input.get())!=0 :
global qr,img
qr = pyqrcode.create(user_input.get())
img = BitmapImage(data = qr.xbm(scale=8))
else:
messagebox.showwarning('warning', 'All Fields are Required!')
try:
display_code()
except:
pass
def display_code():
img_lbl.config(image = img)
output.config(text="QR code of " + user_input.get())
lbl = Label(
ws,
text="Enter message or URL",
bg='color_code'
)
lbl.pack()
user_input = StringVar()
entry = Entry(
ws,
textvariable = user_input
)
entry.pack(padx=10)
button = Button(
ws,
text = "generate_QR",
width=15,
command = generate_QR
)
button.pack(pady=10)
img_lbl = Label(
ws,
bg='color_code')
img_lbl.pack()
output = Label(
ws,
text="",
bg='color_code'
)
output.pack()
ws.mainloop()
else:
print('Hex is not valid')
The reason the program closes immediately is because there is no root.mainloop(). Even if there was, there are a lot of other errors that would prevent the program from working.
The first problem is if 'x' == 1. Here you are comparing the literal string "x" to the number 1. These are never going to be equal, so the other window will never show up. I can see what you are trying to do with x, but it won't work as you expect. It is better just to get rid of x completely and call a function after the user selects a colour. I've called this function show_qr_window.
The second problem is how you get the hex code. You use the output of colorchooser.askcolor, which is a tuple containing an rgb tuple representing the colour and it's hex value. You only want the hex value, so you want color_code[1], as the hex value is the second item. I've also added an if statement to make sure color_code is not None. color_code will be None if the user does not choose a colour and just closes the window. If the user has chosen a colour, it is passed to show_qr_window. Because we've checked the user has chosen a colour, you can get rid of all of the other validation as colorchooser will always return a valid hex value. You also no longer have to import re.
The third issue is that you've used Tk twice. This will cause your program to not work properly. Instead, change ws = Tk() to ws = Toplevel().The next issue is str = 'color_code'. This is not how you define a variable. You want to do color_code = 'a string'. In this case, the string is passed to show_qr_window as the variable color, so you can use color_code = color. You also have to change all of the bg = 'color_code' to bg = color_code, as color_code is a variable, not a string. The rest of your code seems to work (I haven't tested the qr code generation as I don't have that module installed). Here is the code with all of the fixes:
from tkinter import *
from tkinter import messagebox
import pyqrcode
from tkinter import colorchooser
def choose_color():
# variable to store hexadecimal code of color
color_code = colorchooser.askcolor(title ="Choose color")
if color_code != None:
show_qr_window(color_code[1])
root = Tk()
button = Button(root, text = "Select color",
command = choose_color)
button.pack()
root.mainloop()
def show_qr_window(color):
ws = Toplevel()
color_code = color
ws.config(bg = color_code)
def generate_QR():
if len(user_input.get())!=0 :
global qr,img
qr = pyqrcode.create(user_input.get())
img = BitmapImage(data = qr.xbm(scale=8))
else:
messagebox.showwarning('warning', 'All Fields are Required!')
try:
display_code()
except:
pass
def display_code():
global img
img_lbl.config(image = img)
output.config(text="QR code of " + user_input.get())
lbl = Label(
ws,
text="Enter message or URL",
bg=color_code
)
lbl.pack()
user_input = StringVar()
entry = Entry(
ws,
textvariable = user_input
)
entry.pack(padx=10)
button = Button(
ws,
text = "generate_QR",
width=15,
command = generate_QR
)
button.pack(pady=10)
img_lbl = Label(
ws,
bg=color_code)
img_lbl.pack()
output = Label(
ws,
text="",
bg=color_code
)
output.pack()
ws.mainloop()
Assuming generate_QR() and display_code() work as they should (I haven't tested them but they look fine), this code will run as expected.
Related
Hope you all in good.
I'm trying to code with python to make google do translate. It has been successfully done, but now 1 challenge is i don't want to press on the translate button, i want it automatically after inputing the text in the input field without press on the translate button ? Can you please help suggest some idea to me to do this ?
my code as belơw:
import tkinter as tk
from tkinter import Button, Frame, font
from tkinter.constants import BOTTOM, END
from typing import Text
import googletrans
#print(googletrans.LANGUAGES)
root = tk.Tk()
from googletrans import Translator
# t = Translator()
# b = a.text
# print(b)
root.geometry("720x900")
root.title("google translator")
title1 = tk.Label(
root,
text="Google Translator",
font=('arial',20)
)
# title2 = tk.Label(
# root,
# text="put what you need to translate to Vietnamese",
# font=('Arial',15),
# )
title1.pack(pady=5)
# title2.pack(pady=5)
# box1 = Text(root, width=30,height=10, font=('arial',12))
box = tk.Text(
root,
width=55,
height=15,
font=('Roboto',14)
)
box.pack(pady=10)
def tran():
input1 = box.get("1.0","end")
t=Translator()
print(input1)
a = t.translate(input1,src='en',dest='vi')
b = a.text
box1.insert(END,b)
def clear():
box.delete("1.0","end")
box1.delete("1.0","end")
Button_frame=tk.Frame(root).pack(side=BOTTOM)
clear_button = tk.Button(
Button_frame,
text="clear content",
font=('Arial',10,'bold'),
bg = '#303030',
fg="#FFFFFF",
command=clear
)
trans_button = tk.Button(
Button_frame,
text="translate",
font=('Arial',10,'bold'),
bg = 'yellow',
fg="red",
command=tran
)
clear_button.place(x=290,y=410)
trans_button.place(x= 150,y=410)
# clear_button.pack(pady=5)
#clear_button.pack(pady=5)
box1 = tk.Text(
root,
width=55,
height=15,
font=('Roboto',14)
)
box1.pack(pady=60)
root.mainloop()
Hello I think what you need here is using the .trace_add() method so you can trigger an event which is the translation method in your case whenever you write in the box.
You need to assign StringVar() to both text variables.
Next, you have to setup the .trace_add ('w',tran)(where the "w" means write)
I'm using python to interact with some excel spreadsheets. I have all that working and now I'm working on a UI using tkinter. I have 3 buttons one to pull the location of a data file, output file save location and I have a start button.
I'm trying to use a tkinter.Label to display the value of the first two buttons, example "c:/user/data_file". However, when ever I get the variable from the user and try to update the GUI with it, a copy of the window is created with the updated information. I need it to update directly to the current window seamlessly. I've been working to try to resolve this, but I just can't figure it out. Below is the code for my tkinter stuff.
def main():
def InputFilePrompt():
global InputFileLocation
InputFileLocation = askopenfilename()
update()
def OutputFilePrompt():
global OutputFileLocation
OutputFileLocation = filedialog.asksaveasfilename()
update()
def update():
root = Tk()
root.title("test")
root.resizable(width=TRUE,height=TRUE)
InputFile = Button(root, text = "input data", command = InputFilePrompt)
InputFile.grid(row = 0,column = 0)
InputFileValue = Label(root, text = InputFileLocation, bg = 'white')
InputFileValue.grid(row = 1,column = 0)
OutputFile = Button(root, text = "Compiled Data save loacation", command = OutputFilePrompt)
OutputFile.grid(row = 4,column = 0)
OutputFileValue = Label(root, text = "location: N/A", bg = 'white')
OutputFileValue.grid(row = 5,column = 0)
startButton = Button(root, text = "start", bg = 'light green', command = Excel)
startButton.grid(row = 7)
BlankUI = [0 for x in range(2)]
for blankspace in range(2):
BlankUI[blankspace] = Label(root, text = "")
BlankUI[0].grid(row = 2)
BlankUI[1].grid(row = 6)
root.mainloop()
update()
Error:
Here's a version that doesn't create the duplicate window. I've incorporated most of the suggestions I made in comments—except for the one about defining functions inside of other functions. The following still does this because doing so made it very easy to avoid using global variables (which are generally considered a poor programming practice).
Notice that there's no update() function. The values of the two tkinter.Labels are now being stored in two tkinter.StringVars objects instead of in regular Python strings. A StringVar is one of the tkinter so-called "Variable" classes. Their primary feature is that they will cause all widgets referencing them to automatically update themselves whenever their contents get changed. To use them in a Label, they're specified by using the textvariable= option (instead of the text= option) when the constructor is called.
Here's some documentation I found about them with more details on how they work.
import tkinter as tk
from tkinter.filedialog import askopenfilename, asksaveasfilename
def excel():
""" Undefined. """
pass
def main():
def get_input_file_location():
input_file_location.set(askopenfilename())
def get_output_file_location():
output_file_location.set(asksaveasfilename(confirmoverwrite=False))
root = tk.Tk()
root.title('test')
root.resizable(width=True, height=True)
input_file_location = tk.StringVar()
input_file_location.set('<undefined>')
output_file_location = tk.StringVar()
output_file_location.set('<undefined>')
input_file = tk.Button(root, text="Input data",
command=get_input_file_location)
input_file.grid(row=0, column=0)
input_file_value = tk.Label(root, textvariable=input_file_location,
bg='white')
input_file_value.grid(row=1, column=0)
output_file = tk.Button(root, text='Compiled data save loacation',
command=get_output_file_location)
output_file.grid(row=4, column=0)
output_file_value = tk.Label(root, textvariable=output_file_location,
bg='white')
output_file_value.grid(row=5, column=0)
startButton = tk.Button(root, text='start', bg='light green',
command=excel)
startButton.grid(row=7)
blank_ui = [tk.Label(root, text='') for _ in range(2)]
blank_ui[0].grid(row=2)
blank_ui[1].grid(row=6)
root.mainloop()
if __name__ == '__main__':
main()
I wrote an Arduino code which reacts to buttons and physical interactions and then send the results to the computer on which my python program (2.7) is running.
The python code has two functions:
Create a new text file named after the unixtimestamp and fill it
with all the data it receives.
Look through the data it receives for the code phrases "a1" and "b1"
and then show the corresponding image.
When the Arduino starts it will send the "a1" as a first value to fill the window. After that, it should switch based on the data it sends.
This is my current code:
from Tkinter import *
from random import *
import serial
import time
root = Tk()
prompt = StringVar()
root.title("vision")
label = Label(root, fg="dark green")
label.pack()
frame = Frame(root,background='red')
frame.pack()
canvas = Canvas(height=200,width=200)
canvas.pack()
timestamp = int(time.time())
filename=str(timestamp)+".txt"
f = open(str(filename),"w")
f.write("\n")
f.write(str(filename))
f.write("\n")
arduino = serial.Serial('COM5', 115200, timeout=.1)
while True:
data = arduino.readline()[:-2] #the last bit gets rid of the new-line chars
print data
f.write(str(data))
f.write("\n")
#Invoking through button
TextWindow = Label(frame,anchor = NW, justify = LEFT, bg= 'white', fg = 'blue', textvariable = prompt, width = 75, height=20)
TextWindow.pack(side = TOP)
if data == "a1":
canvas.delete("all")
image1 = PhotoImage(file = "c2.gif")
canvas.create_image(0,0,anchor='nw',image=image1)
canvas.image = image1
if data == "b1":
canvas.delete("all")
image1 = PhotoImage(file = "c2.gif")
canvas.create_image(0,0,anchor='nw',image=image1)
canvas.image = image1
root.mainloop()
It generates the window but it is empty.
I can not seem to find where my error is.
Additionaly:
I used an other tutorial wich gave me he basic code for the gui and images. In this there are two buttons wich switch the images which works.
from Tkinter import *
from random import *
pathy = randint(1, 2)
root = Tk()
prompt = StringVar()
root.title("vision")
label = Label(root, fg="dark green")
label.pack()
frame = Frame(root,background='red')
frame.pack()
canvas = Canvas(height=200,width=200)
canvas.pack()
def Image1():
canvas.delete("all")
image1 = PhotoImage(file = "c2.gif")
canvas.create_image(0,0,anchor='nw',image=image1)
canvas.image = image1
def Image2():
canvas.delete("all")
image1 = PhotoImage(file = "c1.gif")
canvas.create_image(0,0,anchor='nw',image=image1)
canvas.image = image1
TextWindow = Label(frame,anchor = NW, justify = LEFT, bg= 'white', fg = 'blue', textvariable = prompt, width = 75, height=20)
TextWindow.pack(side = TOP)
conversationbutton = Button(frame, text='right button',width=25,fg="green",command = Image1)
conversationbutton.pack(side = RIGHT)
stopbutton = Button(frame, text='left button',width=25,fg="red",command = Image2)
stopbutton.pack(side = RIGHT)
root.mainloop()
Once the mainloop() function has been called you have to use callbacks in order to run your own code. The Tkinter after() method can be used to run a section of code after a set amount of time.
In your case your code would look something like:
def update():
#your code here
root.after(1000, update)
update()
root.mainloop()
Calling root.after() inside of the update functions allows the function to keep running until the window is closed.
The after method as described at effbot gives the arguments as:
root.after(milliseconds, callback)
In your case you might have to call your processing code more often then every second.
I was wondering how you get the tkinter to notify the user if their input is invalid. When they input a negative integer or something that's not an integer, a dialog would pop up and say that their input is invalid. It would then let the user know and then it would let the user go back to the program. I've got the 2nd part working, but I'm getting some errors when I try to do the invalid input popup. It also pops up 2 windows as well which I have no idea why.
Code in question:
import tkinter
from tkinter import *
import tkinter as tk
class TimeConverterUI():
def __init__(self):
#main functions
self.root_window = Tk()
self.root_window.geometry('400x150')
self.root_window.title('Seconds Converter')
self.text()
self.quitValue=tk.Toplevel()
self.invalidinputDialog=tk.Toplevel()
self.calculate_button()
self.quit_button()
self.root_window.wait_window()
def text(self):
#label for seconds text along with the grid for it
row_label = tkinter.Label(
master = self.root_window, text = 'Seconds: ')
row_label.grid( row = 0,
sticky = tkinter.W)
self.secondsEntry = Entry(master = self.root_window)
self.secondsEntry.grid(row = 0, column = 1)
#label for converted time along with the grid
convert_label = tkinter.Label(
master = self.root_window, text = 'Converted Time(H:M:S): ')
convert_label.grid(row=1)
self.result = Entry(master= self.root_window)
self.result.grid(row = 1, column = 1)
def calculate_button(self):
#calculate button along with the placement
quit = Button(self.root_window, text = "Calculate", command = self.calculate)
quit.grid(row = 3, column = 0, columnspan = 3, pady=20,
sticky = tkinter.W)
def calculate(self):
try:
#divides the seconds into minutes
m,s = divmod(int(self.secondsEntry.get()),60)
#divides the minutes into hours and returns h:m:s format
h,m = divmod(m,60)
c= ("%d:%02d:%02d" % (h, m, s))
#after displaying the result, if the user wants to calculate again, deletes
#previous result and recalculates
self.result.delete(0,END)
self.result.insert(0,c)
except ValueError:
#if user enters an input that's not an integer, exception is placed
#d= 'Invalid Input'
self.invalidinputDialog()
def invalidinputDialog(self):
self.invalidValue = tk.Toplevel()
messageLabel = tk.Label(master=self.invalidValue,
text="Invalid Input.").grid(row=0,column=0)
invalidContinue = tk.Button(master=self.invalidValue, text='Close',
command = self.invalidValue.destroy).grid(row=1,column=1)
self.result.delete(0,END)
self.result.insert(0,d)
def quit_button(self):
#button for grid
quit = Button(self.root_window, text = "Quit", command = self.quitDialog)
quit.grid(row = 3, column = 3, columnspan = 3, pady=20,
sticky = tkinter.E)
def quitDialog(self):
self.quitValue = tk.Toplevel()
messageLabel = tk.Label(master=self.quitValue,
text="Are you sure you want to quit?").grid(row=0,column=0)
#closes both the main window and the message window
continueButton = tk.Button(master=self.quitValue,text='Continue',
command=self.root_window.destroy).grid(row=1,column=2)
#lets the user go back to previous screen if they cancel
cancelButton = tk.Button(master=self.quitValue,text='Cancel',
command=self.quitValue.destroy).grid(row=1,column=1)
def quit(self) -> bool:
#quits the program and shell is refreshed
self.root_window.destroy()
return True
if __name__ == '__main__':
convert=TimeConverterUI()
Here's where the problem lies.
def calculate(self):
try:
#divides the seconds into minutes
m,s = divmod(int(self.secondsEntry.get()),60)
#divides the minutes into hours and returns h:m:s format
h,m = divmod(m,60)
c= ("%d:%02d:%02d" % (h, m, s))
#after displaying the result, if the user wants to calculate again, deletes
#previous result and recalculates
self.result.delete(0,END)
self.result.insert(0,c)
except ValueError:
#if user enters an input that's not an integer, exception is placed
#d= 'Invalid Input'
self.invalidinputDialog()
def invalidinputDialog(self):
self.invalidValue = tk.Toplevel()
messageLabel = tk.Label(master=self.invalidValue,
text="Invalid Input.").grid(row=0,column=0)
invalidContinue = tk.Button(master=self.invalidValue, text='Close',
command = self.invalidValue.destroy).grid(row=1,column=1)
self.result.delete(0,END)
self.result.insert(0,d)
If you are looking to simply tell the user the input was invalid you can do
from tkinter import messagebox
messagebox.showinfo("Title", "Input invalid.")
Messagebox does need to be imported separately from tkinters main library.
That being said you need to import tkinter only once. You are currently importing tkinter 3 times with:
import tkinter
from tkinter import *
import tkinter as tk
instead you should use:
import tkinter as tk
you can use this for most of tkinter methods. You just need to use the prefix tk. on your widgets.
examples tk.Entry(), tk.Label(), tk.Text() and so on.
As for your extra blank windows that are opening they are coming from your __init__ portion of your class.
class TimeConverterUI():
def __init__(self):
self.quitValue=tk.Toplevel() # causing an empty toplevel window to open in init
self.invalidinputDialog=tk.Toplevel() # causing an empty toplevel window to open in init
You do not need to set up the toplevel ahead of time. You can simply create it in a method when you need one.
The program is meant to review a set of sentences one at a time. I want to show one and then when the "next" button is clicked, it shows the next input. Right now it blasts through them. How do I get it to stop? I have a feeling I'm missing something small.
So here's the code:
from Tkinter import *
import ttk
root = Tk()
def iterate(number):
return number + 1
inputs = open("inputs.txt").readlines
lines = inputs()
numlines = len(lines)
x=0
for tq in lines:
sentence = lines[x].strip('\n')
sen = StringVar()
sen.set(sentence)
x = iterate(x)
ttk.Label(textvariable = sen).grid(column=1, row=1, columnspan=99)
ttk.Button(text = "next", command = x).grid(column=99, row=5, pady=5)
root.update()
root.mainloop()
To change what is displayed in a label you can call the configure method, giving it any of the same arguments you give when you create it. So, you would create a single label, then call this method to modify what is displayed.
The basic logic looks like this:
def do_next():
s = get_next_string_to_display()
the_label.configure(text=s)
the_label = ttk.Label(...)
the_button = ttk.Button(..., command=do_next)
This is the code I ultimately used to solve the issue:
from Tkinter import *
import ttk
root = Tk()
root.title("This space intentionally left blank")
root.minsize(800,200)
mainframe = ttk.Frame(root)
mainframe.grid(column = 0, row = 0)
def nextInputs(*args):
sen.set(inputs())
inputs = open("inputs.txt").readline
sen = StringVar()
ttk.Label(mainframe, textvariable=sen).grid(column=1, row=1, columnspan=99)
Button = ttk.Button(mainframe, text = "next", command = nextInputs).grid(column=99, row=5, pady=5)
root.bind('<Return>', nextInputs)
root.mainloop()