I've read a few threads all over the internet regarding clearing a text box on tkinter. Basically everyone says it's simple:
text.delete("1.0", END)
However, perhaps it has something to do with the way I structured it, or the way I'm calling it, but for some reason, this does not work for me. It simply does nothing.
I've tried re-positioning the def, and re-writing the text.delete("1.0", END) in a number of ways, most of which lead me to other errors, but I cannot seem to get this to work.
Ultimately, what I'm trying to accomplish is that when I click a button, the text box will clear, before populating with new information.
Below is my code.
from tkinter import *
from PIL import Image, ImageTk
import functions
class MainWindow(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("pyTicket")
# TOOLBAR ####################################################
toolbar = Frame(self.parent, bd=1, relief=RAISED)
self.img = Image.open("Icons\startupcheck.png")
eimg = ImageTk.PhotoImage(self.img)
startupButton = Button(toolbar, text="Re-Check ", image=eimg, compound="left", relief=RAISED, command=self.StartUpChecker)
startupButton.image = eimg
startupButton.pack(side=RIGHT, padx=2, pady=2)
toolbar.pack(side=TOP, fill=X)
self.parent.config(menu=menubar)
self.pack(anchor=N, side=TOP, fill=X, expand=False)
# TOOLBAR ####################################################
# TEXTBOX ####################################################
self.textbox = Text(self, wrap="word", height=5)
self.textbox.pack(side="bottom", fill="both", expand=True)
self.textbox.tag_configure("TextBox", foreground="#b22222")
self.pack(anchor=S, side=BOTTOM, fill=BOTH, expand=True)
# TEXTBOX ####################################################
# Functions ###################################################
def StartUpChecker(self):
self.clear_text()
functions.StartUpChecker()
def clear_text(self):
self.textbox.delete("1.0", END)
class TextRedirector(object):
def __init__(self, widget, tag="stdout"):
self.widget = widget
self.tag = tag
def write(self, str):
self.widget.configure(state="normal")
self.widget.insert("end", str, (self.tag,))
self.widget.configure(state="disabled")
def main():
root = Tk()
#Width X Height
root.geometry("500x300+300+300")
root.update()
root.minsize(400,200)
app = MainWindow(root)
root.mainloop()
if __name__ == '__main__':
main()
You don't appear to actually use the TextRedirector class in the code you posted, but if you're using it in your actual code, note that its .write() method leaves the textbox in a disabled state - which prevents ALL modifications, even those resulting from code instead of direct user action. Your .clear_text() method needs to temporarily enable the textbox so that you can modify it, exactly as .write() does.
Related
i'm just new to programming in python.
I'd like to create a sample project wherein I import a text file in a Button click command and display it in an Text widget. The Button function is in a different class called ButtonAction, and the widget is created in another class called Window. The problem is I don't have an idea how to get the existing Text widget so i can append the imported data.
I removed some formatting codes.
Code:
from tkinter.filedialog import *
class Window(Frame):
def __init__(self):
super().__init__()
self.initgui()
def initgui(self):
self.pack(fill=BOTH, expand=True)
textarea = Text(self)
textarea.grid(row=0, column=0, columnspan=2, rowspan=4,
padx=10, pady=10, sticky=E + W + S + N)
imprtbutton = Button(self, text="Import XML", command=ButtonAction().import_onclick)
imprtbutton.grid(row=0, column=2, padx=5, sticky=S)
class ButtonAction:
def __init__(self):
pass
def import_onclick(self):
file = askopenfile(mode='r')
if file is not None:
content = file.read()
print(content) #just so i can see if i successfully imported my txt file
if __name__ == '__main__':
root = Tk()
root.geometry("500x500+300+200")
root.title("Test Project")
gui = Window()
root.mainloop()
Hello and welcome to Stackoverflow.
When I started your script, I was not able to see the "Import XML" button at all. I needed to resize the window first. That is the reason, why I played around with the .pack and .grid calls in your code.
To solve your problem, I added the argument callback to your import_onclick method. This provides a means for the ButtonAction class to return the data back to the Window class. Here the new method update_text is responsible for filling the content of textarea.
Because we now need an additional argument for import_onclick, I wrapped the former ButtonAction().import_onclick argument into a lambda:
lambda: ButtonAction().import_onclick(self.update_text)
The resulting code works fine for me:
from tkinter.filedialog import *
class Window(Frame):
def __init__(self):
super().__init__()
self.textarea = Text(self)
self.initgui()
def initgui(self):
self.pack(fill=BOTH, expand=True)
self.textarea.pack(side=LEFT, padx=5, pady=5)
import_button = Button(self,
text="Import XML",
command=lambda: ButtonAction().import_onclick(self.update_text)
)
import_button.pack(side=RIGHT, padx=5, pady=5)
def update_text(self, text):
self.textarea.delete(1.0, END)
self.textarea.insert(END, text)
class ButtonAction:
def __init__(self):
pass
def import_onclick(self, callback):
file = askopenfile(mode='r')
if file is not None:
content = file.read()
# just so i can see if i successfully imported my txt file
print(f"read {len(content)} lines")
callback(content)
if __name__ == '__main__':
root = Tk()
root.title("Test Project")
gui = Window()
root.mainloop()
I want to create some simple tkinter python app (like StickyNotes on Windows), i have create the class mainApplication and i do not know how to by just simply triggering the button create another instance of this class which will be displayed pararell to other window (or even multiple windows). I know how to assigned function to pushButton, and other simple stuff but the problem is with this pararell window displaying. Thanks in advance for help.
class mainApplication(Frame):
_ids = count(0)
def __init__(self, parent):
""" """
self.id = next(self._ids)
Frame.__init__(self, parent)
self.parent = parent
self.parent.minsize(width=200,height=100)
self.parent.geometry(('%dx%d+%d+%d' % (200, 100, 1700, 0+self.id*100)))
self.initUI()
def initUI(self):
""" """
self.parent.title("a2l")
self.pack(fill=BOTH, expand=True)
style = Style()
style.configure("TFrame", background="#333")
frame1 = Frame(self, style="TFrame")
frame1.pack(fill=X)
self.lbl0 = Label(frame1, text="api", width=7, background="#333", foreground = "red")
self.lbl0.pack(side=TOP, padx=5, pady=5)
self.closeButton = Button(self, text="new", command = self.createNewInstance)
self.closeButton.pack(side=RIGHT, padx=5, pady=5)
#=======================================================================
# self.generateButton = Button(self, text="GENERATE", command = self.)
# self.generateButton.pack(side=RIGHT, padx=5, pady=5)
#=======================================================================
def createNewInstance(self):
y = mainApplication()
return y
if __name__ == "__main__":
root = Tk()
x = mainApplication(root).pack(side="top", expand=False)
Tk().mainloop()
You shouldn't create more than one Tk() window in one application with tkinter. Instead tkinter provides a widget called Toplevel which can be useful for this kind of thing.
It creates another window which can exist along side the Tk() window and alongside other Toplevel widgets.
You could use this to create a series of persistent windows with whatever text or widgets you wanted on them at any kind of trigger including a Button.
See my example below for a demonstration:
from tkinter import *
class App:
def __init__(self, root):
self.root = root
self.top = [] #list to contain the Toplevel widgets
self.entry = Entry(self.root)
self.button = Button(self.root, text="Create window", command=self.command)
self.entry.pack()
self.button.pack()
def command(self): #called when button is pressed
self.top.append(Toplevel(self.root)) #adds new Toplevel to the list
Label(self.top[len(self.top)-1], text=self.entry.get()).pack() #Adds label equal to the entry widget to the new toplevel
root = Tk()
App(root)
root.mainloop()
How can I get a blocking modal input dialog box in standard Python?
I need the user to input a value before the code can proceed.
Here is some not-working test code, but the idea is that I should be able to call MyDialog from anywhere in the script, so this is just a simplified example.
import tkinter
class MyDialog:
def __init__(self, prompt):
self.top = tkinter.Toplevel()
tkinter.Label(self.top, text=prompt).pack()
self.e = tkinter.Entry(self.top)
self.e.pack(padx=5)
tkinter.Button(self.top, text="OK", command=self.ok).pack(pady=5)
def ok(self):
self.top.destroy()
return self.e.get()
root = tkinter.Tk()
userName = MyDialog('Enter your name')
tkinter.Label(root, text="Hello {}".format(userName)).pack()
root.mainloop()
The dialog should not only disable the master window, but block whatever code called it. And it should be able to pass the value back to the calling code.
The solution requires two critical pieces. First, use grab_set to block all events in the other window (or, more correctly, send all events to the dialog window). Second, use wait_window to prevent the method from returning until the dialog has been destroyed.
That being said, you shouldn't be using it like in your example. You need to have the mainloop running before you create the window. It might work OK on some platforms, but in general you shouldn't expect your GUI to behave properly until mainloop is running.
Here's a simple example:
import Tkinter as tk
class MyDialog(object):
def __init__(self, parent, prompt):
self.toplevel = tk.Toplevel(parent)
self.var = tk.StringVar()
label = tk.Label(self.toplevel, text=prompt)
entry = tk.Entry(self.toplevel, width=40, textvariable=self.var)
button = tk.Button(self.toplevel, text="OK", command=self.toplevel.destroy)
label.pack(side="top", fill="x")
entry.pack(side="top", fill="x")
button.pack(side="bottom", anchor="e", padx=4, pady=4)
def show(self):
self.toplevel.grab_set()
self.toplevel.wait_window()
value = self.var.get()
return value
class Example(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.button = tk.Button(self, text="Click me!", command=self.on_click)
self.label = tk.Label(self, text="", width=40)
self.label.pack(side="top", fill="x")
self.button.pack(padx=20, pady=20)
def on_click(self):
result = MyDialog(self, "Enter your name:").show()
self.label.configure(text="your result: '%s'" % result)
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack(fill="both", expand=True)
root.mainloop()
I'm working on my very first Python GUI and I'm trying to modify this tkinter example, but I simply cannot figure out how to write a callback function for the OK button that will pass on the entered value to the main program.
#!/usr/bin/python
# -*- coding: utf-8 -*-
from Tkinter import Tk, BOTH, StringVar, IntVar
from ttk import Frame, Button, Style, Label, Entry
class Example(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("Get Value")
self.style = Style()
self.style.theme_use("default")
self.pack(fill=BOTH, expand=1)
valueLabel = Label(self, text="Value: ")
valueLabel.place(x=10, y=10)
value=StringVar(None)
value.set("this is the default value")
valueEntry=Entry(self, textvariable=value)
valueEntry.place(x=70, y=10)
quitButton = Button(self, text="Quit", command=self.quit)
quitButton.place(x=10, y=50)
okButton = Button(self, text="OK", command=self.quit)
okButton.place(x=120, y=50)
def main():
root = Tk()
root.geometry("220x100+300+300")
app = Example(root)
root.mainloop()
if __name__ == '__main__':
main()
I've read a gazillion of tutorials, but none of them explains this clearly. Theoretically, I should be able to get the selected value with value.get(), but I keep getting error messages no matter where I put it. Also, AFAIK, I should be able to define a default value with value.set(), but this doesn't seem to have an effect, since the text box is empty when I run the program.
What is the easiest way to pass on values to the main python program after root.mainloop() terminates? (The actual dialog box contains several entry boxes for entering string and integer values.)
I.e. I want to be able to use something like:
root = Tk()
root.geometry("220x100+300+300")
app = Example(root)
root.mainloop()
print value
print value2
print value3
How do I define default values for entry boxes?
Change every occurrence of the value variable with self.value. This should fix it and the default value will be displayed.
UPDATE
from Tkinter import Tk, BOTH, StringVar, IntVar
from ttk import Frame, Button, Style, Label, Entry
class Example(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def showMe(self):
print(self.value.get())
def initUI(self):
self.parent.title("Get Value")
self.style = Style()
self.style.theme_use("default")
self.pack(fill=BOTH, expand=1)
valueLabel = Label(self, text="Value: ")
valueLabel.place(x=10, y=10)
self.value=StringVar(None)
self.value.set("this is the default value")
valueEntry=Entry(self, textvariable=self.value)
valueEntry.place(x=70, y=10)
quitButton = Button(self, text="Quit", command=self.quit)
quitButton.place(x=10, y=50)
okButton = Button(self, text="OK", command=self.showMe)
okButton.place(x=120, y=50)
def main():
root = Tk()
root.geometry("220x100+300+300")
app = Example(root)
root.mainloop()
if __name__ == '__main__':
main()
Both your quitButton and okButton call the self.quit functions. So no mater what value you enter when you press the OK button you are calling the quit function which has its own problems as well outside the scope of your question.
Try to define value as self.value and make the okButton call a function that does: print self.value.get().
I'm trying to create a fairly simple e-reader, and I've managed to use tkinter to create something akin to one. But what I can't seem to work out is how to create a scrollbar to allow the user to scroll through the text at will. I can get it working in other pieces of coding, but I can't make it work within this program and I can't work out what the problem is. I've put my simple e-reader, without the attempted scrollbar below.
from Tkinter import *
import tkFileDialog
import ScrolledText
class Example(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("File dialog")
self.pack(fill=BOTH, expand=1)
menubar = Menu(self.parent)
self.parent.config(menu=menubar)
fileMenu = Menu(menubar)
fileMenu.add_command(label="Open", command=self.onOpen)
menubar.add_cascade(label="File", menu=fileMenu)
self.txt = Text(self)
self.txt.pack(fill=BOTH, expand=1)
def onOpen(self):
ftypes = [('Python files', '*.py'), ('All files', '*')]
dlg = tkFileDialog.Open(self, filetypes = ftypes)
fl = dlg.show()
if fl != '':
text = self.readFile(fl)
self.txt.insert(END, text)
def readFile(self, filename):
f = open(filename, "r")
text = f.read()
return text
self.txt = ScrolledText(self, undo=True)
self.txt['font'] = ('consolas', '12')
self.txt.pack(expand=True, fill='both')
def main():
root = Tk()
ex = Example(root)
root.geometry("300x250+300+300")
root.mainloop()
if __name__ == '__main__':
main()
Adding a scrollbar to a text widget requires you to do two things in addition to creating the actual widgets:
you must set the yscrollcommand attribute of the text widget to point to the set method of the scrollbar
you must set the command attribute of the scrollbar to point to the yview method of the text widget
For example:
self.text.configure(yscrollcommand=self.scrollbar.set)
self.scrollbar.configure(command=self.text.yview)
I've long wondered whether this could really be the answer to your question, but after the discussion in the comments, it seems it is: You just put the code creating the ScrolledText in the wrong place!
Try moving these three lines (that are now outside of the class, causing a NameError for self)
self.txt = ScrolledText(self, undo=True)
self.txt['font'] = ('consolas', '12')
self.txt.pack(expand=True, fill='both')
to where these lines are in your initUI method (replace these lines)
self.txt = Text(self)
self.txt.pack(fill=BOTH, expand=1)
With other words, in your initUI method, instead of creating a Text widget, create a ScrolledText. Also, change import ScrolledText to from ScrolledText import ScrolledText so that ScrolledText is the actual widget, and not the module defining the widget.