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.
Related
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()
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.
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()
Is it possible to resize text in a tkinter box in python? I know I can add text and, when doing so, among other traits, define the font size. Is it possible to resize the text if say, something triggers the program to do so?
If you are using a Text box you can use tags for formatting its contents. For instance:
#!/usr/bin/env python
import Tkinter
import tkFont
class App:
def __init__(self):
# Set up the text box
self.root = Tkinter.Tk()
self.text = Tkinter.Text(self.root, width=20, height=5)
self.text.insert(Tkinter.INSERT, "Hello...")
self.text.pack()
# set up a mouse event
self.text.bind("<Button-1>", self.click)
# Set Tkniter's main loop
self.root.mainloop()
def click(self, event):
self.text.tag_add("here", "1.0", "1.4")
self.text.tag_config("here", background="yellow", font=tkFont.Font(size=36))
if __name__ == "__main__":
App()
will change the background and size of a section of the entered text when you click the box with your mouse.
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()