0

I'm new to Python and all that stuff and currently trying to write some code to analyse some data. I have been stuck for days with a "unimportant" part of a bigger task. For this part I wanted to make three entry fields, where I state the lower (mint), upper bounds(maxt) and an interval(ranget). These should be processed by "plot_range" and give me the result "anz" in Label "lb5" AS I type the numbers how many list entities I would get with these parameters through a calculation of the

I should, according to my current research with google and stuff, use a combination of "trace_add" and "textvariable" to do that, but as I type inside the fields, the callback function is not executed. If I manually set the variables after the tracing is set, it works. Here is the abridged code, I hope it shows what I mean.

... 
class RangeWindow:
    def __init__(self, data):
        self.rw = Tk()
        rw = self.rw
        self.all_dat = data.copy()
        self.mod_dat = []
        self.mint = DoubleVar()
        self.maxt = DoubleVar()
        self.ranget = IntVar()

        self.mint.set(self.all_dat[0][1])
        self.maxt.set(self.all_dat[-1][1])
        self.ranget.set(1)

        self.mint.trace_add("write", self.plot_range)
        self.maxt.trace_add("write", self.plot_range)
        self.ranget.trace_add("write", self.plot_range)

        lb1 = Label(rw, text='%s \u00b0C to %s \u00b0C with %s meassurements' % (self.all_dat[0][1], self.all_dat[-1][1], len(self.all_dat)))
        lb2 = Label(rw, text="from temp [\u00b0C]")
        lb3 = Label(rw, text="to temo [\u00b0C]")
        lb4 = Label(rw, text="in range of.")

        lb1.grid(row=0, column=1)
        lb2.grid(row=1, column=1)
        lb3.grid(row=2, column=1)
        lb4.grid(row=3, column=1)

        self.e1 = Entry(rw, textvariable=self.mint)
        self.e2 = Entry(rw, textvariable=self.maxt)
        self.e3 = Entry(rw, textvariable=self.ranget)

        self.e1.grid(row=1, column=2)
        self.e2.grid(row=2, column=2)
        self.e3.grid(row=3, column=2)

        self.anz = StringVar()
        lb5 = Label(self.rw, textvariable=self.anz)
        lb5.grid(row=4, column=1)

        self.mint.set(100)

        rw.mainloop()

    def plot_range(self,n, m, o):
...

Thank you very much for any help if you see what the problem is/might be.

Edit:

Shortened code, which somewhat works as I intended is here:

from tkinter import *


# some example-data, which has the same structure as real-data, which is imported beforehand ([[[xdata],[ydata]],temperature] as fat as I know)

def exampledata(cnt):
    a = []
    b = [[1, 2], [3, 4], [5, 6]]
    c = 10

    for x in range(cnt):
        t = c * (x + 1)
        d = [[[j*(x+1) for j in i] for i in b], t]
        a.append(d)
    return a


class RangeWindow:
    def __init__(self):
        self.rw = Tk()
        rw = self.rw
        self.all_dat = exampledata(10)
        self.mod_dat = []
        self.mint = DoubleVar()
        self.maxt = DoubleVar()
        self.ranget = IntVar()

        self.mint.set(self.all_dat[0][1])
        self.maxt.set(self.all_dat[-1][1])
        self.ranget.set(1)

        self.mint.trace_add("write", self.plot_range)
        self.maxt.trace_add("write", self.plot_range)
        self.ranget.trace_add("write", self.plot_range)

        lb1 = Label(rw, text='%s \u00b0C to %s \u00b0C with %s meassurements' % (self.all_dat[0][1], self.all_dat[-1][1], len(self.all_dat)))
        lb2 = Label(rw, text="from temp [\u00b0C]")
        lb3 = Label(rw, text="to temo [\u00b0C]")
        lb4 = Label(rw, text="in range of.")

        lb1.grid(row=0, column=1)
        lb2.grid(row=1, column=1)
        lb3.grid(row=2, column=1)
        lb4.grid(row=3, column=1)

        self.e1 = Entry(rw, textvariable=self.mint)
        self.e2 = Entry(rw, textvariable=self.maxt)
        self.e3 = Entry(rw, textvariable=self.ranget)

        self.e1.grid(row=1, column=2)
        self.e2.grid(row=2, column=2)
        self.e3.grid(row=3, column=2)

        self.anz = StringVar()
        lb5 = Label(self.rw, textvariable=self.anz)
        lb5.grid(row=4, column=1)

        self.mint.set(100)

        rw.mainloop()

    def plot_range(self,n, m, o): # potentially easily doable with list comprehension, but works somewhat as intended, so a third priority
        print("started") # something I used to check, if the methode is called, which was only via manual setting of the variables
        t1 = self.mint.get()
        t2 = self.maxt.get()
        n = self.ranget.get()
        if not t1 or not t2 or not n:
            return
        self.mod_dat.clear()
        startindex = -1
        for i in range(0, len(self.all_dat)):
            if t1 <= self.all_dat[i][1] <= t2:
                startindex = i
                break
        if startindex == -1:
            return
        for i in range(startindex, len(self.all_dat), n): 
            if t1 <= self.all_dat[i][1] <= t2:
                self.mod_dat.append(self.all_dat[i])
            else:
                break
        self.anz.set("Count of measurements will be %s with Tmin %s \u00b0C and Tmax %s \u00b0C " % (len(self.mod_dat), self.mod_dat[0][1], self.mod_dat[-1][1]))
        print("done")


gui = RangeWindow()

Edit 2: So I think now that there is the problem with the rest of the code, which is now implemented too:

from tkinter import *


# some hopefully representative example-data, although for this part of the program I only look at t
def exampledata(cnt):
    a = []
    b = [[1, 2], [3, 4], [5, 6]]
    c = 10

    for x in range(cnt):
        t = c * (x + 1)
        d = [[[j*(x+1) for j in i] for i in b], t]
        a.append(d)
    return a

class MainWindow:
    def __init__(self):
        self.mw = Tk()
        mw = self.mw
        mw.geometry("100x100")
        openbut = Button(mw, text='Open', command=self.openfile)
        openbut.grid(row=0, column=0, sticky=W, pady=4)
        self.mess_dat = []
        mw.mainloop()

    def openfile(self): # shortened with the example-data
        self.mess_dat = exampledata(10)
        rangegui = RangeWindow(self.mess_dat)


class RangeWindow:
    def __init__(self,data):
        self.rw = Tk()
        rw = self.rw
        self.all_dat = data
        self.mod_dat = []
        self.mint = DoubleVar()
        self.maxt = DoubleVar()
        self.ranget = IntVar()

        self.mint.set(self.all_dat[0][1])
        self.maxt.set(self.all_dat[-1][1])
        self.ranget.set(1)

        self.mint.trace_add("write", self.plot_range)
        self.maxt.trace_add("write", self.plot_range)
        self.ranget.trace_add("write", self.plot_range)

        lb1 = Label(rw, text='%s \u00b0C to %s \u00b0C with %s meassurements' % (self.all_dat[0][1], self.all_dat[-1][1], len(self.all_dat)))
        lb2 = Label(rw, text="from temp [\u00b0C]")
        lb3 = Label(rw, text="to temo [\u00b0C]")
        lb4 = Label(rw, text="in range of.")

        lb1.grid(row=0, column=1)
        lb2.grid(row=1, column=1)
        lb3.grid(row=2, column=1)
        lb4.grid(row=3, column=1)

        self.e1 = Entry(rw, textvariable=self.mint)
        self.e2 = Entry(rw, textvariable=self.maxt)
        self.e3 = Entry(rw, textvariable=self.ranget)

        self.e1.grid(row=1, column=2)
        self.e2.grid(row=2, column=2)
        self.e3.grid(row=3, column=2)

        self.anz = StringVar()
        lb5 = Label(self.rw, textvariable=self.anz)
        lb5.grid(row=4, column=1)

        self.mint.set(100)

        rw.mainloop()

    def plot_range(self,n, m, o):
        print("started")
        t1 = self.mint.get()
        t2 = self.maxt.get()
        n = self.ranget.get()
        if not t1 or not t2 or not n:
            return
        self.mod_dat.clear()
        startindex = -1
        for i in range(0, len(self.all_dat)):
            if t1 <= self.all_dat[i][1] <= t2:
                startindex = i
                break
        if startindex == -1:
            return
        for i in range(startindex, len(self.all_dat), n):  # neue Liste mit den Werten im Bereich wird erstellt
            if t1 <= self.all_dat[i][1] <= t2:
                self.mod_dat.append(self.all_dat[i])
            else:
                break
        self.anz.set("Count of measurements will be %s with Tmin %s \u00b0C and Tmax %s \u00b0C " % (len(self.mod_dat), self.mod_dat[0][1], self.mod_dat[-1][1]))
        print("done")


gui = MainWindow()


I hope it makes sense, as shown here. In comparison to the minimal example it doesn't call the method when writing in the entries and it doesn't even show the label lb5. I have a feeling it has to do something with the "mainlooping" although, if I simply use textvariable to transfer the entries to a lable it works, so that should not be the problem. So I would be happy, if anyone has any ideas, what the problem might be.

Brutaler
  • 43
  • 4
  • When I run the posted code, with just enough extra code to make it work, `plot_range` is called every time I type into the entry widgets. We need to see a complete [mcve], but we only need to see an example with a single variable. Please try to [edit] your question to include a minimal but complete example which reproduces the problem you're asking about. – Bryan Oakley Sep 05 '20 at 15:30
  • Hoped, that it would not come to this, as I thought that it would be too much work (which was not the case) but I did it and ... it kinda works now with an abridged version with generated sample-data (although not quite free of errors, but that is secondar)y. So now I think it has to do something with the way my current code is structured. I'll post it up there – Brutaler Sep 06 '20 at 12:03
  • We don't need code which works. We need an example that illustrates the problem you are asking about. – Bryan Oakley Sep 06 '20 at 13:03
  • Alright, hoped the abstract example was enough, as it appears to be a problem of mine understanding object-oriented-programming or something, but here is the complet example. – Brutaler Sep 06 '20 at 13:17

1 Answers1

0

The problem is due to the creation of more than one instance of Tk. You should almost never create a second instance of Tk - widgets and variables created in one instance are not visible in any other instances. Second and subsequent windows should be made with Toplevel.

Also, you should not call mainloop more than once.

For more information see Why are multiple instances of Tk discouraged?

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685