|
|
TkDocs_Tk Styles and Themes. |
H.Kamifuji . |
新しい Ttk ウィジェットの "themed" は、新しいウィジェットセットの中で最も強力でエキサイティングな側面の 1 つです。 それは、Tk が伝統的に働いていた方法とはまったく異なったやり方をしているし、柔軟性を持たせることで多くのことをするので、確かに多くの人々にとって最も混乱しているからです。 |
最初に、Ttk のテーマやスタイルが依存するいくつかの概念と用語を定義します。 |
ウィジェットクラスは、特定のウィジェットのタイプを識別するために Tk によって使用されます。基本的にはボタン、ラベル、キャンバスなのかどうかなどです。古典的な Tk では、すべてのボタンは同じクラス( "Button" )を持ち、すべてのラベルは同じクラス( "Label" )などです。 イントロスペクションとオプションデータベースを使用してオプションをグローバルに変更するために、このウィジェットクラスを使用できます。たとえば、デフォルトですべてのボタンに赤い背景が表示されているとします。 フレームとトップレベルのウィジェットを含むいくつかの古典的な Tk ウィジェットがありました。このウィジェットは、ウィジェットが最初に作成されたときに特定のウィジェットのクラスを "class" 設定オプションに渡すことで変更できます。だから通常のフレームはウィジェットクラス "Frame" を持っていますが、特定のフレームウィジェットのウィジェットクラスが "SpecialFrame" であることを指定することができます。 そのため、オプションデータベースを使用して、さまざまなタイプのフレームウィジェット(すべてのフレームウィジェットまたは階層内の特定の場所に配置されたフレームウィジェット)だけでなく、さまざまなタイプの異なる外観を定義することができます。 Ttk がしているのは、そのシンプルなアイデアを取り入れ、ロケットブースターを与えることです。 |
ウィジェット状態は、マウス位置、アプリケーションによって設定されたさまざまな状態オプションなどに応じて、1 つのウィジェットが複数の外観または動作を持つことを可能にします。古典的な Tk では、いくつかのウィジェットには "state" の設定オプションがあり、これを "normal" または "disabled" に設定することができました。例えばボタンの "disabled" 状態は、そのラベルをグレー表示する。いくつかは、別の状態を使用していました。 ウィジェット自体、またはより典型的には、ウィジェットのクラス・バインディングは、典型的には "foreground" 、 "activeforeground" 、および "disabledforeground" のようなコンサルティング・ウィジェット構成オプションを介して、ウィジェットの外観が様々な状態でどのように変化するかを制御した。 Ttk は、ウィジェット状態のこの基本的な考え方を2つの重要な方法で再び拡張し、一般化します。まず、ウィジェット固有のものではなく、すべての Ttk ウィジェットには状態オプションがあり、実際にはすべて "state" ウィジェットコマンドと "instate" ウィジェットコマンドによってアクセスされる同じ状態オプションがあります。 Ttkウィジェットの状態は、実際には、"active", "disabled", "focus", "pressed", "selected", "background", "readonly" などのフラグの 0 以上を含む独立した状態フラグのセットです。 "alternate" または "invalid" (正確な意味についてはリファレンスマニュアルのウィジェットページを参照してください)。 これらの状態フラグはすべてすべてのウィジェットで使用可能ですが、各ウィジェットでは使用できないことに注意してください。たとえば、ラベルウィジェットは "invalid" 状態フラグを無視する可能性が高いため、そのフラグに特別な外観は関連付けられません。 Ttk の第 2 の大きな変更点は、状態がウィジェットのコントロールから調整されたときに何を変更するかの決定が必要なことです。つまり、ウィジェット作成者は、「状態が無効になっているときに、disabledforeground 設定オプションを参照してフォアグラウンドカラーに使用する」というロジックをハードコードすることはもうありません。そのロジックをハードコード化することで、コーディングウィジェットを長くしてくれるだけでなく、その状態に基づいてウィジェットを変更する方法も制限されました。つまり、ウィジェット作成者が、状態が変わったときにフォントを変更するロジックをコーディングしていないと、ウィジェットのユーザーが不運になりました。 各ウィジェット内でこれらの決定をハードコーディングする代わりに、Ttk は決定を別の場所、スタイルに移動します。つまり、ウィジェットの作成者は、ウィジェットを単純化するだけでなく、ウィジェット作成者が予期しなかったものを含め、より広範な外観を設定できるように、すべての外観オプションにコードを提供する必要はありません。 |
それではウィジェットスタイルを定義します。非常に単純に、スタイルはTtkウィジェットクラスの外観(または外見)を記述します。そのウィジ>ェットクラスで作成されたすべてのウィジェットは、同じ外観を持ちます。それぞれのテーマウィジェットはデフォルトのクラス(例えば、 "ttk::button" ウィジェット用の "TButton" )を持っていますが、クラシック Tk と違って、あなたが作成する任意のテーマウィジェットに対して異なるウィジェットクラスを割り当てることができます。これはTtkの "style" 設定オプションを使用して行われ、すべてのテーマウィジェットがサポートしています。 したがって、スタイルは特定のウィジェットクラスのウィジェットの通常の外観を定義しますが、現在の状態フラグに依存する外観のバリエーションを定義することもできます。したがって、例えば、スタイルは、 "pressed" 状態フラグがセットされたときに、外観が特定の方法で変化するように指定することができる。このため、スタイルには、状態に応じてウィジェットが表示される 1 つ以上の方法を記述することができます。 この章の残りの部分では、スタイルが実際にどのようなものであるかをもっと詳しく調べますが、少なくとも今はそのスタイルが持つ責任を知っています。 |
あなたはテーマをスタイルのコレクションと考えることができます。 各スタイルはウィジェットに特化していますが(ボタン用、エントリ用など)、テーマは多くのスタイルをまとめて収集します。 一般的に、テーマはウィジェットの種類ごとに 1 つのスタイルを定義しますが、それぞれのスタイルは互いに視覚的に "fit" するように設計されていますが、残念ながらTtkでは技術的に悪い設計や判断を制限しません。 アプリケーションに特定のテーマを使用するには、実際にはスタイルのセットを定義して、デフォルトですべての異なるタイプのウィジェットが共通の外観を持ち、お互いにうまく収まるようにしたいと言うことです。 |
それでは、スタイルとテーマがどのようなことをするのかを知っていますが、どのように使っていますか? これを行うには、スタイルやテーマを参照する方法、ウィジェットやユーザーインターフェイスにそれらを適用する方法を知る必要があります。 |
すべてのスタイルには名前があります。 スタイルを変更したり、新しいスタイルを作成したり、ウィジェットのスタイルを使用する場合は、その名前を知る必要があります。 どのようにスタイルの名前が分かっていますか? あなたが特定のウィジェットを持っていて、それが現在使っているスタイルを知りたければ、まずその "style" 設定オプションの値を調べることができます。 それが空の場合は、ウィジェットがウィジェットのデフォルトスタイルを使用していることを意味します。 あなたはウィジェットのクラスを介してそれを取得することができます。 例えば: perl Tkx : Perl> $b = $mw->new_ttk__button() .b Perl> $b->cget(-style) # empty string as a result Perl> Tkx::winfo('class', $b) TButtonPython : >>> b = ttk.Button() >>> b['style'] '' >>> b.winfo_class() 'TButton'この場合、使用されているスタイルは "TButton" です。 他のテーマウィジェットのデフォルトスタイルは、同様に名前が付けられます。 "TEntry" 、 "TLabel" 、 "TSizeGrip" などがあります。 たとえば、ツリービューウィジェットのクラスは "TTreeview" ではなく "Treeview" です。 しかし、デフォルトのスタイル以外にも、スタイルにはほとんど何も名前を付けることができます。 "FunButton" 、 "NuclearReactorButton" 、ま>たは "GuessWhatIAm"(スマートな選択ではない)という独自のスタイルを作成する(またはスタイルを持つテーマを使用する)かもしれません。 多くの場合、 "Fun.TButton"や "NuclearReactor.TButton" のような名前があります。これは基本スタイルのバリエーションを示唆しています。 これはTtkがスタイルの作成と変更をサポートするものです。 現在利用可能なすべてのスタイルのリストを取得する機能は、現在サポートされていません。 |
スタイルを使用するとは、そのスタイルを個々のウィジェットに適用することです。 あなたが使いたいスタイルの名前と、それを適用するウィジェットを知っていれば、簡単です。 スタイルの設定は作成時に行うことができます: perl Tkx : $b = $parent->new_ttk__button(-text => "Hello", -style => "Fun.TButton");Python : b = ttk.Button(parent, text='Hello', style='Fun.TButton')また、 "style" 設定オプションを使用してウィジェットを作成した後、いつでもウィジェットのスタイルを変更することができます: perl Tkx : $b->configure(-style => "NuclearReactor.TButton");Python : b['style'] = 'NuclearReactor.TButton' |
スタイルは個々のウィジェットの外観を制御しますが、テーマはユーザーインターフェイス全体の外観を制御します。 テーマを切り替える機能は、テーマウィジェットの重要な機能の1つです。 perl Tkx : Perl> Tkx::ttk__style_theme_names() aqua clam alt default classicPython : >>> s = ttk.Style() >>> s.theme_names() ('aqua', 'step', 'clam', 'alt', 'default', 'classic')一度にアクティブにできるテーマは1つだけです。 現在使用されているテーマの名前を取得するには、以下を使用します。 perl Tkx : Perl> Tkx::ttk__style_theme_use() aquaPython : >>> s.theme_use() 'aqua'新しいテーマに切り替えるには、次のようにします。 perl Tkx : Tkx::ttk__style_theme_use("themename");Python : s.theme_use('themename')これは実際に何をするのですか? 明らかに、現在のテーマを指定されたテーマに設定します。 これにより、現在利用可能なすべてのスタイルがテーマで定義されたスタイルセットに置き換えられます。 最後に、すべてのウィジェットをリフレッシュして、新しいテーマで記述された外観を引き継ぎます。 |
あなたがしたいのは、スタイルを使用するだけであれば、必要なものすべてを知ることができます。 しかし、独自のスタイルを作成したり、既存のスタイルを変更したりする場合は、 "interesting" となります。 |
各スタイルは単一のウィジェットを表しますが、各ウィジェットは通常、要素と呼ばれる小さな部分で構成されています。 これらの小さな要素からウィジェット全体を構築するのは、スタイル作成者の仕事です。 これらの要素は、ウィジェットによって異なります。 ここにボタンの例があります。 1 つの要素である非常に外側に境界線があるかもしれません。 その中にフォーカスリングがありますが、これは通常は背景色ですが、ユーザーがボタンにタブを当てると強調表示されることがあります。 それは第二の要素です。 その場合、フォーカスリングとボタンのラベルの間にはある程度の間隔があります。 その間隔は 3 番目の要素になります。 最後に、ボタン自体のラベル、4 番目の要素があります。 ![]() なぜそのスタイルの作者がそれを分割したのでしょうか? ウィジェットの一部が別のウィジェットと異なる場所にあるか、別のウィジェットと異なる色になる可能性がある場合、そのウィジェットはウィジェットの候補になる可能性があります。 これは、要素からボタンを構成する方法の一例に過ぎないことに注意してください。 異なるスタイルやテーマでは、さまざまな方法でこれを達成できます。 次に、垂直スクロールバーの2番目の例を示します。残りの部分を含む "trough" 要素を含みます。両端に上下の矢印要素があり、中央に "thumb" 要素があります。 ![]() |
どの要素がウィジェットの一部であるかの選択に加えて、スタイルは、ウィジェット内で要素がどのように配置されるか、つまりそのレイアウトを定義します。 ボタンの例では、focus 要素の内側の border 要素の内側に border 要素の内側に label 要素がありました。 論理レイアウトはこうですborder { focus { spacing { label } } }Ttk に TButton スタイルのレイアウトを次のように尋ねることができます: perl Tkx : Perl> Tkx::ttk__style_layout('TButton') Button.button -sticky nswe -border 1 -children {Button.padding -sticky nswe -children {Button.spacing -sticky nswe -children {Button.label -sticky nswe}}}Python : >>> s.layout('TButton') [("Button.border", {"children": [("Button.focus", {"children": [("Button.spacing", {"children": [("Button.label", {"sticky": "nswe"})], "sticky": "nswe"})], "sticky": "nswe"})], "sticky": "nswe", "border": "1"})]これをきれいにしてフォーマットすると、次のような構造のものが得られます。 Button.border -sticky nswe -border 1 -children { Button.focus -sticky nswe -children { Button.spacing -sticky nswe -children { Button.label -sticky nswe } } }これは意味をなさない。 "Button.border"、 "Button.focus"、 "Button.spacing"、 "Button.label" の4つの要素があります。 これらのそれぞれには、レイアウトやサイズを指定する "-children"、 "-sticky"、 "-border" など、さまざまな要素オプションがあります。 この時点で 2 つの詳細に分かれることなく、 "-children" 属性と "-sticky" 属性に基づいてネストされたレイアウトを明確に見ることができます。 Ttk は Tk の "pack" ジオメトリマネージャの簡略化されたバージョンを使用して要素レイアウトを指定します。 |
これらの異なる要素の各々は、多数の異なる選択肢を有することができる。 たとえば、スクロールバーのサムには背景色を設定するオプションがあり、境界がある場合にはその幅を指定するオプションもあります。 これらをカスタマイズして、ウィジェット内の要素の見た目を調整することができます。 各要素にはどのようなオプションがありますか? 次に、ボタン内のラベルに使用できるオプションを確認する例を示します( "layout" コマンドでわかっているものは "Button.label" となります)。 perl Tkx : Perl> Tkx::ttk__style_element_options("Button.label") -compound -space -text -font -foreground -underline -width -anchor -justify -wraplength -embossed -image -stipple -backgroundPython : >>> s.element_options('Button.label') ('-compound', '-space', '-text', '-font', '-foreground', '-underline', '-width', '-anchor', '-justify', '-wraplength', '-embossed', '-image', '-stipple', '-background')おそらく、これらのオプションは、それらの先頭のダッシュを持つべきではありません。 次のセクションでは、要素オプションを扱うことができる完全ではない単純な方法を見ていきます。 |
このセクションでは、スタイルオプションを変更してスタイルの外観を変更する方法を見ていきます。 既存のスタイルを変更するか、より一般的には新しいスタイルを作成して、これを行うことができます。 |
既存のスタイルの設定オプションの変更は、他の設定オプションを変更するのと同様に、スタイルのスタイル、オプションの名前、および新しい値を指定することによって行われます。 perl Tkx : Tkx::ttk__style_configure("TButton", -font => "helvetica 24");Python : .configure('TButton', font='helvetica 24')まもなく有効なオプションの詳細について学びます。 オプションの現在の値を取得する必要がある場合は、これを "lookup" メソッドで行うことができます。 perl Tkx : Perl> Tkx::ttk__style_lookup("TButton", "-font") helvetica 24Python : >>> s.lookup('TButton', 'font') 'helvetica 24' |
"TButton" のような既存のスタイルを変更すると、そのスタイルを使用するすべてのウィジェットにその変更が適用されます(デフォルトではすべてのボタンになります)。 それはあなたがしたいことと同じかもしれません。 既存のスタイルに似ていますが、特定の側面で変化する新しいスタイルを作成することに興味があることがよくあります。 たとえば、アプリケーションのほとんどのボタンを通常の外観に保ちたい場合は、特別な "emergency" ボタンを作成します。このボタンは、別の方法で強調表示されます。 この場合、ベーススタイル( "TButton" )から派生した新しいスタイル( "Emergency.TButton" など)を作成することが適切なことになります。 既存のスタイルにドットを付けた別の名前( "Emergency" )を前に付けることによって、既存のスタイルから派生した新しいスタイルを暗黙的に作成します。 この例では、新しいスタイルには、指定された相違点を除いて、通常のボタンとまったく同じオプションがあります。 perl Tkx : Tkx::ttk__style_configure("Emergency.TButton", -font => "helvetica 24", -foreground => "red", -padding => 10);Python : s.configure('Emergency.TButton', font='helvetica 24', foreground='red', padding=10) |
スタイルの通常の設定オプションの他に、ウィジェット作成者は、ウィジェットが特定のウィジェット状態にあるときに使用するさまざまなオプションを指定している場合があります。 たとえば、ボタンが無効になっている場合は、ボタンのラベルの色がグレー表示されます。 これを行うには、スタイルの設定オプションの 1 つ以上のバリエーションを指定できる "map" を指定します。 各設定オプションについて、ウィジェットがその状態にあるときに割り当てられるべき特定の値とともに、ウィジェット状態のリストを指定することができます。 状態は、ウィジェットの "state" メソッドによって設定される 1 つまたは複数の状態フラグ(またはその否定)から構成されるか、または "instate" メソッドを介して照会されることに注意してください。 次の例では、ボタンの "normal" 外観から次のバリエーションを提供しています。
#Python : s.map('TButton', background=[('disabled','#d9d9d9), ('active','#ececec)], foreground=[('disabled','#a3a3a3')], relief=[('pressed', '!disabled', 'sunken')])過去には古典的な Tk ウィジェットでは、ウィジェットが各状態にあったときに変更されたのは、ウィジェット作成者だけが決定していたことを思い出してください。 テーマウィジェットでは、元のウィジェット作成者が予期していなかったものを含む可能性のある変更を決定するのはスタイルそのものです。 ウィジェットの状態には複数のフラグが含まれる可能性があるため、複数の状態がオプションに一致する可能性があります(たとえば、 "pressed" と "pressed!disabled" はウィジェットの "pressed" 状態フラグが設定されている場合に一致します)。 状態のリストは、"map" コマンドで指定した順序で評価され、使用されているリストの最初の状態が使用されます。 |
だから、スタイルはさまざまなオプションを持つ要素で構成され、特定のレイアウトで一緒に構成されていることが分かります。スタイルのさまざまなオプションを変更して、スタイルを使用するすべてのウィジェットを異なるように表示することができます。そのスタイルを使用するウィジェットは、そのスタイルが定義する外観を使用します。テーマは関連するスタイル全体を集め、ユーザーインターフェイス全体の外観を簡単に変更できます。 だから、スタイルやテーマを実際には難しくしているのは何ですか?三つの事。最初: You can only modify options for a style, not element options (except sometimes).
スタイルのレイアウトを調べることによってスタイル内で使用された要素を調べる方法と、各要素で使用可能なオプションがどのように見つかったかについて、以前に話しました。しかし、スタイルを変更しようとしたとき、個々の要素を指定せずにスタイルのオプションを設定しているようでした。どうしたの?繰り返しになりますが、私たちのボタンの例では、 "Button.label" という要素がありました。それは、その "Button.label" 要素が描画されるときに、スタイルに設定された "font" 構成オプションを調べて、どのフォントを描画するかを決定することです。 理由を理解するためには、スタイルに要素が含まれている場合、その要素は(要素固有の)記憶域を保持していないことを知る必要があります。特に、設定オプション自体は保存されません。オプションを取得する必要があるときは、要素に渡される包含スタイルを使用してオプションを取得します。したがって個々の要素は、GoF パターンの用語で "flyweight" オブジェクトです。 同様に、他の要素は、スタイルに設定されたオプションから構成オプションを検索します。 2 つの要素が同じ設定オプション(背景色など)を使用する場合はどうなりますか? スタイルに格納されている背景構成オプションは 1 つだけなので、両方の要素が同じ背景色を使用することを意味します。ある要素に 1 つの背景色を使用させ、もう 1 つの要素に異なる背景色を使用させることはできません。 あなたができる時を除いて。 TButton.Labelのようなオプションを設定することで、たった一つの要素を変更できるようにする、現在の実装では「 "sublayouts" と呼ばれるウィジェット固有のものがいくつかあります。スタイル)。あなたがこれを行うことができる場合は文書化されていますか? あなたがこれをいつ行うことができるかを決定するためにイントロスペクトするための何らかの方法がありますか? 両方にはいいよ。これは、テーマウィジェット API の 1 つの領域であり、時間の経過とともに進化すると確信しています。 2 番目の難点は、スタイルオプションを変更することです。 Options that are available don't necessarily have an effect, and it's not an error to modify a bogus option.
要素オプションに従って存在するはずのオプションを変更しようとしますが、効果はありません。たとえば、Mac OS X で使用されている「アクア」テーマのボタンの背景色を変更することはできません。これらのケースには正当な理由がありますが、現時点ではそれを発見することは容易ではなく、時々イライラします。あなたが実験しているときに、おそらくもっと不満は、 "incorrect" スタイル名やオプション名を指定してもエラーが発生しないということです。"configure" や "lookup" を実行するときには、実際にはスタイルの名前を指定することができ、オプションの名前を指定することもできます。だから、もしあなたが "background" と "font" オプションに飽きているなら、 "dowhatimean" オプションを自由に設定してください。それは何もしないかもしれませんが、それは誤りではありません。繰り返しますが、修正する必要があるものとしたくないものを知ることが難しくなる可能性があります。 これは、非常に軽量でダイナミックなシステムを持つことの欠点の 1 つです。スタイルオプションを設定するときに名前を入力するだけで新しいスタイルを作成できます。つまり、明示的にスタイルオブジェクトを作成する必要はありません。同時に、これはエラーを発生させます。現在存在するスタイルや使用されているスタイルを見つけることもできません。また、スタイルオプションは要素オプションのフロントエンドにすぎず、スタイルの要素はいつでも変更できるため、現在の要素のみで参照されるオプションに限定する必要はありません。イントロスペクターブル。 最後に、スタイルとテーマを非常に難しくする最後のものがここにあります: The elements available, the names of those elements, which options are available or have an effect for each of those elements, and which areused for a particular widget can be different in every theme.
そう?他のものの中でも、各プラットフォーム( Windows、Mac OS X、Linux )のデフォルトのテーマは異なっています(これは良いことです)。これにはいくつかの意味があります。
一番下の行は、古典的なTkで、個々のウィジェットの大きな属性のセットを修正する能力があったので、あるプラットフォームで何かできるように なり、ちょっとした作業が必要になるでしょう )他の人に。 テーマTkでは、簡単なオプションは存在しません。あなたのアプリケーションが複数 のテーマ/プラットフォームで動作するようにしたいのであれば、あなたは正しい方法でやる必要があります。 それはもっと前の仕事です。 |
これは、このチュートリアルではスタイルやテーマについて説明していますが、興味のあるユーザーや新しいテーマの作成をさらに深めたいユーザーにとっては、要素に関するいくつかの興味深い情報を提供することができます。 要素はスタイルやテーマのビルディングブロックなので、「要素はどこから来たの?具体的に言えば、要素は通常Cコードで作成され、テーマエンジンが理解できる特定の API に準拠しているといえます。 非常に低いレベルでは、要素は要素ファクトリと呼ばれるものから来ます。現在、ほとんどのテーマで使用されている "default" があり、Tk 描画ルーチンを使用して要素を作成しています。秒はイメージから要素を作成することを可能にし、実際には "ttk::style element create" メソッド( Tcl から)を使ってスクリプトレベルでアクセス可能です。最後に、基盤となる "Visual Styles" プラットフォーム API を使用した Windows 固有の3番目のエンジンがあります。 テーマがプラットフォームのネイティブウィジェットを介して作成された要素を使用する場合、それらのネイティブウィジェットを使用する呼び出しは通常、そのテーマの要素仕様コード内に表示されます。もちろん、要素がネイティブウィジェットやAPI呼び出しに依存するテーマは、それらをサポートするプラットフォームでのみ実行できます。 テーマは一連の要素を取り、それらを使用して実際にウィジェットで使用されるスタイルを組み立てます。テーマの考え方全体が同じであるため、複数のスタイルが同じ外観を共有することができるので、異なるスタイルが同じ要素を共有することは驚くことではありません。 "TButton" スタイルには "Button.padding" 要素が含まれ、 "TEntry" スタイルには "Entry.padding" 要素が含まれていますが、これらのパディング要素の下には複数の可能性があります。それらは異なるように見えるかもしれませんが、これは、構成オプションが異なるためです。これは、使用している要素を使用するスタイルに格納されています。 スタイルがそれ以外のものを指定していない場合、テーマが各スタイルのデフォルトとして使用される共通のオプションのセットを提供できることがわかるのはおそらく驚くべきことではありません。これは、テーマ全体が緑色の背景を持っていれば、テーマごとにスタイルごとに明示的に言う必要はないということです。これは "."という名前のルートスタイルを使用します。結局、 "Fun.TButton" が "TButton" から継承できれば、 "TButton" は "." を継承できないのはなぜですか? 最後に、Tk の C ライブラリのCコードレベルと Tk の "library / ttk" ディレクトリにあるTkスクリプトの両方で、既存のテーマがどのように定義されているかを見ておく価値があります。 Tk の C ライブラリの "Ttk_RegisterElementSpec" を検索し、要素の指定方法を確認してください。 |
Styles and Themes |
|