autoscroll of text and scrollbar in python text box - python

I have a tkinter 'Text' and 'Scrollbar' working fine. In my program in the text window automatically lines will keep on adding. So When a new line of text is inserted and data reached out of limit I would like the text and scrollbar to be scrolled to the bottom automatically, so that the latest line of text is always shown. How to do this?
Also how to link the scroll of text window and scroll bar, because when I do scrolling over the text window scroll wont happen. Only way I observed is to drag the scroll bar.
scrollbar = Tkinter.Scrollbar(group4.interior())
scrollbar.pack(side = 'right',fill='y')
Details1 = Output()
outputwindow = Tkinter.Text(group4.interior(), yscrollcommand = scrollbar.set,wrap = "word",width = 200,font = "{Times new Roman} 9")
outputwindow.pack( side = 'left',fill='y')
scrollbar.config( command = outputwindow.yview )
outputwindow.yview('end')
outputwindow.config(yscrollcommand=scrollbar.set)
outputwindow.insert('end',Details1)
In the program the function output() will continuously send data, which should scroll
Thanks in advance,

You can cause the text widget to scroll to any location with the see which takes an index.
For example, to make the last line of the widget visible you can use the index "end":
outputwindow.see("end")
Here's a complete working example:
import time
try:
# python 2.x
import Tkinter as tk
except ImportError:
# python 3.x
import tkinter as tk
class Example(tk.Frame):
def __init__(self, *args, **kwargs):
tk.Frame.__init__(self, *args, **kwargs)
self.text = tk.Text(self, height=6, width=40)
self.vsb = tk.Scrollbar(self, orient="vertical", command=self.text.yview)
self.text.configure(yscrollcommand=self.vsb.set)
self.vsb.pack(side="right", fill="y")
self.text.pack(side="left", fill="both", expand=True)
self.add_timestamp()
def add_timestamp(self):
self.text.insert("end", time.ctime() + "\n")
self.text.see("end")
self.after(1000, self.add_timestamp)
if __name__ == "__main__":
root =tk.Tk()
frame = Example(root)
frame.pack(fill="both", expand=True)
root.mainloop()

Take a look at Text.see(...) method.
TextWidget.insert(tk.END, str(new_txt))
TextWidget.see(tk.END)
I used this pattern to add (aka insert) text new_txt to my output window and scroll (see) to the bottom (tk.END)

Add this after the insert
TextBox.yview(END)

although very useful, using Text.see(...) in the above manner defeats the purpose of having a scrollbar. Better would be insert text at "0." instead of tk.END. That way, it initially autoscrolls, but you can drag it down to anywhere and it will stay there (while updating its range as more text is added, but the text you see remains constant until you scroll elsewhere). Once you want it to autoscroll again, you simply slide the scrollbar all the way back to the top.
Another solution (which wouldn't affect the flow direction of incoming text) would be to add some extra logic, such as a checkbox, then everytime you update Text, check that checkbox's state before you decide whether or not to call Text.see(...).
I don't know if there is a more elegant solution.

Related

Make Button in Python Tkinter Stop Moving when Pressed

So I am working on making an application inside of Tkinter and I am not that experienced in it, but I noticed that when you press a button it moves the text inside down and to the right just a couple pixels and I can't figure out how to make it not do that. Any help finding what parameter I need to change would be greatly appreciated.
I tried finding any docs on the subject but whenever I looked it up I would only get things that pertained to how to place a button on the window or in a frame/canvas with place, grid, pack.
will you can change the relief value to be SUNKEN and adjust the border values like this
Button(root, text = 'Click me !', borderwidth=5, relief=SUNKEN)
the button will look a little weird
or you can use widget other than a button just like this answer (https://stackoverflow.com/a/10674950/20411925)
import tkinter
class main:
def __init__(self,root):
# make a label with some space around the text
self.lbl1 = tkinter.Label(root,
width = 16, height = 4,
text = "Foobar")
self.lbl1.pack()
# Call a function when lbl1 is clicked
# <Button-1> means a left mouse button click
self.lbl1.bind("<Button-1>", self.yadda)
self.lbl1.bind("<Enter>", self.green)
self.lbl1.bind("<Leave>", self.red)
def yadda(self, event):
self.lbl1.config(text="Clicked!")
def green(self, event):
self.lbl1.config(bg="green")
def red(self,event):
self.lbl1.config(bg="red")
if __name__ == "__main__":
root = tkinter.Tk()
main(root)
root.mainloop()

Python: Tkinter: Multi line scrolling entry box

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()

Wrapping a Tkinter program in a scroll bar

I am trying to incorporate a scrollbar in my Tkinter window so as I add more things the user can scroll down. From what I've read so far it seems I need to use a Listbox widget but running into trouble adding the scrollbar as it is only getting added to the bottom of the program and not wrapping the entire thing? My code is below.
import Tkinter as Tk
from Tkinter import StringVar
class SampleApp(Tk.Tk):
def __init__(self):
Tk.Tk.__init__(self)
self.button = Tk.Button(self, text="Get", command=self.on_button)
self.button.pack()#place(x=150, y=600)
####Name#####
labelText=StringVar()
labelText.set(" Name")
labelDir=Tk.Label(self, textvariable=labelText, height=1)
labelDir.pack()
directory=StringVar(None)
self.name =Tk.Entry(self,textvariable=directory,width=25)
self.name .pack()
def on_button(self):
with open('filename.html', 'w') as myfile:
myfile.write('The button worked')
app = SampleApp()
scrollbar = Tk.Scrollbar(app)
scrollbar.pack( side = Tk.RIGHT, fill=Tk.Y )
app.mainloop()
The issue is that the Scrollbar widget is only implemented for Canvas, Listbox, and Text widgets. The Scrollbar must be configured to one of those widgets, and then you add widgets to that parent. Unfortunately, it's not the most straightforward widget to use. See Effbot's Scrollbar page for an example.

Separate command for clicking each line in Python Tkinter Text Widget

Background
Each one of the items appearing in my text widget represent tasks. I am using a Text widget over a ListBox because Text widget allows different colors for different items. The color of each task is its status. Is it possible to set a separate LC command for each task?
I have a split-pane application with tasks on the right (possibly scrollable), and I want clicking on a task to open it up for scrutiny in the pane on the left.
Main Question
Can I in any way activate separate events on left-clicking separate lines in a Python Text Tkinter widget?
Just set a binding on <1>. It's easy to get the line number that was clicked on using the index method of the widget and the x/y coordinate of the event.
Here's a simple example:
import Tkinter as tk
class ExampleApp(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.status = tk.Label(self, anchor="w")
self.status.pack(side="bottom", fill="x")
self.text = tk.Text(self, wrap="word", width=40, height=8)
self.text.pack(fill="both", expand=True)
self.text.bind("<1>", self.on_text_button)
for n in range(1,20):
self.text.insert("end", "this is line %s\n" % n)
def on_text_button(self, event):
index = self.text.index("#%s,%s" % (event.x, event.y))
line, char = index.split(".")
self.status.configure(text="you clicked line %s" % line)
if __name__ == "__main__":
app = ExampleApp()
app.mainloop()
I think you can do something like this. tkHyperlinkManger does it ( http://effbot.org/zone/tkinter-text-hyperlink.htm )
Since you're already coloring the lines differently, I assume you're using tag_config. Then all you need is tag_bind to bind a callback to the region of text.

How to disable text shaking when I click a button?

I am working with buttons in Tkinter, Python.
The thing is when I click in one button the text of the button shakes. It might be a default behavior for this widget and I don't know how to disable it and make it static.
I assume that you mean the relief change from raised to sunken when you click a button.
This is what I found on http://wiki.tcl.tk/1048 (click 'Show Discussion' to see it):
Unfortunately, the relief used when you click is hardcoded (as
'sunken'), so you can't configure it per-widget without hacking the Tk
internals for the binding for buttons.
So the simplest way around this would be to always make the button appear sunken
MyButton = Tkinter.Button(
self.frame,
text = "Foobar",
command = self.foobar,
relief=Tkinter.SUNKEN
)
The disadvantage of that is that it might make the button look unresponsive.
You can also use a widget other than a button to be used as a clickable item (suggested by Joel Cornett). Here is a simple example with a label used as a button:
import Tkinter
class main:
def __init__(self,root):
# make a label with some space around the text
self.lbl1 = Tkinter.Label(root,
width = 16, height = 4,
text = "Foobar")
self.lbl1.pack()
# Call a function when lbl1 is clicked
# <Button-1> means a left mouse button click
self.lbl1.bind("<Button-1>", self.yadda)
self.lbl1.bind("<Enter>", self.green)
self.lbl1.bind("<Leave>", self.red)
def yadda(self, event):
self.lbl1.config(text="Clicked!")
def green(self, event):
self.lbl1.config(bg="green")
def red(self,event):
self.lbl1.config(bg="red")
if __name__ == "__main__":
root = Tkinter.Tk()
main(root)
root.mainloop()

Categories