1

I cannot find a way to access this textbox and append to it from another class using Tkinter.

I can't use the method I've used before (by calling other entries StringVar()), which has lead to a halt in my programming. As textbox cannot be named a StringVar(), I am confused as to how I could go about doing this.

import tkinter as tk

class MainWindow(tk.Tk):

    def __init__(self, *args, **kwargs):

        tk.Tk.__init__(self, *args, **kwargs)
        self.geometry("1350x750")

        container = tk.Frame(self)
        container.grid(row=0, column=0)

        container.config(bg="gray20")

        self.frames = {}

        for F in (ReservationPage, ReceiptPage):
            frame = F(container, self)
            self.frames[F] = frame
            frame.grid(row=0, column=0)

        self.show_frame(ReservationPage)

    def show_frame(self, cont):
        frame = self.frames[cont]
        frame.tkraise()


class ReservationPage(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        self.MainFrame = tk.Frame(self, width=1350, height=700, bg="gray20")
        self.MainFrame.grid(row=0,column=0)
        self.MoorFrame = tk.LabelFrame(self, bg="gray20", width=300, height=150)
        self.MoorFrame.place(x=450, y=120)

        ReceiptPageButton1 = tk.Button(self, text="Receipts", font=("Helvetica", 20, "bold"),bg="gray20", fg="light grey",
                                       bd=0,command=lambda: controller.show_frame(ReceiptPage))
        ReceiptPageButton1.place(x=100, y=30)


class ReceiptPage(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        self.MainFrame = tk.Frame(self, width=1350, height=700, bg="gray20")
        self.MainFrame.grid(row=0,column=0)

        ReservationPageButton1 = tk.Button(self, text="Reservations", font=("Helvetica", 20, "bold"),bg="gray20", fg="light grey",
                                       bd=0,command=lambda: controller.show_frame(ReservationPage))
        ReservationPageButton1.place(x=80, y=30)

        ReceiptBox = tk.Text(self, height=20, width=137, font=("Helvetica",11,"bold"))
        ReceiptBox.place(x=27, y=165)
martineau
  • 119,623
  • 25
  • 170
  • 301
TrainTirade
  • 106
  • 8
  • 1
    Yes, if you make the Textbox an instance variable, you can access it from another from with `self.master.frames[Page1].textbox`. You need to show a [mcve] if you want an example of that. – Novel Jul 08 '19 at 16:40
  • Also, your `controller` Frame and `MainFrame` Frame seem pretty useless. Why do you have those? – Novel Jul 08 '19 at 16:40
  • @Novel, I have updated my post. Apologies for the inconvenience. – TrainTirade Jul 08 '19 at 16:56
  • @Novel: the controller and `MainFrame` are there because he copied and pasted this code from an online tutorial. That tutorial stole code from an early version of this answer: https://stackoverflow.com/questions/7546050/switch-between-two-frames-in-tkinter – Bryan Oakley Jul 08 '19 at 18:42

2 Answers2

0

Here is an example. Note I also removed a lot of other useless code. The one thing I didn't do that I recommend you do is stop using place(). Learn to use grid() and pack() instead. It's a little harder to learn but once you know how they work it's much MUCH easier to program because tkinter will figure out all those pixel locations for you.

import tkinter as tk

bg_color = "gray20"
button_style = dict(
    font=("Helvetica", 20, "bold"),
    bg=bg_color,
    fg="light grey",
    bd=0)

class MainWindow(tk.Tk):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.geometry("1350x750")

        self.frames = {}
        for F in (ReservationPage, ReceiptPage):
            frame = F(self)
            self.frames[F] = frame
            frame.grid(row=0, column=0, sticky="nsew")
        self.rowconfigure(0, weight=1)
        self.columnconfigure(0, weight=1)
        self.show_frame(ReservationPage)

    def show_frame(self, cont):
        frame = self.frames[cont]
        frame.tkraise()

class ReservationPage(tk.Frame):
    def __init__(self, parent, **kwargs):
        super().__init__(parent, bg=bg_color, **kwargs)
        self.MoorFrame = tk.LabelFrame(self, bg=bg_color, width=300, height=150)
        self.MoorFrame.place(x=450, y=120)

        ReceiptPageButton1 = tk.Button(self, text="Receipts", command=lambda: parent.show_frame(ReceiptPage), **button_style)
        ReceiptPageButton1.place(x=100, y=30)

        test_button = tk.Button(self, text="Test add text", command=self.add, **button_style)
        test_button.place(x=100, y=100)

    def add(self):
        textbox = self.master.frames[ReceiptPage].ReceiptBox
        textbox.insert(tk.END, "This is only a test\n")

class ReceiptPage(tk.Frame):
    def __init__(self, parent, **kwargs):
        super().__init__(parent, bg=bg_color, **kwargs)

        ReservationPageButton1 = tk.Button(self, text="Reservations", command=lambda: parent.show_frame(ReservationPage), **button_style)
        ReservationPageButton1.place(x=80, y=30)

        # using a name that starts with "self." makes this an instance variable
        self.ReceiptBox = tk.Text(self, height=20, width=137, font=("Helvetica",11,"bold"))
        self.ReceiptBox.place(x=27, y=165)

def main():
    root = MainWindow()
    root.mainloop()

if __name__ == '__main__':
    main()
Novel
  • 13,406
  • 2
  • 25
  • 41
  • Your `add` function is missing a step. OP's code would raise the receipt window to the front when the button was clicked. – Bryan Oakley Jul 08 '19 at 19:00
0

You have a controller, which is designed to be a conduit between the pages. You need to update it to have a function that returns the page you want, and from there you can access any of the attributes of that page.

First, add the following definition to MainWindow:

def get_page(self, page_class):
    return self.frames[page_class]

Next, save the Text widget to an instance variable:

class ReceiptPage(tk.Frame):
    def __init__(self, parent, controller):
        ...
        self.ReceiptBox = tk.Text(self, ...)
        ...

With that, you can access ReceiptBox from any other page like this:

receipt_page = self.controller.get_page(ReceiptPage)
receipt_page.delete("1.0", "end")

In your case you probably want to tie your button to a function that writes the receipt and then switches to it.

class ReservationPage(tk.Frame):

    def __init__(self, parent, controller):
        ...
        ReceiptPageButton1 = tk.Button(..., command=self.generate_receipt)
        ...

    def generate_receipt(self):
        receipt_page = self.controller.get_page(ReceiptPage)
        receipt_page.ReceiptBox.delete("1.0", "end")
        receipt_page.ReceiptBox.insert("end", "Here is your receipt...")
        self.controller.show_frame(ReceiptPage)
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685