0

I'm not at all familiar with Tkinter's validatecommands, but I have done some research and would like to implement it in a widget that creates a tree graph from a bunch of entries. I want to restrict each entry so that the user can create lists of numbers from 0 to the highest row, not including the same row. So, for example, Row 0 entry can't have 0 in it or 12. So far I have only attempted to restrict the input from being the same value as the row, but I haven't been able to get that to work. I must be implementing the validate command incorrectly.

enter image description here

Any help would be much appreciated.

import tkinter as tk

class widget:
    def __init__(self,master):
        # vcmd = (master.register(self.validate),
                # '%d', '%i', '%P', '%s', '%S', '%v', '%V', '%W')
        self.master = master
        self.entryNumbers = tk.Entry(master,justify = tk.CENTER)
        self.entryNumbers.insert(0, "5")
        self.entryNumbers.grid(row = 0,column = 0,columnspan =2,sticky="EW")
        self.createEntriesButton = tk.Button(master,text = "Create Entries",command = self.createEntries)
        self.createEntriesButton.grid(row = 1, column = 0,columnspan = 2,sticky="EW")

    def createEntries(self):
        self.entryNumbers.grid_forget()
        self.createEntriesButton.grid_forget()

        self.entries = []
        self.entryLabels = []

        vcmd = self.master.register(self.validateEntry)

        for i in range(int(self.entryNumbers.get())):
            self.entryLabels.append(tk.Label(self.master,text = "Row {}".format(i)))
            self.entryLabels[-1].grid(row = i,column = 0)
            self.entries.append(tk.Entry(self.master, validatecommand=(vcmd,'%P',i)))
            self.entries[-1].grid(row = i,column = 1)

        self.addEntriesButton = tk.Button(self.master,text = "Add Entries",command = self.addEntry)
        self.addEntriesButton.grid(row = i+1, column = 0,columnspan = 2,sticky="EW")

    def addEntry(self): 
        count = len(self.entries)

        vcmd = self.master.register(self.validateEntry)

        self.entryLabels.append(tk.Label(self.master,text = "Row {}".format(count)))
        self.entryLabels[-1].grid(row = count+1,column = 0)
        self.entries.append(tk.Entry(self.master, validatecommand=(vcmd,'%P',count)))
        self.entries[-1].grid(row = count+1,column = 1)
        self.addEntriesButton.grid(row = count+2, column = 0,columnspan = 2,sticky="EW")

    def validateEntry(self,P,row):
        if P != row:
            return True
        else:
            return False

root1=tk.Tk()
widget(root1)
root1.mainloop()

Also, can vcmd be a member variable? I would like to only initialize it once?

Jadon Erwin
  • 551
  • 5
  • 25
  • 1
    Read up on [Entry validation](https://stackoverflow.com/a/60904457/7414759) to adjust your `%` parameters. – stovfl Apr 16 '20 at 21:22
  • So I tried changing vcmd to (self.master.register(self.validateEntry),'%P') and I can get it to print P, but I want to pass the row number as well? – Jadon Erwin Apr 16 '20 at 21:39
  • You need `%W`, then you can get the Row by [`w.grid_info`](http://effbot.org/tkinterbook/grid.htm#Tkinter.Grid.grid_info-method) – stovfl Apr 16 '20 at 22:08

1 Answers1

0

I figured it out using a lambda function:

vcmd = lambda row:(self.master.register(self.validateEntry),'%P',row)

        for i in range(int(self.entryNumbers.get())):
            self.entryLabels.append(tk.Label(self.master,text = "Row {}".format(i)))
            self.entryLabels[-1].grid(row = i,column = 0)
            self.entries.append(tk.Entry(self.master, validate = "all", validatecommand=vcmd(i)))
Jadon Erwin
  • 551
  • 5
  • 25