Tkinter Text selection_get() Error - python

I am currently working on a Tkinter app, which uses as a main widget a TextWidget.
When I try to get the current selection, an error is raised, but I don't get why...
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python27\lib\lib-tk\Tkinter.py", line 1410, in __call__
return self.func(*args)
File "C:\Users\Lina\Documents\Programmation\VPE project.py", line 502, in rechercher
texte=code_text.selection_get()
File "C:\Python27\lib\lib-tk\Tkinter.py", line 626, in selection_get
return self.tk.call(('selection', 'get') + self._options(kw))
TclError: PRIMARY selection doesn't exist or form "STRING" not defined
Thanks.
EDIT: I know why it wasn't working, i binded to Ctrl-F, but it is already binded in the TextWidgets (by default, it does exactly the same thing as LeftArrow).
Now the problem is, how do I get rid of that?

That error is simply telling you that nothing is selected. It's not an error per se, just it's way of saying "there's nothing to get". That may be true, or you may have something selected but it isn't being exported to "the selection". If you have the exportselection option on the widget set to true, anything you select should be copied to the selection. If it's not, there's not enough code in your question to answer why.
However, to answer the question of "how do I get the text that is selected in the widget": The text that is selected in a text widget has the tag 'sel'. You can get this text with textwidget.get('sel.first', 'sel.last')
Using the get method with the tags is more correct than using selection_get since it's possible to have nothing selected in the widget yet still have selection_get return something (eg: return whatever other widget has exported to the selection)

I got the error when selecting empty space in text box. To avoid the error, I have used
checking with re.search for text in the selection.
word = text.selection_get()
if re.search(r'\w+', word):
some_action()

Related

Why am I receiving a tkinter.TclError when trying to get the content of a text widget?

I'm trying to get the input from a tkinter text widget, but it is coming up with the error:
_tkinter.TclError: invalid command name ".!text"
Here is where I define the textbox: textbox = tkinter.Text(main_root)
And this is how I call the get() function: textbox.get("1.0", "end-1c")
Anyone got any ideas what is going on? Usually this works fine.
I was calling textbox.destroy() before calling the get() function. This is what caused the error to be raised.

tkinter AttributeError: 'Entry' object has no attribute 'yview'

A am trying to add a scroll bar that scrolls downwards but it doesn't work. though it works when i do xview so I'm not sure why its not working for yview.
sry for bad grammar.
round_desc_scroll=tk.Scrollbar(root,orient='vertical',command=round_desc_label.yview)
round_desc_scroll.pack(side=tk.RIGHT,fill=tk.Y)
Traceback (most recent call last):
File "/Volumes/AMIN ALI/zorc save after scroll.py", line 134, in <module>
round_desc_scroll=tk.Scrollbar(root, orient='vertical',command=round_desc_label.yview)
AttributeError: 'Entry' object has no attribute 'yview'
Like the error says, an Entry widget does not have a yview method. This is because the Entry widget can only ever display a single line of text. It has an xview method to scroll in the horizontal direction because the data can be longer than the widget.
If you need to display or allow the user to input multiline data, you need to use a Text widget which supports scrolling in both directions.

AttributeError: StringVar instance has no attribute 'endswith' while trying to call from a Tkinter button

I would like to create a GUI that receives two paths (a directory full of .txt documents and the destination of a new .csv file created from the files of the previously mentioned folder).
I am having trouble calling the function munge():
action = tk.Button(win, text="To .csv",command=munge(input_directory,output_directory))
Nevertheless, this exception raised:
/usr/local/Cellar/python/2.7.10_2/Frameworks/Python.framework/Versions/2.7/bin/python2.7 /Users/user/PycharmProjects/script.py
Traceback (most recent call last):
File "/Users/user/PycharmProjects/script.py", line 82, in <module>
action = tk.Button(win, text="To .csv", command=munge(input_directory,output_directory))
File "/Users/user/PycharmProjects/script.py", line 39, in munge
test = tuple(retrive(directory))
File "/Users/user/PycharmProjects/script.py", line 31, in retrive
for filename in sorted(glob.glob(os.path.join(directory_path, '*.txt'))):
File "/usr/local/Cellar/python/2.7.10_2/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.py", line 70, in join
elif path == '' or path.endswith('/'):
AttributeError: StringVar instance has no attribute 'endswith'
Process finished with exit code 1
How can I correctly call the aforementioned function with the help of the Button widget?. I tried to set the name of the variable as indicated here question, but it did not worked.
update
Then from an answer of this question, I tried the following:
action = tk.Button(win, text="To .csv", command=lambda:munge(input_directory,output_directory))
Based on the error message, you seem to be trying to call the endswith method of a StringVar object. If you look at the documentation for such an object you'll see there's no such method. That is why you get the error that you do.
Assuming that path is an instance of a StringVar, you must call the get method in order to have the string stored by the object:
path_string = path.get()
if path_string == "" or path_string.endswith('/'):
...
You might want to consider reading a bit on callback functions in Tkinter, here is a useful link in order to do so http://effbot.org/zone/tkinter-callbacks.htm:
For simple cases like this, you can use a lambda expression as a link
between Tkinter and the callback function:
def callback(number):
print "button", number
Button(text="one", command=lambda: callback(1))
your function is being executed as soon as your Button widget loads, you want to avoid this.
After all, it worked with: action = tk.Button(win, text="To .csv", command=lambda:munge(input_directory.get(),output_directory.get())). However, from Bryan Oakley answer I belive that this is not the correct way to do this.
You want to call the .get() method on the StringVar to get the string it contains otherwise it's just the StringVar instance.

Intercepting the close window button (Tkinter window) throws an Tcl error

I have a program that at some point opens a new window (filled with buttons and gizmo's for the user to select and play around with) that is defined as follows:
def window(self,master):
def close(self):
# change some variables
self.destroy()
top = self.top = Toplevel()
# Several lines of buttons
top.lift()
top.protocol("WM_DELETE_WINDOW",close(self))
I initially had a close button there that would wrap everything up nicely but I noticed that if the user used the standard 'X' in the corner of the window, this function obviously would not be called and that would give a lot of problems later on. I found out about the 'WM_DELETE_WINDOW' suggestion from some other questions on this website but it gives me a rather strange error:
File "/usr/lib/python2.7/lib-tk/Tkinter.py", line 1630, in wm_protocol
'wm', 'protocol', self._w, name, command)
TclError: bad window path name ".33862072"
I assume that it somehow has gotten the wrong window ID and is unable to catch the event. My question is thus, is that true or not and secondly how should I continue to deal with this issue.
Let's examine this line of code:
top.protocol("WM_DELETE_WINDOW",close(self))
This line of code is saying "immediately call the function close(self), and assign the result to the protocol handler. See the problem? It's immediately calling close, likely before self has been fully constructed. You don't want the function to be called, you want to pass in a reference to the function.
Make close be a method of self (rather than an embedded function) and change the call to top.protocol to look like this (note the lack of trailing parenthesis):
top.protocol("WM_DELETE_WINDOW", self.close)
If you prefer to keep the nested function, you can use lambda:
top.protocol("WM_DELETE_WINDOW", lambda window=self: close(window))

Strange Exception in Tkinter callback

I'm still working on my little Tkinter project which is simple a logging console that prints incoming text from the serial line to a Text Widget with some coloring applied.
One question is open and can be found here: Python Tkinter Text Widget with Auto & Custom Scroll
However, even without manual scrolling (so I'm using self.text.yview(END) to auto-scroll to the bottom after inserting text with self.text.insert(END, str(parsed_line)).
The script actually works but every now and then it throws some "silent" exceptions within the Tkinter thread that does not let the whole application crash:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python26\lib\lib-tk\Tkinter.py", line 1410, in __call__
return self.func(*args)
File "C:\Python26\lib\lib-tk\Tkinter.py", line 2813, in set
self.tk.call((self._w, 'set') + args)
TclError: expected floating-point number but got "0.7807017543859649integer but got "end""
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python26\lib\lib-tk\Tkinter.py", line 1410, in __call__
return self.func(*args)
File "C:\Python26\lib\lib-tk\Tkinter.py", line 2813, in set
self.tk.call((self._w, 'set') + args)
TclError: invalid command name ".15427224integer but got "end""
It looks as if some method expected a an integer, returns the string integer but got "end" to a method that expected a float which is concatinated with the error message. The float number in that string looks like the position of the scrollbar that I have attached to my text widget:
(...)
scrollbar = Scrollbar(root)
scrollbar.pack(side=RIGHT, fill=Y)
text = Text(wrap=WORD, yscrollcommand=scrollbar.set)
scrollbar.config(command=text.yview)
text.pack(expand=YES, fill=BOTH)
(...)
I have the feeling that it happens when a lot of lines are inserted within a short time. But since I only have one thread interacting with Tkinter this cannot be a threading issue.
I also got very random errors like that before I had applied the str() function to parsed_line in self.text.insert(END, str(parsed_line)).
This is very strange behavior and I'm wondering if anyone could explain what this is about and how to fix it.
Thanks a lot!
mtTkinter allows multithreading with Tkinter, you can get it here:
http://tkinter.unpythonic.net/wiki/mtTkinter
Just import mtTkinter in place of Tkinter. This will allow you to insert text into a Text widget from multiple threads without conflict. I used it for some instant messaging software I wrote and it works wonderfully.

Categories