0

関連するチェックボックスの変数と一致するように、単純な「アプリケーショングローバル」ブール変数のペアを更新するように tkinter を取得できません。ブール値は 1 つのファイルで初期化、更新、および保存され、別のファイルによって参照 (読み取り専用) されます。チェックボックスの状態に関係なく、ブール値はデフォルト値から変更されません。(注意点: False/True の初期値は 0/1 に変更されます。これは、おそらく tkinter がブール値を実装する方法に問題があるためです)。興味深いことに、tkinter チェックボックスのテーブルに対応するブール値の同様の「アプリケーション グローバル」テーブルには問題はありません。テーブルは、3 番目のファイルで定義されたクラスのインスタンスです。テーブルは、単純なブール値と同じファイルに存在します (同じ方法で処理されます)。
すべてのブール値は 1 つのファイル (File1.py) で使用 (読み取り専用) され、他のファイル (File2.py) によってのみ変更されます。問題のブール値 (File2.py から File1.py へ) を明示的に返すことは機能しませんでした。

使用されている環境は、Windows 7、Python 3.2.2 on Eclipse Juno (4.2.2、ビルド M20130204-1200)、Pydev 2.7.32013031601 プラグインです。アプリケーションは Eclipse コンソールから実行されています。

LEGB スコープ規則により、すべて問題ないように見えます (include ステートメントと global ステートメントが存在し、外部で定義された「アプリケーション レベル」グローバル変数にドット ネーム形式が使用されています)。私が見ているように、すべてのブール値の更新が機能するか、まったく機能しないかのいずれかです。では、ブール テーブルは適切に機能するのに、単純なブール値は機能しないのはなぜですか? また、単純なブール値を適切に機能させるには何が必要なのでしょうか?
推測すると、Python が基本的な値 (たとえば、0、1、2、3、True? False?) を持つ変数を個別の変数ではなく「共有値」として実装する方法と関係がある可能性があります。これは、参照時に問題を引き起こします。他のモジュールからのこれらの単純な値?

サンプル アプリケーションは 3 つのファイルで構成されています。問題を表示できるようにしながら、それぞれを可能な限り削減しました。Windows 7 で実行すると、次のように表示されます。サンプルコードを実行する Tkinter ウィンドウの種まき rusluts

File1.py - メインラインには、コールバック関数「Get_User_Selections」が含まれています。

from tkinter  import *
from tkinter  import ttk
import File2 
#==========================================================================
def Get_User_Selections( ):

    print( "\nDoAllReports=", File2.DoAllReports, "DoNoReports=", File2.DoNoReports )

    if ( not File2.DoNoReports ) :  
        for row in range( len( File2.ChosenReports ) ):
            for column in range( len( File2.ChosenReports[ 0 ] ) ) :              
                if ( File2.ChosenReports[ row ][ column ].get() or
                     File2.DoAllReports ) :

                    print( "Do report  (", row, ',', column, ')' )               
    return
#==========================================================================         
def CreateTheReports( *args ):
    Get_User_Selections( )
    return
#==========================================================================
''' *********** MAIN PROCEDURE ***************** '''
root = Tk()
root.title( 'tkinter Boolean problem' )

mainframe = ttk.Frame( root )
mainframe.grid( )

File2.ChooseReports( mainframe )

DoItButton  = Button( mainframe, text = 'DO IT!', command = CreateTheReports )
DoItButton.grid()

root.mainloop()      
#==========================================================================

File2.py - GUI を定義し、すべての「アプリケーション レベル グローバル」ブール値を更新します。

from tkinter  import *

# import the custom "GUI table" widgit class (which works as expected)

from TkinterCheckBoxTableClass import TkinterCheckBoxTableClass

# Determine the table "shape" (in the original application the strings become  
# the row and column headers, these headers NOT shown by this example code).

RowTitles    = [ "A", "B" ] 
ColumnTitles = [ "1", "2", "3", "4" ]

DefaultReports = [ ]
for i in RowTitles :
    for j in ColumnTitles :
        DefaultReports = DefaultReports + [ False ] 

# Initialize the three "APPLICATION LEVEL" global variables that preserve the
# user choices across invocations of the routine.  Each invocation is caused
# by the user pressing the "DO IT!" button on the GUI.

ChosenReports = DefaultReports     # table of user choices (works properly)

# These two "application" globals override the table (above) of individual 
# choices.  "DoNoReports" overrides "DoAllReports"; both override the table. 

DoAllReports  = False    # does not work, value never changes    
DoNoReports   = False    # does not work, value never changes    

#==========================================================================
def ChooseReports( ParentFrame ):    
    # Purpose : Interface between the "application globals" and what appears
    #           on the GUI.  Called from File1.py whenever user presses 
    #           the "DO IT" button

    global ChosenReports   # "application" global, resides in this file
    global DoAllReports    # "application" global, resides in this file
    global DoNoReports     # "application" global, resides in this file

    GuiTable = [ [ IntVar() for j in range( len( ColumnTitles ) ) ]
                                        for i in range( len( RowTitles ) ) ]

    ThisFrame = LabelFrame( ParentFrame, text = " Select Reports " )    
    ThisFrame.grid( row = 1, column = 0 )

    DoAll  = IntVar( value = DoAllReports )
    DoNone = IntVar( value = DoNoReports )

    SelectAll = Checkbutton( ThisFrame, variable = DoAll, text = "All",
                             onvalue = True, offvalue = False)
    SelectAll.grid( row = 0, column = 1 )

    SelectNone = Checkbutton( ThisFrame, variable = DoNone, text ='None',
                              onvalue = True, offvalue = False )
    SelectNone.grid( row = 0, column = 2 )

    TableFrame = LabelFrame( ThisFrame, background = 'grey', 
                             borderwidth = 1, relief = FLAT )
    TableFrame.grid( row = 1, column = 0, columnspan = 3, rowspan = 2 )

    # Create the custom Checkbox Table, works without any problems.

    ChooseTheReports =  TkinterCheckBoxTableClass( FrameID = TableFrame,
                                              UserSelections = GuiTable )
    # Update the "application level" globals
    DoAllReports  = DoAll.get( )
    DoNoReports   = DoNone.get( )
    ChosenReports = ChooseTheReports.getTable( )
    # Passing back the above variables in the return statement did NOT work.
    # Returning them shouldn't even be needed since a) they have "application" 
    # level scope, b) they reside in THIS file and c) are ONLY modified by THIS 
    # file (with the new values being accessible from other files).   
    return  

#==========================================================================

TkinterCheckBoxTableClass.py - ブール値のテーブルを実装します:

'''
Implements a 2-D matrix (table) of tkinter checkboxes (for Python 3.x).
'''
from tkinter import *
from tkinter import ttk

class TkinterCheckBoxTableClass( object ):   
    '''
    Python 3.x interface to a matrix (2-D table) of tkinter checkboxes.
    Must pass a tkinter frame and the matrix to the constructor.
    Class constructor parameters:    
        FrameID             - tkinter parent frame that displays the table
        UserSelections      - matrix of True/False values passed to/from to GUI         
    Entire Table Methods:    
        getTable()         - extracts 2-D array of UserSelections from tkinter
    '''
    '''----------------------------------------------------------------------'''
    '''
    Constructor
    '''   
    def __init__( self , FrameID, UserSelections ) :               
        self.frameID             = FrameID      
        self.userSelections      = UserSelections       
        self.rowCount            = max( 1, len( self.userSelections ) )
        self.columnCount         = max( 1, len( self.userSelections[ 0 ] ) )                              
        self.checkBoxTable  = [ [ IntVar() for j in range( self.columnCount ) ]
                                           for i in range( self.rowCount ) ]
        # Construct and display the table of tkinter checkboxes
        for i in range( self.rowCount ) :
            for j in range( self.columnCount ) :
                self.checkBoxTable[i][j] = Checkbutton( self.frameID,
                                    variable = self.userSelections[ i ][ j ],
                                    onvalue  = True, offvalue = False )
                self.checkBoxTable[i][j].grid( row =  i + 1, column =  j + 1, 
                                               sticky = W )
    '''----------------------------------------------------------------------'''
    '''Methods:'''    
    def getTable( self ) :
        for i in range( self.rowCount ) :
            for j in range( self.columnCount ) :
                self.checkBoxTable[i][j] = Checkbutton( self.frameID,
                                     variable = self.userSelections[ i ][ j ],
                                     onvalue  = True,offvalue = False )
                self.checkBoxTable[i][j].grid( row = i + 1, column = j + 1,
                                               sticky = W )
        return self.userSelections   
''' END CLASS '''

ところで、PEP8 については、PEP8 の紹介の直後のセクションを参照してください。;>) また、「アプリケーション グローバル」の長所と短所、および「ユニバーサル インクルード ファイルを作成し、どこにでもインポートする」という面倒なアプローチについてもよく認識しています。私の問題を解決する簡単な方法が他に絶対にない場合を除き、使用したくないものです。(私は、必要な場所にのみモジュールをインポートすることを好みます。)

4

2 に答える 2

0

GUIを作成するときに、これらのグローバル変数の値のみを設定しているようです。GUIが表示され、ユーザーがチェックボタンを操作できるようになると、値を変更するコードはありません。の結果でそれらを初期化したからといって、DoAll.get()チェックボタンがチェックされたときにそれらが更新され続けるとは限りません。

なぜこれらの変数が必要なのですか? ユーザーがチェックボタンをクリックしたときに更新する を既に作成IntVarしてますが、別のレベルの抽象化を追加する必要はありません。DoAll.get()値が必要なときはいつでも使用してください。

テーブルが機能する理由はIntVar、チェックボタンの値が変更されると常に更新される のテーブルであるためです。

于 2013-10-02T23:30:22.523 に答える