Python Tkinter 更改 StringVar 值以将其用作 UI 上的背景指示器

标签 python user-interface tkinter

我正在构建一个 UI,用户必须在其中选择一些日期。我添加了一个名为 Date Indicator 的行,它显示了一个带有颜色的框。起始颜色(直到用户选择两个日期)为 grey。此颜色必须根据用户选择的日期而改变。

  • 如果他选择的两个日期之间的天数超过两周,则该框必须变为绿色
  • 如果他选择的两个日期之间的天数少于两周,则该框必须变为黄色
    如果他选择的两个日期之间的天数小于 一周,则该框必须变为红色

这是所需解决方案的 Photoshop 结果: enter image description here

代码好像有点长,不过只要查到tkCalendar类就可以了。从那里到底部只是您不需要更改的日历代码。 (是的,有一些 imports 不需要用于此代码,我维护它们是因为我必须将它们用于其他东西,但你可以删除它们)

# -*- coding: utf-8 -*-
import os
from Tkinter import *
import Image
import ImageTk
import tkFileDialog
import xlrd
import csv
from tkMessageBox import *
from win32com.client import Dispatch
import datetime
import time
import calendar

year = time.localtime()[0]
month = time.localtime()[1]
day =time.localtime()[2]
strdate = (str(year) +  "/" + str(month) + "/" + str(day))

fnta = ("Helvetica", 10)
fnt = ("Helvetica", 10)
fntc = ("Helvetica", 10, 'bold')


strtitle = "Calendario"
strdays= "Do  Lu  Ma  Mi  Ju  Vi  Sa"
dictmonths = {'1':'Ene','2':'Feb','3':'Mar','4':'Abr','5':'May',
    '6':'Jun','7':'Jul','8':'Ago','9':'Sep','10':'Oct','11':'Nov',
    '12':'Dic'}


class Planificador(Frame):
    def __init__(self,master):
        Frame.__init__(self, master)
        self.master = master
        self.initUI()

    def initUI(self):
        self.master.title("Planner")
        self.frameOne = Frame(self.master)
        self.frameOne.grid(row=0,column=0)
        self.frameTwo = Frame(self.master)
        self.frameTwo.grid(row=0, column=1)
        self.frameThree = Frame(self.master)
        self.frameThree.grid(row=0, column=2)

        self.frameFour = Frame(self.master)
        self.frameFour.grid(row=1,column=0, sticky=N)
        self.frameFive = Frame(self.master)
        self.frameFive.grid(row=1, column=1)
        self.frameSix = Frame(self.master)
        self.frameSix.grid(row=1, column=2, sticky=N)

        self.frameSeven = Frame(self.master)
        self.frameSeven.grid(row=2,column=0)
        self.frameEight = Frame(self.master)
        self.frameEight.grid(row=2, column=1, sticky=S)
        self.frameNine = Frame(self.master)
        self.frameNine.grid(row=2, column=2)

        self.start_date_menu()

    def start_date_menu(self):
        self.initial_num_elements = 4
        self.TEXT_MENU_ROW = 0  # initial date menu grid row
        self.COL_WIDTH = 10  # width of each subcolumn of dates

        for frame in (self.frameFour, self.frameSix):
            self.dayintext = Label(frame, text="Day in",
                                        width=self.COL_WIDTH, justify="center")
            self.dayintext.grid(row=self.TEXT_MENU_ROW, column=0)
            self.dayouttext = Label(frame, text="Day out", width=self.COL_WIDTH,
                                   justify="center")
            self.dayouttext.grid(row=self.TEXT_MENU_ROW, column=1)
            self.status = Label(frame, text="Date indicator", width=self.COL_WIDTH,
                                   justify="center")
            self.status.grid(row=self.TEXT_MENU_ROW, column=2)

        self.dates = [self.create_all_entrys(aux_index)
                        for aux_index in xrange(self.initial_num_elements)]

        self.anadirpiezas = Button(self.frameEight, text="add more",
                                   command=self.addone, width=self.COL_WIDTH)
        self.anadirpiezas.grid(row=0, column=3)


    def addone(self):
        self.dates.append(self.create_all_entrys(len(self.dates)))
        self.printdates()

    def printdates(self):
        print "IN:"
        for i in xrange(self.initial_num_elements):
            print self.dates[i][0].get() # col 0
        print "OUT:"
        for i in xrange(self.initial_num_elements):
            print self.dates[i][2].get() # col 2

    def create_all_entrys(self, aux_index):
        menu_col = aux_index % 2  # left/right column of the date frame
        menu_row = self.TEXT_MENU_ROW + aux_index/2 + 1
        frame = self.frameSix if aux_index % 2 else self.frameFour

        in_var = StringVar(value="--------")
        in_btn = Button(frame, textvariable=in_var, width=self.COL_WIDTH,
                        command=lambda v=in_var: self.fnCalendar(v))
        in_btn.grid(row=menu_row, column=0)

        out_var = StringVar(value="--------")
        out_btn = Button(frame, textvariable=out_var, width=self.COL_WIDTH,
                         command=lambda v=out_var: self.fnCalendar(v))
        out_btn.grid(row=menu_row, column=1)

        self.colorvar = StringVar()
        self.colorvar.set('grey')
        self.status_color = Label(frame, width=2, bg=self.colorvar.get())
        self.status_color.grid(row=menu_row,column=2)

        return in_var, in_btn, out_var, out_btn

    def fnCalendar(self, datebar):
        tkCalendar(self.master, year, month, day, datebar)

class tkCalendar :
  def __init__ (self, master, arg_year, arg_month, arg_day,
       arg_parent_updatable_var):
    print arg_parent_updatable_var.get()
    self.update_var = arg_parent_updatable_var
    top = self.top = Toplevel(master)
    top.title("Choose a date")
    try : self.intmonth = int(arg_month)
    except: self.intmonth = int(1)
    self.canvas =Canvas (top, width =200, height =220,
      relief =RIDGE, background ="#ece9d8", borderwidth =0)
    self.canvas.create_rectangle(0,0,303,30, fill="#ece9d8",width=0 )
    self.canvas.create_text(100,17, text="Choose!",  font=fntc, fill="#BA1111")
    stryear = str(arg_year)

    self.year_var=StringVar()
    self.year_var.set(stryear)
    self.lblYear = Label(top, textvariable = self.year_var,
        font = fnta, background="#ece9d8")
    self.lblYear.place(x=85, y = 30)

    self.month_var=StringVar()
    strnummonth = str(self.intmonth)
    strmonth = dictmonths[strnummonth]
    self.month_var.set(strmonth)

    self.lblYear = Label(top, textvariable = self.month_var,
        font = fnta, background="#ece9d8")
    self.lblYear.place(x=85, y = 50)
    #Variable muy usada
    tagBaseButton = "Arrow"
    self.tagBaseNumber = "DayButton"
    #draw year arrows
    x,y = 40, 43
    tagThisButton = "leftyear"
    tagFinalThisButton = tuple((tagBaseButton,tagThisButton))
    self.fnCreateLeftArrow(self.canvas, x,y, tagFinalThisButton)
    x,y = 150, 43
    tagThisButton = "rightyear"
    tagFinalThisButton = tuple((tagBaseButton,tagThisButton))
    self.fnCreateRightArrow(self.canvas, x,y, tagFinalThisButton)
    #draw month arrows
    x,y = 40, 63
    tagThisButton = "leftmonth"
    tagFinalThisButton = tuple((tagBaseButton,tagThisButton))
    self.fnCreateLeftArrow(self.canvas, x,y, tagFinalThisButton)
    x,y = 150, 63
    tagThisButton = "rightmonth"
    tagFinalThisButton = tuple((tagBaseButton,tagThisButton))
    self.fnCreateRightArrow(self.canvas, x,y, tagFinalThisButton)
    #Print days
    self.canvas.create_text(100,90, text=strdays, font=fnta)
    self.canvas.pack (expand =1, fill =BOTH)
    self.canvas.tag_bind ("Arrow", "<ButtonRelease-1>", self.fnClick)
    self.canvas.tag_bind ("Arrow", "<Enter>", self.fnOnMouseOver)
    self.canvas.tag_bind ("Arrow", "<Leave>", self.fnOnMouseOut)
    self.fnFillCalendar()

  def fnCreateRightArrow(self, canv, x, y, strtagname):
    canv.create_polygon(x,y, [[x+0,y-5], [x+10, y-5] , [x+10,y-10] ,
        [x+20,y+0], [x+10,y+10] , [x+10,y+5] , [x+0,y+5]],
        tags = strtagname , fill="black", width=0)

  def fnCreateLeftArrow(self, canv, x, y, strtagname):
    canv.create_polygon(x,y, [[x+10,y-10], [x+10, y-5] , [x+20,y-5] ,
        [x+20,y+5], [x+10,y+5] , [x+10,y+10] ],
        tags = strtagname , fill="black", width=0)


  def fnClick(self,event):
    owntags =self.canvas.gettags(CURRENT)
    if "rightyear" in owntags:
    intyear = int(self.year_var.get())
    intyear +=1
    stryear = str(intyear)
    self.year_var.set(stryear)
    if "leftyear" in owntags:
    intyear = int(self.year_var.get())
    intyear -=1
    stryear = str(intyear)
    self.year_var.set(stryear)
    if "rightmonth" in owntags:
    if self.intmonth < 12 :
        self.intmonth += 1
        strnummonth = str(self.intmonth)
        strmonth = dictmonths[strnummonth]
        self.month_var.set(strmonth)
    else :
        self.intmonth = 1
        strnummonth = str(self.intmonth)
        strmonth = dictmonths[strnummonth]
        self.month_var.set(strmonth)
        intyear = int(self.year_var.get())
        intyear +=1
        stryear = str(intyear)
        self.year_var.set(stryear)
    if "leftmonth" in owntags:
    if self.intmonth > 1 :
        self.intmonth -= 1
        strnummonth = str(self.intmonth)
        strmonth = dictmonths[strnummonth]
        self.month_var.set(strmonth)
    else :
        self.intmonth = 12
        strnummonth = str(self.intmonth)
        strmonth = dictmonths[strnummonth]
        self.month_var.set(strmonth)
        intyear = int(self.year_var.get())
        intyear -=1
        stryear = str(intyear)
        self.year_var.set(stryear)
    self.fnFillCalendar()
  def fnFillCalendar(self):
    init_x_pos = 20
    arr_y_pos = [110,130,150,170,190,210]
    intposarr = 0
    self.canvas.delete("DayButton")
    self.canvas.update()
    intyear = int(self.year_var.get())
    monthcal = calendar.monthcalendar(intyear, self.intmonth)
    for row in monthcal:
    xpos = init_x_pos
    ypos = arr_y_pos[intposarr]
    for item in row:
        stritem = str(item)
        if stritem == "0":
        xpos += 27
        else :
        tagNumber = tuple((self.tagBaseNumber,stritem))
        self.canvas.create_text(xpos, ypos , text=stritem,
            font=fnta,tags=tagNumber)
            xpos += 27
    intposarr += 1
    self.canvas.tag_bind ("DayButton", "<ButtonRelease-1>", self.fnClickNumber)
    self.canvas.tag_bind ("DayButton", "<Enter>", self.fnOnMouseOver)
    self.canvas.tag_bind ("DayButton", "<Leave>", self.fnOnMouseOut)

  def fnClickNumber(self,event):
    owntags =self.canvas.gettags(CURRENT)
    for x in owntags:
    if (x == "current") or (x == "DayButton"): pass
    else :
        strdate = (str(self.year_var.get()) + "/" +
            str(self.intmonth) + "/" +
            str(x))
        self.update_var.set(strdate)
        self.top.withdraw()

  def fnOnMouseOver(self,event):
    self.canvas.move(CURRENT, 1, 1)
    self.canvas.update()

  def fnOnMouseOut(self,event):
    self.canvas.move(CURRENT, -1, -1)
    self.canvas.update()


if __name__ == "__main__":
    root = Tk()
    aplicacion = Planificador(root)
    root.mainloop()

我完全迷失了尝试这样做。我知道我必须更改 self.colorvar 但我不知道该怎么做。例如,我尝试使用 self.colorvar.set('red') 但我无法按照上面解释的方式进行操作。 inout 日期可以在 printdates 函数中找到。非常感谢您的帮助。

最佳答案

我认为您不能将 bg 选项链接到 StringVar。您只能使用选项 textvariable 来完成它。你应该这样做的方式是通过 Label.config() 方法。

所以你可以这样写:

self.status_color.config(bg='red')

或者,如果您想继续使用 colorvar:

self.colorvar.set('red')
self.status_color.config(bg=self.colorvar.get())

这应该行得通,我想您可以在 2 周内弄清楚。

编辑:

您还可以将 StringVar self.colorvar“链接”到更改 self.status_color 的函数(使用 trace 方法);这样每当 colorvar 改变时,你的函数就会被调用,它会改变状态颜色。 这是我的建议:

def myFunc(*args):
    self.status_color.config(bg=self.colorvar.get())

self.colorvar.trace('w',self.myFunc)

现在每次调用 self.colorvar.set() 时,您也会调用 self.myFunc。

编辑:

至于周的事情,我不打算完全回答,因为它看起来很容易。只需获取 IN 和 OUT 的月份和日期的整数,然后执行如下操作:

monthdiff = monthout-monthin
if monthdiff!=0:
    dayout += monthdiff*30 #or 31, depending on the month. Just add an if/else

weeks = ((dayout-dayin)//7)+1 #For python2.7 use only one slash

然后您的 if/else 具有颜色更改功能。一月份也要小心,如果多的话就加一个。我想您可以自己解析 IN 和 OUT 字符串来获取月份和日期。

关于Python Tkinter 更改 StringVar 值以将其用作 UI 上的背景指示器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20070637/

相关文章:

python - Tkinter:按钮打开另一个窗口(并关闭当前窗口)

python - 为什么 tkinter 进度条会让事情变慢?

列表中的Python计数列表

python - 是否可以从具有相同名称的查询字符串中获取值?

java - 必需的空布局,用于绘图 + 标签

sql - 是否可以从复杂的数据库查询中创建详细的错误消息?

Python List 对象属性 'append' 是只读的

python - 绕 x 轴旋转图像

python - 使用 QAbstractTableModel 在 pyqt 中编辑表

python - 如何在 Tkinter 标签中使用下标?