読者です 読者をやめる 読者になる 読者になる

chikuchikugonzalezの雑記帳

趣味とか日記とかメモとか(∩゚д゚)

Tkinterでテキストエディタを作りたい

昔挫折したTkinterによるテキストエディタにまた手を出してみた。前はたしかタブエディタにしようとして挫折したので今回は普通のMDIなエディタにしよう、うん。
とりあえずメニュー項目をXMLから作れるようにしてみた。

↓こんなXMLを用意してやると

<?xml version="1.0" encoding="UTF-8"?>
<menus>
  <menu type="cascade" label="ファイル(F)" name="fileMenu" underline="5" tearoff="True">
    <menu type="command" label="新規作成(N)" name="new" underline="5"/>
    <menu type="command" label="開く(O)" name="open" underline="3"/>
    <menu type="command" label="保存(S)" name="save" underline="3"/>
    <menu type="command" label="名前をつけて保存(A)" name="saveAs" underline="9"/>
    <menu type="separator"/>
    <menu type="command" label="閉じる(C)" name="close" underline="4"/>
    <menu type="command" label="終了(X)" name="quit" underline="3" command="application.quit()"/>
  </menu>
  <menu type="cascade" label="編集(E)" name="editMenu">
    <menu type="command" label="元に戻す(U)" name="undo"/>
    <menu type="command" label="やり直す(R)" name="redo"/>
    <menu type="separator"/>
    <menu type="command" label="切り取り(T)" name="cut"/>
    <menu type="command" label="コピー(C)" name="copy"/>
    <menu type="command" label="貼り付け(P)" name="paste"/>
    <menu type="command" label="削除(D)" name="delete"/>
  </menu>
</menus>

↓こんな感じのメニューになるようにしてみた。

↓以下ソースコード (2010/04/24時点)

# -*- coding: utf-8 -*-

import xml.dom
import xml.dom.minidom
import sys
import codecs

import Tkinter
import ScrolledText
import tkFileDialog
import tkMessageBox
import tkFont

class Menu(Tkinter.Menu):

    def createMenuItem(bar, xmlElement, parent):
        attrs = xmlElement.attributes
        type = attrs['type'].value if attrs.has_key('type') else None
        tearoffMenu = True if attrs.has_key('tearoff') and attrs['tearoff'].value == 'True' else False
        labelText = attrs['label'].value if attrs.has_key('label') else ''
        commandText = attrs['command'].value if attrs.has_key('command') else '0'
        underlineText = attrs['underline'].value if attrs.has_key('underline') else None
        acceleratorText = attrs['accelerator'].value if attrs.has_key('accelerator') else None

        menuItem = None

        if type == 'cascade':
            menuItem = Tkinter.Menu(parent, tearoff = tearoffMenu)
            parent.add_cascade(label = labelText, menu = menuItem, underline = underlineText)
            for element in xmlElement.childNodes:
                if element.nodeType == xml.dom.Node.ELEMENT_NODE:
                    bar.createMenuItem(element, menuItem)
        elif type == 'command':
            parent.add_command(label = labelText, command = lambda: eval(commandText), underline = underlineText, accelerator = acceleratorText)
        elif type == 'separator':
            parent.add_separator()

        return menuItem

    def __init__(self, master = None, xmlObject = None):
        Tkinter.Menu.__init__(self, master)

        # XML Parsing
        for element in xmlObject.getElementsByTagName('menus'):
            for node in element.childNodes:
                if node.nodeType == xml.dom.Node.ELEMENT_NODE:
                    self.createMenuItem(node, self)

     #   self.pack()

class TextArea(ScrolledText.ScrolledText):

    def __init__(self, master):
        ScrolledText.ScrolledText.__init__(self, master, maxundo = 256, wrap = None)

class Application(Tkinter.Frame):

    def __init__(self, master = None):
        Tkinter.Frame.__init__(self, master)

        self.master.title('Editor')
        self.config(width = 640, height = 480)

        # menubar
        # XMLロード
        xmlObject = xml.dom.minidom.parse("menus.xml")

        # メニューバー作成
        menuBar = Menu(self, xmlObject)
        self.master.configure(menu = menuBar)

        # コンテンツ
        textArea = TextArea(self)

        self.pack()


if __name__ == '__main__':
    root = Tkinter.Tk()
    application = Application()
    application.mainloop()
    #root.destroy()