简体   繁体   中英

Copying formatted text from Text widget in tkinter

I'm working on an APA citation maker in Python using tkinter. I use the Text widget to display the citation once it's generated, but whenever I copy the text (using the ctrl+c shortcut, at the moment) it loses its formatting. Is there some way to copy formatted text (italicized, for instance) from the Text widget rather than unformatted text?

To copy formatted text to the clipboard, you need an interface between python and the system's clipboard which supports text formatting. I have found klembord which should works in Linux and Windows (Mac users can probably adapt the below solution to richxerox ).

The idea is to (1) convert the formatted text from the text widget to html then to (2) add it to the clipboard:

  1. With text.dump(index1, index2, tag=True, text=True) it is possible to retrieve the text and tags from the widget. It returns a list like (this is the content of the widget in the example below):

     [('text', 'Author et al. (2012). The title of the article. ', '1.0'), ('tagon', 'italic', '1.48'), ('text', 'Journal Name', '1.48'), ('tagoff', 'italic', '1.60'), ('text', ', ', '1.60'), ('tagon', 'bold', '1.62'), ('text', '2', '1.62'), ('tagoff', 'bold', '1.63'), ('text', '(599), 1–5.', '1.63'), ('text', '\\n', '1.74')]

    So it is easy to associate each ('tagon/off', tagname) pair with the corresponding html tag using a dictionary and convert the widget content to html.

  2. klembord.set_with_rich_text(txt, rich_txt) puts the string txt and its html formatted equivalent in the clipboard.

Here is a full example (tested in Linux, I was able to copy the text from the text widget and paste it into a word processor with the formatting):

import tkinter as tk
import klembord

root = tk.Tk()
text = tk.Text(root)
text.pack(fill='both', expand=True)

text.tag_configure('italic', font='TkDefaultFont 9 italic')
text.tag_configure('bold', font='TkDefaultFont 9 bold')

TAG_TO_HTML = {
    ('tagon', 'italic'): '<i>',
    ('tagon', 'bold'): '<b>',
    ('tagoff', 'italic'): '</i>',
    ('tagoff', 'bold'): '</b>',
}

def copy_rich_text(event):
    try:
        txt = text.get('sel.first', 'sel.last')
    except tk.TclError:
        # no selection
        return "break"
    content = text.dump('sel.first', 'sel.last', tag=True, text=True)
    html_text = []
    for key, value, index in content:
        if key == "text":
            html_text.append(value)
        else:
            html_text.append(TAG_TO_HTML.get((key, value), ''))
    klembord.set_with_rich_text(txt, ''.join(html_text))
    return "break"  # prevent class binding to be triggered

text.bind('<Control-c>', copy_rich_text)

text.insert("1.0", "Author et al. (2012). The title of the article. ")
text.insert("end", "Journal Name", "italic")
text.insert("end", ", ")
text.insert("end", "2", "bold")
text.insert("end", "(599), 1–5.")

root.mainloop()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM