[PR]今日のニュースは
「Infoseek モバイル」


トップレベル

 Tkinterのルートウィンドウ以外のウィンドウを出すことも、 もちろんできます。Tcl/Tkと同様、トップレベル(Toplevel)を作ればいいのですが、 ここはPythonの正統なオブジェクト指向の考えに基づいたつもりで、 Toplevelを継承(サブクラス化)して作ってみます。

from Tkinter import *
from tkFont import *

class MyToplevel(Toplevel):
  def __init__(self, labeltext, master=None):
    Toplevel.__init__(self, master)
    self.title("トップレベル")
    la = Label(self, text=labeltext, fg="#800040",
               font=Font(family="helvetica", size=18, weight=NORMAL))
    la.bind("", self.close)
    la.pack(side=TOP)

  def close(self, event):
    self.destroy()

class App(Frame):
  def init(self):
    self.master.title("ボタンども")
    self.master.bind("<Control-q>", self.close)
    b = {}
    for n in range(1, 10):
      b[n] = Button(self, text=str(n))
      b[n].bind("", self.popupToplevel)
      b[n].grid(row=int((n-1)/3), column=int((n-1)%3))

  def popupToplevel(self, event):
    labeltext = event.widget.cget("text")
    g = MyToplevel(labeltext)

  def close(self, event): self.master.destroy()

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

if __name__ == "__main__":
  app = App()
  app.mainloop()
# end.

スクリーンショット

 なお、ここでは出てきていませんが、 トップレベルは自分のほかのウィンドウの操作を一切できなくするgrab という機能をON/OFFすることができます。通常はOFFですが、 grabをONにする(モーダルにする)にはトップレベルの grab_setメソッドを、OFFにする(モードレスにする) にはgrab_releaseメソッドを使います。 titleでタイトルバーの文字列をセットでき、 自爆するにはdestroyを使います。

ちょっとメモ(5) - キーボードイベントのバインド
 キーボードイベントをトラップするbindを使うときのウィジェットとして、 Tcl/Tkでは普通ウィジェット階層の最上位「.」を使いますが、 Tkinterでも同じで、Frameを継承しているこのサンプルのやり方では、 「.」はself.masterに当たります。 そのため、このような形になっています。
self.master.bind('<Control-q>', self.close)


テキストとファイル選択ダイアログ

 今度は血迷って、いやいや、趣向を変えて、簡単なテキストエディタを作ってみました。

from Tkinter import *
from tkFileDialog import *
import string

def j(str, encoding="japanese.shift_jis"):
  u = unicode(str, encoding)
  return u.encode("utf8")

def uj(str, encoding="japanese.shift_jis"):
  #u = unicode(str, "utf8")
  return str.encode(encoding)

class App(Frame):

  def openFile(self):
    filename = askopenfilename()
    if filename != "":
      fin = open(filename, "r")
      a = fin.read()
      fin.close()
      self.ta.delete("1.0", END)
      self.ta.insert(END, j(a))

  def saveFile(self):
    filename = asksaveasfilename()
    if filename != "":
      fout = open(filename, "w")
      fout.write(uj(self.ta.get("1.0", END)))
      fout.close()

  def init(self):
    # メニューバー部分
    mb = Menu(tearoff=1)
    mc1 = Menu(mb)
    mb.add_cascade(label="File", menu=mc1)
    mc1.add_command(label="Open...", command=self.openFile)
    mc1.add_command(label="Save as...", command=self.saveFile)
    mc1.add_command(label="Quit", command=self.quit)
    self.master.config(menu=mb)

    # テキスト編集部分
    f = Frame(self, relief=GROOVE, bd=2)
    self.ta = Text(f, width=80, height=25)
    scrv = Scrollbar(f, orient=VERTICAL, command=self.ta.yview)
    scrh = Scrollbar(f, orient=HORIZONTAL, command=self.ta.xview)
    self.ta.config(xscrollcommand=scrh.set, yscrollcommand=scrv.set)
    self.ta.grid(row=1, column=1)
    scrv.grid(row=1, column=2, sticky=NS)
    scrh.grid(row=2, column=1, sticky=EW)
    f.pack()

  def quit(self):
    self.master.destroy()

  def __init__(self, master=None):
    Frame.__init__(self, master)
    self.master.title("Simple Text Editor")
    self.init();  self.pack()

if __name__ == '__main__':
  a = App(); a.mainloop()
# end.

スクリーンショット

 いくつかの要点がありますが、まずはメインの Textウィジェットから。 これは複数行を入力できるテキストの入力欄です。 本当は部分部分の色やフォントや文字飾りを変えたり、 ハイパーテキストみたいなこともできたりするスゴいヤツなのですが、 とりあえず、最も基本的なオプションで作りました。 文字列を挿入、削除、取得するには、それぞれ次のようにします。

self.ta.insert(END, j(a))
self.ta.delete("1.0", END)
input_string = self.ta.get("1.0", END)

"1.0"とかENDとかいうのは、 Textウィジェット上の部分文字列の位置を指定する指示子で、 1.0は1行目の零列目、つまりテキストの先頭を、 ENDは記号定数そのまんま、テキストの終端を表します。

 次にメニューバーですが、今度は以前出てきたのとは違い、 トップレベルウィンドウのmenu=オプションで、 プルダウンメニューを指定することで行います。 プルダウンメニューは、 Menuクラスをtearoff=1オプションをつけてインスタンス化して作ります。 ポイントは、そのMenuオブジェクトに載せる直系の項目は、 全てadd_cascadeメソッドを使ってカスケードメニューとして載せることです。 このカスケードメニューのラベルが 「ファイル」「編集」「表示」「書式」…という最上位のメニューになります。 そして、ファイルの下には「新規作成」「開く...」など、 編集の下には「切り取り」「コピー」などの項目を追加していくことになります。

mb = Menu(tearoff=1)
mc1 = Menu(mb)
mb.add_cascade(label="File", menu=mc1)
mc1.add_command(label="Open...", command=self.openFile)
mc1.add_command(label="Save as...", command=self.saveFile)
mc1.add_command(label="Quit", command=self.quit)
self.master.config(menu=mb)

ちょっとメモ(6) - ファイル選択ダイアログ
 ファイル選択ダイアログは、アプリケーションで最も頻繁に使うダイアログで、 Tcl/Tkではtk_getOpenFile、tk_getSaveFile というコマンド1つでダイアログを出せましたが、 Tkinterでも同様に、 メソッド1発で組み込みのファイル選択ダイアログを出すことができます。
filename = tkFileDialog.asksaveasfilename(title='Save As?')
 ファイル選択ダイアログを使うには、 tkFileDialogモジュールをインポートしておき、 tkFileDialogのメソッドaskopenfilename(tk_getOpenFileに相当)または asksaveasfilename(tk_getSaveFileに相当)を使うのが一番簡単な方法です (もっと低位の操作ができる方法もあります)。askopen...とasksaveas... はほとんど同じですが、asksaveas...の方は選択されたファイルが既に存在していれば 「上書きしますか?」という確認を自動的に出してくれます。
 ちなみに、ファイル選択がキャンセルされたときこれらが返す値は、 Noneではなく空文字列 ' ' です。

セクションのサブメニューに戻る
(first uploaded 2001/08/05 last updated 2002/03/11)