tkinter - how to make separate hyperlink button in my loop? - python-3.x

I'm trying to make some simple program to open url if the condition fits.
Here's the minimal reproducible example.
from tkinter import *
import requests
from bs4 import BeautifulSoup
import webbrowser
import time
def call_back(event):
input_id.delete(0,END)
return None
def open_browse(url):
webbrowser.open_new(url)
win = Tk()
win.geometry("150x150")
win.title("Example")
search_btn = Button(win)
search_btn.config(text="search")
search_btn.config(width=5,height=1)
search_btn.grid(column = 2, row = 2)
def search_chr():
chr_list = ["test1","test2"]
result = [(0,"test_r_1"),(0,"test_r_2")]
var_dict = {}
num = -1
for ch in chr_list:
num += 1
var_dict["output%s" %num] = Entry(win, width = 10)
if result[0] == 0:
pass
else:
link_url = result[num][1]
print(link_url)
var_dict["o-button%s" %num] = Button(win, command=lambda aurl=link_url:open_browse(link_url))
var_dict["output"+str(num)].insert(0, "Text")
var_dict["output"+str(num)].grid(column = 0, row = 0+num, columnspan = 4, sticky=W, padx=5, pady=5)
var_dict["o-button"+str(num)].config(text="URL")
var_dict["o-button"+str(num)].grid(column = 4, row = 0+num, sticky=E, padx=5, pady=5)
var_dict["output"+str(num)].config(state="disabled")
search_btn.config(command = search_chr)
win.mainloop()
So, if you run the code, there would be a button.
And if you click it, There will be two sets of Label with "Text" in it and Button with "URL" in it. When you press the URL button, it should open a browse with a given url.
As you see the printed text in your terminal, the url is supposed to be "test_r_1" and "test_r_2"
But, if you press each button, all buttons are directed to "test_r_2".
It seems that it somehow overwrote the previous "test_r_1" as well.
If anyone can explain how to make each button to link to each url, it would be perfect.
Thanks for stopping by, and I hope you can help me with this.

Okay, I tracked down that I didn't fully understand that how lambda works.
So I changed my search keyword and found this beautiful question and answer.
Tkinter assign button command in loop with lambda
I changed
var_dict["o-button%s" %num] = Button(win, command=lambda aurl=link_url:open_browse(link_url))
into
var_dict["o-button%s" %num] = Button(win, command=lambda link_url=link_url:open_browse(link_url))
and it worked.
Thanks all!

Related

How to make a variable equal to the input received from the input field in tkinter?

I was wondering how to make this code work.I always get 12 in the console.
from tkinter import *
s = 12
root = Tk()
root.geometry("200x200")
root.title("Program")
e = Entry(root)
e.pack()
def clicked():
e.get = s
print(s)
button = Button(root,command=clicked,text="ok")
button.pack()
root.mainloop()
You have to change the function clicked as follows:
def clicked():
s=e.get()
print(s)
There were two errors in your code:
You were trying to assign the value 12 to a function.
You were not calling the function (using parenthesis).
this line here:
e.get = s
says the method of e named get is equally to s.
Which is nonsense. You want s to be equally to what is returned by e.get.
to have something returned you need to invoke this method first.
So the logical right way to do this is by:
s = e.get()
Note that it is a variable in the enclosed namespaces of your function.
To make it global you need to global the variable.
from tkinter import *
s = 12
root = Tk()
root.geometry("200x200")
root.title("Program")
e = Entry(root)
e.pack()
def clicked():
#global s
s = e.get()
print(s)
button = Button(root,command=clicked,text="ok")
button.pack()
b2 = Button(root, text='print', command=lambda:print(s))
b2.pack()
root.mainloop()
I have used .place() instead of .pack() and placed my same entry on the same position as it was place before, but this time if value changes as you click on button OK.
Use e.insert(0,"Value") to insert any value in a entry.
This worked for me. Also let me know did it worked for you as well?
from tkinter import *
s = 12
root = Tk()
root.geometry("200x200")
root.title("Program")
e = Entry(root)
e.place(relx=0.1, rely = 0.1)
def clicked():
e = Entry(root)
e.insert(0, s)
e.place(relx=0.1, rely = 0.1)
button = Button(root,command=clicked,text="ok")
button.place(relx=0.4, rely = 0.2)
root.mainloop()

Tkinter create multiple buttons in a loop and change text of clicked ones

I try to access/change button attributes for buttons created in a loop.
My idea was to collect the buttons in a list so that i can access every single button. Is there a better way?
At the moment i try to use the buttons-command to change the text of the clicked button. In the "action"-function i get the error-code "list index out of range" when i try to run the code!?
Since i am a newbie in python and tkinter hours over hours passed so far to find a solution without success.
Every idea would be very appreciated.
I used quite the same code without creating a list. The code was working but when i clicked a button only the last created button changed the text. Could it be that somehow i have to use the "StringVar"-function or "textvariable"?
import tkinter as tk
window = tk.Tk()
window.geometry("300x150")
window.title("Tic Tac Toe")
def action(i):
btns[i].configure(text = 'X')
btn_nr = -1
btns = []
for x in range(1,4):
for y in range(1,4):
btn_nr += 1
print(btn_nr)
btns.append(tk.Button(text='-', command = action(int(btn_nr))))
btns[int(btn_nr)].grid(row=x, column=y)
exit_button = tk.Button(text='Exit Game', command=window.destroy)
exit_button.grid(row=4, column=1, columnspan=15)
window.mainloop()
You were almost there. See below matter being resolved as you need a lambda to pass the btn_nr to the function action. By the way there is no need for int()
import tkinter as tk
window = tk.Tk()
window.geometry("300x150")
window.title("Tic Tac Toe")
def action(button):
if btns[button].cget('text') == '-':
btns[button].configure(text='X')
else:
btns[button].configure(text='-')
btn_nr = -1
btns = []
for x in range(1, 4):
for y in range(1, 4):
btn_nr += 1
print(btn_nr)
btns.append(tk.Button(text='-', command=lambda x=btn_nr: action(x)))
btns[btn_nr].grid(row=x, column=y)
exit_button = tk.Button(text='Exit Game', command=window.destroy)
exit_button.grid(row=4, column=1, columnspan=15)
window.mainloop()
I changed the action function a little to make it toggle between 'X' and '-'.

Returning a value from a tkinter form

I'm using code where I need to ask the user for input, using a tkinter window (I'm not using tkinter in other parts of the code).
My issue is that I simply need to use the tkinter window to return a value upon pressing the OK button on the form, which will also close down the form. The only way I can get it to work so far is by using a global variable. I've searched for other solutions to this but either they don't return a value (they simply print it) or don't allow passing text for the prompt.
Thanks in advance if you can help with this.
from tkinter import *
def input_text(prompt):
def ok():
global ret
ret = entry.get()
master.destroy()
master = Tk()
lbl = Label(master, text=prompt)
lbl.pack()
entry = Entry(master)
entry.pack()
entry.focus_set()
butt = Button(master, text = "OK", width = 10, command = ok)
butt.pack()
mainloop()
print("I am here!")
ret=""
input_text("Enter something")
print("ret is:", ret)
After a good night's sleep I've solved the problem :-)
The solution was to create a class and return the response via an attribute. Here's the code for the archive ... just in case anyone out there has a similar question.
from tkinter import *
class InputForm():
def __init__ (self, prompt):
self.prompt = prompt
self.response = ""
def ok():
self.response = entry.get()
master.destroy()
master = Tk()
lbl = Label(master, text=self.prompt)
lbl.pack()
entry = Entry(master)
entry.pack()
entry.focus_set()
butt = Button(master, text = "OK", width = 10, command = ok)
butt.pack()
mainloop()
abc = InputForm("Enter something").response
print("returned value is:", abc)

Problems with Focus

I'm trying to return the focus to the first entry. If you move the focus to the next entry or the button and the you click on the button, the focus returns fine to first entry. When I try doing the same thing by using the tab key, the focus_set method fails. I've tried many different ways, but the result is always the same. Anyone knows why? And might be so kind as to showing me how to do it right? Thanks in advance.
This is what I got so far:
from tkinter import *
w = Tk()
def focus():
box1.focus_set()
def check(event):
if str(event.widget) == '.!entry2':
print('focus back to box1')
focus()
box1 = Entry(w, width=15)
box2 = Entry(w, width=15)
box1.focus_set()
box2.bind('<Tab>', check)
box1.pack()
box2.pack()
btn = Button(w, text='Box 1 Focus', command=focus)
btn.pack()
w.mainloop()
If I run your code, str(event.widget) is something like ".36580648", not ".!entry2". You can give your widget a custom name like
box2 = Entry(w, width=15, name='second')
You can then check if str(event.widget) == '.second'.
Alternatively, you can just check if event.widget == box2: which is easier and less prone to error.
If you do one of these things, you will see that 'focus back to box1' is printed, but the focus is still transferred to the button instead of the label. This is because your custom event is triggered before the default event for <Tab>, which is to move focus to the next widget. You can stop the default event handling by returning 'break' in your function.
The complete example would become:
from tkinter import *
w = Tk()
def focus():
box1.focus_set()
def check(event):
if event.widget == box2:
print('focus back to box1')
focus()
return 'break'
box1 = Entry(w, width=15)
box2 = Entry(w, width=15)
box1.focus_set()
box2.bind('<Tab>', check)
box1.pack()
box2.pack()
btn = Button(w, text='Box 1 Focus', command=focus)
btn.pack()
w.mainloop()

tkinter messagebox link to notebook page

referwork = ttk.Notebook(root, style =".TNotebook")
f1 = ttk.Frame(referwork)
f2 = ttk.Frame(referwork)
referwork.add(f1, text="Search", padding = 1)
referwork.add(f2, text="Add/Delete", padding = 1)
#referwork.configure (height = 500, width = 800)
referwork.grid(row=0, column=0, sticky=(N,W,S,E))
I have used the above to create a two-tab notebook. On the first a search is performed. What I want to do is to have an alert in a message box appear messagebox.askyesno and when 'yes' is selected that the focus moves to the second page of the notebook
messagebox.askyesno(0.0,'"{0}"{1} \n {2}\n'.format(search_analyte.get(),' is not in the database.','Add,if appropriate'))
if True:
is as far as I have got. I cannot figure out how to 'open' the second page using this dialogue and conditional. Many thanks for any help
Use Notebook.select(tab) method, where tab is one of the notebook child widgets.
from tkinter import *
from tkinter.ttk import *
from tkinter.messagebox import askyesno
def open_first():
referwork.select(f1)
def open_second():
if askyesno('Title', 'Press "Yes" to open second page') == YES:
referwork.select(f2)
root = Tk()
referwork = Notebook(root, style =".TNotebook")
f1 = Frame(referwork)
f2 = Frame(referwork)
Button(f1, text='Go =>', command=open_second).pack(padx=100, pady=100)
Button(f2, text='<= Go', command=open_first).pack(padx=100, pady=100)
referwork.add(f1, text="Search", padding = 1)
referwork.add(f2, text="Add/Delete", padding = 1)
referwork.grid(row=0, column=0, sticky=(N,W,S,E))
root.mainloop()

Resources