1

I try to code a to-do-list. When I click on the button self.button_check to change the color from a white entry to green it works until I create a second entry. The Problem is the new entry with the new check.button also look for the variable self.check_var which is used for the first. My Question is now: Is there a way to check the current bg color of an entry, to change if the entry is white or green instead of using the self.check_var variable?

Sry for obvious mistakes, I just started coding 😅

import tkinter as tk
from tkinter.constants import ANCHOR, CENTER, X

class App():

    def __init__(self):
        self.window = tk.Tk()
        self.window.title("To-Do-List")
        self.window.geometry("700x700")

        self.x_but, self.y_but = 0.05, 0.2 
        self.x_ent, self.y_ent = 0.05, 0.2
        self.x_but2 = 0.3
        self.check_var = True

        self.start_frame()
        self.grid1()
        self.window.mainloop()
        
    def start_frame(self):
        self.label1 = tk.Label(text="To Do List", font=("", 30))
        self.label1.place(relx=0.5, rely=0.05, anchor=CENTER)

    def grid1(self):
        self.button1 = tk.Button(text="Create", command= self.create_field)
        self.button1.place(relx = self.x_but, rely= self.y_but)

    def create_field(self):
        self.y_but += 0.05
        self.button1.place(relx= self.x_but, rely= self.y_but)

        self.entry1 = tk.Entry()
        self.entry1.place(relx= self.x_ent, rely= self.y_ent)
        x = self.entry1
        

        self.button_check = tk.Button(text="✅", height= 1,command=lambda x=self.entry1: self.check(x))
        self.button_check.place(relx= self.x_but2, rely=self.y_ent)
       



        self.y_ent += 0.05
    
    def check(self,ent):
        if self.check_var:
            ent.configure(bg="Green")
            self.check_var = False

        else:
            ent.configure(bg="White")
            self.check_var = True

    

app = App()

2 Answers 2

2

You can assign the value to the Entry itself:

def create_field(self):
    self.y_but += 0.05
    self.button1.place(relx= self.x_but, rely= self.y_but)
    
    # you don't need to use `self.` here necessarily, the instance attribute will get
    # overwritten anyways when you create a new `Entry`, same for button below
    entry = tk.Entry()
    entry.place(relx= self.x_ent, rely= self.y_ent)

    # create an attribute for the `Entry` and set it to True
    # when you pass the `Entry` to the function, you will be able to 
    # access this attribute too
    entry.check_var = True

    button_check = tk.Button(text="✅", height= 1,command=lambda x=entry: self.check(x))
    button_check.place(relx= self.x_but2, rely=self.y_ent)

    self.y_ent += 0.05

Then change your check method:

# add this decorator because the method doesn't require `self` anymore
@staticmethod
def check(ent):
    # here you can access the `Entry`'s attribute `check_var`
    # which was created in the other method
    if ent.check_var:
        ent.configure(bg="Green")
        ent.check_var = False

    else:
        ent.configure(bg="White")
        ent.check_var = True

Also I suggest that you use pack instead of place, as it is much easier to use in such cases (kind of, may be harder to adapt now). And you don't need to use the constants from tkinter, they just contain a string of the same name, so you can easily just use the string instead, for example: anchor='center'.

Sign up to request clarification or add additional context in comments.

13 Comments

Even though I think this is an elegant way to acomplish this task. I just started coding makes me think this answer needs either a lot more context on lambda, references, decorators and namespaces or it should be more self-explanatory and intuitiv.
For me, a beginner, everything is hard if u learn it for the first time. In my code I used a class method for the first time, because I tried to code it without a class and it was awful long and complicated. I give my best to understand everything and I'm grateful for every tip :) Basically I believe for now that the static method can be used if I don't need a self. That's all I got to know for now. I surely will understand more when I need it later.
@antal maybe Matiiss is right and a pointer in the right direction, to challange the people to make their own research, is better than a lot of explanation that no one ever reads till its needed.
@antal you want to start placing entries in a second column? well, you check for when self.y_ent reaches a certain value and then you change the value of self.x_ent, so in the method that creates entries add an if statement for example if self.y_ent > 0.3: self.x_ent += 0.4 self.y_ent = 0.2 and do the same for button coordinates, but I would suggest for sth like this to use grid
@antal if you would take the advice from Matiiss to use pack or grid, things can get easy and exciting. For exampel
|
2

What I think you could do here is instead of using a global check_var you can store the entry object and check_var as key and value in a dictionary. This way, since it is a to-do app, you can easily get the value by indexing the dictionary it with the entry object.

class App():
    def __init__(self):
        ....
        self.info = {} # Create a dictionary
    
    def create_field(self):
        .....
        self.entry1 = tk.Entry()
        self.entry1.place(relx= self.x_ent, rely= self.y_ent)
        

        self.button_check = tk.Button(text="✅", height= 1,command=lambda x=self.entry1: self.check(x))
        self.button_check.place(relx= self.x_but2, rely=self.y_ent)
       
        self.info[self.entry1] = False # Add the item to the dictionary
    
    def check(self,ent):
        check_var = self.info[ent]
        
        if not check_var: ent.configure(bg="Green")
        else: ent.configure(bg="White")

        self.info[ent] = not check_var

Also this way if you want to expand the app in future, you can just add more information into your dictionary related to the given task, like the task text itself. Perhaps something like:

def create_field(self):
    self.y_but += 0.05
    self.button1.place(relx= self.x_but, rely= self.y_but)

    self.entry1 = tk.Entry()
    self.entry1.place(relx= self.x_ent, rely= self.y_ent)
    
    tk.Button(text="✅", height= 1,command=lambda x=self.entry1: self.check(x)).place(relx= self.x_but2, rely=self.y_ent)
    tk.Button(text="Get details", height= 1,command=lambda x=self.entry1: self.get_details(x)).place(relx= self.x_but2+0.05, rely=self.y_ent)
    tk.Button(text="Update details", height= 1,command=lambda x=self.entry1: self.update_details(x)).place(relx= self.x_but2+0.17, rely=self.y_ent)
    
    data = '', False
    self.info[self.entry1] = data

    self.y_ent += 0.05

def check(self,ent):
    idx       = self.info[ent]
    check_var = idx[1]

    if not check_var:
        ent.configure(bg="Green")
        self.info[ent] = ent.get(),True

    else:
        ent.configure(bg="White")
        self.info[ent] = ent.get(),False
        
def get_details(self,ent):
    idx       = self.info[ent] # Get the details
    text      = idx[0]
    check_var = idx[1]
    print(f'The task is: {text} and it is {"completed" if check_var else "incomplete"}') # Print the details

def update_details(self,ent):
    idx       = self.info[ent] # Get the item
    check_var = idx[1] # Get the flag
    data      = ent.get(), check_var # Make a tuple of data
    
    self.info[ent] = data # Update the info

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.