Tkinter Enter widget is not taking input into floating number - python

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.'}

Related

How to print row values from their corresponding buttons in a QTableWidget?

Apologies if the title is not clear.
Brief: I'm using PYQT5 to create a table using QTableWidget. To pull data from my server and populate it on the table, I'm using a JSON API. Along with that, I'm inserting a button called "Acknowledge" at the end of every row.
Objective: What I wish to do is every time I click the "Acknowledge" button (shown in the above pic), it should call JSON value from the same API and then print it.
An idea of the API I'm using (Sorry can't post the real data):
[{"Zone":"Zone1","Room":"Room1","Device":"10","date_added":"2022-10-02 01:45:45","data_id":"120"},{"Zone":" Zone2","Room":" Room2","Device":"11","date_added":"2022-11-02 01:19:29","data_id":"121"},{"Zone":" Zone1","Room":" Room1","Device":"12","date_added":"2022-12-02 07:19:11","data_id":"122"}]
Code to insert data and button into the table:
def __init__(self):
self.dictAck = {}
def latestdata(self):
req = requests.get('...') #JSON API
response = req.json()
my_data_str = json.dumps(response)
dataResponse = json.loads(my_data_str)
row=0
self.latestdatatable.setRowCount(len(dataResponse))
for item in dataResponse:
self.my_buttons.append(None)
self.ack_btn = QtWidgets.QPushButton("Acknowledge")
self.ack_btn.setGeometry(QtCore.QRect(500, 290, 112, 34))
self.ack_btn.setStyleSheet("border: none;")
self.ack_btn.setText("")
icon7 = QtGui.QIcon()
icon7.addPixmap(QtGui.QPixmap("images/check.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.ack_btn.setIcon(icon7)
self.ack_btn.setIconSize(QtCore.QSize(40, 35))
self.latestdatatable.setItem(row,0,QtWidgets.QTableWidgetItem(str(item["date_added"])))
self.latestdatatable.setItem(row,1,QtWidgets.QTableWidgetItem(str(item["Zone"])))
self.latestdatatable.setItem(row,2,QtWidgets.QTableWidgetItem(str(item["Room"])))
self.latestdatatable.setItem(row,3,QtWidgets.QTableWidgetItem(str(item["Device"])))
self.latestdatatable.setCellWidget(row, 4, self.ack_btn)
self.dictAck[self.ack_btn] = (row,item["data_id"])
self.ack_btn.clicked.connect(self.acknowledge)
row=row+1
The below function is called when the button is clicked. This is the function I've implemented to print the JSON value. I need to output the value of the data_id key.
def acknowledge(self):
req = requests.get('...') #JSON API
response = req.json()
my_data_str = json.dumps(response)
dataResponse = json.loads(my_data_str)
row=0
self.latestdatatable.setRowCount(len(dataResponse))
for item in dataResponse:
data_id = (str(item["data_id"]))
print(data_id);
Problem: Unfortunately the code above is printing all values after clicking any 1 button instead of the only value I wish to print from the 1 button I clicked from its corresponding row.
Undesirable Result (After clicking the first button, for example):
120 121 122
Expected Result (After clicking the first button, for example):
120
Apologies for asking the question in a complex manner.
You should pass arguments when define connect signal like that:
self.ack_btn.clicked.connect(lambda: self.acknowledge(data_id))
And define acknowledge funciton with data_id argument:
def acknowledge(self, data_id):
print(data_id)

My code isn't getting the values I insert into an entry

I've got some code in python using tkinter which retrieves the name of a room and uses that to to insert into an SQL database the room name and which site it belongs to. However when I run the code its not retrieving the room name from the entry box.
Can anyone help?
def addroom():
global screen14
global roomsinsite
roomsinsite = StringVar()
screen14 = Tk()
screen14.geometry("300x250")
screen14.title("Insert rooms")
Label(screen14, text = "Insert room name:", bg = "LightSkyBlue1", width = "300", height = "2").pack()
Label(screen14, text = "").pack()
roomsinsite_entry = Entry(screen14, textvariable = roomsinsite)
roomsinsite_entry.pack()
Button(screen14, text = "Register room", width = "12", height = "1", command = insertroom).pack()
def insertroom():
sitename4_info = sitename2.get()
print(sitename4_info)
roomname1_info = roomsinsite.get()
print(roomname1_info)
cursor = cnn.cursor()
# SQL to select the siteID and insert rooms for that paticular site.
siteID_fetch3 = "SELECT siteID FROM Sites WHERE siteName = %s"
cursor.execute(siteID_fetch3, [sitename4_info])
siteID_fetch3 = cursor.fetchall()
# print out the values retrieved
print(siteID_fetch3[0][0])
insertRooms = "INSERT INTO `rooms`(`siteID_fk2`, `roomname`) VALUES (%s,%s)"
insertRooms_val = (siteID_fetch3[0][0], roomname1_info)
cursor.execute(insertRooms, insertRooms_val)
# print out the rows inserted.
print(cursor.rowcount)
cnn.commit()
You are probably having more than one Tk in your code, which means your StringVar does not know which Tk to belong to. So here there are three possible solutions:
Avoid using more than one Tk and replace all child windows with Toplevel, so:
screen14 = Toplevel()
roomsinsite = StringVar()
If you are adamant that you want to use more than one instance of Tk then you can specify master for each StringVar, like:
screen14 = Tk()
roomsinsite = StringVar(master=screen14)
To be honest, I wouldn't use StringVar with entry widgets except when I want to use trace, here if the only purpose of using StringVar is for getting the value of the entry widget, then remove it and use get() method of the entry widget, like:
roomname1_info = roomsinsite_entry.get()
The combination of first and third method seems like best practice, if you ask me. Also here, even if you are not using more than one Tk, one of the above methods would certainly solve the problem(as far as something is inputted inside the entry and then the insertroom() is called).

Python tkinter: create a dynamic dropdown menu and call different actions after selection

I am pretty new to python and this is the first time I use tkinter so I hope someone can help me to find the right direction.
Basically this is what I would like to achieve:
I retrieve from an XML 2 lists (APPs, IDs);
The APP List will be shown in a Dropdown menu;
The APP selection in the Dropdown menu will call the APP status using its ID.
I can't get the last point work, basically I think I understand why (I have no matching between the two lists or a function to match them, and the selection calls automatically the last ID of second list) but I am to the best of my knowledge not able to solve it.
import requests
import xml.etree.ElementTree as ET
import tkinter as tk
APP_OPTIONS = []
ID_OPTIONS = []
session = requests.Session()
session.auth = ('USER', 'PW')
applications = session.get('https://getapplicationslist.myurl.com/application/')
applications_xml = applications.content
root = ET.fromstring(applications_xml)
for application in root.findall('application'):
app_name = application.find('name').text
app_id = application.find('id').text
APP_OPTIONS.append(app_name)
ID_OPTIONS.append(app_id)
def appcall(*args):
app_status = session.get('https://getapplicationstatus.myurl.com?Id=' + app_id)
status_xml = app_status.content
root = ET.fromstring(status_xml)
for appStatus in root.findall('appStatus'):
status = appStatus.find('status').text
print(status)
root = tk.Tk()
root.title('Application List')
root.geometry("300x200")
var =tk.StringVar(root)
var.set('Choose an Application')
var.trace('w', appcall)
dropDownMenu = tk.OptionMenu(root, var, *APP_OPTIONS)
dropDownMenu.pack()
root.mainloop()
print('End Request')
As mentioned in my comment, the issue is your app_id in appcall does not change. You need to get the corresponding ID from the ID_OPTIONS instead.
def appcall(*args):
app_id = ID_OPTIONS[APP_OPTIONS.index(var.get())] # Add this line
app_status = session.get('https://getapplicationstatus.myurl.com?Id=' + app_id)
...
The app_id is now set to the ID_OPTIONS of the same index based on the app_name (since the insertion order is the same).
However, a better approach would be to initialize your options as a dictionary instead:
# instead of APP_OPTIONS / ID_OPTIONS, create:
apps = {}
...
for application in root.findall('application'):
app_name = application.find('name').text
app_id = application.find('id').text
# add to dictionary here:
apps[app_name] = app_id
def appcall(*args):
# Change the app_id to apps.get(var.get())
app_status = session.get('https://getapplicationstatus.myurl.com?Id=' + apps.get(var.get())
...
See how much simpler it is to recall the same reference?
If you are feeling comfortable about the language, you might even opt for a dictionary comprehension:
...
root = ET.fromstring(applications_xml)
app_id = {application.find('name').text: application.find('id').text for application in root.findall('application')}
...

Open Tkinter frame based on logical expression result in Python

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!

Is it possible to display hyperlinks in a Tkinter message widget?

I am creating a news feed program that uses the Feedparser module to read the Yahoo! RSS API, write key data to a text file, and then display the data organised in a Tkinter GUI.
I was enquiring if it is possible to have clickable hyperlinks in a text file/Tkinter message widget.
My current thinking is that you could write code that runs in the following fashion:
If item in the text file includes 'http', make it a hyperlink.
If anyone knows of a Pythonic way to achieve this, or knows if it is not in fact possible, please contribute.
Thank you for your time, here is my code:
def news_feed(event):
''' This function creates a new window within the main window, passes an event(left mouse click), and creates a text heading'''
root = Toplevel(window)
# Create a text heading and define its placement within the grid
menu_heading = Label(root, text = 'News feed', font = 'bold')
menu_heading.grid(row = 0, column = 0, columnspan = 3, pady = 4)
# Create a variable of the selected radio button
button_choice = IntVar()
def selection():
''' This function gets the activated radio button and calls its corresponding function.'''
# Get the value of the activated radio button, and call its corresponding function
news_choice = button_choice.get()
# If the user's choice is industry news, ask them which feed they would like (E.g. Stock market),
if news_choice == 0:
# grab the corresponding url segment to the user's feed choice from the dictionary,
news_choice_url = news_areas[news_feed]
# set the url variable using by inserting this segment into the API url,
rss_url = feedparser.parse('https://au.finance.yahoo.com/news/' + news_choice_url + '/?format=rss')
# and call the feed parsing function.
parse_feed()
# If the user's choice is the second button, call the company news function
elif news_choice == 1:
company_news()
def read_news_file(news_feed_message):
'''This function opens the companyNews text file and reads its contents, line by line'''
with open('C:\\Users\\nicks_000\\PycharmProjects\\untitled\\SAT\\GUI\\Text Files\\companyNews.txt', mode='r') as inFile:
news_data_read = inFile.read()
print('\n')
news_feed_message.configure(text = news_data_read)
def parse_feed(news_feed_message, rss_url):
''' This function parses the Yahoo! RSS API for data of the latest five articles, and writes it to the company news text file'''
# Define the RSS feed to parse from, as the url passed in of the company the user chose
feed = feedparser.parse(rss_url)
try:
# Define the file to write the news data to the company news text file
with open('C:\\Users\\nicks_000\\PycharmProjects\\untitled\\SAT\\GUI\\Text Files\\companyNews.txt', mode='w') as outFile:
# Create a list to store the news data parsed from the Yahoo! RSS
news_data_write = []
# Initialise a count
count = 0
# For the number of articles to append to the file, append the article's title, link, and published date to the news_elements list
for count in range(10):
news_data_write.append(feed['entries'][count].title)
news_data_write.append(feed['entries'][count].published)
article_link = (feed['entries'][count].link)
article_link = article_link.split('*')[1]
news_data_write.append(article_link)
# Add one to the count, so that the next article is parsed
count+=1
# For each item in the news_elements list, convert it to a string and write it to the company news text file
for item in news_data_write:
item = str(item)
outFile.write(item+'\n')
# For each article, write a new line to the company news text file, so that each article's data is on its own line
outFile.write('\n')
# Clear the news_elements list so that data is not written to the file more than once
del(news_data_write[:])
finally:
outFile.close()
read_news_file(news_feed_message)
def industry_news():
''' This function creates a new window within the main window, and displays industry news'''
industry_window = Toplevel(root)
Label(industry_window, text = 'Industry news').grid()
def company_news():
''' This function creates a new window within the main window, and displays company news'''
company_window = Toplevel(root)
company_label = Label(company_window, text = 'Company news')
company_label.grid(row = 0, column = 0, columnspan = 6)
def company_news_handling(company_ticker):
''' This function gets the input from the entry widget (stock ticker) to be graphed.'''
# set the url variable by inserting the stock ticker into the API url,
rss_url = ('http://finance.yahoo.com/rss/headline?s={0}'.format(company_ticker))
# and call the feed parsing function.
parse_feed(news_feed_message, rss_url)
# Create the entry widget where the user enters a stock ticker, and define its location within the grid
company_ticker_entry = Entry(company_window)
company_ticker_entry.grid(row = 1, column = 0, columnspan = 6, padx = 10)
def entry_handling():
'''This function validates the input of the entry box, and if there is nothing entered, an error is outputted until a value is'''
# Create a variable that equals the input from the entry widget
company_ticker = company_ticker_entry.get()
# Convert the input into a string
company_ticker = str(company_ticker)
if company_ticker == '':
news_feed_message.configure(text = 'Please input a stock ticker in the entry box.')
else:
company_news_handling(company_ticker)
# Create the button that the user presses when they wish to graph the data of the stock ticker they inputted in the entry widget
graph_button = Button(company_window, text = 'SHOW', command = entry_handling, width = 10).grid(row = 2, column = 0, columnspan = 6)
news_feed_message = Message(company_window, text='', width=500, borderwidth=5, justify=LEFT, relief=RAISED)
news_feed_message.grid(row=3, column=0, columnspan=6)
Most uses of hyperlinks in a tkinter application i have seen involved using the webbrowser and attaching events to your tkinter object to trigger callbacks, but there may be simpler ways, but heres what i mean :
from tkinter import *
import webbrowser
def callback(event):
webbrowser.open_new(r"http://www.google.com")
root = Tk()
link = Label(root, text="Google Hyperlink", fg="blue", cursor="hand2")
link.pack()
link.bind("<Button-1>", callback)
root.mainloop()
From this source
You could do as you said and read from a text file, and if the line contains "http" create a new label, and event, attaching the hyper link from the file to the event.
import re
with open(fname) as f:
content = f.readlines()
urls = re.findall('http[s]?://(?:[a-zA-Z]|[0-9]|[$-_#.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', content)
Access the url's after this and generate your label's or whatever widget you attach the url's too and you can then have all of them open the web page when clicked.
Hope this helps in some way, let me know if you need more help :)
I think it is easy to create hyperlink in tkinter using following link and its easy for modifying as per your requirement
Updated Hyperlink in tkinter
hope this works for you.
regards Midhun
(Answer taken from effbot)
Support module for Text hyperlinks (File: tkHyperlinkManager.py)
from Tkinter import *
class HyperlinkManager:
def __init__(self, text):
self.text = text
self.text.tag_config("hyper", foreground="blue", underline=1)
self.text.tag_bind("hyper", "<Enter>", self._enter)
self.text.tag_bind("hyper", "<Leave>", self._leave)
self.text.tag_bind("hyper", "<Button-1>", self._click)
self.reset()
def reset(self):
self.links = {}
def add(self, action):
# add an action to the manager. returns tags to use in
# associated text widget
tag = "hyper-%d" % len(self.links)
self.links[tag] = action
return "hyper", tag
def _enter(self, event):
self.text.config(cursor="hand2")
def _leave(self, event):
self.text.config(cursor="")
def _click(self, event):
for tag in self.text.tag_names(CURRENT):
if tag[:6] == "hyper-":
self.links[tag]()
return
And here’s an example:
# File: hyperlink-1.py
import tkHyperlinkManager
from Tkinter import *
root = Tk()
root.title("hyperlink-1")
text = Text(root)
text.pack()
hyperlink = tkHyperlinkManager.HyperlinkManager(text)
def click1():
print "click 1"
text.insert(INSERT, "this is a ")
text.insert(INSERT, "link", hyperlink.add(click1))
text.insert(INSERT, "\n\n")
def click2():
print "click 2"
text.insert(INSERT, "this is another ")
text.insert(INSERT, "link", hyperlink.add(click2))
text.insert(INSERT, "\n\n")
mainloop()

Categories

Resources