|
|
TkDocs_Tk Menus. |
H.Kamifuji . |
この章では、Tk でメニューバーとポップアップメニューを処理する方法について説明します。 洗練されたアプリケーションの場合は、特に注目したい分野です。 アプリケーションをユーザーのプラットフォーム上の他のアプリケーションに合わせたい場合は、メニューに特別な注意が必要です。 それについて言えば、どのプラットフォームを実行しているかを知るには、以下の方法が推奨されます。 perl Tkx : Tkx::tk_windowingsystem(); # will return x11, win32 or aquaPython : root.tk.call('tk', 'windowingsystem') # will return x11, win32 or aqua私の知る限りでは、Tkinter はこの呼び出しに直接相当するものを提供しません。 ただし、この例からわかるように、Tkinter ウィジェットで使用できる ".tk.call()" 関数を使用して、Tclベースの Tk コマンドを直接実行することは可能です。 これはおそらく、tcl_platformやRUBY_PLATFORM などのグローバル変数を調べるよりも有用であり、これらのメソッドを使った古いチェックを調べる必要があります。 昔はプラットフォームとウィンドウシステムの間にかなり良い相関関係がありましたが、今日はあまり真実ではありません。 たとえば、Unix 上でプラットフォームが特定されている場合、Linux は X11、Mac OS X は Aqua、さらには X11 の Mac OS X を意味する可能性があります。 |
このセクションでは、メニューバーの作成方法、作成方法、使用方法などについて説明します。 メニューバーとそのメニューセットを適切に設計することは、このチュートリアルの範囲を超えていますが、いくつかのアドバイスがあります。第一に、多数のメニュー、非常に長いメニュー、または深くネストされたメニューで自分自身を見つけた場合は、ユーザーインターフェイスの仕組みを再考する必要があります。第二に、多くの人がメニューを使用して、プログラムが何をすることができるかを探求します。特に、初めて学習するときには、メニューから主要な機能にアクセスできるようにしてください。最後に、ターゲットとする各プラットフォームについて、アプリケーションがどのようにメニューを使用するかを理解し、設計、用語、ショートカットなどの詳細については、プラットフォームのヒューマンインタフェースガイドラインを参照してください。これは、各プラットフォームでカスタマイズする必要がある領域です。 最近のいくつかの Linux ディストリビューションでは、ウィンドウ自体ではなく、アクティブなときに画面の上部に多くのアプリケーションがメニューを表示することに気付くでしょう。 Tk はまだこのスタイルのメニューをサポートしていません。 |
メニューは、ボタンやエントリのように、Tk のウィジェットとして実装されています。 各メニューウィジェットは、メニュー内のいくつかの異なる項目で構成されています。 アイテムは、[ファイル]メニューの[開く...]コマンドのようなものですが、他のアイテム間のセパレータ、および独自のサブメニューを開くアイテム(いわゆるカスケードメニュー)です。 これらの各メニュー項目には、項目に表示するテキスト、キーボードアクセラレータ、および起動するコマンドなどの属性もあります。 メニューは階層構造になっています。 メニューバーはそれ自身メニューウィジェットです。 それには、 "file" 、 "edit" などの項目で構成される複数の子(サブメニュー)があります。 それらの各々は、異なる項目を含むメニューであり、その中にはサブメニューが含まれているものもあります。 あなたが既にTkで見たことがある他のものから期待しているように、いつでもサブメニューを持っているので、それはその親メニューの子として作られなければなりません。 |
メニュー作成を開始する前に、次の行をアプリケーションのどこかに置くことが重要です。 perl Tkx : Tkx::option_add("*tearOff", 0);Python : root.option_add('*tearOff', FALSE)それがなければ、各メニュー( Windows と X11 上)は破線のように表示され、メニューを切り離して自分のウィンドウに表示させることができます。 あなたは本当にそれが欲しいとは思わない。 これは Motif スタイルの X11 に戻ってきたもので、Tk のオリジナルのルックアンドフィールはそれに基づいていました。 あなたのアプリケーションが地下室のほこりを集めているその古い箱で動くように設計されていない限り、あなたは現代のユーザーインターフェーススタイルの一部ではないので、これを見たくはありません。 そして、私たちは皆、この後方互換性が保存されていない Tk のバージョンを楽しみにしています。デフォルトではこれらのティアオフメニューはありません。 |
Tk では、メニューバーは個々のウィンドウに関連付けられています。各最上位ウィンドウは最大で1つのメニューバーを持つことができます。 Windows と X11 では、メニューが各ウィンドウの一部であり、タイトルバーのすぐ下に一番上にあるため、これは視覚的に明白です。 Mac OS X では、画面の上部には、各ウィンドウで共有される単一のメニューバーがあります。あなたのTkプログラムに関する限り、各ウィンドウには独自のメニューバーがあります。ウィンドウを切り替えると、Tk は自動的に正しいメニューバーが画面の上部に表示されるようにします。特定のウィンドウに対してメニューバーを指定しない場合、Tk はルートウィンドウに関連付けられたメニューバーを使用します。 Tk アプリケーションの起動時にこれが自動的に作成されることに注目したでしょう。 Mac OS X ではすべてのウィンドウにメニューバーがあるので、各ウィンドウまたはルートウィンドウ用のフォールバックメニューバーのいずれかを定義することを確認することが重要です。さもなければ、インタプリタに直接コマンドを入力するときにのみ使用するためのメニューを含む "built-in" メニューバーで終わるでしょう。 ウィンドウのメニューバーを実際に作成するには、最初にメニューウィジェットを作成し、そのウィンドウの "menu" 設定オプションを使用してメニューウィジェットをウィンドウにアタッチします。 perl Tkx : $w = $mw->new_toplevel; $m = $w->new_menu; $w->configure(-menu => $m);Python : win = Toplevel(root) menubar = Menu(win) win['menu'] = menubar複数のウィンドウで同じメニューバーを使用することができます(つまり、異なるトップレベルウィンドウの "menu" 設定オプションの値として 1 つのメニューバーを使用します)。 これは、ウィンドウをメニューに含めることができますが、必ずしもアプリケーションのさまざまなメニューを混乱させる必要はない Windows および X11 で特に役立ちます。 しかし、メニューバーの内容や状態がアクティブなウィンドウで何が起こっているかに依存している場合は、それに対処する必要があります。 これは本当に古くからの歴史ですが、メニューバーを作成し、それを他のウィジェットと同じようにウィンドウの上部に詰め込むことでメニューバーを作成する必要がありました。 うまくいけば、まだこれを行うコードやドキュメントはありません。 |
私たちは今メニューバーを持っていますが、それはそこに入るいくつかのメニューなしではかなり役に立たないです。 もう一度、メニューバーにあるメニューバー(各メニューバーの子)をメニューバーに追加し、すべてをメニューバーに追加したいと考えています。 perl Tkx : $m = $w->new_menu; $file = $m->new_menu; $edit = $m->new_menu; $m->add_cascade(-menu => $file, -label => "File"); $m->add_cascade(-menu => $edit, -label => "Edit");Python : menubar = Menu(parent) menu_file = Menu(menubar) menu_edit = Menu(menubar) menubar.add_cascade(menu=menu_file, label='File') menubar.add_cascade(menu=menu_edit, label='Edit') |
メニューバーにはいくつかのメニューがありますので、各メニューにいくつかの項目を追加すると良いでしょう。 メニュー項目はメニューそのものの一部であることを覚えておいてください。私たちはありがたいことに、それぞれのメニューウィジェットを作る必要はありません。 perl Tkx : $file->add_command(-label => "New", -command => sub {newFile()}); $file->add_command(-label => "Open...", -command => sub {openFile()}); $file->add_command(-label => "Close", -command => sub {closeFile()});Mac OS X では、省略記号 ("...") は実際には特殊文字で、3 つのピリオドよりも間隔が狭くなっています。 Tk はあなたのためにこのキャラクターを自動的に代用します。 だから、メニュー項目をメニューに追加することは、サブメニューを追加することと本質的に同じですが、 "cascade" タイプのメニュー項目を追加するのではなく、 "command" タイプを追加します。 ウィジェットと同じように、各メニュー項目にはさまざまな設定オプションが関連付けられていますが、各メニュー項目タイプには異なるオプションがあります。カスケードメニュー項目にはサブメニューを指定するための "menu" オプションがあり、コマンドメニュー項目には項目が選択されたときに呼び出すコマンドを指定する "command" オプションがあり、どちらにもテキストを指定する「ラベル」オプションがありますアイテムの表示。 メニューの最後に項目を追加するだけでなく、メニューの途中で「インデックスの種類を挿入する?オプションの値...」を使用して項目を挿入することもできます。方法;ここで "index" は、挿入したいアイテムの位置 ( 0..n-1 ) です。また、 "delete index" メソッドを使用してメニューを削除することもできます。 |
すでに "command" メニュー項目があります。これは、選択するとコマンドを呼び出す一般的なメニュー項目です。 メニューバーにメニューを追加するために使用される "cascade" メニュー項目の使用も見てきました。 驚くことではないが、既存のメニューにサブメニューを追加する場合は、まったく同様に "cascade" メニュー項目も使用します。 メニュー項目の第3のタイプは、 "separator" であり、異なるメニュー項目のセットの間でしばしば見られる分割線を生成する。 perl Tkx : $file->add_separatorPython : menu_file.add_separator()最後に、 "checkbutton" と "radiobutton" のメニュー項目もあります。これは、チェックボタンとラジオボタンのウィジェットと同じように動作します。 これらのメニュー項目には変数が関連付けられており、その変数の値に応じて、項目ラベルの隣にインジケータ(チェックマークまたは選択されたラジオボタン)が表示されます。 perl Tkx : $file->add_checkbutton(-label => "Check", -variable => \$check, -onvalue => 1, -offvalue => 0); $file->add_radiobutton(-label => "One", -variable => \$radio, -value => 1); $file->add_radiobutton(-label => "Two", -variable => \$radio, -value => 2);Python : check = StringVar() menu_file.add_checkbutton(label='Check', variable=check, onvalue=1, offvalue=0) radio = StringVar() menu_file.add_radiobutton(label='One', variable=radio, value=1) menu_file.add_radiobutton(label='Two', variable=radio, value=2)ユーザーがまだチェックされていないチェックボタン項目を選択すると、関連付けられた変数は "onvalue" の値に設定され、チェックされている項目を選択すると "offvalue" の値に設定されます。ラジオボタン項目を選択すると、関連する変数が「値」の値に設定されます。どちらのタイプの項目も、プログラム内の他の部分からの関連変数の変更に反応します。 コマンド項目と同様に、チェックボタンとラジオボタンのメニュー項目は、メニュー項目が選択されたときに呼び出される "command" 設定オプションを受け入れます。関連付けられた変数、したがってメニュー項目の状態は、コールバックが呼び出される前に更新されます。 ラジオボタンのメニュー項目は、WindowsまたはMac OS X のヒューマンインタフェースのガイドラインには含まれていないため、これらのプラットフォームでは、項目のラベルの横のインジケータは、チェックボタン項目と同様にチェックマークです。セマンティクスはまだ動作します。ディスプレイには選択されているアイテムの 1 つが表示されるので、複数のアイテムの中から選択することをお勧めします。 |
"accelerator" オプションは、このメニューに関連付けるメニューアクセラレータを示すために使用されます。これは実際にアクセラレータを作成するのではなく、メニュー項目の横にあるものだけを表示します。それでも自分でアクセラレータのバインドを作成する必要があります。 イベントバインディングは、個々のウィジェット、特定のタイプのすべてのウィジェット、関心のあるウィジェットを含むトップレベルウ>ィンドウ、またはアプリケーション全体として設定できます。メニューバーは個々のウィンドウに関連付けられているので、作成するイベントバインディングは、メニューが関連付けられているトップレベルウィンドウに表示されます。 アクセラレータは、どんな操作にどのキーが使われているかだけでなく、メニューアクセラレータにどのような修飾キーが使われているかという点で非常にプラットフォーム固有のものです(例えば、Mac OS X では Windows と X11 では "Command" キーです。 "control" キー)。有効なアクセラレータオプションの例は、 "Command-N" 、 "Shift + Ctrl + X" 、 "Command-Option-B" です。一般に使用される修飾子には、"Ctrl" 、"Ctrl" 、"Option" 、"Opt" 、"Alt" 、"Shift" 、 "Command" 、 "Cmd" および "Meta" が含まれます。 Mac OS X では、これらの修飾子は、メニューに表示されるさまざまな修飾子アイコンに自動的にマップされます。 |
メニュー項目には、一般的なオプションがいくつかあります。 |
すべてのプラットフォームが矢印キーによるメニューバーのキーボードトラバーサルをサポートしていますが、Windows およびX11では、他のキーを使用して特定のメニューまたはメニュー項目にジャンプすることもできます。これらのジャンプを引き起こすキーは、メニュー項目のラベルに下線が引かれた文字で示されます。これらのメニュー項目の 1 つをメニュー項目に追加する場合は、その項目に "underline" 設定オプションを使用できます。このオプションの値は、下線を付ける文字のインデックスでなければなりません( 0 から文字列の長さ -1 まで)。 |
また、メニュー項目のラベルの横の画像を使用することも、メニュー項目のラベルを置き換えることもできます。これを行うには、ラベルウィジェットと同じように機能する "image" オプションと "compound" オプションを使用できます。 "image" の値はTk 画像オブジェクトでなければならず、 "compound" は "bottom" 、 "center" 、 "left" 、 "right" 、 "top" または "none" の値を持つことができます。 |
メニューを無効にして、ユーザーが選択できないようにすることもできます。これは、 "state" オプションを使用して、 "disabled" の値に設定するか、 "normal" の値を設定してアイテムを再び有効にすることができます。 |
Tk のほとんどすべてのものと同様に、項目のオプションの値をいつでも見たり変更することができます。アイテムはインデックスを介して参照されます。通常、これはメニュー内の項目の位置を示す数値 ( 0..n-1 ) ですが、メニュー項目のラベルを指定することもできます(実際は、項目の文字列と一致する "glob-style" パターンラベル)。 perl Tkx : print $file->entrycget(0, -label); # get label of top entry in menu $file->entryconfigure("Close", -state => "disabled"); # change an entry print $file->entryconfigure(0); # print info on all options for an itemPython : print( menu_file.entrycget(0, 'label') ) menu_file.entryconfigure('Close', state=DISABLED) print( menu_file.entryconfigure(0) ) |
各プラットフォームにはTkによって特別に扱われるいくつかのメニューがあります。 |
Windows では、各ウィンドウにはウィンドウフレームの左上に "system" メニューがあり、アプリケーションには小さなアイコンが付きます。 "Close" 、 "Minimize" などの項目があります。システムメニューを作成すると、標準項目の下に表示される新しい項目を追加できます。 perl Tkx : $system = Tkx::widget->new(Tkx::menu($m->_mpath . ".system")); $m->add_cascade(-menu => $system);メニューのパス名は、明示的に指定する必要があります。この場合、名前は ".system" です。 Python : sysmenu = Menu(menubar, name='system') menubar.add_cascade(menu=sysmenu)通常、Tkinter は私たちのためにウィジェットのパス名を選択しますが、ここでは明示的に 'system' という名前を与えなければなりません。 これは Tk がそれをシステムメニューとして認識する必要があるという手がかりです。 |
X11 では、ヘルプメニューを作成すると、Tk は常にメニューバーの最後のメニューであることを確認します。 perl Tkx : $help = Tkx::widget->new(Tkx::menu($m->_mpath . ".help")); $m->add_cascade(-menu => $help);メニューのパス名は明示的に指定しなければなりません。この場合、名前は ".help" となります。 Python : menu_help = Menu(menubar, name='help') menubar.add_cascade(menu=menu_help, label='Help')メニューのウィジェットのパス名は明示的に指定しなければなりません。この場合、名前は "help" です。 これは、ウィジェットを作成するときに 'name' オプションを使って Tkinter ウィジェットに指定できます。 |
コンテキストメニュー(ポップアップメニュー)は通常、アプリケーション内のオブジェクトを右クリックすることによって呼び出されま>す。マウスカーソルの位置にメニューがポップアップし、ユーザーはメニュー内のいずれかの項目から選択することができます(またはメニューの外をクリックすると、項目を選択せずにメニューを閉じることができます)。 コンテキストメニューを作成するには、メニューバーにメニューを作成するのとまったく同じコマンドを使用します。通常、いくつかのコマンド項目を含む 1 つのメニューを作成し、いくつかのカスケードメニュー項目とその関連メニューを作成します。 メニューをアクティブにするには、ユーザーはコンテキストメニューのクリックを使用します。これはバインドする必要があります。しかし、それは異なるプラットフォーム上で異なることを意味する可能性があります。 Windows と X11 では、マウスの右ボタンがクリックされています( 3 番目のマウスボタン)。 Mac OS X では、これは、コントロールキーが押された状態で左(または唯一)ボタンをクリックするか、複数ボタンマウスを右クリックするかのいずれかです。 Windows と X11 とは異なり、Mac OS X はこれを第2のマウスボタンといい、第3のマウスボタンではないので、あなたのプログラムで見られるイベントです。 ポップアップメニューを使用していたほとんどの以前のプログラムは、彼らが心配する必要があったのは "button 3" だけであると想定していました。 正しいコンテキストメニューイベントをキャプチャするだけでなく、マウスがクリックされた場所もキャプチャする必要があります。あなたがクリックしたウィンドウやウィジェット(ローカル座標)に対してローカルではなく、画面全体(グローバル座標)に関連してこれを行う必要があることが分かります。 Tk のイベントバインディングシステムにおける "%X" と "%Y" の置換は、あなたのためのものを取得します。 最後のステップは、特定の場所でメニューをポップアップすることです。次に、アプリケーションのメインウィンドウでポップアップメニューを使用して、プロセス全体の例を示します。 perl Tkx : use Tkx; my $mw = Tkx::widget->new("."); my $menu = $mw->new_menu(); foreach ("One", "Two", "Three") {$menu->add_command(-label => $_);} if (Tkx::tk_windowingsystem() eq "aqua") { $mw->g_bind("<2>", [sub {my($x,$y) = @_; $menu->g_tk___popup($x,$y)}, Tkx::Ev("%X", "%Y")] ); $mw->g_bind("Python : from tkinter import * root = Tk() menu = Menu(root) for i in ('One', 'Two', 'Three'): menu.add_command(label=i) if (root.tk.call('tk', 'windowingsystem')=='aqua'): root.bind('<2>', lambda e: menu.post(e.x_root, e.y_root)) root.bind(' ![]() ![]() |
Menus |
|