2noの日記

メモ用

【wxPython】メニューバーを付ける

追記: 2014/11/20 21:41
調べてみたら、もっとたくさん ID 用意されてた。
SpecialIDs - wxPyWiki
あと、新たに ID を追加する場合は wx.NewId で生成する方が良いようだ。


メニューを追加する際は ID が必要だが、一部は事前に用意されている。

  • wx.ID_UNDO
  • wx.ID_REDO
  • wx.ID_CUT
  • wx.ID_COPY
  • wx.ID_PASTE

新たに ID を用意するなら、別にこれらの ID を必ず使う必要はない。

メニューの UI の更新に関しては、wx.EVT_UPDATE_UI イベントを使うと良い。

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

import wxversion
wxversion.select("3.0")
import wx
import wx.html2
import wx.stc as stc
import markdown


#==============================================================================
# 定数群
#------------------------------------------------------------------------------

MENU_FILE_CLOSE = 1


#==============================================================================
# 関数群
#------------------------------------------------------------------------------

def update():
    timer.Start(milliseconds=100, oneShot=True)

def update_preview():
    # 変数 html が空文字だと SetPage で反映されないので、html 要素など加えておく
    html = """\
        <!DOCTYPE html>
        <html lang="ja">
            <head><meta charset="utf-8"></head>
            <body>%s</body>
        </html>
    """ % convert_str_to_html(text.GetValue())
    browser.SetPage(html, "")

def convert_str_to_html(str):
    codehilite = "codehilite(force_linenos=True, guess_lang=False, css_class=syntax)"
    return markdown.markdown(str, ["extra", codehilite])

def exit_app():
    dialog = wx.MessageDialog(frame,
                              u"ウィンドウを閉じますか?", u"確認",
                              wx.OK|wx.CANCEL|wx.ICON_QUESTION)
    result = dialog.ShowModal()
    if result == wx.ID_OK:
        frame.Destroy()

# イベントハンドラ
#------------------------------------------------------------------------------

def close_handler(event):
    exit_app()

def char_handler(event):
    update()
    event.Skip()

def timer_handler(event):
    update_preview()
    event.Skip()

def update_ui_handler(event):
    menu_edit.Enable(id=wx.ID_UNDO,  enable=text.CanUndo())
    menu_edit.Enable(id=wx.ID_REDO,  enable=text.CanRedo())
    menu_edit.Enable(id=wx.ID_CUT,   enable=text.CanCut())
    menu_edit.Enable(id=wx.ID_COPY,  enable=text.CanCopy())
    menu_edit.Enable(id=wx.ID_PASTE, enable=text.CanPaste())

def menu_handler(event):
    id = event.GetId()
    if id == MENU_FILE_CLOSE:
        exit_app()
        return
    elif id == wx.ID_UNDO:
        text.Undo()
    elif id == wx.ID_REDO:
        text.Redo()
    elif id == wx.ID_CUT:
        text.Cut()
    elif id == wx.ID_COPY:
        text.Copy()
    elif id == wx.ID_PASTE:
        text.Paste()
    update()


#==============================================================================
# 処理
#------------------------------------------------------------------------------

if __name__ == "__main__":
    app = wx.App()

    # 多重起動チェック
    instance_name = u"%s-%s" % (app.GetAppName(), wx.GetUserId())
    instance = wx.SingleInstanceChecker(instance_name)
    if instance.IsAnotherRunning():
        exit()

    frame = wx.Frame(None, wx.ID_ANY, "Markdown test", size=(800, 600))

    menu_bar = wx.MenuBar()

    menu_file = wx.Menu()
    menu_file.Append(MENU_FILE_CLOSE, u"閉じる\tCtrl+Q")
    menu_bar.Append(menu_file, u"ファイル")

    menu_edit = wx.Menu()
    menu_edit.Append(wx.ID_UNDO, u"取り消し\tCtrl+Z")
    menu_edit.Append(wx.ID_REDO, u"やり直し\tCtrl+Shift+Z")
    menu_edit.AppendSeparator()
    menu_edit.Append(wx.ID_CUT, u"カット\tCtrl+X")
    menu_edit.Append(wx.ID_COPY, u"コピー\tCtrl+C")
    menu_edit.Append(wx.ID_PASTE, u"ペースト\tCtrl+V")
    menu_bar.Append(menu_edit, u"編集")
    frame.Bind(wx.EVT_MENU, menu_handler)
    frame.SetMenuBar(menu_bar)

    sw    = wx.SplitterWindow(frame, -1, style=wx.SP_LIVE_UPDATE)
    pane1 = wx.Panel(sw, -1)

    text = stc.StyledTextCtrl(pane1, wx.ID_ANY)
    text.SetMarginType(1, stc.STC_MARGIN_NUMBER)
    text.SetMarginWidth(1, 30)
    text.StyleSetSpec(stc.STC_STYLE_LINENUMBER, "fore:#999999")
    text.SetLexer(stc.STC_LEX_MARKDOWN)
    text.Bind(wx.EVT_CHAR, char_handler)

    pane1_sizer = wx.BoxSizer()
    pane1_sizer.Add(text, 1, wx.EXPAND, 10)
    pane1.SetSizer(pane1_sizer)

    pane2 = wx.Panel(sw, -1)
    browser = wx.html2.WebView.New(pane2)

    pane2_sizer = wx.BoxSizer()
    pane2_sizer.Add(browser, 1, wx.EXPAND, 10)
    pane2.SetSizer(pane2_sizer)

    sw.SetSashGravity(0.5)
    sw.SplitVertically(pane1, pane2)

    timer = wx.Timer(frame)
    frame.Bind(wx.EVT_TIMER, timer_handler, timer)
    frame.Bind(wx.EVT_UPDATE_UI, update_ui_handler)
    frame.Bind(wx.EVT_CLOSE, close_handler)

    frame.Show()
    app.MainLoop()

f:id:wakuworks:20141119124037p:plain