views:

135

answers:

2

I am working on a simple messaging system, and need to add the following to a Tkinter text box widget:

1) Spell Check
2) Option To Change Font (  on selected text )
3) Option to change font color ( on selected text )
4) Option to Change Font Size ( on selected text )

I have used Google to try and find examples or modules I could use, but have had no luck. I am using Python 2.6 on Windows 7.

A: 

1) Tk does'nt have an integrated spellchecker. You may be interested by PyEnchant.

2) 3) 4) is not that difficult (please forget my previous suggestion to use wxPython). You can pass a tag_config as 3rd arg of the insert method of the text widget. It defines the config of this selection.

See the following code which is adapted from the Scrolledtext example and effbot which the best reference about Tk.

"""
Some text
hello
"""

from Tkinter import *
from Tkconstants import RIGHT, LEFT, Y, BOTH
from tkFont import Font
from ScrolledText import ScrolledText

def example():
    import __main__
    from Tkconstants import END

    stext = ScrolledText(bg='white', height=10)
    stext.insert(END, __main__.__doc__)

    f = Font(family="times", size=30, weight="bold")
    stext.tag_config("font", font=f)

    stext.insert(END, "Hello", "font")
    stext.pack(fill=BOTH, side=LEFT, expand=True)
    stext.focus_set()
    stext.mainloop()

if __name__ == "__main__":
    example()
luc
Ok, I'm open to using wxPython. Have any idea how this would be done in wx?
Zachary Brown
Forget my wxPython suggestion. I've found a Tk solution thanks to effbot. I hope it helps. Best
luc
Besides adding tags during insertion, you can also add them at insertion time with tag_add. So, for example, you can get the range of characters selected by the user and apply a tag or tags to that range of text.
Bryan Oakley
+2  A: 

The Tkinter text widget is remarkably powerful, but you do have to do some advanced features yourself. It doesn't have built-in spell check or built-in buttons for bolding text, etc, but they are quite easy to implement. All the capabilities are there in the widget, you just need to know how to do it.

The following example gives you a button to toggle the bold state of the highlighted text -- select a range of characters then click the button to add and then remove the bold attribute. It should be pretty easy for you to extend this example for fonts and colors.

Spell check is also pretty easy. the following example uses the words in /usr/share/dict/words (which almost certainly doesn't exist on Windows 7, so you'll need to supply a suitable list of words) It's rather simplistic in that it only spell-checks when you press the space key, but that's only to keep the code size of the example to a minimal level. In the real world you'll want to be a bit more smart about when you do the spell checking.

import Tkinter as tk
import tkFont

class App(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)

        ## Toolbar
        self.toolbar = tk.Frame()
        self.bold = tk.Button(name="toolbar", text="bold", 
                              borderwidth=1, command=self.OnBold,)
        self.bold.pack(in_=self.toolbar, side="left")

        ## Main part of the GUI
        # I'll use a frame to contain the widget and 
        # scrollbar; it looks a little nicer that way...
        text_frame = tk.Frame(borderwidth=1, relief="sunken")
        self.text = tk.Text(wrap="word", background="white", 
                            borderwidth=0, highlightthickness=0)
        self.vsb = tk.Scrollbar(orient="vertical", borderwidth=1,
                                command=self.text.yview)
        self.text.configure(yscrollcommand=self.vsb.set)
        self.vsb.pack(in_=text_frame,side="right", fill="y", expand=False)
        self.text.pack(in_=text_frame, side="left", fill="both", expand=True)
        self.toolbar.pack(side="top", fill="x")
        text_frame.pack(side="bottom", fill="both", expand=True)

        # clone the text widget font and use it as a basis for some
        # tags
        bold_font = tkFont.Font(self.text, self.text.cget("font"))
        bold_font.configure(weight="bold")
        self.text.tag_configure("bold", font=bold_font)
        self.text.tag_configure("misspelled", foreground="red", underline=True)

        # set up a binding to do simple spell check. This merely
        # checks the previous word when you type a space. For production
        # use you'll need to be a bit more intelligent about when
        # to do it.
        self.text.bind("<space>", self.Spellcheck)

        # initialize the spell checking dictionary. YMMV.
        self._words=open("/usr/share/dict/words").read().split("\n")

    def Spellcheck(self, event):
        '''Spellcheck the word preceeding the insertion point'''
        index = self.text.search(r'\s', "insert", backwards=True, regexp=True)
        if index == "":
            index ="1.0"
        else:
            index = self.text.index("%s+1c" % index)
        word = self.text.get(index, "insert")
        if word in self._words:
            self.text.tag_remove("misspelled", index, "%s+%dc" % (index, len(word)))
        else:
            self.text.tag_add("misspelled", index, "%s+%dc" % (index, len(word)))


    def OnBold(self):
        '''Toggle the bold state of the selected text'''

        # toggle the bold state based on the first character
        # in the selected range. If bold, unbold it. If not
        # bold, bold it.
        current_tags = self.text.tag_names("sel.first")
        if "bold" in current_tags:
            # first char is bold, so unbold the range
            self.text.tag_remove("bold", "sel.first", "sel.last")
        else:
            # first char is normal, so bold the whole selection
            self.text.tag_add("bold", "sel.first", "sel.last")

if __name__ == "__main__":
    app=App()
    app.mainloop()
Bryan Oakley
WOW! This is what I was looking for! Thanks! Didn't actually realize how easy it would be! +1 for you!
Zachary Brown
I keep getting an error that says ("sel.first") is a bad index. How do I fix this?
Zachary Brown
Sorry, that was just a typo, but I isn't setting the text to bold for some reason.
Zachary Brown
Another typo, sorry again.... Thanks again!
Zachary Brown