プログラミング工房 > Python > IronPythonサンプルアプリケーション

付箋紙風メモソフト - cMemo ソーススクリプト

ソース一覧

cmemo.py
cmemo_app.py
cmemo_cmdmenu.py
cmemo_memo.py
cmemo_nicon.py
cmemo_tbox.py
my_textbox.py


メインスクリプト

cmemo.py

# coding: shift-jis

import System.IO

from   cmemo_app     import *
from   cmemo_memo    import *
from   cmemo_nicon   import *


# トレイアイコン作成 #
icon  =  CmemoNotifyIcon()

# 既存のメモを開く #
list  =  System.IO.Directory.GetFiles(CmemoApp.DIR_DATA, '*.txt')
for path in list:
   CmemoMemo(path).Show()

# イベントループスタート #
Application.Run()

# トレイアイコン消去 #
icon.Hide()


プログラム全体で使われる定数、サブルーチンなどを含むクラス

cmemo_app.py

# coding: shift-jis

import System.IO


# このクラスはインスタンスを作らずに利用する #
class CmemoApp:

   IS_DEBUG =  1  # デバッグ時(スクリプトからの実行時)は1、
                  # 実行ファイル作成時は0を必ずセットする
   
   # スクリプトまたは実行ファイルの起動ディレクトリ #
   DIR_EXE     =  System.IO.Path.GetDirectoryName(System.Environment.GetCommandLineArgs()[IS_DEBUG])
   
   # メモデータ保存ディレクトリ #
   DIR_DATA    =  DIR_EXE + System.IO.Path.DirectorySeparatorChar + 'data'
   # 存在チェック #
   if not System.IO.Directory.Exists(DIR_DATA):
      System.IO.Directory.CreateDirectory(DIR_DATA)
      
   # Readmeファイルパス #
   PATH_README =  DIR_EXE + System.IO.Path.DirectorySeparatorChar + 'readme.txt'
   
   TEXT_APP_NAME  =  'cMemo'
   TEXT_APP_VER   =  'v0.3'
   
   
   #--------------#
   # コマンド関連 #
   #--------------#
      
   @classmethod
   def OpenReadme(Class):
      if System.IO.File.Exists(CmemoApp.PATH_README):
         System.Diagnostics.Process.Start(CmemoApp.PATH_README)


メモ操作用メニューを作るためのクラス

cmemo_cmdmenu.py

# coding: shift-jis

import clr
clr.AddReference("System.Windows.Forms")
from   System.Windows.Forms import *


MENU_TEXT_EXIT       =  '終了(&Q)'
MENU_TEXT_README     =  'Readme(&R)\tF1'
MENU_TEXT_CHGFONT    =  'フォント変更\tCtrl+F'
MENU_TEXT_CHGBGCLR   =  '背景色変更\tCtrl+B'
MENU_TEXT_CHGFGCLR   =  '文字色変更\tCtrl+T'
MENU_TEXT_SRKXPD     =  'たたむ / 広げる\tF4'
MENU_TEXT_XPDALL     =  'すべて広げる(&E)\tF3'
MENU_TEXT_SRKALL     =  'すべてたたむ(&S)\tF2'
MENU_TEXT_FRONTALL   =  'すべて前面に(&M)\tF12'
MENU_TEXT_NEXTMEMO   =  '次のメモ\tF11'
MENU_TEXT_DELETE     =  '削除\tAlt+F4'
MENU_TEXT_SAVEALL    =  'すべて保存(&V)\tCtrl+Shift+S'
MENU_TEXT_SAVE       =  '保存\tCtrl+S'
MENU_TEXT_NEWCLIP    =  'クリップボードテキストで新規メモ(&B)\tCtrl+P'
MENU_TEXT_NEW        =  '新規メモ(&N)\tCtrl+N'
MENU_TEXT_CANCEL     =  'キャンセル(&C)'
MENU_TEXT_BORDER     =  '-'

_list_icon_menu_text =  []
_list_icon_menu_text.append(MENU_TEXT_EXIT)
_list_icon_menu_text.append(MENU_TEXT_BORDER)
_list_icon_menu_text.append(MENU_TEXT_README)
_list_icon_menu_text.append(MENU_TEXT_BORDER)
_list_icon_menu_text.append(MENU_TEXT_CHGFONT)
_list_icon_menu_text.append(MENU_TEXT_CHGBGCLR)
_list_icon_menu_text.append(MENU_TEXT_CHGFGCLR)
_list_icon_menu_text.append(MENU_TEXT_BORDER)
_list_icon_menu_text.append(MENU_TEXT_SRKXPD)
_list_icon_menu_text.append(MENU_TEXT_XPDALL)
_list_icon_menu_text.append(MENU_TEXT_SRKALL)
_list_icon_menu_text.append(MENU_TEXT_FRONTALL)
_list_icon_menu_text.append(MENU_TEXT_NEXTMEMO)
_list_icon_menu_text.append(MENU_TEXT_BORDER)
_list_icon_menu_text.append(MENU_TEXT_DELETE)
_list_icon_menu_text.append(MENU_TEXT_SAVEALL)
_list_icon_menu_text.append(MENU_TEXT_SAVE)
_list_icon_menu_text.append(MENU_TEXT_NEWCLIP)
_list_icon_menu_text.append(MENU_TEXT_NEW)
_list_icon_menu_text.append(MENU_TEXT_BORDER)
_list_icon_menu_text.append(MENU_TEXT_CANCEL)

_list_memo_menu_text =  _list_icon_menu_text[:]    # コピー
_list_memo_menu_text.reverse()                     # 並び順反転


class CmemoIconCmdMenu(ContextMenu):

   IDX_ICON_MENU_CHGFONT   =  4
   IDX_ICON_MENU_CHGBGCLR  =  5
   IDX_ICON_MENU_CHGFGCLR  =  6
   IDX_ICON_MENU_SRKXPD    =  8
   IDX_ICON_MENU_NEXTMEMO  =  12
   IDX_ICON_MENU_DELETE    =  14
   IDX_ICON_MENU_SAVE      =  16

   IDX_ICON_MENU_EXIT      =  0
   IDX_ICON_MENU_README    =  2
   IDX_ICON_MENU_XPDALL    =  9
   IDX_ICON_MENU_SRKALL    =  10
   IDX_ICON_MENU_FRONTALL  =  11
   IDX_ICON_MENU_SAVEALL   =  15
   IDX_ICON_MENU_NEWCLIP   =  17
   IDX_ICON_MENU_NEW       =  18
   
   
   def __init__(self):
   
      super(CmemoIconCmdMenu, self).__init__()
   
      # トレイアイコン用メニュー作成 #
      for text in _list_icon_menu_text:
         item        =  MenuItem()
         item.Text   =  text
         if text == MENU_TEXT_CHGFONT:
            item.Enabled   =  False
         elif text == MENU_TEXT_CHGBGCLR:
            item.Enabled   =  False
         elif text == MENU_TEXT_CHGFGCLR:
            item.Enabled   =  False
         elif text == MENU_TEXT_SRKXPD:
            item.Enabled   =  False
         elif text == MENU_TEXT_NEXTMEMO:
            item.Enabled   =  False
         elif text == MENU_TEXT_DELETE:
            item.Enabled   =  False
         elif text == MENU_TEXT_SAVE:
            item.Enabled   =  False
         self.MenuItems.Add(item)

      
class CmemoMemoCmdMenu(ContextMenu):

   IDX_MEMO_MENU_CHGFONT   =  16
   IDX_MEMO_MENU_CHGBGCLR  =  15
   IDX_MEMO_MENU_CHGFGCLR  =  14
   IDX_MEMO_MENU_SRKXPD    =  12
   IDX_MEMO_MENU_NEXTMEMO  =  8
   IDX_MEMO_MENU_DELETE    =  6
   IDX_MEMO_MENU_SAVE      =  4

   IDX_MEMO_MENU_EXIT      =  20
   IDX_MEMO_MENU_README    =  18
   IDX_MEMO_MENU_XPDALL    =  11
   IDX_MEMO_MENU_SRKALL    =  10
   IDX_MEMO_MENU_FRONTALL  =  9
   IDX_MEMO_MENU_SAVEALL   =  5
   IDX_MEMO_MENU_NEWCLIP   =  3
   IDX_MEMO_MENU_NEW       =  2
   
   
   def __init__(self):
   
      super(CmemoMemoCmdMenu, self).__init__()
   
      # メモフォーム用メニュー作成 #
      for text in _list_memo_menu_text:
         item        =  MenuItem()
         item.Text   =  text
         self.MenuItems.Add(item)


個別のメモおよび作成済みのメモのリストを管理・操作するためのクラス

cmemo_memo.py

# coding: shift-jis

import clr
clr.AddReference("System.Windows.Forms")
clr.AddReference("System.Drawing")
from   System.Windows.Forms import *
import System.Drawing
import System.IO
import System.Text

from   cmemo_app     import *
from   cmemo_cmdmenu import *
from   cmemo_tbox    import *


class CmemoMemo(Form):

   # メモ表示設定保存時(データファイル1行目)の項目位置 #
   MEMO_WID          =  0
   MEMO_HEI          =  1
   MEMO_X            =  2
   MEMO_Y            =  3
   MEMO_FONTNAME     =  4
   MEMO_FONTSIZE     =  5
   MEMO_FONTSTYLE    =  6
   MEMO_R            =  7
   MEMO_G            =  8
   MEMO_B            =  9
   MEMO_BG_R         =  10
   MEMO_BG_G         =  11
   MEMO_BG_B         =  12
   MEMO_TBOX_ENABLED =  13
   
   # ウィンドウメッセージ #
   WM_NCLBUTTONDBLCLK   =  0x00a3
   WM_NCRBUTTONDOWN     =  0x00a4
   WM_NCMBUTTONDOWN     =  0x00a7

   # メモ一覧メニューの表示先 #
   MENU_OWNER_MEMO   =  0
   MENU_OWNER_ICON   =  1
   
   # FontクラスのStyleプロパティを文字列化したときの区切り文字(複数スタイル設定時) #
   SPLITTER_FONT_STYLE     =  ', '     
   
   # テキストボックスのFontStyleをメモ表示設定として保存するときの区切り文字(複数スタイル設定時) #
   SPLITTER_FONT_STYLE_INI =  '-'      
   
   # デフォルトメモ属性 #
   DEF_MEMO_WID            =  '200'
   DEF_MEMO_HEI            =  '100'
   DEF_MEMO_X              =  '100'
   DEF_MEMO_Y              =  '100'
   DEF_MEMO_FONTNAME       =  'MS UI Gothic'
   DEF_MEMO_FONTSIZE       =  '10.0'
   DEF_MEMO_FONTSTYLE      =  'Regular'
   DEF_MEMO_R              =  '128'
   DEF_MEMO_G              =  '255'
   DEF_MEMO_B              =  '255'
   DEF_MEMO_BG_R           =  '0'
   DEF_MEMO_BG_G           =  '0'
   DEF_MEMO_BG_B           =  '64'
   DEF_MEMO_TBOX_ENABLED   =  'True'
   
   # ファイル保存時のメモ属性情報区切り文字 #
   MEMO_INI_DELIMITER      =  ','
   
   # メモが最大数に達しているときに、新規メモデータファイルのパスの代わりに返す値 #
   NO_MORE_MEMO            =  ''
   
   MAX_NUM_MEMO            =  100               # メモ最大数
   
   NAME_ICON               =  'cmemo_icon.ico'  # フォーム用アイコン名


   _memo_list                    =  []                # メモインスタンスリスト
   _font_dialog                  =  FontDialog()      # テキストボックス用フォントダイアログ
   _font_dialog.FontMustExist    =  True
   _font_dialog.ShowApply        =  True
   _color_dialog                 =  ColorDialog()     # テキストボックス用カラーダイアログ
   _color_dialog.FullOpen        =  True
   
   
   def __init__(self, path):
      super(CmemoMemo, self).__init__()
   
      # メモファイル存在チェック #
      path  =  path.Trim('"')
      if not System.IO.File.Exists(path):
         raise 'ファイル "' + path + '"は存在しません。'
      self.file_path =  path
         
      # メモファイル読み込み #
      reader   =  System.IO.StreamReader(path, System.Text.Encoding.GetEncoding("shift-jis"))
      i        =  0
      data     =  ''
      while reader.Peek() >= 0:
         if i == 0:
            prms  =  reader.ReadLine().Split(CmemoMemo.MEMO_INI_DELIMITER)  # 表示設定を取得
         else:
            data  =  reader.ReadToEnd()            # メモデータを取得
         i  += 1
      reader.Close()

      # フォーム作成 #
      # self.FormBorderStyle =  FormBorderStyle.Sizable
      self.Width           =  int(prms[CmemoMemo.MEMO_WID])
      self.Height          =  int(prms[CmemoMemo.MEMO_HEI])
      self._width          =  self.Width
      self._height         =  self.Height
      self.Location        =  System.Drawing.Point(int(prms[CmemoMemo.MEMO_X]), int(prms[CmemoMemo.MEMO_Y]))
      self.StartPosition   =  FormStartPosition.Manual
      self.ShowInTaskbar   =  False
      self.MaximizeBox     =  False
      self.MinimizeBox     =  False
      self.KeyPreview      =  True
      self.ControlBox      =  False
      path  =  CmemoApp.DIR_EXE + System.IO.Path.DirectorySeparatorChar + CmemoMemo.NAME_ICON
      self.Icon            =  System.Drawing.Icon(path)
      
      # テキストボックス作成 #
      wid         =  self.ClientSize.Width
      hei         =  self.ClientSize.Height
      self.tbox   =  CmemoTextBox(data, wid, hei)
      
      # フォント設定 #
      name           =  prms[CmemoMemo.MEMO_FONTNAME]
      size           =  float(prms[CmemoMemo.MEMO_FONTSIZE])
      # (CmemoMemo.SPLITTER_FONT_STYLE_INIで区切られている
      # フォントスタイル設定文字列をFont.Styleに合う型に変換)
      strs_style     =  prms[CmemoMemo.MEMO_FONTSTYLE].split(CmemoMemo.SPLITTER_FONT_STYLE_INI)
      style          =  System.Drawing.FontStyle.Regular
      for i in range(len(strs_style)):
         style =  style | self._GetFontStyleEnum(strs_style[i])
      self.tbox.Font =  System.Drawing.Font(name, size, style)
      
      # カラー設定 #
      r  =  int(prms[CmemoMemo.MEMO_R])
      g  =  int(prms[CmemoMemo.MEMO_G])
      b  =  int(prms[CmemoMemo.MEMO_B])
      self.tbox.ForeColor  =  System.Drawing.Color.FromArgb(r, g, b)
      r  =  int(prms[CmemoMemo.MEMO_BG_R])
      g  =  int(prms[CmemoMemo.MEMO_BG_G])
      b  =  int(prms[CmemoMemo.MEMO_BG_B])
      self.tbox.BackColor  =  System.Drawing.Color.FromArgb(r, g, b)
      
      # テキストボックス貼り付け #
      self.Controls.Add(self.tbox)
      
      # タイトルキャプション設定 #
      self._SetTitleMemoLength()
      
      # メモフォーム用コマンドメニュー作成 #
      menu  =  CmemoMemoCmdMenu()
      self._SetMemoCmdMemu(menu)

      # イベントハンドラ設定(メニュー以外) #
      self.KeyUp              += self._OnKeyUp
      self.FormClosing        += self._OnFormClosing
      self.tbox.KeyUp         += self._OnTextBoxKeyUp
      self.KeyPress           += self._OnKeyPress
      self.tbox.TextChanged   += self._OnTextBoxTextChanged
      
      # インスタンスリストに自分自身を追加 #
      CmemoMemo._memo_list.append(self)
      
      # 折りたたみ状態復元
      if prms[CmemoMemo.MEMO_TBOX_ENABLED] == str(False):   # 前回終了時のtbox.EnabledがFalse
         self._Shrink()
         
         
   def Show(self):
      super(CmemoMemo, self).Show()
      # テキストの選択状態を監視するためのタイマーを作成 #
      self._len_selected_text =  0
      self._timer             =  Timer()
      self._timer.Interval    =  100
      self._timer.Tick        += self._OnTimerTick
      self._timer.Start()
      
      
   #------------------------#
   # ウィンドウプロシージャ #
   #------------------------#

   def WndProc(self, msg):
      if msg.Value.Msg == CmemoMemo.WM_NCLBUTTONDBLCLK:
         self._OnTitleDoubleClick()
         return
      elif msg.Value.Msg == CmemoMemo.WM_NCRBUTTONDOWN:
         self._OnTitleRightClick()
         return
      elif msg.Value.Msg == CmemoMemo.WM_NCMBUTTONDOWN:
         # この部分の処理はWindowsのマウスコントロールパネルのホイールクリックの
         # 設定が既定(オートスクロール)のままになっていないと実行されない。
         MessageBox.Show('_OnTitleWheelClick')
         return
      super(CmemoMemo, self).WndProc(msg)
         
         
   #------------------#
   # イベントハンドラ #
   #------------------#
   
   def _OnKeyUp(self, obj, eargs):
      if Form.ModifierKeys:
         if  (eargs.KeyCode  ==  Keys.N) and eargs.Control and not eargs.Shift:   # 新規メモ
            CmemoMemo._Create()
            eargs.Handled  =  True
            return
         elif  (eargs.KeyCode  ==  Keys.P) and eargs.Control and not eargs.Shift:   # クリップボードテキストで新規メモ
            CmemoMemo._CreateFromClipboard()
            eargs.Handled  =  True
            return
         elif  (eargs.KeyCode  ==  Keys.S) and eargs.Control and not eargs.Shift:   # 保存
            self._Save()
            eargs.Handled  =  True
            return
         elif  (eargs.KeyCode  ==  Keys.S) and eargs.Control and eargs.Shift:   # すべて保存
            CmemoMemo._SaveAll()
            eargs.Handled  =  True
            return
      else:
         if  eargs.KeyCode  ==  Keys.F1:     # Readmeを開く
            CmemoApp.OpenReadme()
            eargs.Handled  =  True
            return
         elif  eargs.KeyCode  ==  Keys.F11:   # 次のメモ
            self._ActivateNext()
            eargs.Handled  =  True
            return
         elif  eargs.KeyCode  ==  Keys.F12:   # すべて前面に
            CmemoMemo._MoveAllToFront()
            eargs.Handled  =  True
            return
         elif  eargs.KeyCode  ==  Keys.F2:  # すべてたたむ
            CmemoMemo._ShrinkAll()
            eargs.Handled  =  True
            return
         elif  eargs.KeyCode  ==  Keys.F3:  # すべて広げる
            CmemoMemo._ExpandAll()
            eargs.Handled  =  True
            return
         elif  eargs.KeyCode  ==  Keys.F4:   # たたむ / 広げる
            self._ShrinkExpand()
            eargs.Handled  =  True
         
         
   def _OnKeyPress(self, obj, eargs):  # ビープ音抑制のための処理
      if  Form.ModifierKeys:
         if  eargs.KeyChar.CompareTo('n'.ToCharArray()[0]) + CmemoTextBox.KEYCHAR_CONTROL == 0:
            eargs.Handled  =  True
            return
         if  eargs.KeyChar.CompareTo('p'.ToCharArray()[0]) + CmemoTextBox.KEYCHAR_CONTROL == 0:
            eargs.Handled  =  True
            return
         if  eargs.KeyChar.CompareTo('s'.ToCharArray()[0]) + CmemoTextBox.KEYCHAR_CONTROL == 0:
            eargs.Handled  =  True
            return
         if  eargs.KeyChar.CompareTo('t'.ToCharArray()[0]) + CmemoTextBox.KEYCHAR_CONTROL == 0:
            eargs.Handled  =  True
            return
         if  eargs.KeyChar.CompareTo('b'.ToCharArray()[0]) + CmemoTextBox.KEYCHAR_CONTROL == 0:
            eargs.Handled  =  True
            return
         if  eargs.KeyChar.CompareTo('f'.ToCharArray()[0]) + CmemoTextBox.KEYCHAR_CONTROL == 0:
            eargs.Handled  =  True


   def _OnTextBoxKeyUp(self, obj, eargs):
      if    (eargs.KeyCode  ==  Keys.T) and eargs.Control:  # 文字色変更
         self._ChangeFgColor()
         return
      elif  (eargs.KeyCode  ==  Keys.B) and eargs.Control:  # 背景色変更
         self._ChangeBgColor()
         return
      elif  (eargs.KeyCode  ==  Keys.F) and eargs.Control:  # フォント変更
         self._ChangeFont()
         
         
   def _OnTextBoxTextChanged(self, obj, eargs):
      self._SetTitleMemoLength()
   
   
   def _OnFormClosing(self, obj, eargs):
      if eargs.CloseReason == CloseReason.UserClosing:
         # 削除の意思確認 #
         message  =  'このメモを削除します。削除したメモは復活できません。削除してもよろしいですか?'
         caption  =  '確認'
         buttons  =  MessageBoxButtons.OKCancel
         icon     =  MessageBoxIcon.Question
         default  =  MessageBoxDefaultButton.Button2
         result   =  MessageBox.Show(self, message, caption, buttons, icon, default)
         
         if result == DialogResult.OK:
            # メモファイル削除 #
            System.IO.File.Delete(self.file_path)
            # リストから削除 #
            CmemoMemo._memo_list.remove(self)
         else:
            eargs.Cancel   =  True
      else:
         # アプリケーション終了に伴うものなのでメモ保存 #
         self._Save()
         
         
   def _OnFontDialogApply(self, obj, eargs):
      self._ApplyFontDialog()
         
         
   def _OnTimerTick(self, obj, eargs):
      self._CheckTextBoxSelectionLength()
         
         
   def _OnTitleDoubleClick(self):
      self._ShrinkExpand()
         
         
   def _OnTitleRightClick(self):
      if    Form.ModifierKeys == Keys.Control:
         self._ShowMemoListMenu()
      elif  not Form.ModifierKeys:
         self._ShowMemoCmdMenu()
         
         
   #----------------------------#
   # メニュー用イベントハンドラ #
   #----------------------------#
   
   @classmethod
   def OnMenuCreate(Class, obj, eargs):
      Class._Create()
   
   @classmethod
   def OnMenuCreateFromClipboard(Class, obj, eargs):
      Class._CreateFromClipboard()
      
   @classmethod
   def OnMenuSaveAll(Class, obj, eargs):
      Class._SaveAll()

   @classmethod
   def OnMenuMoveAllToFront(Class, obj, eargs):
      Class._MoveAllToFront()
      
   @classmethod
   def OnMenuShrinkAll(Class, obj, eargs):
      Class._ShrinkAll()

   @classmethod
   def OnMenuExpandAll(Class, obj, eargs):
      Class._ExpandAll()
      
   @classmethod
   def OnMenuReadme(Class, obj, eargs):
      CmemoApp.OpenReadme()

   @classmethod
   def OnMenuExit(Class, obj, eargs):
      Application.Exit()
      
   
   def _OnMenuSave(self, obj, eargs):
      self._Save()
      
   def _OnMenuDelete(self, obj, eargs):
      self.Close()
      
   def _OnMenuNextMemo(self, obj, eargs):
      self._ActivateNext()
      
   def _OnMenuShrinkExpand(self, obj, eargs):
      self._ShrinkExpand()
      
   def _OnMenuChangeFgColor(self, obj, eargs):
      self._ChangeFgColor()

   def _OnMenuChangeBgColor(self, obj, eargs):
      self._ChangeBgColor()

   def _OnMenuChangeFont(self, obj, eargs):
      self._ChangeFont()
      
      
   def _OnMemoListMenuClick(self, obj, eargs):
      self.Activate()

      
   #----------#
   # コマンド #
   #----------#
   
   # 新規メモ #
   @classmethod
   def _Create(Class):
      text  =  ''
      path  =  Class._CreateMemoFile(text)
      
      if not path == CmemoMemo.NO_MORE_MEMO:     # 新規メモファイル作成成功
         # 作成したファイルのパスを引数としてCmemoMemoオブジェクト生成・表示 #
         CmemoMemo(path).Show()
         
         
   # クリップボードテキストで新規メモ #
   @classmethod
   def _CreateFromClipboard(Class):
      if Clipboard.ContainsText():     # クリップボード内にテキストがある
         text  =  Clipboard.GetText()
      else:
         text  =  ''
      path  =  Class._CreateMemoFile(text)
      
      if not path == CmemoMemo.NO_MORE_MEMO:     # 新規メモファイル作成成功
         # 作成したファイルのパスを引数としてCmemoMemoオブジェクト生成・表示 #
         CmemoMemo(path).Show()
         
         
   # 保存 #
   def _Save(self):
      #------------------------#
      # 保存データ作成(data) #
      #------------------------#
      
      # サイズと位置情報
      if self.tbox.Enabled:
         data  =  str(self.Width)            + CmemoMemo.MEMO_INI_DELIMITER
         data  += str(self.Height)           + CmemoMemo.MEMO_INI_DELIMITER
      else:
         data  =  str(self._width)           + CmemoMemo.MEMO_INI_DELIMITER
         data  += str(self._height)          + CmemoMemo.MEMO_INI_DELIMITER
      data  += str(self.Location.X)          + CmemoMemo.MEMO_INI_DELIMITER
      data  += str(self.Location.Y)          + CmemoMemo.MEMO_INI_DELIMITER
      
      # フォント設定
      data  += self.tbox.Font.Name           + CmemoMemo.MEMO_INI_DELIMITER
      data  += str(self.tbox.Font.Size) + CmemoMemo.MEMO_INI_DELIMITER
      # (スタイル設定の区切り文字がメモ設定全体の区切り文字とダブっているため
      # 別の文字に変換した上で保存)
      styles   =  str(self.tbox.Font.Style).split(CmemoMemo.SPLITTER_FONT_STYLE)
      for i in range(len(styles)):
         if i > 0:
            data  += CmemoMemo.SPLITTER_FONT_STYLE_INI
         data  += styles[i]
      data  += CmemoMemo.MEMO_INI_DELIMITER
      
      # 色設定
      data  += str(self.tbox.ForeColor.R)    + CmemoMemo.MEMO_INI_DELIMITER
      data  += str(self.tbox.ForeColor.G)    + CmemoMemo.MEMO_INI_DELIMITER
      data  += str(self.tbox.ForeColor.B)    + CmemoMemo.MEMO_INI_DELIMITER
      data  += str(self.tbox.BackColor.R)    + CmemoMemo.MEMO_INI_DELIMITER
      data  += str(self.tbox.BackColor.G)    + CmemoMemo.MEMO_INI_DELIMITER
      data  += str(self.tbox.BackColor.B)    + CmemoMemo.MEMO_INI_DELIMITER
      
      # たたまれているかどうか(self.tbox.Enabled == True -> たたまれていない)
      data  += str(self.tbox.Enabled)        + System.Environment.NewLine
      
      # メモ内容
      data  += self.tbox.Text
   
      #--------------#
      # ファイル保存 #
      #--------------#
      file     =  System.IO.FileStream(self.file_path, System.IO.FileMode.Create)
      writer   =  System.IO.StreamWriter(file, System.Text.Encoding.GetEncoding('shift-jis'))
      writer.Write(data)
      writer.Close()
      file.Close()
      
      
   # すべて保存 #
   @classmethod
   def _SaveAll(Class):
      for memo in Class._memo_list:
         memo._Save()
         

   # 次のメモ #
   def _ActivateNext(self):
      i  =  CmemoMemo._memo_list.IndexOf(self)
      if i == len(CmemoMemo._memo_list) - 1:
         i  =  0
      else:
         i += 1
      CmemoMemo._memo_list[i].Activate()
   
   
   # すべて前面に #
   @classmethod
   def _MoveAllToFront(Class):
      for memo in Class._memo_list:
         memo.Activate()


   # すべてたたむ #
   @classmethod
   def _ShrinkAll(Class):
      for memo in Class._memo_list:
         memo._Shrink()
   
   
   # すべて広げる #
   @classmethod
   def _ExpandAll(Class):
      for memo in Class._memo_list:
         memo._Expand()
         
         
   # たたむ / 広げる #
   def _ShrinkExpand(self):
      if self.tbox.Enabled:
         self._Shrink()
      else:
         self._Expand()
         
         
   # 文字色変更 #
   def _ChangeFgColor(self):
      CmemoMemo._color_dialog.Color  =  self.tbox.ForeColor
      if CmemoMemo._color_dialog.ShowDialog() == DialogResult.OK:
         self.tbox.ForeColor  =  CmemoMemo._color_dialog.Color
      
      
   # 背景色変更 #
   def _ChangeBgColor(self):
      CmemoMemo._color_dialog.Color  =  self.tbox.BackColor
      if CmemoMemo._color_dialog.ShowDialog() == DialogResult.OK:
         self.tbox.BackColor  =  CmemoMemo._color_dialog.Color
      
      
   # フォント変更 #
   def _ChangeFont(self):
      CmemoMemo._font_dialog.Font   =  self.tbox.Font
      CmemoMemo._font_dialog.Apply  += self._OnFontDialogApply
      if CmemoMemo._font_dialog.ShowDialog() == DialogResult.OK:
         self._ApplyFontDialog()
      CmemoMemo._font_dialog.Apply  -= self._OnFontDialogApply
      
      
   # メモ一覧メニュー作成、表示 #
   def _ShowMemoListMenu(self):
      menu  =  CmemoMemo.GetMemoListMenu(CmemoMemo.MENU_OWNER_MEMO)
      menu.Show(self, self.PointToClient(Cursor.Position))
   
      
   # コマンドメニュー表示 #
   def _ShowMemoCmdMenu(self):
      self.ContextMenu.Show(self, self.PointToClient(Cursor.Position))
      
      
   #--------------#
   # サブルーチン #
   #--------------#

   # 新規メモファイル作成 #
   @classmethod
   def _CreateMemoFile(Class, text):
      # 空き番号検索と同時にメモ数上限チェック #
      for i in range(Class.MAX_NUM_MEMO):
         path  =  CmemoApp.DIR_DATA + System.IO.Path.DirectorySeparatorChar + i.ToString('00') + '.txt'
         if System.IO.File.Exists(path):
            path  =  Class.NO_MORE_MEMO
         else:
            break
            
      if path == Class.NO_MORE_MEMO:    # 既にメモの数が上限いっぱい
         # print 'これ以上メモを作ることはできません。新しいメモを作るには不要なメモを削除して下さい。'
         MessageBox.Show('これ以上メモを作ることはできません。新しいメモを作るには不要なメモを削除して下さい。')
         return path
         
      # 空き番号を名前としてテキストファイル作成 #
      data  =  Class.DEF_MEMO_WID            + Class.MEMO_INI_DELIMITER
      data  += Class.DEF_MEMO_HEI            + Class.MEMO_INI_DELIMITER
      data  += Class.DEF_MEMO_X              + Class.MEMO_INI_DELIMITER
      data  += Class.DEF_MEMO_Y              + Class.MEMO_INI_DELIMITER
      data  += Class.DEF_MEMO_FONTNAME       + Class.MEMO_INI_DELIMITER
      data  += Class.DEF_MEMO_FONTSIZE       + Class.MEMO_INI_DELIMITER
      data  += Class.DEF_MEMO_FONTSTYLE      + Class.MEMO_INI_DELIMITER
      data  += Class.DEF_MEMO_R              + Class.MEMO_INI_DELIMITER
      data  += Class.DEF_MEMO_G              + Class.MEMO_INI_DELIMITER
      data  += Class.DEF_MEMO_B              + Class.MEMO_INI_DELIMITER
      data  += Class.DEF_MEMO_BG_R           + Class.MEMO_INI_DELIMITER
      data  += Class.DEF_MEMO_BG_G           + Class.MEMO_INI_DELIMITER
      data  += Class.DEF_MEMO_BG_B           + Class.MEMO_INI_DELIMITER
      data  += Class.DEF_MEMO_TBOX_ENABLED   + System.Environment.NewLine
      data  += text
      
      file     =  System.IO.FileStream(path, System.IO.FileMode.Create)
      writer   =  System.IO.StreamWriter(file, System.Text.Encoding.GetEncoding('shift-jis'))
      writer.Write(data)
      writer.Close()
      file.Close()

      return path


   # たたむ #
   def _Shrink(self):
      if self.tbox.Enabled:
         self.Text            =  self._GetMemo1stLine() + ' '   # スペースを追加しないとなぜか落ちる
         self.tbox.Enabled    =  False
         # たたむ前のサイズを記録してから、FormBorderStyleとサイズを変更 #
         self._width          =  self.Width
         self._height         =  self.Height
         self.FormBorderStyle =  FormBorderStyle.Fixed3D
         self.Width           =  self._width
         self.Height          =  0
         # 外見変更系メニューを無効に #
         self.ContextMenu.MenuItems[CmemoMemoCmdMenu.IDX_MEMO_MENU_CHGFONT].Enabled    =  False
         self.ContextMenu.MenuItems[CmemoMemoCmdMenu.IDX_MEMO_MENU_CHGBGCLR].Enabled   =  False
         self.ContextMenu.MenuItems[CmemoMemoCmdMenu.IDX_MEMO_MENU_CHGFGCLR].Enabled   =  False
   
   
   # 広げる #
   def _Expand(self):
      if not self.tbox.Enabled:
         self._SetTitleMemoLength()
         self.tbox.Enabled    =  True
         # FormBorderStyleを戻してからサイズを変更 #
         self.FormBorderStyle =  FormBorderStyle.Sizable
         self.Width           =  self._width
         self.Height          =  self._height
         self.tbox.Focus()
         # 外見変更系メニューを有効に #
         self.ContextMenu.MenuItems[CmemoMemoCmdMenu.IDX_MEMO_MENU_CHGFONT].Enabled    =  True
         self.ContextMenu.MenuItems[CmemoMemoCmdMenu.IDX_MEMO_MENU_CHGBGCLR].Enabled   =  True
         self.ContextMenu.MenuItems[CmemoMemoCmdMenu.IDX_MEMO_MENU_CHGFGCLR].Enabled   =  True
         
         
   def _GetFontStyleEnum(self, str_style):
      if    str_style == str(System.Drawing.FontStyle.Bold):
         return  System.Drawing.FontStyle.Bold
      elif  str_style == str(System.Drawing.FontStyle.Italic):
         return  System.Drawing.FontStyle.Italic
      elif  str_style == str(System.Drawing.FontStyle.Underline):
         return  System.Drawing.FontStyle.Underline
      elif  str_style == str(System.Drawing.FontStyle.Strikeout):
         return  System.Drawing.FontStyle.Strikeout
      else:
         return  System.Drawing.FontStyle.Regular
         
         
   # FontDialogの内容をテキストボックス(メモ)に反映 #
   def _ApplyFontDialog(self):
      self.tbox.Font =  CmemoMemo._font_dialog.Font
         
         
   # メモ全体または選択テキストの長さをタイトルバーに表示 #
   def _SetTitleMemoLength(self):
      if self.tbox.SelectionLength == 0:
         text     =  self.tbox.Text
      else:
         text     =  self.tbox.SelectedText
      len         =  System.Text.Encoding.GetEncoding("shift-jis").GetBytes(text).Length
      self.Text   =  str(len) + 'バイト'
      
      
   def _CheckTextBoxSelectionLength(self):
      if self.tbox.SelectionLength != self._len_selected_text:
         self._SetTitleMemoLength()
         self._len_selected_text =  self.tbox.SelectionLength
      

   # メモの1行目を取得 #
   def _GetMemo1stLine(self):
      len   =  self.tbox.Text.IndexOf(System.Environment.NewLine)
      if len < 0:
         return self.tbox.Text
      else:
         return self.tbox.Text.Substring(0, len)
         
         
   def _SetMemoCmdMemu(self, menu):
      self.ContextMenu  =  menu
      self.ContextMenu.MenuItems[CmemoMemoCmdMenu.IDX_MEMO_MENU_NEW].Click       += CmemoMemo.OnMenuCreate
      self.ContextMenu.MenuItems[CmemoMemoCmdMenu.IDX_MEMO_MENU_NEWCLIP].Click   += CmemoMemo.OnMenuCreateFromClipboard
      self.ContextMenu.MenuItems[CmemoMemoCmdMenu.IDX_MEMO_MENU_SAVE].Click      += self._OnMenuSave
      self.ContextMenu.MenuItems[CmemoMemoCmdMenu.IDX_MEMO_MENU_SAVEALL].Click   += CmemoMemo.OnMenuSaveAll
      self.ContextMenu.MenuItems[CmemoMemoCmdMenu.IDX_MEMO_MENU_DELETE].Click    += self._OnMenuDelete
      self.ContextMenu.MenuItems[CmemoMemoCmdMenu.IDX_MEMO_MENU_NEXTMEMO].Click  += self._OnMenuNextMemo
      self.ContextMenu.MenuItems[CmemoMemoCmdMenu.IDX_MEMO_MENU_FRONTALL].Click  += CmemoMemo.OnMenuMoveAllToFront
      self.ContextMenu.MenuItems[CmemoMemoCmdMenu.IDX_MEMO_MENU_SRKALL].Click    += CmemoMemo.OnMenuShrinkAll
      self.ContextMenu.MenuItems[CmemoMemoCmdMenu.IDX_MEMO_MENU_XPDALL].Click    += CmemoMemo.OnMenuExpandAll
      self.ContextMenu.MenuItems[CmemoMemoCmdMenu.IDX_MEMO_MENU_SRKXPD].Click    += self._OnMenuShrinkExpand
      
      self.ContextMenu.MenuItems[CmemoMemoCmdMenu.IDX_MEMO_MENU_CHGFGCLR].Click  += self._OnMenuChangeFgColor
      self.ContextMenu.MenuItems[CmemoMemoCmdMenu.IDX_MEMO_MENU_CHGBGCLR].Click  += self._OnMenuChangeBgColor
      self.ContextMenu.MenuItems[CmemoMemoCmdMenu.IDX_MEMO_MENU_CHGFONT].Click   += self._OnMenuChangeFont
      
      self.ContextMenu.MenuItems[CmemoMemoCmdMenu.IDX_MEMO_MENU_README].Click    += CmemoMemo.OnMenuReadme
      self.ContextMenu.MenuItems[CmemoMemoCmdMenu.IDX_MEMO_MENU_EXIT].Click      += CmemoMemo.OnMenuExit

   
   # メモ一覧メニュー作成 #
   @classmethod
   def GetMemoListMenu(Class, owner):
      menu  =  ContextMenu()
      if owner == Class.MENU_OWNER_MEMO:
         item         =  MenuItem()
         item.Text    =  MENU_TEXT_CANCEL
         menu.MenuItems.Add(item)
         item         =  MenuItem()
         item.Text    =  MENU_TEXT_BORDER
         menu.MenuItems.Add(item)
      for memo in Class._memo_list:
         item         =  MenuItem()
         item.Text    =  memo._GetMemo1stLine()
         item.Click   += memo._OnMemoListMenuClick
         menu.MenuItems.Add(item)
      if owner == Class.MENU_OWNER_ICON:
         item         =  MenuItem()
         item.Text    =  MENU_TEXT_BORDER
         menu.MenuItems.Add(item)
         item         =  MenuItem()
         item.Text    =  MENU_TEXT_CANCEL
         menu.MenuItems.Add(item)
      return menu


タスクトレイアイコン管理クラス

cmemo_nicon.py

# coding: shift-jis

import clr
clr.AddReference('System.Windows.Forms')
clr.AddReference('System.Drawing')
from   System.Windows.Forms import *
import System.Drawing
import System.IO

from   cmemo_app     import *
from   cmemo_cmdmenu import *
from   cmemo_memo    import *


class CmemoNotifyIcon:

   NAME_ICON   =  'cmemo_nicon.ico'
   
   # メモ一覧メニューを正しい位置に表示するために使う隠しフォーム #
   _form                =  Form()
   _form.Width          =  0
   _form.Height         =  0
   _form.ClientSize     =  System.Drawing.Size(0, 0)
   _form.Text           =  CmemoApp.TEXT_APP_NAME
   _form.ShowInTaskbar  =  False
   _form.Opacity        =  0        # 完全に透明

   
   def __init__(self):
      # アイコン取得 #
      path  =  CmemoApp.DIR_EXE + System.IO.Path.DirectorySeparatorChar + CmemoNotifyIcon.NAME_ICON
      icon  =  System.Drawing.Icon(path)

      # トレイアイコン作成 #
      self._nicon       =  NotifyIcon()
      self._nicon.Icon  =  icon
      self._nicon.Text  =  CmemoApp.TEXT_APP_NAME + ' ' + CmemoApp.TEXT_APP_VER

      # トレイアイコン用メニュー作成 #
      menu  =  CmemoIconCmdMenu()
      menu.MenuItems[CmemoIconCmdMenu.IDX_ICON_MENU_EXIT].Click      += CmemoMemo.OnMenuExit
      menu.MenuItems[CmemoIconCmdMenu.IDX_ICON_MENU_README].Click    += CmemoMemo.OnMenuReadme
      menu.MenuItems[CmemoIconCmdMenu.IDX_ICON_MENU_XPDALL].Click    += CmemoMemo.OnMenuExpandAll
      menu.MenuItems[CmemoIconCmdMenu.IDX_ICON_MENU_SRKALL].Click    += CmemoMemo.OnMenuShrinkAll
      menu.MenuItems[CmemoIconCmdMenu.IDX_ICON_MENU_FRONTALL].Click  += CmemoMemo.OnMenuMoveAllToFront
      menu.MenuItems[CmemoIconCmdMenu.IDX_ICON_MENU_SAVEALL].Click   += CmemoMemo.OnMenuSaveAll
      menu.MenuItems[CmemoIconCmdMenu.IDX_ICON_MENU_NEWCLIP].Click   += CmemoMemo.OnMenuCreateFromClipboard
      menu.MenuItems[CmemoIconCmdMenu.IDX_ICON_MENU_NEW].Click       += CmemoMemo.OnMenuCreate
      self._nicon.ContextMenu  =  menu
      
      self._nicon.Click        += self._OnClick
      self._nicon.Visible      =  True
      
      
   def Hide(self):
      self._nicon.Visible   =  False
      
      
   #------------------#
   # イベントハンドラ #
   #------------------#
   
   def _OnClick(self, obj, eargs):
      if eargs.Button == MouseButtons.Middle:
         # この部分の処理はWindowsのマウスコントロールパネルのホイールクリックの
         # 設定が既定(オートスクロール)のままになっていないと実行されない。
         CmemoNotifyIcon._form.Show()       # メニューの正常動作のために必要
         CmemoNotifyIcon._form.Activate()   # メニューの正常動作のために必要
         MessageBox.Show('_OnWheelClick')
         CmemoNotifyIcon._form.Hide()       # Alt+Tabキーで表示されるウィンドウ一覧に表示されないように
         return
      if eargs.Button == MouseButtons.Left:
         # メモ一覧メニューを表示 #
         CmemoNotifyIcon._form.ContextMenu  =  CmemoMemo.GetMemoListMenu(CmemoMemo.MENU_OWNER_ICON)
         CmemoNotifyIcon._form.Show()       # メニューの正常動作のために必要
         CmemoNotifyIcon._form.Activate()   # メニューの正常動作のために必要
         CmemoNotifyIcon._form.ContextMenu.Show(CmemoNotifyIcon._form, CmemoNotifyIcon._form.PointToClient(Cursor.Position))
         CmemoNotifyIcon._form.Hide()       # Alt+Tabキーで表示されるウィンドウ一覧に表示されないように


テキストボックス管理クラス

cmemo_tbox.py

# coding: shift-jis

import clr
clr.AddReference("System.Windows.Forms")
from   System.Windows.Forms import *

from   my_textbox import *


class CmemoTextBox(MyTextBox):

   def __init__(self, data, wid, hei):
      super(CmemoTextBox, self).__init__()

      self.Text            =  data
      self.Width           =  wid
      self.Height          =  hei
      self.SelectionStart  =  self.TextLength   # テキストの末尾にキャレットを置く
      self.Multiline       =  True
      self.ScrollBars      =  ScrollBars.Vertical
      # 常にウィンドウいっぱいに表示 #
      self.Anchor =  AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom


汎用のテキストボックス管理クラス

my_textbox.py

# coding: shift-jis

import clr
clr.AddReference("System.Windows.Forms")
from   System.Windows.Forms import *
import System


class MyTextBox(TextBox):

   _list_menu_text   =  []
   _list_menu_text.append('切り取り(T)\tCtrl+X')
   _list_menu_text.append('コピー(C)\tCtrl+C')
   _list_menu_text.append('貼り付け(P)\tCtrl+V')
   _list_menu_text.append('削除(D)\tDelete')
   _list_menu_text.append('-')
   _list_menu_text.append('元に戻す(U)\tCtrl+Z')
   _list_menu_text.append('-')
   _list_menu_text.append('すべて選択(A)\tCtrl+A')
   
   IDX_MENU_CUT         =  0
   IDX_MENU_COPY        =  1
   IDX_MENU_PASTE       =  2
   IDX_MENU_DELETE      =  3
   IDX_MENU_UNDO        =  5
   IDX_MENU_SELECTALL   =  7

   KEYCHAR_CONTROL      =  96


   def __init__(self):
      super(MyTextBox, self).__init__()

      self.ContextMenu  =  self._CreateContextMenu()

      self.KeyPress     += self._OnKeyPress
      
      
   def _CreateContextMenu(self):
   
      menu  =  ContextMenu()
      
      for text in MyTextBox._list_menu_text:
         item        =  MenuItem()
         item.Text   =  text
         menu.MenuItems.Add(item)
      menu.MenuItems[MyTextBox.IDX_MENU_CUT].Click       +=  self._OnMenuCut
      menu.MenuItems[MyTextBox.IDX_MENU_COPY].Click      +=  self._OnMenuCopy
      menu.MenuItems[MyTextBox.IDX_MENU_PASTE].Click     +=  self._OnMenuPaste
      menu.MenuItems[MyTextBox.IDX_MENU_DELETE].Click    +=  self._OnMenuDelete
      menu.MenuItems[MyTextBox.IDX_MENU_UNDO].Click      +=  self._OnMenuUndo
      menu.MenuItems[MyTextBox.IDX_MENU_SELECTALL].Click +=  self._OnMenuSelectAll
      return menu
      
      
   def _OnMenuUndo(self, obj, eargs):
      self.Undo()
   
   def _OnMenuCut(self, obj, eargs):
      self.Cut()
   
   def _OnMenuCopy(self, obj, eargs):
      self.Copy()
   
   def _OnMenuPaste(self, obj, eargs):
      self.Paste()
   
   def _OnMenuDelete(self, obj, eargs):
      self.SelectedText =  ''
   
   def _OnMenuSelectAll(self, obj, eargs):
      self.SelectAll()
      
      
   # 常に有効にしたい機能を実行すると共にビープ音抑制
   def _OnKeyPress(self, obj, eargs):
      if  Form.ModifierKeys:
         if  eargs.KeyChar.CompareTo('a'.ToCharArray()[0]) + MyTextBox.KEYCHAR_CONTROL == 0:
            self.SelectAll()
            eargs.Handled  =  True