Problem when defining a function in python with tkinter - python

Im making a program that searches a website for a specific word.
Exampel : Word: football on the website fifa.com.
I made it in a terminal which was very easy. Now i want to make a program using tkinter and it wont work.
The problem i have is when i run my program it says
File "c:/Users/Censored/Desktop/PythonFolder/Program.py", line 22, in
temp = Button(root, text='GO', command=searchgo)
NameError: name 'searchgo' is not defined
This is my code:
import requests
import re
from tkinter import *
root = Tk()
root.title('WordCounter')
root.configure(bg='#2f3136')
root.geometry('700x700')
root.resizable(False, False)
# Buttons
e1 = Entry(root, width='35')
label1 = Label(root, text='Write The Word You Want To Search For', bg='#2f3136', fg='white',)
e2 = Entry(root, width='35')
label2 = Label(root, text='Write the websites URL', bg='#2f3136', fg='white',)
temp = Button(root, text='GO', command=searchgo)
# Buttons on screen
label1.grid(row='1', column='1',padx='10')
e1.grid(row='2', column='1', padx='10')
label2.grid(row='1', column='2', padx='10')
e2.grid(row='2', column='2', padx='10')
temp.pack()
# Define Functions
def searchgo():
word = e1.get()
URL = e2.get()
page = requests.get(URL).text
print(page.find(word))
root.mainloop()
Thanks for helping me!

Your code has couple of bugs,
Define the function searchgo before you assign the callback to your button
In this code, better use grid to place you button instead of place or you get the following error
cannot use geometry manager pack inside . (root) which already has slaves managed by grid
The reason of this error is that, you cannot use pack and grid geometry managers inside the same master window (root in this program). Since you have used grid for most of the widgets, use grid for placing the button also.
Also, in case you are not aware, in grid geometry manager row and column position values start at 0 and not 1
Here is the code:
import requests
import re
from tkinter import *
root = Tk()
root.title('WordCounter')
root.configure(bg='#2f3136')
root.geometry('700x700')
root.resizable(False, False)
# Buttons
e1 = Entry(root, width='35')
label1 = Label(root, text='Write The Word You Want To Search For', bg='#2f3136', fg='white',)
e2 = Entry(root, width='35')
label2 = Label(root, text='Write the websites URL', bg='#2f3136', fg='white',)
# Define Functions
def searchgo():
word = e1.get()
URL = e2.get()
page = requests.get(URL).text
print(page.find(word))
temp = Button(root, text='GO', command=searchgo)
# Buttons on screen
label1.grid(row='0', column='0',padx='10')
e1.grid(row='1', column='0', padx='10')
label2.grid(row='0', column='1', padx='10')
e2.grid(row='1', column='1', padx='10')
# use the grid manager to place your button
temp.grid(row='1', column='2', padx='10')
root.mainloop()
I have tried explaining the changes I made with some theory. I hope you understand!

Should the function be defined before you assigne it as Button attribute?
This will raise same exception:
class A:
def __init__(self, something):
self.something = something
a = A(func)
def func():
return
But, this works as expected:
def func():
return
class A:
def __init__(self, something):
self.something = something
a = A(func)

Related

Taking input from Entry in Tkinter and using it in the back-end

I have created a code for plotting graphs using csv files and also a Python GUI using Tkinter which is a simple GUI for getting the input from the user and plotting graphs.
Ps. The input a date that is to be added in the back-end file to the file path of csv which is read and plotted.
Here's my code in short:
def backend():
*importing libraries*
root= Tk()
inp = tkinter.StringVar()
e = Entry(root, textvariable=inp)
e.pack()
s = inp.get()
csv = glob.glob("path" + s + "*.csv")
*rest of the code for plotting graph*
//frontend
*importing libraries*
from file import backend()
root= Tk()
inp = tkinter.StringVar()
e = Entry(root, textvariable=inp)
e.pack()
def submit():
s = inp.get()
*rest of the frontend code*
This code is running without any error but plot is not getting plotted after entering the data in the Tkinter window and clicking the button for plotting graphs.
I also tried by importing the entry variable directly from front-end but it is showing circular input error.
Please help if any ideas.
Thank you
You need to bind an action to make something happen.
I bind the Return key (Enter key) to the 'Entry' widget and added a button. Both will call the 'backend' function:
def backend(event=None):
s = inp.get()
print(s)
root = Tk()
inp = StringVar()
e = Entry(root, textvariable=inp)
e.pack()
# Return key will call backend
e.bind('<Return>', backend)
# Button will call backend
b = Button(root, text='backend', command=backend)
b.pack()
root.mainloop()

entry.get() shell/idle output issue

Okay so I'm trying to learn some GUI using tkinter following along this website's guide: https://realpython.com/python-gui-tkinter/#building-your-first-python-gui-application-with-tkinter
Depending on how I run the code it works using IDLE verse shell.
What happens in Idle is it is calling name long before anything is ever actually typed in the entry. which is why the output is "" . Where in shell I can type something into the entry "john doe" and when I get to 'name' it has something it can output.
import tkinter as tk
window = tk.Tk()
label = tk.Label(text = "Name")
entry = tk.Entry()
label.pack()
entry.pack()
name = entry.get()
name
Typically you would create a button that initiates the .get and start the mainloop for the window, like this:
import tkinter as tk
def print_entry(widget):
name = widget.get()
print(name)
window = tk.Tk()
label = tk.Label(text = "Name")
entry = tk.Entry()
button = tk.Button(text = "Get Entry",
command = lambda e = entry: print_entry(e))
label.pack()
entry.pack()
button.pack()
window.mainloop()

How to get the entry text and display in another entry?

I just want that when I type my name inside the entry box then appears in another entry with some add text. The idea is type in the entry below and after that it showed in the big entry.I was looking for this solution, but just found place in Label. I don't want in Label. The window is more big, must drag to show the entry. There's is a picture that i use in this script:
from tkinter import *
from PIL import Image, ImageTk
root = Tk()
cat = Entry(root)
cat.place(x=48, y=25, width= 350, height=140)
user = Entry(root)
user.place(x=75, y=550)
btn = Button(root, text='START')
btn.place(x=220, y=410)
root.mainloop()
#
Ok, It works the way you told me,thank you!
But now i'm facing another problem.
The problem is when i insert the function of the game in the second window. I tested in one window and it works, but when i place the function in the second window gives an error when i press the "Start" button:
'''user_try = int(txt.get())
NameError: name 'txt' is not defined'''
When i press reset button gives another error:
'''user_try = int(txt.get())
NameError: name 'txt' is not defined'''
So i know that is missing definition, but i don't know how to make a reference for this command that it's in the second window. Like i said running with just one window the program works.
Maybe i should make using class, i don't know, but i wish to make this way that i started. However if there's no other way to do as i'm doing, let's go.
I just simplify the script here, actualy the main script is more bigger, so my idea is when open the program, there is a window and the user read the instructions about the game and proceed open the second window. The window have pictures and some hidden buttons in the next picture, so there will be an interactivity with the environment.
The guess number is just the beggining. After that there will be new challeges.
I'm very excited doing this, but i'm stuck in this point. The part one i finished, the pictures, the hidden buttons it's exacly the way i want, but the challenge stops here in this problem.
from tkinter import *
from PIL import Image, ImageTk, ImageSequence
import random
from tkinter import messagebox
pc = random.randint(1,10)
def reset():
global pc
pc = random.randint(1,10)
cat['text'] = 'Ok! Lets Try Again!'
def openwin2():
win1.withdraw()
win2 = Toplevel()
win2.geometry('350x300+180+100')
win2.title('second window')
txt = Entry(win2)
txt.place(x=10,y=10)
cat = Label(win2,wraplength=300)
cat.place(x=10,y=50)
cat.config(text='Hi! I Am thinking a number between 1 and 10.')
btn = Button(win2,text='start',command=check)
btn.place(x=30, y=150)
btn2 = Button(win2, text='reset', command=reset)
btn2.place(x=110,y=150)
win2.mainloop()
def check():
user_try = int(txt.get())
if user_try < pc:
msg = 'Hmmmm... the number, which I thought of, is greater than this.'
elif user_try > pc:
msg = 'How about trying a smaller number ?!'
elif user_try == pc:
msg = 'Well Done! You guessed! It was %s the number!' % user_try
else:
msg = 'Something Went Wrong...'
cat['text'] = msg
win1 = Tk()
win1.title('First Window')
win1.geometry('350x300')
user = Label(win1,text='first window')
user.place(x=10,y=10)
btn1 = Button(win1,text='Open Window 2', command=openwin2)
btn1.place(x=10,y=50)
win1.mainloop()
There are multiple ways to do this in tkinter, here's a rework of your code using StringVar objects set to the textvariable properties of your Entry objects:
import tkinter as tk
def doit():
out_string.set("Hello " + in_string.get())
root = tk.Tk()
in_string = tk.StringVar()
out_string = tk.StringVar()
cat = tk.Entry(root, textvariable=in_string)
cat.place(x=20, y=25, width=100)
user = tk.Entry(root, textvariable=out_string)
user.place(x=20, y=75)
btn = tk.Button(root, text='START', command=doit)
btn.place(x=20, y=150)
root.mainloop()
Per #Mike-SMT, here's a different approach using Entry.get() and Entry.insert(). It augments the text when the user clicks the button:
import tkinter as tk
def doit():
user.insert(tk.END, cat.get())
root = tk.Tk()
cat = tk.Entry(root)
cat.place(x=20, y=25, width=100)
user = tk.Entry(root)
user.place(x=20, y=75)
user.insert(0, "Hello ")
btn = tk.Button(root, text='START', command=doit)
btn.place(x=20, y=150)
root.mainloop()
However, you'll see that subsequent button clicks keep appending the text. When working with Entry.insert(), you need to work with Entry.delete() and/or other Entry methods to properly manipulate the text.

Can this be done more than once?

from tkinter import *
from tkinter import ttk
import webbrowser
import urllib
root = Tk()
w = Label(root, text="Where can I take you?")
w.pack()
url = 'http://sampdm.net/member.php?action=profile&uid=1'
def Openurl(url):
webbrowser.open_new(url)
button = Button(root, text = "Open Owners Profile #1", command = lambda:
Openurl(url))
button.pack()
root.mainloop()
Is there any way to make another button with another link like it?
I know there will be but I can't seem to figure out
From reading the comments it looks like you are not sure how to create multiple buttons inside your Tkinter window.
Its really easy and all you need to do is repeat the process that you used to create your first button.
I will provide 2 examples.
Here is how you can create each button manually for each website you wish to provide a button for.
from tkinter import *
import webbrowser
root = Tk()
url = 'http://sampdm.net/member.php?action=profile&uid=1'
url2 = 'www.google.com' # assign any variable name you want.
some_other_url = 'https://www.yahoo.com/'
def Openurl(url):
webbrowser.open_new(url)
w = Label(root, text="Where can I take you?")
w.pack()
# Here you can keep creating buttons using the same method as the first button.
# Just make sure you assign the correct url variable to the command.
button = Button(root, text = "Open Owners Profile #1", command = lambda: Openurl(url)).pack()
button2 = Button(root, text = "Open Google", command = lambda: Openurl(url2)).pack()
some_other_button = Button(root, text = "Open something else", command = lambda: Openurl(some_other_url)).pack()
root.mainloop()
Here is an example where your buttons are created from a list. This is a simple example but it should be enough to illustrate how it can be done.
from tkinter import *
import webbrowser
root = Tk()
# Here we create a list to use in button creation.
url_list = ['www.google.com', 'www.yahoo.com']
w = Label(root, text="Where can I take you?")
w.pack()
def Openurl(url):
webbrowser.open_new(url)
def create_buttons():
for url in url_list: # for each string in our url list
# creating buttons from our for loop values that will pack
# in the order they are created.
Button(root, text = url, command = lambda u = url: Openurl(u)).pack()
create_buttons()
root.mainloop()

Python's tkinter smart entry password

I want to create a password entry.
One easy solution is:
password = Entry(root, font="Verdana 22")
password.config(show="*");
but the problem is that to avoid typos, I want to show the item clicked to be visible only for a few seconds, while everything else is hidden. After a few seconds everything is hidden.
It's not easy to do exactly what you want with Tkinter, but here's something close: when you press a key it displays the whole contents of the Entry, but after one second the text is hidden again.
I developed this on Python 2; to use it on Python 3 change Tkinter to tkinter.
import Tkinter as tk
class PasswordTest(object):
''' Password Entry Demo '''
def __init__(self):
root = tk.Tk()
root.title("Password Entry Demo")
self.entry = e = tk.Entry(root)
e.pack()
e.bind("<Key>", self.entry_cb)
b = tk.Button(root, text="show", command=self.button_cb)
b.pack()
root.mainloop()
def entry_cb(self, event):
#print(`event.char`, event.keycode, event.keysym )
self.entry.config(show='')
#Hide text after 1000 milliseconds
self.entry.after(1000, lambda: self.entry.config(show='*'))
def button_cb(self):
print('Contents:', repr(self.entry.get()))
PasswordTest()
It would be tricky to only display the last char entered. You'd have to modify the displayed string manually while maintaining the real password string in a separate variable and that's a bit fiddly because the user can move the insertion point cursor at any time.
On a final note, I really don't recommend doing anything like this. Keep passwords hidden at all times! If you want to reduce the chance of typos in newly-chosen passwords, the usual practice is to make the user enter the password twice.
This a simple trick to visible the password with a checkbutton.
When it is checked the password will be visible
from Tkinter import *
from tkinter import ttk
def show_hide_psd():
if(check_var.get()):
entry_psw.config(show="")
else:
entry_psw.config(show="*")
window = Tk()
window.wm_title("Password")
window.geometry("300x100+30+30")
window.resizable(0,0)
entry_psw = Entry(window, width=30, show="*", bd=3)
entry_psw.place(x = 5, y = 25)
check_var = IntVar()
check_show_psw = Checkbutton(window, text = "Show", variable = check_var, \
onvalue = 1, offvalue = 0, height=2, \
width = 5, command = show_hide_psd)
check_show_psw.place(x = 5, y = 50)
window.mainloop()

Categories

Resources