Print to Tkinter GUI, not console - python

I have some scripts written containing a handful of functions to do some webscraping. When running the scripts, the results print to the IDLE shell using simple 'print' commands.
I have a basic tkinter GUI that will run the script when a button is clicked, but the results still get printed to the shell. How could I adjust my code so that when Master.master() is called, all the print statements embedded in that process print to some area on my GUI. The code I have is the following:
from tkinter import *
import Master #Importing my scraper function
win = Tk()
win.title('Hashtag Scraper')
SearchButton = Button(win,text = 'Search')
SearchButton.grid(row=2,column = 1)
htag_label = Label(win,text = 'What Hashtag?')
htag_label.grid(row = 1,column = 0)
email_label = Label(win,text = 'FB Email')
email_label.grid(row = 1,column = 1)
password_label = Label(win,text = 'FB Password')
password_label.grid(row = 1,column = 2)
def button():
htag = hashtag.get()
user = usr.get()
password = pwd.get()
Master.master(htag,refresh = 3,usr = user,pwd = password) #Function call - want this to print on GUI instead of shell
#win.bind('<Return>', SearchButton)
SearchButton.configure(command = button)
hashtag = StringVar()
#hashtag.set('Hashtag')
hashtag_entry = Entry(win,textvariable=hashtag)
hashtag_entry.grid(row = 0, column = 0)
usr = StringVar()
usr.set('test#aol.com')
usr_entry = Entry(win,textvariable=usr)
usr_entry.grid(row = 0, column = 1)
pwd = StringVar()
#pwd.set('FB Password')
pwd_entry = Entry(win,textvariable=pwd)
pwd_entry.grid(row = 0, column = 2)

Depending on where on your GUI and what kind of widget you want to display the result of your master method call, or perhaps in a new popup TextBox window as mentioned in the comments, change it to the kind of widget you wish to use:
class Master:
def __init__(self, htag, refresh, usr, pwd):
self.htag = htag
self.refresh = refresh
self.usr = usr
self.pwd = pwd
def master(self):
return '\n'.join([self.htag, str(self.refresh), self.usr, self.pwd])
...
def button():
htag = hashtag.get()
user = usr.get()
password = pwd.get()
m = Master(htag, refresh = 3, usr = user, pwd = password)
master_response = m.master() #Function call - want this to print on GUI instead of shell
top = Toplevel()
top.title("Response from master method")
# response_message = "Search Button pushed response"
msg = Message(top, text=master_response)
msg.pack()
button = Button(top, text="Dismiss", command=top.destroy)
button.pack()
output:

Related

How do I get a recursive function call to save its out put from a tkinter GUI user input?

I am relatively new to Python and new to GUI development. Below is Python code for a draft GUI that I am developing for tracking the review progress of a document. Eventually the GUI will provide status on document review progress based on user input but I am not there yet. At this stage I am just trying to get the base functions debugged. The current sticking point involves an issue where a recursive function call (compare_stages()) fails to either save its output or run at all. Specifically, when I test run the last function (enter_stage_completed()) edge case that triggers the recursive call in compare_stages(), a NoneType error occurs. The edge case of user input selections is:
Select review stage (click on "client_review").
Select reviewer name (click on "Sue", text box appears prompting user to choose another review stage because the reviewer (Sue) has already reviewed the selected stage).
Select review stage (click on "reg_review").
Select reviewer name (click on "Sue").
Step 4 is where the NoneType error occurs because the output of compare_stages() does not occur and thus there is no object for the variable stage[0] needed in enter_stage_completed(). I have no idea why this is happening. Any and all help would be greatly appreciated.
Here is the code:
from tkinter import *
doc_list = ["doc_A","doc_B","doc_C","doc_D"]
review_stages = ["internal_review","client_review","reg_review"]
reviewer_list = ["Sue","Joe","Don","Billy"]
doc_reviews_completed = ["doc_B"]
review_stages_completed = ["internal_review"]
Sue_stages_complete = ["client_review"]
Joe_stages_complete = []
Don_stages_complete = []
Billy_stages_complete = []
def select_doc():
win = Tk()
win.geometry("715x250")
def save_selected(choice):
choice = menu.get()
return choice
menu = StringVar()
menu.set("Select Document")
drop = OptionMenu(
win,
menu,
*doc_list,
command=save_selected
)
drop.pack()
win.mainloop()
return save_selected(menu)
def prnt_doc_complete():
win = Tk()
win.geometry("250x170")
T = Text(win, height = 5, width = 40)
l = Label(win, text = "Oops!")
l.config(font =("Courier", 14))
message = """Document review complete. Please choose again."""
l.pack()
T.pack()
T.insert(END, message)
return win.mainloop()
def compare_doc_lists():
a = select_doc()
if a in doc_reviews_completed:
prnt_doc_complete()
compare_doc_lists()
else:
return a
#compare_doc_lists()
def select_reviewer():
win = Tk()
win.geometry("715x250")
def save_selected(choice):
choice = menu.get()
return choice
menu = StringVar()
menu.set("Select reviewer name.")
drop = OptionMenu(
win,
menu,
*reviewer_list,
command=save_selected
)
drop.pack()
win.mainloop()
return save_selected(menu)
# select_reviewer()
def select_stage():
win = Tk()
win.geometry("715x250")
def save_selected(choice):
choice = menu.get()
return choice
menu = StringVar()
menu.set("Select review stage.")
drop = OptionMenu(
win,
menu,
*review_stages,
command=save_selected
)
drop.pack()
win.mainloop()
return save_selected(menu)
# select_stage()
def prnt_stage_complete():
win = Tk()
win.geometry("250x170")
T = Text(win, height = 5, width = 40)
l = Label(win, text = "Oops!")
l.config(font =("Courier", 14))
message = """The selected stage is complete for this document. Please choose again."""
l.pack()
T.pack()
T.insert(END, message)
return win.mainloop()
def prnt_stage_complete_reviewer():
win = Tk()
win.geometry("250x170")
T = Text(win, height = 5, width = 40)
l = Label(win, text = "Oops!")
l.config(font =("Courier", 14))
message = """You have already completed this review stage. Please choose again."""
l.pack()
T.pack()
T.insert(END, message)
return win.mainloop()
def compare_stages():
stage_choice = select_stage()
reviewer = select_reviewer()
if reviewer == "Sue":
stage_list = Sue_stages_complete
if reviewer == "Joe":
stage_list = Joe_stages_complete
if reviewer == "Don":
stage_list = Don_stages_complete
if reviewer == "Billy":
stage_list = Billy_stages_complete
if stage_choice in review_stages_completed:
prnt_stage_complete()
compare_stages()
elif stage_choice in stage_list:
prnt_stage_complete_reviewer()
compare_stages()
else:
return stage_choice, reviewer
def prnt_all_stage_complete():
win = Tk()
win.geometry("250x170")
T = Text(win, height = 5, width = 40)
l = Label(win, text = "Oops!")
l.config(font =("Courier", 14))
message = """All reviews already completed. You are done!"""
l.pack()
T.pack()
T.insert(END, message)
return win.mainloop()
def enter_stage_completed():
"""
Function for user to select the current stage that they are completing.
Returns
-------
Updates to docs_complete, stages_complete, and/or reviewer_stages complete lists. User indicates that the stage is complete and the stage is added to their stages_completed list. For tracking, a MySQL database will be populated (allows nulls).
"""
stage = compare_stages()
win = Tk()
win.geometry("100x100")
def save_selected():
text=f"{stage[0]}"
return text
l = Label(win, text="Click to confirm that you completed reviewing the previously selected review stage.")
l.pack()
btn = Button(
master = win,
text=f"{stage[0]}",
command=save_selected
)
#txt = btn.text
btn.pack()
win.mainloop()
return save_selected()

Extra tk window showing in odd situation

This is my first question so be gentle!
Situation:
I have two scripts that each use tkinter to prompt for some info. They are separate because sometimes I'll need one, sometime I'll need both.
I also have a main script that imports the two tkinter scripts and calls them.
When I run each tkinter by itself, or from the main script without the other script imported, it works fine. When I import both scripts, a blank tkinter (title = "tk") window pops up.
Questions:
1. What is causing this?
2. How can I prevent that stupid window from popping up?
3. Is there an automated way to see that extra window and kill it when it does show?
What I've done:
Googled my hiney off
Renamed Tk import so each script has its own instance
Banged my head on the desk
Code:
uidpassform (first script that directly uses tkinter)
from tkinter import Tk as lf2Tk
from tkinter import Label, StringVar, Entry, Button
o_window = lf2Tk()
username = StringVar()
password = StringVar()
def close_dialog():
o_window.destroy()
def uidpass form():
#Return the value of the selected option
o_window.title('Oracle Login Credentials')
#username label and text entry box
Label(o_window, text="User Name").grid(row=2, column=0,padx = 5,pady = 20)
Entry(o_window, textvariable=username).grid(row=2, column=2, padx=20)
#password label and password entry box
Label(o_window,text="Password").grid(row=3, column=0,padx = 5)
Entry(o_window, textvariable=password, show='*').grid(row=3, column=2,padx = 20)
#login button
Button(o_window, text="Connect", command=close_dialog).grid(row=4, column=3,columnspan=2, padx = 20)
Label(o_window, text="").grid(row=5)
o_window.mainloop()
print (username.get())
print (password.get())
return [username.get(), password.get()]
if __name__ == "__main__":
uidpassform()
radiobutton form (second tkinter form)
from tkinter import Tk as rbTK
from tkinter import Radiobutton, Button, Label, IntVar, LEFT, W
rb_window = rbTK()
v = IntVar()
def validate():
#Display the value of the selected option for debugging purposes
value = v.get()
return (value)
def close_dialog():
#Check to see if the Radiobutton has a value and if so, close the form
value = v.get()
if value == 0:
value = v.get()
else:
rb_window.destroy()
def fnradiobutton():
#Return the value of the selected option
rb_window.title("Connection")
Label(rb_window, text="Choose a Data Connection:", justify=LEFT, padx=20).grid(row=0, sticky=W)
Radiobutton(rb_window, text="Production", variable=v, value=1, command=validate).grid(row=1, padx=20, sticky=W)
Radiobutton(rb_window, text="Test", variable=v, value=2, command=validate).grid(row=2, padx=20, sticky=W)
Button(rb_window, text="Done", command=close_dialog).grid(row=3, column=2, padx=10)
Label(rb_window, text="").grid(row=4)
#print(str(V.get()) + " from fnradiobutton")
rb_window.mainloop()
return v.get()
if __name__ == "__main__":
fnradiobutton()
Main script (calls the two tkinter scripts)
import cx_Oracle
import lf2 as lf
import time
import radiobutton as rb
import pyodbc
def oracle_connection():
#Get Oracle UserID and password
uidpass_list = lf.uidpassform()
#Create the connection
try:
oracle_conn = cx_Oracle.connect(uidpass_list[0], uidpass_list[1], 'robanner', encoding='UTF-8')
except:
return oracle_conn
def dbconnect(switch):
#Choose the proper connection, based on the radiobutton form
if switch == 1:
connection = pyodbc.connect('DSN=PCard_Production;Trusted_Connection=yes;')
else:
connection = pyodbc.connect('DSN=PCardTest;Trusted_Connection=yes;')
return connection
def run_script():
start = time.time()
oracle_conn = oracle_connection()
swich = rb.fnradiobutton()
conn = dbconnect(swich)
if __name__ =='__main__':
# This is the summary spot
run_script()
Try putting code for creating Root Window into functions and have them return variables. Then you have to modify your other functions to use the variables.
def initialize():
o_window = lf2Tk()
username = StringVar()
password = StringVar()
return o_window, username, password
def close_dialog(o_window):
o_window.destroy()
...
def initialize():
rb_window = rbTK()
v = IntVar()
return rb_window, v
def validate(v):
#Display the value of the selected option for debugging purposes
value = v.get()
return (value)
...
Then in your main script:
def oracle_connection():
#Get Oracle UserID and password
o_window, username, password = lf.initialize()
uidpass_list = lf.uidpassform(o_window, username, password)
#Create the connection
try:
oracle_conn = cx_Oracle.connect(uidpass_list[0], uidpass_list[1], 'robanner', encoding='UTF-8')
except:
return oracle_conn
...

reading and playing a word in the message window

I have a problem with the code and an error message appears in word -> word = "" word = str (Entry.get (input_text)) which obviously refers to printing full text which does not work the way I want it when I want it to work in a non-root window window but reading window.
This is the codes :
from tkinter import *
import sys
import tkinter as tk
from tkinter import messagebox
#---------
root = Tk()
root.title("Window")
#----------
#toiminnot root ikkunassa
functions = Label(root, text = "Select an action!")
functions.place(x = 70, y= 10)
#lue toimonto koodi alkaa
def read():
reading_window = Tk()
reading_window.title("Read function")
frame = Frame(reading_window)
frame.pack()
read_the_text = Label(reading_window, text = "Enter text in the box!")
read_the_text.place(x = 70, y = 10)
word = ""
word = str(Entry.get(input_text))
#frame johon kirjoitetaan
input_text = Entry(reading_window)
input_text.place(x=55, y=30)
#lueikkuna koko ja sijoitus
reading_window.geometry("300x300+100+100")
#lue sana painike joka tuo viestin
print_button = tk.Button(reading_window, text = 'Show typed text', height = 1, width = 15) #, command = print1)
print_button.place(x=80, y=60)
text_a_tip = Label(reading_window, text ="The typed text is displayed in\nthe message window!")
text_a_tip.place(x = 50, y = 90)
def print1():
tk.messagebox.showinfo('Kirjoitetun tekstin tulostus viestiikkunaan', (Entry.get(input_text)))
def close():
reading_window.destroy()
read_close_button = tk.Button(reading_window, text = 'Close the reading function', height = 1, width = 20, command = close)
read_close_button.place(x = 60, y = 270)
read.mainloop()
#lue toiminto koodi loppuu
read_function = tk.Button(root, text='Read function', height = 1, width = 15, command = read)
read_function.place(x = 55,y = 35)
#ohjleman lopettamisen koodi alkaa
def quit_prog():
MsgBox = tk.messagebox.askquestion('Quit program', ' Are you sure you want to close the program?',icon = 'warning')
if MsgBox == 'yes':
root.destroy()
sys.exit(0)
else:
tk.messagebox.showinfo('Back','Now you are back!')
quit_programbutton = tk.Button(root, text='Close program', height = 1, width = 15, command = quit_prog)
quit_programbutton.place(x=50, y=220)
#ohjelman lopettamisen koodi loppuu tähän
#----------
#----------
root.geometry("250x250+20+60") #"450x450=leveysxkorkeus"+"20+40=vasenreuna+yläreuna"
root.mainloop()
source
I don't really see what is "word" variable for, but I assume that You need it. You can't use variable defined under line in which you use it.
word = ""
word = str(Entry.get(input_text)) # input_text is defined below, interpreter doesn't know what is it "input_text" yet.
input_text = Entry(reading_window)
input_text.place(x=55, y=30)
It should be rather.
input_text = Entry(reading_window)
input_text.place(x=55, y=30)
word = ""
word = str(Entry.get(input_text)) # now there is no error
It doesn't solve your problem, because I see that in function print1 you use again imput_text but it's defined in different function so it won't work.
def print1():
# input_text is local variable in read function.
tk.messagebox.showinfo('Kirjoitetun tekstin tulostus viestiikkunaan', (Entry.get(input_text)))
To solve your problem you can pass input_text as argument of print1, like in this working example.
def read():
reading_window = Tk()
reading_window.title("Read function")
frame = Frame(reading_window)
frame.pack()
read_the_text = Label(reading_window, text = "Enter text in the box!")
read_the_text.place(x = 70, y = 10)
input_text = Entry(reading_window)
input_text.place(x=55, y=30)
word = ""
word = str(Entry.get(input_text))
reading_window.geometry("300x300+100+100")
# pass input_text to print1
print_button = tk.Button(reading_window, text = 'Show typed text', height = 1, width = 15, command = lambda: print1(input_text))
print_button.place(x=80, y=60)
text_a_tip = Label(reading_window, text ="The typed text is displayed in\nthe message window!")
text_a_tip.place(x = 50, y = 90)
def print1(input_text):
# print1 takes now one argument and has reference to input_text
tk.messagebox.showinfo('Kirjoitetun tekstin tulostus viestiikkunaan', (Entry.get(input_text)))
def close():
reading_window.destroy()
read_close_button = tk.Button(reading_window, text = 'Close the reading function', height = 1, width = 20, command = close)
read_close_button.place(x = 60, y = 270)
read.mainloop()
Consider also using different geometry manager than place, it is even written in effbot doc:
It is usually not a good idea to use place for ordinary window and dialog layouts; its simply to much work to get things working as they should. Use the pack or grid managers for such purposes.
Place Geometry Manager

Tkinter entry getting text entered by user

I am very new to Tkinter ( I find it very difficult to learn). I have a python script working based on user input. I would like to wrap a GUI around it and eventually put it on web. In any case for user input I would like to get this from the GUI with a combination of Entry widgets and some buttons. First thing is I was reading and some people mentioned to use a class so I have the following. I have a few questions
I would like to check to see if indeed the users entered a value before he hits the GO button. How do I do this?
I would like the value entered to be made accessible by the rest of the program in the main body. How do I do this?
Thanks,
from Tkinter import *
class MainWindow():
def get_fc(self):
a = self.fc_gui.get()
return a
def __init__(self, master):
self.master = master
self.master.title('TEST')
self.fc_gui = DoubleVar(self.master, value = 500.00)
self.fclabel1 = Label(self.master, text = 'Please Enter a value', fg = 'black', bg = 'yellow')
self.fclabel1.grid(row = 0, column = 0)
self.fcedit1 = Entry(self.master, textvariable = self.fc_gui, bd = 5 )
self.fcedit1.grid(row = 1, column = 0)
fcbutton1 = Button(self.master, text='GO', command = self.get_fc)
fcbutton1.grid(row = 1, column = 1)
master = Tk()
MainWindow(master)
master.mainloop()
It doesn't make sense to return to a Button. The Button can't do anything with the value. Instead, save the value as an instance variable.
You don't have a mainloop().
You can't really check if the user entered a value before they hit "Go" - at the start of the program, of course they haven't entered anything yet. If you needed to track the contents of this field, there are ways to do that, but it's not necessary for a simple validation. Just check the value when they hit the button.
from Tkinter import *
class MainWindow():
def get_fc(self):
a = self.fc_gui.get()
if a: # this block will execute if a has content
self.a = a # save it for future use
def __init__(self, master):
self.master = master
self.master.title('TEST')
self.fc_gui = DoubleVar(self.master, value = 500.00)
self.fclabel1 = Label(self.master, text='Please Enter a value',
fg = 'black', bg = 'yellow')
self.fclabel1.grid(row = 0, column = 0)
self.fcedit1 = Entry(self.master, textvariable = self.fc_gui, bd = 5 )
self.fcedit1.grid(row = 1, column = 0)
fcbutton1 = Button(self.master, text='GO', command = self.get_fc)
fcbutton1.grid(row = 1, column = 1)
master = Tk()
MainWindow(master)
master.mainloop() # don't forget mainloop()

How do I make the program wait for an input using an Entry box in Python GUI?

This is the code for the function I'm using to start the main part of the program, however I want some sort of loop or something which creates ten questions, but waits for an input from the Entry box before moving onto the next question.
Any ideas?
def StartGame():
root = Tk()
root.title("Maths Quiz - Trigonometry and Pythagoras' Theorem | Start The Game")
root.geometry("640x480")
root.configure(background = "gray92")
global AnswerEntry
TotScore = 0
Count = 0
AnswerReply = None
WorkingArea = Text(root, width = 70, height = 10, wrap = WORD).place(x = 38, y = 100)
n = GetRandomNumber()
Angle,Opposite,Adjacent,Hypotenuse = Triangle()
Question,RealAnswer = QuestionLibrary(Opposite,Adjacent,Hypotenuse,Angle,n)
AskQuestion = Label(root, text = Question, wraplength = 560).place(x = 48, y = 300)
PauseButton = ttk.Button(root, text = "Pause").place(x = 380, y = 10)
HelpButton = ttk.Button(root, text = "Help", command = helpbutton_click).place(x = 460, y = 10)
QuitButton = ttk.Button(root, text = "Quit", command = root.destroy).place(x = 540, y = 10)
AnswerEntry = Entry(root)
AnswerEntry.place(x = 252, y = 375)
SubmitButton = ttk.Button(root, text = "Submit", command = submit_answer).place(x = 276, y = 400)
TotScore,AnswerReply = IsAnswerCorrect(Answer,RealAnswer)
ScoreLabel = ttk.Label(root, text = TotScore).place(x = 38, y = 10)
AnswerReplyLabel = ttk.Label(root, text = AnswerReply).place(x = 295, y = 440)
root.mainloop()
I want the loop to start after the AnswerReply = None
You don't want a loop. The only really important loop inside a GUI should be the mainloop(), handling signal and executing callbacks.
Example:
try:
import Tkinter as Tk
except ImportError:
import tkinter as Tk
class QAGame(Tk.Tk):
def __init__(self, questions, answers, *args, **kwargs):
Tk.Tk.__init__(self, *args, **kwargs)
self.title("Questions and answers game")
self._setup_gui()
self._questions = questions[:]
self._answers = answers
self._show_next_question()
def _setup_gui(self):
self._label_value = Tk.StringVar()
self._label = Tk.Label(textvariable=self._label_value)
self._label.pack()
self._entry_value = Tk.StringVar()
self._entry = Tk.Entry(textvariable=self._entry_value)
self._entry.pack()
self._button = Tk.Button(text="Next", command=self._move_next)
self._button.pack()
def _show_next_question(self):
q = self._questions.pop(0)
self._label_value.set(str(q))
def _move_next(self):
self._read_answer()
if len(self._questions) > 0:
self._show_next_question()
self._entry_value.set("")
else:
self.quit()
self.destroy()
def _read_answer(self):
answer = self._entry_value.get()
self._answers.append(answer)
def _button_classification_callback(self, args, class_idx):
self._classification_callback(args, self._classes[class_idx])
self.classify_next_plot()
if __name__ == "__main__":
questions = ["How old are you?",
"What is your name?"]
answers = []
root = QAGame(questions, answers)
root.mainloop()
for q,a in zip(questions, answers):
print "%s\n>>> %s" % (q, a)
We only have a Label, an Entry and a Button (I did not care about layout!, just pack()).
Attached to the button is a command (aka callback). When the button is pressed, the answer is read and the new question is assigned to the label.
Usage of this class is understandable from the example in the `if name == "main" block. Please note: the answers-list is filled in place, the questions-list is kept unchanged.
I don't know Tk, but is there no any signals of input text changed? There should be for sure. Just check if this signal occured and then move onto new question, because it means that someone typed something in input box.

Categories

Resources