Hi Tkinter and Python Masters,
Here's my problem. I'm creating a simple GUI with Tkinter. I have a background image that I would like to change based on the value of a variable defined in a function that connects to an API (JSON). The variable will hold one of two values. Either a 1 or a 2.
What I would like to do in Tkinter (which I'm totally lost on) is have a background image. If the value of the variable in my API function is 1 show Image1 as the background. If the value of the variable is 2, show Image2 as the background.
It is a bit messy, but here's my API function
def apiconnect(statusvar):
def to_serializable(ticketid):
return str(ticketid)
url = "http://staging2.apiname.com/ticket_api/tickets"
data = {'ticket_id' : ticketid, 'direction' : 'up'}
headers = {'Content-Type' : 'application/json', 'Authorization' : 'J0XxxxxVRy9hMF9Fo7j5'}
r = requests.post(url, data=json.dumps(data), headers=headers)
requestpost = requests.post(url, headers = headers, json = data)
response_data = requestpost.json()
statusvar = (response_data["status"])
messagevar = (response_data["message"])
json.dumps(url,data)
global accessResult
if statusvar == "successful":
accessResult = 1
else:
accessResult = 2
Is this possible in Tkinter? I basically want to reference my variable accessResult in my Tkinter frame, and change the background image based on that value.
Be gentle with me, I'm all new and such
So I'm no expert with Tkinter but if you want to change the background based on only two values why not use a boolean instead so:
# Here is where we make the check.
if accessResult == True:
background_photo = PhotoImage(file = "C:\\Path\\To\\My\First\\\Photo1.png")
else:
background_photo = PhotoImage(file = "C:\\Path\\To\\My\\Second\\Photo2.png")
backgroundLabel = Label(top, image=backgroundPhoto)
backgroundLabel.place(x=0, y=0, relwidth=1, relheight=1)
Good luck! Hope this helps!
Related
I'm using an API to convert one unit to another. I'm trying to get input from user by "Entry Widget" as floating number. This is my code.
import requests
import tkinter as tk
root = tk.Tk()
def pressMe():
out_entry.insert(1, f'{result}')
in_entry = tk.Entry(root)
in_entry.pack()
out_entry = tk.Entry(root)
out_entry.pack()
but = tk.Button(root, command=pressMe)
but.pack()
val = float(in_entry.get())
url1 = "https://measurement-unit-converter.p.rapidapi.com/length/units"
querystring = {"value":val,"from":"km","to":"m"}
headers = {
"X-RapidAPI-Key": "0760466864***********************4jsnb3eaeb63d084",
"X-RapidAPI-Host": "measurement-unit-converter.p.rapidapi.com"
}
response = requests.request("GET", url1, headers=headers, params=querystring)
data = response.json()
result = data['result']
root.mainloop()
In here I'm making first entry widget in_entry by which I can take input and the second one out_entry to show the output, one button is made to do so. But I'm getting this error.
Traceback (most recent call last):
File "d:\5ht project\check.py", line 290, in <module>
val = float(in_entry.get())
ValueError: could not convert string to float: ''
I know that this problem is because I'm trying to convert the empty string into float which is not possible. But I'm not able to find any solution to this. Is there any way by which I can have input from user by in_entry and after that I can use that value in API which can return me the converted value, and then I can insert this converted value to the second entry widget out_entry. Hope you get my question.
This is the link of API I'm using.
https://rapidapi.com/me-Egq5JBzo4/api/measurement-unit-converter/
it is as jasonharper said: "You are calling .get() on your Entry a millisecond or so after it was created - it's not physically possible for the user to have typed in anything yet!"
what you can do:
import requests
import tkinter as tk
root = tk.Tk()
in_entry = tk.Entry(root)
in_entry.pack()
out_entry = tk.Entry(root)
out_entry.pack()
url1 = "https://measurement-unit-converter.p.rapidapi.com/length/units" #this is a constant, isn't it?
def pressMe(): # the in entry must be above because this function it will get the value
val = float(in_entry.get()) # you get the value here to make sure the user has clicked the button (then you know there is a number in the entry)
querystring = {"value":val,"from":"km","to":"m"}
headers = {
"X-RapidAPI-Key": "0760466864***********************4jsnb3eaeb63d084",
"X-RapidAPI-Host": "measurement-unit-converter.p.rapidapi.com"
} # maybe also a constant? you can this piece of code also place at the top of your program
response = requests.request("GET", url1, headers=headers, params=querystring)
data = response.json()
result = data['result'] #here i get an keyerror because i'm not subscribed
out_entry.insert(1, f'{result}')
but = tk.Button(root, command=pressMe) # the button is created here, because its command is pressme. for that, it's really important that it is below pressme
but.pack()
root.mainloop()
then i can't help you further because the only thing i get from your url is:
{'message': 'You are not subscribed to this API.'}
When I try to translate text using the googletrans module, I get an error:
httpcore._exceptions.ConnectTimeout: _ssl.c:1106: The handshake operation timed out
Here's my code:
from tkinter import *
from googletrans import Translator , LANGUAGES
root = Tk()
root.geometry("500x500")
def translate():
translator = Translator()
translated_text = translator.translate(text=entry.get(),
dest=languages_listbox.get(languages_listbox.curselection())) # Text does not get get translated and it throws an error
output_label.config(text = f"Translated Text: {translated_text}")
entry = Entry(root , font = "consolas 14")
entry.place(x = 120 , y = 0)
entry.insert(0 , "Hello world")
languages_list = []
for key, value in LANGUAGES.items():
languages_list.append(value)
languages_listbox_frame = Frame(root)
languages_listbox_frame.place(x = 120 , y = 50)
languages_listbox = Listbox(languages_listbox_frame , font = "calibri 14")
languages_listbox.grid(row = 0 , column = 0)
scrollbar = Scrollbar(languages_listbox_frame , orient = VERTICAL , command = languages_listbox.yview)
scrollbar.grid(row = 0 , column = 1 , sticky = N+S+E+W)
languages_listbox.config(yscrollcommand = scrollbar.set)
for language in languages_list:
languages_listbox.insert(END , language)
languages_listbox.select_set(0)
translate_button = Button(root , text = "Translate" , font = "comicsansms 18 bold" , command = translate)
translate_button.place(x = 160 , y = 370)
output_label = Label(root , text = "Translated Text: " , font = "comicsansms 16 bold")
output_label.place(x = 5 , y = 460)
mainloop()
My code is very simple and I can't figure out what's wrong with it.
I tried changing the network connection, but it made no difference.
Is there any way to fix this problem?
It would be great if anyone could help me out.
Well that seems very much like an API error as google does not like when you send too much request, I cannot close this question either as the answer there is not an accepted one, anyway here is an alternative using deep_translator.
Start by installing it:
pip install deep-translator
Now I recommend you take a stroll down its docs, but ill include an example using Google Translate anyway. Start by importing it:
from deep_translator import GoogleTranslator
Now create an initial instance of it, just to get the language map.
translator = GoogleTranslator(target='en')
languages_list = []
lang_map = translator.get_supported_languages(as_dict=True) # Get in form of dict
for key, value in lang_map.items():
languages_list.append(key.title()) # Making first letter capital with title()
Now for the translation part, change your function to the following:
def translate():
lang = lang_map[languages_listbox.get(languages_listbox.curselection()[0]).lower()] # Get the corresponding language code from the dictionary
translator = GoogleTranslator(source='en',target=lang) # Create new instance with selected language
translated_text = translator.translate(entry.get()) # Translate
output_label.config(text = f"Translated Text: {translated_text}") # Update the text
Yes creating a new instance every time function is run is not a good idea, but I couldn't find another successful method to change the target language once it is initially set. It does not seem to give any error as of now, unless your source and target languages are both same.
On a side note, it is better to use threading, as sometimes the API might take time to respond and it will freeze the GUI.
Here is a part of my code, which loads images in a LabelFrame based on JSON objects from an external file. The code is inside a function (seems like that plays a role too, who knows).
# the black blackboard where images will be stored
black_background = tk.LabelFrame(pivote_tab, width=1340, height=290, bg="black")
black_background.grid(row=0, column=0, sticky="E")
# open the .json file
json_file = open('path/to/file.json', 'r')
json_data = json_file.read()
#the init position for image inside the blackboard
live_pc_position = 10
# make a loop for every object inside JSON
obj = json.loads(json_data)
for i in range(int(len(obj))):
os = (str(obj[i].get('operating_system')))
if "Mac" in os:
img_src = "image/macos_pc.png"
elif "Win" in os and "10" in os:
img_src = "image/windows_10.png"
elif "Linux" in os:
img_src = "image/linux_pc_image.png"
else:
img_src = "image/undetected_pc.png"
# defining the image based on operating system and store it to the pc_image variable
pc_image = PhotoImage(file=img_src)
# adding the computer icon inside the blackboard
computer_icon = Label(black_background, image=pc_image, bg="black")
computer_icon.place(x=live_pc_position, y=10)
# update values so the next image will load to the right
live_pc_position = live_pc_position + 40
The script doesn't make any error, however for some reason only the first image is displayed when there are more images expected to be loaded, because JSON has more objects.
This is what I was suggesting in my comment. See ALL CAPS COMMENT.
obj = json.loads(json_data)
for i in range(int(len(obj))):
os = (str(obj[i].get('operating_system')))
...
# defining the image based on operating system and store it to the pc_image variable
pc_image = PhotoImage(file=img_src)
# adding the computer icon inside the blackboard
computer_icon = Label(black_background, image=pc_image, bg="black")
computer_icon.img = pc_image # KEEP A REFERENCE SO IMAGE IS NOT GARBAGE COLLECTED.
computer_icon.place(x=live_pc_position, y=10)
...
The problem with image is not loading in tkinter is almost always related to this.
At every loop you replace the value in pc_image and python garbage collector discards the Tkinter image object. The solution is to storage each Tkinter object in a different variable, which can be done with an object attribute or a list like the example bellow:
pc_images=[]
for i in range(int(len(obj))):
...
pc_images.append(PhotoImage(file=img_src))
Label(black_background, image=pc_images[i], bg="black").place(x=live_pc_position, y=10)
live_pc_position = live_pc_position + 40
The script is from #flavio-moraes logically works, however with a mix of the answers I got, I made the final script which fullfills my needs.
pc_images=[]
for i in range(int(len(obj))):
...
pc_images.append(PhotoImage(file=img_src))
live_pc_position = 10
for pc in pc_images:
#create the image
computer_icon = Label(black_background, image=pc, bg="black")
computer_icon.img = pc_images
computer_icon.place(x=live_pc_position, y=10)
# update values so the next image will load to the right
live_pc_position = live_pc_position + 40
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I am creating a GUI that is meant to emulate an online shop of some sort.
One part of the task is to have a button that will generate a HTML document with images of the user's chosen product category.
Below I have provided my four radio buttons along with their IntVar and commands.
Each of the RadioButton commands do the same thing but extract information from different websites, so for brevity I have only provided the command for the slipper category.
home_hobbies = Tk()
status = IntVar()
def show_slippers():
#open downloaded file to extract info
slipperfile = open('slippers.html','r',encoding = 'utf-8').read()
prices = findall("<span.*value'>(.*)</span>", slipperfile) #regex prices
titles = findall('<h3.*body ">\n\s*(.*)', slipperfile) #regex titles
select_categ.config(state=NORMAL) #make the text box edit-able
select_categ.delete(1.0, END) #delete any text already in the text box
#for loop to find first five items and print them
for i in range(5):
title = titles[i]
price = prices[i]
result = str(i+1) + ". " + title + ' - $' + price + "\n"
select_categ.insert(END, result) #write list of products
select_categ.config(state=DISABLED) #make sure the user can't edit the text box
slippers = Radiobutton(home_hobbies, command = show_slippers, indicator = 'off', variable = status, value = 1, text = 'Winter Slippers')
diy = Radiobutton(home_hobbies, command = show_diy, indicator = 'off', variable = status, value = 2, text = "DIY Supplies")
#newstock radiobuttons
sports = Radiobutton(home_hobbies, command = show_sports, indicator = 'off', variable = status, value = 3, text = "Pool Toys")
novelties = Radiobutton(home_hobbies, command = show_novelties, indicator = 'off', variable = status, value = 4, text = "Novelty Items")
select_categ = Text(home_hobbies, wrap = WORD, font = content_font, bg = widgetbg, fg = fontcolour, width = 40)
Above, I also provided the line of code that generates the Text widget as it may help in answering my question (I don't have a very deep understanding of this widget despite reading the effbot page about 20 times over).
I now have a different button whose task is to generate a HTML doc with it's own command, "show_img":
htmlshow = Button(home_hobbies, text = "View Product Images", command = show_img)
I am trying to make the show_img() command work such that I have a preamble of HTML coding, and then, depending on which radibutton has been chosen, the function will replace sections of the code with the corresponding information:
def show_img():
#in this section I write my HTML code which includes replaceable sections such as "image1" and source_url
if slipper_trig:
table = table.replace("source_url", ' Etsy - Shop Unique Gifts for Everyone')
imgfile = open('slippers.html', 'r', encoding = 'utf-8').read()
images = findall('<img\n*.*image\n*\s*src="(.*)"', imgfile)
for i in range(5):
image = images[i]
table = table.replace("image"+str(i+1), image)
I tried to add BooleanVar into the commands for my Radio Buttons like this:
slipper_trig = False
diy_trig = False
pool_trig = False
novelty_trig = False
#Function for the product category buttons
#
def show_slippers():
#make selected category true and change all others to false
slipper_trig = True
diy_trig = False
pool_trig = False
novelty_trig = False
As a way to distinguish between the categories but the GUI clearly doesn't remember the value of "slipper_trig" after its been defined as true in the "show_slippers" function.
Maybe I need to try and integrate the "show_img" command into my original functions that define the RadioButtons? Maybe I should be figuring out how to determine the category chosen by what's shown in the text box?
Any advice would be appreciated.
Thanks!
You didn't show minimal working code with your problem so I can only show some minimal example with Button and RadioButton to show how to use these widgets.
I don't know if you used command=function_name in Button.
BTW: it has to be function's name without ()
I don't know if you used .get() to get value from StringVar/Intvar/BooleanVar assigned to RadioButtons.
EDIT I added Checkbutton because probably you may need it instead of Radiobutton
import tkinter as tk
# --- functions ---
def on_click():
selected = result_var.get()
print('selected:', selected)
if selected == 'hello':
print("add HELLO to html")
elif selected == 'bye':
print("add BYE to html")
else:
print("???")
print('option1:', option1_var.get()) # 1 or 0 if you use IntVar
print('option2:', option2_var.get()) # 1 or 0 if you use IntVar
if option1_var.get() == 1:
print("add OPTION 1 to html")
if option2_var.get() == 1:
print("add OPTION 2 to html")
# --- main ---
root = tk.Tk()
result_var = tk.StringVar(root, value='hello')
rb1 = tk.Radiobutton(root, text="Hello World", variable=result_var, value='hello')
rb1.pack()
rb2 = tk.Radiobutton(root, text="Good Bye", variable=result_var, value='bye')
rb2.pack()
option1_var = tk.IntVar(root, value=0)
opt1 = tk.Checkbutton(root, text='Option 1', variable=option1_var)
opt1.pack()
option2_var = tk.IntVar(root, value=0)
opt2 = tk.Checkbutton(root, text='Option 2', variable=option2_var)
opt2.pack()
button = tk.Button(root, text='OK', command=on_click)
button.pack()
root.mainloop()
Doc on effbot.org: Button, Radiobutton, Checkbutton
I have a bunch of images which I want the user to select using a scale. As the user updates the scale value, I want the GUI to update which image is shown.
I have just started dealing with GUIs and I'm stuck. I've managed to print the new values from the scale using the command keyword argument of the Scale widget. However, it is not clear how I can get this value to update the image on the interface.
class MainProgram():
def AcquireDicomFiles(self):
# HERE I GET THE IMAGES PATHS. IT WORKS FINE.
def GUI(self):
root_window = Tk()
slice_number = DoubleVar()
bar_length = 200
main_title = Label(root_window, text="Seleção de corte e echo").pack()
scale_slice = Scale(root_window, variable=slice_number, orient=HORIZONTAL, from_=1, to=24, length=bar_length,
cursor="hand", label="Slice Number", command=MainProgram().get_slice_value)
scale_slice.pack(anchor=CENTER)
echo_time = DoubleVar()
scale_echo = Scale(root_window, variable=echo_time, orient=HORIZONTAL, from_=1, to=6, length=bar_length,
cursor="hand", label="Echo Time")
scale_echo.pack(anchor=CENTER)
imagefile = Image.open("image.png")
tk_image = ImageTk.PhotoImage(imagefile)
panel = Label(root_window, image=tk_image).pack(fill="both", expand="yes")
root_window.mainloop()
def get_slice_number(self,user_slice_number):
user_slice_number = np.int(user_slice_number)
def showImage(self):
# Code below works fine for user input in terminal. It uses user_slice_number and user_echo_time to find image. I want these two values to come from the pair of scales
# indexes = np.where(slice_and_echo[:][0] == user_slice_number)[0] #indexes of the elements where the user input match the element
# for i in indexes: #Go through index values. Check and record those in which echo time (element) matches user input
# if slice_and_echo[i][1] == user_echo_time:
# selected_echo_time = user_echo_time
# selected_slice_number = slice_and_echo[i][0]
# index = i
# file_path = os.path.join(dcm_folder, dcm_files[index]) #path of the file whose index match user input
# dcm_read = dicom.read_file(file_path) #read file user wants
# dcm_pixel_values = dcm_read.pixel_array #extract pixel values
slice_and_echo = MainProgram().AcquireDicomFiles()
MainProgram().GUI()
Set echo_time.trace(slider_callback), (which calls the method given to it, whenever the echo_time changes value) and then within slider_callback, you set root_window.iconify(file_name).