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

[Tkinter][Python]インスパイヤ!!Tkinterで遊んでみた。

ゴールデンウィークにTkinterで遊んだ話。もう1ヶ月経つのか。


ゴールデンウィークに入る前にTkinterでテキストエディタを作りたいって記事読んで、「あ、作ってみよう」と作った。


結果、xmlから表示するロジックは作った。

機能が抽象化しきってないし、汚いコードだけど吐き出しとく。

ところで、PythonGUI用のフレームワークってないのかな?



templates/gui.xml

<?xml version="1.0" encoding="UTF-8"?>
<master title="サンプルアプリケーション" minsize="400, 300" maxsize="800, 600">
  <menus>
    <menu type="cascade" label="ファイル(F)" name="menu_file" underline="5">
      <menu type="command" label="新規作成(N)" name="new" underline="5" accelerator="Ctrl-N" />
      <menu type="command" label="開く(O)" name="open" underline="5" accelerator="Ctrl-O" />
      <menu type="command" label="保存(S)" name="save" underline="5" accelerator="Ctrl-S" />
      <menu type="command" label="名前をつけて保存(A)" name="save_as" underline="5" accelerator="Ctrl-A" />
      <menu type="separator" />
      <menu type="command" label="閉じる(C)" name="close" underline="5" accelerator="Ctrl-C" />
      <menu type="command" label="終了(X)" name="quit" underline="5" command="quit()" accelerator="Ctrl-X" />
    </menu>
    <menu type="cascade" label="編集(E)" name="menu_edit" underline="5">
      <menu type="command" label="元に戻す(U)" name="undo" underline="5" accelerator="Ctrl-U" />
      <menu type="command" label="やり直す(R)" name="redo" underline="5" accelerator="Ctrl-R" />
      <menu type="separator" />
      <menu type="command" label="切り取り(T)" name="cut" underline="5" accelerator="Ctrl-T" />
      <menu type="command" label="コピー(C)" name="copy" underline="5" accelerator="Ctrl-C" />
      <menu type="command" label="貼り付け(P)" name="paste" underline="5" accelerator="Ctrl-P" />
      <menu type="command" label="削除(D)" name="delete" underline="5" accelerator="Ctrl-D" />
    </menu>
    <menu type="cascade" label="ヘルプ(H)" name="menu_help" underline="5" />
  </menus>
  <text height="7" width="40" bg="white" fg="red" />
</master>


main.py

# -*- coding: utf-8 -*-
from Tkinter import *
import xml.dom
from xml.dom.minidom import parse
from xml.parsers.expat import ExpatError

#FONT = (u'Helvetica', '10', 'normal')
#FONT = (u'MS 明朝', '10', 'normal')
FONT = (u'MS ゴシック', '10', 'normal')

properties = (
    # color options
    "activebackground",
    "activeforeground",
    "backgroud",
    "bg",
    "backgroud",
    "foreground",
    "fg",
    "highlightbackground",
    "highlightcolor",
    "selectbackground",
    "selectforeground",
    # length options
    "borderwidth",
    "highlightthickness",
    "padx",
    "pady",
    "selectborderwidth",
    "wraplength",
    # font options
    "height",
    "underline",
    "width",
    # other options
    "anchor",
    "command",
    "font",
    "image",
    "justify",
    "relief",
    "state",
    "takefocus",
    "text",
    "textvariable",
    )

class Reader(object):
    u"""Reader class."""

    pass

class JSONReader(Reader):
    u"""JSON Reader class."""

    pass

class XMLReader(Reader):
    u"""XML Reader"""

    def __init__(self, xml=None):
	Reader.__init__(self)
	self._dom = parse(xml)

    def dom(self):
	return self._dom

class Application(Frame):
    u"""Application class."""

    class AttributeDict(dict):
        u"""custom attribute class"""

        def __getattr__(self, name):
            return None

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

    def set(self):
        pass

    def set_master(self, dict):
        u"""set master value."""

        self.master.title(dict.get("title", u''))
	self.master.minsize(dict.get("minsize-x"), dict.get("minsize-y"))
        self.master.maxsize(dict.get("maxsize-x"), dict.get("maxsize-y"))

    def create_menus(self, element):
        u"""create menus."""

        values = self.attribute(element)

	if values.get("type") == "cascade":

            exec """self.%(menu_name)s = Menu(self.menu_bar, tearoff=%(tearoff)s)""" % dict(
                menu_name=values.get("name", 0),
                tearoff=values.get("tearoff", 0),
		)

            exec """self.menu_bar.add_cascade(label=u"%(label)s", menu=self.%(menu_name)s, underline=%(underline)s, accelerator="%(accelerator)s", font=%(font)s)""" % dict(
                menu_name=values.get("name", 0),
                label=values.get("label", ""),
		underline=values.get("underline", 0),
	        accelerator=values.get("accelerator", ""),
		font=FONT,
                )

            for node in element.childNodes:
                if node.nodeType == xml.dom.Node.ELEMENT_NODE:
                    self.create_menu(node, parent_name=values.get("name"))

	else:
            raise ValueError("element type cascade isn't exist.")


class XMLApplication(Application):
    u"""xml file based Application class."""

    def set(self, file):

	self._dom = XMLReader(file).dom()

        masters = self._dom.getElementsByTagName("master")
	master = masters[0]

        key = self.attribute(master)
        self.set_master(key)

        # menu
        self.menu_bar = Menu(self, tearoff=0)
        for element in self._dom.getElementsByTagName('menus'):
            for node in element.childNodes:
                if node.nodeType == xml.dom.Node.ELEMENT_NODE:
                    self.create_menus(node)

        # add menu bar
	try:
            self.master.config(menu=self.menu_bar)     # this required to show the menu bar                                                                                                               
        except AttributeError:
            self.master.Tk.call(self.master, "config", "-menu", self.menu_bar)

if __name__ == '__main__':

    application = XMLApplication()
    application.set("templates/gui.xml")
    application.mainloop()