首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >动态设置tkinter Spinbox的范围

动态设置tkinter Spinbox的范围
EN

Stack Overflow用户
提问于 2013-12-11 19:49:46
回答 1查看 7.4K关注 0票数 2

我正在使用Python3.x创建一个多语言的“日历”小部件,它为年份、月、日等提供了独立的派生框。一个要求是,无论使用什么小部件,都不能在任何时候隐藏GUI的任何部分,从而排除了下拉列表等,从而使派生框成为一个明显的选择。

如果有人知道在哪里可以找到纯python/tkinter“日期和时间条目”的公共域源代码(理想地处理闰年和所有月底的情况),请告诉我那个存储库。

我能找到的最接近的解决方案是这个OptionMenu解决方案(Change OptionMenu based on what is selected in another OptionMenu ),但由于“不要隐藏”的要求,它不能使用。使用它作为灵感(在回顾了http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/spinbox.html的Spinbox文档之后),我提出了下面的代码。为了保持简单,我删除了处理闰年和月末问题的代码。除了两个问题外,该代码可以工作:

问题1-我无法让“DaySpinBox”动态调整其“范围”以将其设置为“MonthSpinBox”中的月份:

根据我阅读Mark的“编程Python”(第三版,第383和384页)的方式,我应该能够动态地设置DaySpinBox的最大/最后一天(通过使用“values=”或“to=”和“from_=”选项)来匹配MonthSpinBox中出现的月份。我正在跟踪MonthSpinBox变量(“SelectedMonth”),根据这本书,我尝试使用以下方法更新DaySpinBox :1-使用“to=SelectedMonth”。对此的一些尝试在创建DaySpinBox的调用中显示为注释。(我刚接触过兰巴达,也许我没有正确地使用它们?)

2-使用“DaySpinBox‘to’= SelectedMonth”,3-使用“DaySpinBox.config(to= SelectedMonth )”。

我还尝试过在所有方法中使用“values=”,但都没有成功(“to=.”)(优先选择)。

问题1: Spinbox是否可以设置为使用动态范围,或者,正如我开始怀疑的那样,在创建Spinbox之后,它们的范围是否不可更改?

问题2:在进行了大量的网络搜索之后,我没有发现任何可以显式声明哪些Spinbox参数(“to=”、“from=”和“value=”关键字)可以动态更改,哪些不能--在哪里可以找到这些信息(对于所有小部件类型)?

问题2- MonthSpinBox总是被初始化为一月而不是当前月份。

我使用“textvariable”关键字将年份、月和日的旋转框初始化为“今天”。这适用于YearSpinBox和DaySpinBox,但不适用于MonthSpinBox。(令人恼火的是,我认为MonthSpinBox在工作,但我试图修复DaySpinBox,却把它弄坏了)。唯一明显的区别是,年份和日旋量箱使用整数,而月份spinbox使用字符串。有什么建议吗?

对于这两个问题,我考虑了LEGB问题的可能性,但没有嵌套函数,因此变量隐藏不应该是一个问题--除非我的一个变量正在复制和隐藏在tkinter中定义的变量,等等。

我遗漏了什么?

顺便说一句,我知道使用globals的利弊,也了解PEP8 (http://www.python.org/dev/peps/pep-0008/) --见目录中的第二个项目。;>)

谢谢。

代码语言:javascript
复制
from tkinter  import *
from tkinter  import ttk
from datetime import datetime
from collections import OrderedDict  

root = Tk()     # put here so IntVar (etc.) is useable during initialization

StartUpDateTime    = datetime.now()
DefaultYear        = StartUpDateTime.year   
DefaultMonthNumber = StartUpDateTime.month  
DefaultDayOfMonth  = StartUpDateTime.day   

# These are only used to build the Month name & length dictionary  
YearAndMonthLengths =  [ 365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ] 
EnglishMonthNames = ( 'Entire Year', 'January', 'February', 'March', 
                      'April', 'May', 'June', 'July', 'August', 'September', 
                      'October', 'November', 'December' )
FrenchMonthNames  = ( 'année entière', 'janvier', 'février', 'mars', 
                      'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 
                      'octobre', 'novembre', 'décembre' )
#SpanishMonthNames = ....
#ItalianMonthNames = ....

Month_Names = FrenchMonthNames
Month_Names = EnglishMonthNames    # comment out this line to use French

# Create dictionary containing month names that appear in the Month spinbox.
# OrderedDict used because Month name (=key) field must be language-independent.

DaysInMonth = OrderedDict()    
for i in range( 0, len( Month_Names ) ) :   
    DaysInMonth[ Month_Names[ i ] ] = YearAndMonthLengths[ i ]  

DefaultMonthName   = Month_Names[ DefaultMonthNumber ]
DefaultMonthLength = DaysInMonth[ DefaultMonthName ]
# Initialize the Spinbox interface variables to todays date
SelectedYear        = IntVar(    value = DefaultYear )
SelectedMonthName   = StringVar( value = DefaultMonthName ) 
SelectedMonthLength = IntVar(    value = DefaultMonthLength )
SelectedDay         = IntVar(    value = DefaultDayOfMonth )

#-------------------------------------------------------------------------------

def GetChosenMonthLength( *args ) :

    global SelectedMonthLength
    SelectedMonthLength.set( DaysInMonth[ SelectedMonthName.get()  ] )
    return

#-------------------------------------------------------------------------------

mainframe = Frame( root )
mainframe.grid( row = 0, column = 0 )
# Show today's date.  If it's July 17th, 2023 the spinboxes must be initialized 
# to "July" ("julliet" if using French), "17" and "2023".  
YearSpinBox  = Spinbox( mainframe, 
                        from_ = 2000, to = 2050,
                        textvariable = SelectedYear, 
                        wrap = TRUE, state = 'readonly', width = 5 )
MonthSpinBox  = Spinbox( mainframe,  
                         values = tuple( DaysInMonth.keys() )[1:],                         
                         textvariable = SelectedMonthName, 
                         wrap = TRUE, state = 'readonly', width = 10 )       
DaySpinBox  = Spinbox( mainframe, 
                       from_ = 1, 
                       to = SelectedMonthLength.get(), 
#                       to = DaysInMonth[ SelectedMonthName.get() ],
#                       values = tuple( str( i ) for i in range( 1, SelectedMonthLength.get() + 1 ) ),
#                       values = lambda : tuple( str( i ) for i in range( 1, DaysInMonth[ SelectedMonthName.get() ] + 1 ) )
                       textvariable = SelectedDay,  
                       wrap = TRUE, state = 'readonly', width = 16
                     )
MonthSpinBox.grid( row = 0, column = 0 )
DaySpinBox.grid(   row = 0, column = 1 )
YearSpinBox.grid(  row = 0, column = 2 )

SelectedMonthName.trace( 'w', GetChosenMonthLength ) 

mainloop()

顺便说一句,示例代码省略了调试代码,这些代码证明了所有Spinbox接口变量都被正确更新--包括包含更改/新月的最后一天的变量(该变量使用“TO=”关键字“发送”到day Spinbox )。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-12-12 02:19:10

所有小部件的所有选项都可以动态配置。如果我记得正确的话,只有一个例外,这是几乎没人使用过的一个特性:框架上的class选项。

我不知道你想在哪里更新它,所以我不知道你为什么认为它应该更新。若要更新spinbox,请将命令附加到,然后在回调中进行更新。

例如:

代码语言:javascript
复制
def update_days():
    maxdays = int(DaysInMonth[SelectedMonthName.get()])
    DaySpinBox.config(to=maxdays)

MonthSpinBox  = Spinbox(...,command=update_days) 

至于为什么这个月没有被设定为本月..。我不知道。看上去你做的很对。这与其他小部件之间的唯一区别是,这是一个StringVar而不是一个IntVar,而月份spinbox有一个values参数。这可能是tkinter中由这种差异触发的bug或文档不足的特性。

一个简单的解决方法是在创建了月份派生框之后添加SelectedMonthName.set(DefaultMonthName),以将字符串重置为适当的默认值。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20528596

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档