2016-05-29 18 views
0

説明Tkinterの、カスタムウィジェットとラベルの更新

私はTkinterのためのカスタム"Table Widget"を作りたいとこれまでのところ、それは私が欲しいほとんどようです。

私が持っている問題は、テーブルを"Labels"で構成したいということです。ラベルを更新するために"StringVar()'s"を使用する必要があることがわかりました。

私は実際に1000個の変数を1000個のラベルにしたくないので、今週この問題を解決しようとしました。私が見つけた唯一の解決策は、"Dicts"を使用することですが、私はこれを行うには良い方法だと思いませんか?私は間違っているかもしれないが、それはこのような何かを行う方法である必要がありますようにそれは感じている:

myLabel = Label(root, text='myText') 
myLabel.pack() 
myLabel.setText('new text') 

現在のウィジェットのコードは、この(This is my first custom widget so if this is horribly wrong or wrong in any way, please tell me)

ソース

""" 
Description: 
     A TABLE WIDGET Extension for Tkinter 
""" 
try: 
    #Python 3.X 
    import tkinter #this is quite annoyng, without it (tkinter) wont be available.... 
    from tkinter import * # even with this 
    from tkinter import ttk 
    from tkinter.ttk import * 

except ImportError: 
    #python 2.X 
    import tkinter 
    from Tkinter import * 
    from Tkinter import ttk 
    from Tkinter.ttk import * 



class ETable(tkinter.Frame): 
    def __init__(self, parent, *args, **kwargs): 
     tkinter.Frame.__init__(self, parent) 
     self.init_table(parent, *args, **kwargs) 

    def init_table(self, parent, *args, **kwargs): 
     row_settings = { 
          'anchor': CENTER, 
          'background': '#C5FFFF', 
          'bitmap': None, 
          'borderwidth': 5, 
          'compound': None, 
          'cursor': None, 
          'font': None, 
          'foreground': '#000000', 
          'image': None, 
          'relief': FLAT, 
          'rows': 1, 
          'state': NORMAL, 
          'text': None, 
          'textvariable': None, 
          'underline': -1, 
          'width': 20, 
         } 

     for kwarg in kwargs: 
      if kwarg in row_settings: 
       row_settings[kwarg] = kwargs[kwarg] 

     self.table_rows = self.init_row(parent, *args, **row_settings) 

    def init_row(self, parent, *args, **kwargs): 
     text_list = kwargs.pop('text') 
     row_list = [] 

     cols = [] 
     rows = kwargs.pop('rows') 


     for row in range(rows): 
      for col in range(len(text_list)): 
       tempLabel = Label(parent, text = text_list[col], *args, **kwargs) 
       tempLabel.grid(row=row, column=col) 
       cols.append(tempLabel) 

      row_list.append(cols) 
     return row_list 

のように見えます目標

このようなことをしたいです。

table.getRow[0][0].setText('new text') #This would change col 1 in row 1 to "new text" 

ボーナス質問

(please tell me if I should make a new question for this) 

私は、ユーザーがクリックしたときに、私はTkinterのため"Table Widget"を作りたいが、私は、テーブルに振る舞いを追加したい、IE、言ったように列を編集するには"Entry or Text boxes"を追加することが目的です。

ここでの質問はTkinterで可能ですか?

+0

ああ、誰もが、私はこの前に検索しているうん、頼むこれに似た「stackoverflowの」質問がありますが、私は、カスタムウィジェットを作成するためのインスピレーションを得たところではない、かなり、thatsの。前に – Estrobeda

+0

私は答えを追加しました、あなたがそれを好きであることを願っています。あなたの2番目の質問に関するいくつかの情報については、ブライアンの答え[ここ](http://stackoverflow.com/q/10267465/4014959)と[リンクされた質問](http://stackoverflow.com/q/3819354/4014959 )。ウィジェットの行全体を一度に操作するには、各行をそれぞれのフレームに入れることを検討してください。 –

答えて

1

ラベルを更新するために「StringVar()」を使用する必要があることがわかりました。

これは真実ではありません。任意のウィジェットの属性をconfig/configureメソッドで更新することができます。あなたの最初の例から始めて、それは次のようになります。

myLabel = Label(root, text='myText') 
myLabel.pack() 
myLabel.configure(text='new text') 

そして、あなたの最後の例では:ボーナスの質問については

table.getRow[0][0].configure(text='new text') 

を、はい、それはpossible.Youは、任意のコードあなたをバインドすることができます他のウィジェットと同じようにラベルを付けたいだけでなく、キーとマウスボタンのバインディングに加えて、フォーカスの取得と消失にバインドすることができます。

+0

ああnice = Dありがとうございました。 configureメソッドはcharm = Dのように動作しました。これは、dictsなどよりはるかに優れています。D – Estrobeda

0

Bryan氏によると、にはが必要です。文字列を変更するには、LabelVarをラベルのtextvariableオプションとして使用する必要があります。ただし、ラベルから現在のテキスト文字列を読み込めるようにする場合は、特に便利です。FWIWでは、引数なしの.config()メソッドを呼び出すことでTkinterウィジェットのオプションを読むことができます。これは現在のすべてのオプション値の辞書を返します。しかし、あなたがただ一つの価値を検査したいのであれば、ちょっと混乱していることは認めなければなりません。

の場合 StringVarsを使用したい場合は、別のリストや辞書を保持する必要はありません.Nameオブジェクトに属性としてStringVarを割り当てることができます。ラベルの既存の属性を壊さないように注意してください。 :)

私はコードを少し変更しました。それはあなたのcolsリストのinit_rowメソッドで少しバグがありましたが、かなり良かったです。あなたのコードは、そのリストにエントリを追加した後、row_listにコピーしています。したがって、1つのcolsリストはすべての行のすべてのラベルを含むことになり、row_listはその1つのcolsリストへの複数の参照で終わります。

私が言及する必要があることの1つ:「スター」輸入を避けてください。あなたがするとき

from tkinter import * 

あなたの名前空間に135のTkinter名を入れます。 Python 2には175の名前があります。これは名前空間に不必要な混乱を引き起こし、名前の衝突を引き起こす可能性があります。間違ったバグにつながる可能性のあるインポートされた名前の1つで誤って変数の名前を付けた場合。複数のモジュールを使ってスターの読み込みを行うと、互いの名前を突き止めることができるので、さらに悪化します。また、星のインポートは、ローカルで定義された名前とインポートされた名前を覚えておく必要があるため、コードを読みにくくします。

あなたのコードで変更されたいくつかのことがあります。

row_settingskwargsに更新した方法は問題ありませんが、ジェネレータ式とdict.updateメソッドを使用するともう少しコンパクトで効率的です。

テキストリストの長さから計算するのではなく、明示的に列の数を渡します。また、クラスのインスタンス属性として列数と行数の両方を保存すると便利です。

ラベルの行に簡単にアクセスできるように、クラスに__getitem__メソッドを追加しました。

私はset_textメソッドを作成して各ラベルに追加して、テキストを簡単に変更できるようにしました。構文は質問にあるものと同じではありませんが、私はあなたがそれを好きになると思います。 :)

ETableクラスをテストするためのメインのTkinterウィンドウを作成するコードを追加してset_textメソッドを呼び出します。ボタンのコールバックは、最初に、ラベルのconfigディクショナリを出力してから、そのテキストを更新します。

今後の参考として、特にTkinterの質問でMCVEを投稿することをお勧めします。これにより、たくさんのものを書かなくてもコードを実行してテストできるようになります。

このコードは、Python 2.6.6およびPython 3.6.0a0でテストされています。

""" 
Description: 
     A TABLE WIDGET Extension for Tkinter 

     Written by Estrobeda, with modifications by PM 2Ring 
     2016.05.30 
""" 

from __future__ import print_function 

try: 
    # Python2 
    import Tkinter as tk 
except ImportError: 
    # Python3 
    import tkinter as tk 

class ETable(tk.Frame): 
    def __init__(self, parent, *args, **kwargs): 
     tk.Frame.__init__(self, parent) 
     self.init_table(parent, *args, **kwargs) 

    def init_table(self, parent, *args, **kwargs): 
     row_settings = { 
      'anchor': 'center', 
      'background': '#C5FFFF', 
      'bitmap': None, 
      'borderwidth': 5, 
      'cols': 1, 
      'compound': None, 
      'cursor': None, 
      'font': None, 
      'foreground': '#000000', 
      'image': None, 
      'relief': 'flat', 
      'rows': 1, 
      'state': 'normal', 
      'texts': None, 
      'textvariable': None, 
      'underline': -1, 
      'width': 20, 
     } 

     # Update row_settings with valid entries in kwargs 
     row_settings.update((k, v) for k, v in kwargs.items() if k in row_settings) 
     self.rows = row_settings.pop('rows') 
     self.cols = row_settings.pop('cols') 
     self.table_rows = self.init_rows(parent, *args, **row_settings) 

    def init_rows(self, parent, *args, **kwargs): 
     texts = iter(kwargs.pop('texts')) 

     row_list = [] 
     for row in range(self.rows): 
      col_list = [] 
      for col in range(self.cols): 
       tempLabel = tk.Label(parent, text=next(texts), *args, **kwargs) 
       #Bind a function to the label to change its text 
       tempLabel.set_text = lambda s, w=tempLabel: w.config(text=s) 
       tempLabel.grid(row=row, column=col) 
       col_list.append(tempLabel) 

      row_list.append(col_list) 
     return row_list 

    def __getitem__(self, row): 
     return self.table_rows[row] 

# Test 

root = tk.Tk() 
root.title("LabelTable Demo") 
texts = list('abcdefghijkl') 
table = ETable(root, rows=3, cols=4, texts=texts, relief='ridge', width=10) 

# Change the text of a label 
table[0][1].set_text('new text') 

def change_text(): 
    widget = table[2][3] 
    # Display the widget's current configuration 
    cfg = widget.config() 
    for k in sorted(cfg): 
     print(k, '=', cfg[k]) 
    # Change the text 
    widget.set_text('hello') 

b = tk.Button(root, text='Change', command=change_text) 
b.grid(row=4, column=0) 

root.mainloop() 
+0

WOW、前回の回答をもっと明確に説明してくれました。 コードの変更はすばらしく、この機能の説明とコードの改善のために非常に役立ちます。 – Estrobeda

関連する問題