How to make a text link in Python3.7 tkinter - python-3.x

I'm trying to make a RSS reader with GUI in Python 3.7 and everything is almost working but there is a problem, instead of that each line pointing to another link, each line moves to the exact same link.
What can I do to solve this?
The Code:
import feedparser
from tkinter import *
import webbrowser
def callback(event):
webbrowser.open_new(article_link)
feed = feedparser.parse("http://www.widgeti.co.il/feed/")
feed_title = feed['feed']['title']
feed_entries = feed.entries
root = Tk()
text = Text(root)
for entry in feed.entries:
article_title = entry.title
article_link = entry.link
article_published_at = entry.published # Unicode string
article_published_at_parsed = entry.published_parsed # Time object
article_author = entry.author
content = entry.summary
article_tags = entry.tags
print ("{}[{}]".format(article_title, article_link))
print ("Published at {}".format(article_published_at))
print ("Published by {}".format(article_author))
print("Content {}".format(content))
print("catagory{}".format(article_tags))
link = Label(root, text="{}\n".format(article_title), fg="blue", cursor="hand2")
link.pack()
link.bind("<Button-1>" ,callback)
text.tag_config("here")
root.mainloop()

You are not passing the link in argument to the callback function, therefore when callback is triggered, it uses the current value of article_link which is the link of the last entry. To fix this you can pass the link to callback using a lambda function in the for loop:
def callback(event, article_link):
webbrowser.open_new(article_link)
# ...
for entry in feed.entries:
# ...
link.bind("<Button-1>", lambda event, link=article_link: callback(event, link))

Related

I am unable to fetch return value from a function in python

In the code mentioned I am trying to get value of "text" which is inside the function . Outside of a function with one variable "A" but here I am not getting anything.Can anyone help me on this issue please
Also when I am writing print statement inside the function it is printing the value
enter code here
from tkinter import *
window = Tk()
window.geometry('500x500')
def callback(self):
text = No_of_chances.get()
return text
No_of_chances = Entry(window)
No_of_chances.place(x=50, y=300)
No_of_chances.bind('<Return>', callback)
A=text
print(A)
window.mainloop()
The text variable is not defined when you try to do A=text this is because the function callback() is only called when the enter button is pressed. Therefore text does not exist when you try to assign it to A
The callback function works perfectly fine, it gets the current string within the Number_of_chances Entry you have, and returns it.
That being said your question is very unclear, since you provide no context to what you want to do with the text you get from the Entry when you press enter, if you provide some context I or someone else might be able to help fix your problem better.
Here is a solution so then A will contain the value you want.
from tkinter import *
window = Tk()
window.geometry('500x500')
text = ""
def callback(event):
text = No_of_chances.get()
print(text)
return text
No_of_chances = Entry(window)
No_of_chances.place(x=50, y=300)
No_of_chances.bind('<Return>', callback)
A=text
print(A)
window.mainloop()

Tkinter: displaying label with automatically updated variable

I know there are a lot of questions about this subject, but after long researches I didn't find any that could solve my problem.
I'm trying to display with a label (using tkinter) a variable that I get from the I²C bus. The variable is therefore updated very regularly and automatically. The rest of the window should stay available for the user.
For now, the only way I found to display the label with the updated variable and to keep the rest of the window available for the user is to do so:
window = tk.Tk()
window.title("Gestionnaire de périphériques")
window.minsize(1024,600)
labelValThermo = tk.Label(a_frame_in_the_main_window,text = "")
labelValThermo.grid(row = 1, column = 1)
while True:
if mcp.get_hot_junction_temperature() != 16.0625:
labelValThermo.configure(text = "Température thermocouple: {} °C".format(mcp.get_hot_junction_temperature()))
window.update()
time.sleep(0.75)
The variable that comes from the I²C and got updated is mcp.get_hot_junction_temperature
The fact is that I know it's not the best way to force the update in an infinite loop. This should be the role of the mainloop(). I found out that the after() method could solve my problem but I don't know how to run it. I tried the following code that didn't work:
def displayThermoTemp():
if mcp.get_hot_junction_temperature() != 16.0625:
labelValThermo.configure(text = "Température thermocouple: {} °C".format(mcp.get_hot_junction_temperature()))
labelValThermo.after(500,displayThermoTemp)
window = tk.Tk()
labelValThermo = tk.Label(thermoGraphFrame,text = "")
labelValThermo.after(500, displayThermoTemp)
labelValThermo.grid(row = 1, column = 1)
window.mainloop()
Does anyone have the right syntax ?
How To use after() ?
The after() calls the function callback after the given delay in ms. Just define it inside the given function and it'll run just like a while loop till you call after_cancel(id) .
Here is an example:
import tkinter as tk
Count = 1
root = tk.Tk()
label = tk.Label(root, text=Count, font = ('', 30))
label.pack()
def update():
global Count
Count += 1
label['text'] = Count
root.after(100, update)
update()
root.mainloop()
Update your function with this and call it once before mainloop().
def displayThermoTemp():
if mcp.get_hot_junction_temperature() != 16.0625:
labelValThermo.configure(text = "Température thermocouple: {} °C".format(mcp.get_hot_junction_temperature()))
labelValThermo.after(500,displayThermoTemp)
# 100ms = 0.1 secs
window(100, displayThermoTemp)
after has the following syntax:
after(delay_ms, callback=None, *args)
You need to place the command in your callback function and update the window on which the widget is (in your case the labelValThermo looks to be on the root window:
def displayThermoTemp():
if mcp.get_hot_junction_temperature() != 16.0625:
labelValThermo.configure(text = "Température thermocouple: {} °C".format(mcp.get_hot_junction_temperature()))
root.after(500,displayThermoTemp)

Python 3.7 + tkInter : How can I make sure a button is assigned an individual function from a file?

I am having some issues wrapping my head around something I encountered in python recently.
So, basically, I want to allow for a user to load several json files, all listed in a python list. These files contain parameters used to create buttons with, namely, the color the button should have, the text that should be displayed in it and the command that it needs to execute once clicked.
def createTags(self):
for items in self.LoadedInstallProfiles:
with open(items, "r") as jsonfiles:
self.loadeddata = json.load(jsonfiles)
self.tag = Button(self.tagmenu, text=self.loadeddata.get("profilename"), background=
self.loadeddata.get("profilecolor"), command=print(self.loadeddata.get("profilename")))
self.tag.pack(side="top",fill="x")
The problem is: the buttons show up with their individual color and text, but all seem to print out the same profilename when clicked, which is that in the last json file in the list.
I common way is to store the created button widgets in a list. I have modified your method. See below.
def createTags(self):
# First create the widget and append to list variable
self.tags = [] #List to store button widgets
for items in self.LoadedInstallProfiles:
with open(items, "r") as jsonfiles:
loadeddata = json.load(jsonfiles)
text = loadeddata.get("profilename")
bg = loadeddata.get("profilecolor")
tag = Button( self.tagmenu, text=text, background=bg, command=print(text) )
self.tag.append( tag )
# Then display the widgets
for tag in self.tags:
tag.pack(side="top",fill="x")
I imagine the problem with command=print(self.loadeddata.get("profilename")) is similar to the problem with lambda statements (that said I am surprised your buttons work at all They should print once at init and then never work after that because you are calling print at button creation instead of saving a reference to print).
Due to the nature of how lambda works here in a loop like this you end up only printing the last value in the loop for all commands. Instead you need to use a lambda statement and also define the value in the lambda for each loop to accurately record the correct data for the print statement.\
I created 3 test files for this:
test.json:
{"profilename":"test", "profilecolor": "green"}
test2.json:
{"profilename":"test2", "profilecolor": "blue"}
test3.json:
{"profilename":"test3", "profilecolor": "orange"}
Example code:
import tkinter as tk
import json
class Window(tk.Tk):
def __init__(self):
super().__init__()
self.btn_list = []
for file in ['test.json', 'test2.json', 'test3.json']:
with open(file, 'r') as f:
self.btn_list.append(json.load(f))
self.create_tags()
def create_tags(self):
for item in self.btn_list:
tk.Button(self, text=item.get("profilename"), background=item.get("profilecolor"),
command=lambda x=item.get("profilename"): print(x)).pack(side="top", fill="x")
if __name__ == '__main__':
Window().mainloop()
Results:

Remove letter from python text widget using bind function

I have just started to create a simple text editor. I have already bound a couple of functions to certain keypresses and now I'm trying to add a function that operates on the Return delete being pressed. The aim is to remove the last character entered into the text widget. Here is my code:
from tkinter import *
from tkinter import filedialog
import os
root = Tk()
root.geometry('{}x{}'.format(500, 500))
def addchar(event):
w.insert(END, event.char)
def deletechar(event):
current = w.get()
new = current[:-1]
w.delete(0,END)
w.insert(END, new)
def savefile(event):
file = filedialog.asksaveasfilename(defaultextension=".txt")
if file is None:
return
text2save = str(w.get())
file.append(data)
file.close()
w = Entry(root, bd=1)
w.pack()
w.place(x=0, y=0, width=500)
root.bind("<Key>", addchar)
root.bind("<BackSpace>", deletechar)
root.bind("<Control-s>", savefile)
root.bind("<Return>", newline)
root.mainloop()
The issue I'm having is that nothing is removed upon pressing delete to remove the last character entered. Any help appreciated. P.S. Ive tried adding a savefile function to save the text to a file but it doesn't work if anyone can help there also, it would again be appreciated :)
I didn't try to run your code right know because I'm running out of time. However, first of all, you should not use pack and place geometry manager in the same Toplevel, you should only use one. Second, in your savefile function, you did not open the file, so your file variable is only a string. You should use something like file = open(file).

Scraping stocks - output in tkinter

So here is my problem. I am trying to output my scraping results in a GUI using tkinter in python. The code i use works in the shell, but when i use it with tkinter it doesnt Here is my code.
import sys
from tkinter import *
from urllib.request import urlopen
import re
def stockSearch():
searchTerm = userInput.get()
url = "http://finance.yahoo.com/q?s="+searchTerm+"&q1=1"
htmlfile = urlopen(url)
htmltext = str(htmlfile.read())
regex = '<span id="yfs_l84_'+searchTerm+'">(.+?)</span>'
pattern = re.compile(regex)
price = re.findall(pattern, htmltext)
outputStock = str(["The price of ", searchTerm, "is ", price])
sLabel2 = Label(sGui, text=outputStock).pack()
sGui = Tk()
userInput = StringVar()
sGui.geometry("450x450+200+200")
sGui.title("Stocks")
sLabel = Label(sGui, text="Stocks List", fg="black")
sLabel.pack()
sButton = Button(sGui, text="LookUp", command = stockSearch)
sButton.place(x=200, y=400)
uEntry = Entry(sGui, textvariable=userInput).pack()
sGui.mainloop()
If i input a search for Google (GOOG) for example, I return this:
"The price of GOOG is []"
However, if i use the same code, but i print the result in a shell as opposed to using tkinter, i get the price as it should.
Any ideas anyone?
It appears your code isn't properly handling case. If you search for "goog" the value shows up. The problem is this line:
regex = '<span id="yfs_l84_'+searchTerm+'">(.+?)</span>'
If you type "GOOG", the regex becomes:
<span id="yfs_l84_GOOG'">(.+?)</span>
However, the html that is returned doesn't have that pattern. Doing a case-insensitive search should solve that problem:
pattern = re.compile(regex, flags=re.IGNORECASE)
Also, there's no need to create a new Label every time -- you can create the label once and then change the text each time you do a lookup.

Resources