Python: Tkinter: Multi line scrolling entry box - python

I would like to make a Tkinter window able to ask for a multi line entry
(so the user will add one or more lines of text)
And then when we clic on the button be able to retrieve the values entered by user for further use.
Until now I have this script:
from Tkinter import *
import ScrolledText
class EntryDemo:
def __init__(self, rootWin):
#Create a entry and button to put in the root window
self.textfield = ScrolledText(rootWin)
#Add some text:
self.textfield.delete(0,END)
self.textfield.insert(0, "Change this text!")
self.textfield.pack()
self.button = Button(rootWin, text="Click Me!", command=self.clicked)
self.button.pack()
def clicked(self):
print("Button was clicked!")
eText = self.textfield.get()
print("The Entry has the following text in it:", eText)
#Create the main root window, instantiate the object, and run the main loop
rootWin = Tk()
#app = EntryDemo( rootWin )
rootWin.mainloop()
But it didn't seem to work, A window appear with nothing inside.
Could you help me?
#########EDIT
New code:
from Tkinter import *
import ScrolledText
class EntryDemo:
def __init__(self, rootWin):
self.textfield = ScrolledText.ScrolledText(rootWin)
#Add some text:
#self.textfield.delete(0,END)
self.textfield.insert(INSERT, "Change this text!")
self.textfield.pack()
self.button = Button(rootWin, text="Click Me!", command=self.clicked)
self.button.pack()
def clicked(self):
eText = self.textfield.get(1.0, END)
print(eText)
rootWin = Tk()
app = EntryDemo( rootWin )
rootWin.mainloop()
Sorry if it look like done with no effort by some down voters (even if I spent more than a day on it) but the Multi line text entry is not exactly what we can call well documented to learn by ourself.

Your first problem is that you commented out the app = EntryDemo( rootWin ) call, so you're not actually doing anything but creating a Tk() root window, then starting its main loop.
If you fix that, your next problem is that you're trying to use the ScrolledText module as if it were a class. You need the ScrolledText.ScrolledText class.
If you fix that, your next problem is that you're trying to delete from an empty text field, which is going to raise some kind of Tcl index error, and then you're also trying to insert at position 0 in an empty text field, which will raise the same error. There's no reason to do the delete at all, and for the insert you probably want to use INSERT as the position.
You still have multiple problems after that, but fixing these three will get your edit box up and displayed so you can start debugging everything else.

A working example based on your code. Note the comment above that both the file you import and the class within the file are named "ScrolledText"
from Tkinter import *
import ScrolledText
class EntryDemo:
def __init__(self, rootWin):
#Create a entry and button to put in the root window
self.textfield = ScrolledText.ScrolledText(rootWin)
self.textfield.pack()
#Add some text:
self.textfield.delete('1.0', END)
self.textfield.insert('insert', "Change this text!")
self.button = Button(rootWin, text="Click Me!",
command=self.clicked)
self.button.pack()
def clicked(self):
print("Button was clicked!")
eText = self.textfield.get('1.0', END)
print("The Entry has the following text in it:", eText)
self.textfield.delete('1.0', END)
rootWin = Tk()
app = EntryDemo( rootWin )
rootWin.mainloop()

Related

Tkinter: How do I return the text within an Entry widget to a variable upon a Button press

This is what I tried
GUI.py
from tkinter import *
class Search:
def __init__(self, root):
self.query = None
self.root = root
# Create and draw container
self.frame = Frame(self.root)
self.frame.pack()
# Create widgets
self.search_bar = Entry(self.frame)
self.search_button = Button(self.frame, command = self.get_query, text = 'Search')
# Draw widgets
self.search_bar.pack()
self.search_button.pack()
def get_query(self):
self.query = self.search_bar.get()
def create_gui_root(): # Should I be doing this in a function in GUI.py?
root = Tk()
root.geometry('300x300')
return root
main.py
from GUI import *
def use_query_to_do_stuff(query):
print(query)
def main():
# Create GUI root instance
root = create_gui_root()
# Initialize search page
search_page = Search(root)
# I know this part is wrong, just not sure where to go from here
# It runs the search_submit method on start instead of waiting for the button to be pressed
query = search_page.get_query()
use_query_to_do_stuff(query)
root.mainloop() # Also is this in the right place?
main()
I want the program to wait until I press the button, then assign the text inside the Entry widget to a variable.
I started off with a fully working text-based program in main.py and I'm trying to add a GUI.
I'm trying to learn how to split the logic and GUI into separate Python files so I import the Search class into the main.py file and I need GUI.py to return the search query back to main.py when the button is pressed.
I'm also unsure if I'm going about using classes and functions and separating logic from GUI the right way. Should I be using a bunch of functions instead of a class? Or am I using the class wrong?
Are the root = Tk() and root.mainloop() lines even in the right place?
I thought of importing main.py into GUI.py, creating a method in Search() to call the function use_query_to_do_stuff() from main.py while passing self.search_bar.get() as a parameter directly, then binding that method to the self.search_button command. However, I feel like cross-importing your main.py file into your GUI.py is counter-intuitive, I kind of feel like all roads should 'lead back' to the main.py file, if that makes sense. Then again, maybe I'm completely lost.
I made main.py first and it ran as intended, but now that I'm trying to implement a GUI I feel like I'm going about everything slightly incorrectly.
Add Label in GUI.
Add label.configure in get_query(self) function
.
Snippet code:
# Create widgets
self.search_bar = Entry(self.frame)
self.search_button = Button(self.frame, command = self.get_query, text = 'Search')
self.label = Label(self.frame)
# Draw widgets
self.search_bar.pack()
self.search_button.pack()
self.label.pack(padx=15, pady=35)
def get_query(self):
self.query = self.search_bar.get()
self.label.configure(text=self.query)
self.search_bar.delete(0, END)
print(self.query)
Screenshot before:
Screenshot after:

Why does StringVar() not change value whenever I use it under a second mainloop() window?

I'm currently creating a login system which connects to a main application. The user uses the log in system to log in through a series of window, and after this is done, the log in window should close and the main program should open.
I've created a small example of my project. The issue I'm getting is that StringVar() doesn't seem to work in the second window.
Code for the first window:
# Python program to create a window linking to the second window
from tkinter import *
import tkinter as tk
import test2
class Window(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
frame = Frame(self)
frame.grid()
# creates a button which closes this window and opens the next
button2 = Button(frame, text='next frame', command=lambda: self.open_window())
button2.grid()
def open_window(self):
# runs the 'openWindow' function from the second file named 'test2'
test2.openWindow(app, test2)
if __name__ == '__main__':
app = Window()
app.mainloop()
Code for the second window:
# Second window named 'test2' which is displayed after the button in the first window is pressed
from tkinter import *
import tkinter as tk
def openWindow(app, window):
Application = window.Window2()
app.withdraw() # closes the first window
Application.mainloop() # opens the second window
class Window2(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
frame = Frame(self)
frame.grid()
self.var = StringVar() # creates the StringVar()
self.var.set("default")
# creates an entry which is linked to self.var
entry = Entry(frame, textvar=self.var, width=50, bg='lightgrey', justify=LEFT)
entry.grid(padx=16, ipady=20)
# this button should print the contents of the entry widget
button = Button(frame, text='print', command=lambda: self.print_var())
button.grid()
def print_var(self):
# prints value of self.var
print(self.var.get())
The problem I get is that when I press the button in the second window, it doesn't print the actual contents of the entry widget. I think this means that the StringVar() isn't working properly so doesn't link to the entry widget, but I'm not sure why this is happening.

tkinter use same widget multple times

Since no one in the Spanish StakOverFlow hasn't answered me yet, I'm asking here. I'm from ARG. I am working on an mass document upload automation. The first widget I made with tkinter asks the user what type of document wants to upload to the web. Once this process is done, I want to throw another widget to ask the same question. The thing is I don't know how to write that code. I have not learned yet how to handle classes. And the code for my widget is a copy from an example of the web, and formatted to fit my specs.
from Tkinter import Tk, Label, Button
class DocumentTypeOption:
def __init__(self, master):
self.master = master
master.iconbitmap("bigpython.ico")
master.minsize(280,150)
master.geometry("280x150")
master.title("DOCUMENT TYPE")
self.label = Label(master, text="SELECT THE DOCUMENT TYPE")
self.label.pack()
self.tipo1_button = Button(master, text="Tipo1", command=self.opcion_tipo1)
self.tipo1_button.pack()
self.tipo2_button = Button(master, text="Tipo2", command=self.opcion_tipo2)
self.tipo2_button.pack()
def funciontipo1(self):
def subirtipo1():
"things to upload doc type1"
time.sleep(0.5)
root.destroy()
time.sleep(1)
subirtipo1()
"SHOULD THE WIDGET BE CALLED HERE?"
def funciontipo2(self):
def subirtipo1():
"things to upload doc type2"
time.sleep(0.5)
root.destroy()
time.sleep(1)
subirtipo2()
"SHOULD THE WIDGET BE CALLED HERE?""
root = Tk()
my_gui = OpcionTipoDeDocumento(root)
root.mainloop()
When one type of document was uploaded I need to throw the widget once more in order to ask the user if he wants to continue with the other type of document.
There are a few options. You could simply keep the Tkinter window open and ask the user if they want to load another file. You also are using sleep() inside a tkinter instance. You cannot use sleep() within Tkinter. There is another method called after() that is for setting up timed events to replace the use of sleep(). In this case I don't think you need a delay anyway.
Here is a simple example using a tkinter class and 1 function for the doc and 1 function to ask if you want to load another one.
# import tkinter as tk # for python 3.X
# from tkinter import messagebox # for python 3.X
import Tkinter as tk
import tkMessageBox as messagebox
class DocumentTypeOption(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.iconbitmap("bigpython.ico")
self.minsize(280,150)
self.geometry("280x150")
self.title("DOCUMENT TYPE")
self.label = tk.Label(self, text="SELECT THE DOCUMENT TYPE")
self.label.pack()
self.tipo1_button = tk.Button(self, text="Tipo1", command=lambda: self.do_stuff("Tipo1"))
self.tipo1_button.pack()
self.tipo2_button = tk.Button(self, text="Tipo2", command=lambda: self.do_stuff("Tipo2"))
self.tipo2_button.pack()
def do_stuff(self, doc_type):
# things to upload doc type1
# you can do this part with a single function as long as you check the doc type first.
print(doc_type) # just to verify buttons are working.
self.check_next(doc_type)
def check_next(self, doc_type):
x = messagebox.askyesno("DOCUMENT OPTION", "Would you like to load another {}?".format(doc_type))
if x != True:
self.destroy()
my_gui = DocumentTypeOption()
my_gui.mainloop()

Audio quiz with Tkinter

I'd like to create a simple quiz with Tkinter (Python 2.7). I have a list of audios and for each of them I want to have the following:
A button that reproduces the audio.
An entry where the user can introduce any text.
A label displaying "Incorrect" by default and "Correct!" whenever the text in the entry is the title of the song in the audio.
I managed to create the three objects, but I'm having a hard time trying to update the label according to the entry text: there are many references around but I couldn't get it working. I guess I do not understand well how the loop works and when events are triggered.
Could you please provide a minimal example that does what I intend to? I provide my code below, but it is very likely to be bloated (I'm totally novice to Tkinter and to object oriented programming) since I basically built it from an existing example in the Internet:
#!/usr/bin/env python
#encoding=utf-8
import Tkinter as tk
import vlc
tk.Tk()
var_entry= tk.StringVar()
var_label= tk.StringVar()
class Application(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.grid()
self.createWidgets()
def createWidgets(self):
self.audio= tk.Button(self,text='Play Audio',command=lambda:vlc.MediaPlayer('./audios/my_audio.mp3').play())
self.audio.grid()
self.entry = tk.Entry(self,width=50,textvariable=var_entry)
self.entry.grid()
var_label.set('Correct!\n' if var_entry.get()=='my_audio_title' else 'Incorrect\n')
self.label = tk.Label(self,textvariable=var_label)
self.label.grid()
self.quitButton = tk.Button(self, text='Quit',command=self.quit)
self.quitButton.grid()
app = Application()
app.master.title('Audio Quiz')
app.mainloop()
I'm sure that the line starting by var_label.set is missplaced, but I don't really know where I should write it and how to make the update for the label.
Thanks in advance.
You can use trace to achieve:
A label displaying "Incorrect" by default and "Correct!" whenever the text in the entry is the title of the song in the audio.
When trace is used with 'w' option, it calls a method whenever the variable class(BooleanVar, DoubleVar, IntVar, StringVar) it is attached to is re-written. Below is an example checking whether the text in the entry is "Valid String" or not:
import tkinter as tk
def check_entry(*args):
global entry, entry_var, label
if entry_var.get() == "Valid String":
label['text'] = "Correct"
else:
label['text'] = "Incorrect"
root = tk.Tk()
entry_var = tk.StringVar()
label = tk.Label(root)
entry = tk.Entry(root, textvariable=entry_var)
label.pack()
entry.pack()
entry_var.trace('w', check_entry)
root.mainloop()

Tkinter Browse Button Self Deleting

I am trying to create a browse button in tkinter. I have created the open folder dialog box but when i set it to the button it will exit out of the window.
My ultimate goal is to:
1) click on the button and bring up the file dialogue box
2) select a file
3) insert the file name into an Entry Widget for later use
I should note that I am using multiple window frames for the code that follows is summed up.
import os
import sys
import Tkinter as tk
from tkFileDialog import askopenfilename
def openFile(entryWidgetName):
tk.Tk().withdraw()
filename = askopenfilename()
entryWidgetName.delete(0,tk.END)
entryWidgetName.insert(0,filename)
return
class Welcome():
def __init__(self,master):
self.buttonNewTemplate = tk.Button(self.master, text = 'Create a New Template', command = self.gotoNewTemplate).place(x=100, y=250)
def gotoNewTemplate(self):
root2 = tk.Toplevel(self.master)
newTemplate = NewTemplate(root2)
class NewTemplate():
def __init__(self, master):
#Entry Windows
self.uploadFile = tk.Entry(self.sectionFrame2, width = 80).grid(row=4, column = 1, sticky = 'w')
#Buttons
self.buttonBrowse=tk.Button(self.sectionFrame2, text='Browse', fg='blue', command=lambda:openFile(uploadFile)).grid(row=4, column = 0, padx = 10, sticky = 'w')
Every time I click the browse button the second window destroys itself bringing me back to the main page.
Does anyone have any suggestions?
A tkinter application can only have a single instance of Tk. You are creating at least two: one explicitly in openFile, and one from somewhere else in your code either implicitly or explicitly.
Since the only way to call openFile is from a button click, and the only way to have a button click is to have a button, and the only way to have a button is to already have a root window, you need to remove the statement tk.Tk().withdraw() since that is creating a new root window.
There may be other problems in your code, but it's impossible to know based on the incomplete code in the question.

Categories