i am trying to program text editor by using tkinter.
this is the mark function:
self.text.tag_add("Mark",tk.SEL_FIRST,tk.SEL_LAST)
self.text.tag_config("Mark",background="yellow",foreground="black")
and this is the unmark function
self.text.tag_add("UnMark",tk.SEL_FIRST,tk.SEL_LAST)
self.text.tag_config("UnMark",background="white",foreground = "black")
but the problem is when i mark the text and then unmark it, i cant mark it again.
the mark function dont work when i try to mark the text again that i unmarked it.
The reason is because the "UnMark" tag has a higher priority than the "Mark" tag. You can add the "Mark" tag, but the configuration of "UnMark" takes precedence.
I recommend instead of an "UnMark" tag, you simply remove the "Mark" tag when you don't want something to be marked.
Related
So I have some tags (strings the user made), they are on display in a text widget at all times. Basically if there are tags to display, you need to be able to triple click on them and it will lead to a editing menu. But if there aren't any tags to display, I don't want people to be able to triple click on it.
So my thought was bind triple click to the appropriate function if there are tags to display, and unbind it if there aren't any tags to display.
for tag in sorted(tags_pre_listed):#This loop will just check the tags and OK them for use.
if tag[0:4]=='TAG-' and tag not in used_tags: # Just avoids duplicates.
tags_display_box.insert(Tk.END, '#'+tag[4:]+' ') #inserts the tag to the display.
used_tags.append(tag)
if len(used_tags)>0: #If any tags were used to display, it will bind Triple click.
tags_display_box.bind("<Triple-1>", delete_tag)
else: #This is where it tries to unbind if there are no tags, but fails.
tags_display_box.unbind('<Button-1>',"<Triple-1>")
The issue I get is
TclError: can't delete Tcl command
Sorry It may be a rookie answer for all I know but I have done my research and can't find a way around it at all T-T
Thanks so much for reading and for any advice!
The line:
tags_display_box.unbind('<Button 1>',"<Triple-1>")
should read:
tags_display_box.unbind('<Triple-1>')
As it is you're trying to unbind something that's not bound from a command that does not exist.
I am making a simple text editor, and now I'm trying to make a replace function. The text the user wants to replace is highlighted green by using
.tag_add('select', index, end_index)
and then
.tag_config('select', background='green')
Now, I want to replace it by getting the index of text that has this specific tag and then replacing it by what the user has typed. So, my question is: How do I get the start and end index of text with a specific tag? The widget the text is in is the tkinter scrolledtext widget.
# Assuming you have only one tag matching 'select'...
start, stop = text.tag_ranges('select')
text.delete(start, stop)
text.insert(start, <new_text>)
So, the the tkinter text editor!
The editor obviously needs to have text styles, which need to change typed text to whatever formatting is currently selected, using tags. But the problem is that the tag name needs to change when the formatting changes, otherwise the tag would be applied to the whole text.
(This was a problem that I was struggling to identify for quite some time)
To avoid this, you would need a LOT of tags (like bold, both, calibri etc), so the code would look like this
if style == 'bold':
tag_add('bold', 'insert -1c', 'insert')
tag_configure('bold', font=('Calibri', 12, 'bold'))
if stlye == 'italic':
etc etc
This is awful code, and makes different fonts/sizes impossible.
Is there a correct way of organising multiple tags like this, something like
tag.add(currentstyle, 'insert -1c', 'insert')
tag.config(currentstyle, font=(currentfont, currentsize, currentweight, currentslant))
Thanks for your help
UPDATE
solved with no small amount of help from Bryan
tagname = '{}-{}-{}-{}'.format(font, fontsize, weight, slant)
textbox.tag_add(tagname, 'insert -1c', 'insert')
textbox.tag_configure(tagname, font=(font, fontsize, weight, slant))
now every tag has a unique name
Yes, you will need to create a unique tag for every different font you use. In practice this isn't so bad, because most documents only use 3-4 variations, or perhaps a worst case of maybe a dozen. The only real difficulty is that if you want both bold and italics you have to create a bold tag, an italics tag, and a bold-italics tag.
This is awful code, and makes different fonts/sizes impossible.
It doesn't make it impossible, just slightly difficult. Your code is actually pretty close to how you would do it.
When a user changes the style of a character, you need to create a canonical form for the style name by combining the current style and any new attributes. For example, if the character is currently bold 12 point and they change it to italic 14 point, the new tag might be "italic-12". If they want to keep the bold it might be "bold-italic-12". You then need to check for whether you have a tag by that name, and create it if you don't, then remove any previous font tag and add the new font tag.
This is really only a problem with fonts. For other attributes such as colors and borders you can simply use all the different tags separately (ie: if you create a tag for "background-blue" and "foreground-red", you can apply both of those tags separately to the text.
I provide an example that does something similar to this here: https://stackoverflow.com/a/3736494/7432
I have to retrieve text inside an HTML table, in the cells the text sometimes is inside a <div> and sometimes is not.
How can I make a div in a XPath optional?
My actual code:
stuff = tree.xpath("/html/body/table/tbody/tr/td[5]/div/text()")
Wanted pseudocode:
stuff = tree.xpath("/html/body/table/tbody/tr/td[5]/div or nothing/text()")
You want the string value of the td[5] element. Use string():
stuff = tree.xpath("string(/html/body/table/tbody/tr/td[5])")
This will return text without markup beneath td[5].
You can also indirectly obtain the string value of an element via normalize-space() as suggested by splash58 in the comments, if you also want whitespace to be trimmed on the ends and reduced interiorly.
I have a Tkinter Text() object and I append lines to it using .insert(END, string). When the text fills the available area, I'd expect it to scroll down to show the bottom line of text in the view, but it doesn't scroll (meaning the user has to scroll themselves to see the latest text). I've had a look at the mark_set() method but I can't seem to figure out how to get the cursor to the index of the last item of text.
Any help would be appreciated :)
As usual with Tkinter, there are a number of ways to do this, but one is the easiest: Text.see:
text.insert(END, "spam\n")
text.see(END)
If you want to make sure the start of the new text is visible, not the end of it, or if you only want to do this if the end was already visible beforehand or if the text is active, etc., you may need to look at the other options: scan_mark/scan_dragto, or yview and friends.