2013-12-11 2 views
1

나는 파이썬 3.x를 사용하여 년, 월, 일 등을위한 별도의 스핀 상자가있는 다국어 "캘린더"위젯을 만듭니다. 요구되는 것은 위젯이 사용 되더라도 언제든지 GUI의 일부를 숨기고 목록 등을 드롭 다운하지 않도록하여 스핀 상자를 명백한 선택으로 만듭니다.동적으로 범위를 설정 Spinbox

순수 python/tkinter "date & 시간 항목"widgit (이상적으로 윤년 및 모든 월말 사례 처리)에 대한 공개 도메인 소스 코드를 알면 누구나 저를 가리켜줍니다. 저장소가 인정 될 것이다.

찾을 수있는 가장 가까운 해결책은이 OptionMenu 솔루션 (Change OptionMenu based on what is selected in another OptionMenu) 이었지만 "숨기지 않음"요구 사항으로 인해 사용할 수 없습니다. 이것을 영감으로 사용하여 (그리고 http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/spinbox.html에서 Spinbox 문서를 검토 한 후) 아래 코드를 생각해 냈습니다. 일을 단순하게 유지하기 위해 윤년 및 월말 문제를 처리하는 코드를 삭제했습니다. 코드는 두 가지 문제를 제외하고 작동합니다

문제 1 - 나는 동적 "MonthSpinBox"의 달 자체를 설정하기 위해 '범위를 조정하는 "DaySpinBox"를 얻을 수 없다 : 내가 읽은 방법에 따르면

Mark Lutz의 "Programming Python"책 (제 3 판, 383 페이지, & 384) DaySpinBox의 최대/마지막 날을 동적으로 설정할 수 있어야합니다 ("values ​​="또는 "to ="및 "from_ ="옵션 사용) MonthSpinBox에 나타나는 달과 일치시킵니다. MonthSpinBox 변수 ("SelectedMonth")를 추적 중이며, 책 당, 다음 접근 방식을 사용하여 DaySpinBox를 업데이트 해 보았습니다. 1 - "To = SelectedMonth"사용. 이것에 대한 일부 시도는 DaySpinBox를 생성하는 호출의 주석으로 나타납니다. "나는 DaySpinBox.config (to = SelectedMonth)"를 사용하여 "DaySpinBox [ '] = SelectedMonth"및 2 - 사용하여 람다에 익숙하지 않은, 아마도 그들을 정확하게 사용하고 있습니까?)
2.
나는 "values ​​="를 모든 접근법에 성공없이 사용하려고 시도했다 ("to = ...."옵션이 선호된다).

질문 1 : Spinbox가 동적 범위를 사용하도록 설정할 수 있습니까? 아니면 의심 스럽기 때문에 Spinbox를 만든 후 Spinbox의 범위를 변경할 수 있습니까?

질문 2 : 웹 검색을 많이 한 후에 동적으로 변경할 수있는 Spinbox 매개 변수 ("to =", "from ="및 "value ="키워드)를 명시 적으로 언급하지 않은 것을 발견하지 못했습니다. 이 정보는 어디에서 찾을 수 있습니까 (모든 위젯 유형)?

문제 2 - MonthSpinBox은 항상 내가 년, 월을 초기화하기 위해 "하면 textVariable"키워드를 사용하고 있는데 날이 "오늘"에 spinboxes 현재 월

대신 1월 초기화됩니다. 이것은 YearSpinBox와 DaySpinBox에서는 작동하지만 MonthSpinBox에서는 작동하지 않습니다. (annoyingly 나는 MonthSpinBox가 일하고 있었다고 생각하지만 DaySpinBox를 고치려고 노력했다.) 유일하게 분명한 차이점은 Month and Day 스핀 상자는 정수를 사용하는 반면 Month 스핀 상자는 문자열을 사용한다는 것입니다. 어떤 제안? 두 문제에 대한

은 내가 LEGB 문제의 가능성을 고려하지만 기능은 너무 변수 숨기기가 문제가 안 중첩되지 않습니다 - 내 변수 중 하나하지 않는 복제 및 Tkinter의 정의를 숨기고 등

내가 뭘 놓치고 있니?

BTW, 나는 PEP8 (http://www.python.org/dev/peps/pep-0008/)에 관한 전역 변수 사용에 대한 찬반론을 알고 있습니다. 목차의 두 번째 글 머리표를 참조하십시오. ;>)

감사합니다.오늘로 "전송"가져옵니다 변경/새로운 달의 마지막 날을 (포함하는 변수를 포함하여 -

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() 

BTW, 샘플 코드는 모든 Spinbox 인터페이스 변수가 제대로 업데이트되고 입증 디버깅 코드를 생략 Spinbox는 "TO ="키워드 사용).

+0

이러한 질문을 고유 한 질문으로 제시하면 더 빨리 응답을 얻을 수 있습니다. – duhaime

답변

1

모든 위젯에 대한 모든 옵션은 항상 동적으로 구성 할 수 있습니다. 아무도 거의 사용하지 않는 기능인 프레임을 정확히옵션으로 리콜하면 예외가 하나뿐입니다.

일 spinbox를 업데이트하는 것과 관련하여 업데이트를 시도하는 위치가 표시되지 않아 업데이트해야한다고 생각하는 이유가 확실하지 않습니다. 스핀 상자를 업데이트하려면 월 스핀 상자에 명령을 첨부 한 다음 콜백에서 업데이트하십시오. 예를 들어

: 달이 현재 월에 설정되지 않는 이유에 대해서는

def update_days(): 
    maxdays = int(DaysInMonth[SelectedMonthName.get()]) 
    DaySpinBox.config(to=maxdays) 

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

... 모르겠어요. 당신이 일을 제대로하고있는 것처럼 보입니다. 이 위젯과 다른 위젯의 유일한 차이점은 IntVar가 아니라 StringVar이고 월 스핀 상자의 인수는 values입니다. 아마도이 차이로 인해 발생하는 tkinter의 버그 또는 잘못 문서화 된 기능 일 것입니다.

간단히 해결하려면 월 스핀 상자를 만든 후 SelectedMonthName.set(DefaultMonthName)을 추가하여 stringvar를 적절한 기본값으로 재설정하십시오.

+0

@Bryan에게 저의 이해를 확인해 주신 데 감사드립니다. 그러나 Day Spinbox를 업데이트하려고 시도한 방법 중 아무 것도 작동하지 않았습니다. 문제는 월간 스피 인 박스의 달 마지막 날과 일치하도록 날짜 스핀 상자의 최대 값이 업데이트되지 않는다는 것입니다. (스핀 박스의 값은 올바르게 업데이트됩니다.) 문제를 보려면 1 월 31 일을 선택한 다음 월을 2 월으로 변경하십시오. 원하는대로 Spinbox의 표시 날짜가 2 월 28 일 (윤년 ​​무시)으로 변경되지만 Day Spinbox에서는 여전히 2 월 31 일로 변경할 수 있습니다! 내가 고칠 필요가있는이 (년과 달에 달려있는) 문제입니다. – user1459519

+0

@ user1459519 : 대답을 업데이트하여 수행 방법을 알려 드렸습니다. –

+0

Doh! 문제를 발견해 주셔서 감사합니다. 다시 한번 귀하의 도움은 매우 귀중합니다. 오랫동안 코드를 살펴 봤는데 나무 숲을 볼 수 없었습니다 (생략 된 "command ="키워드와 도우미 기능이 관련되어 있음). 두 가지 변경을 한 후에 코드가 작동합니다. 다른 사람들은 올해가 바뀌면 2 월 29 일을 처리하기 위해 Year Spinbox에도 같은 "명령 ="행을 추가했다는 것을 알아 두어야합니다. – user1459519