Table input value not being stored to be retrieved outside of customtkinter table editing interface

I’ve build a dataframe editor that has an entry box at the top for someone to put their name in. I’ve tried several different ways to store the input into the “reviewed_by” variable, but it always returns blank, both inside and outside of the class. What could be happening here? How can I fix it?

class DataFrameEditor(ctk.CTk):
    def __init__(self, dataframe, corresponding_value, selected_month):
        super().__init__()
        self.title("Review Invoice")
        self.geometry("725x660")  # Adjusted window size

        self.dataframe = dataframe.copy().fillna(0)  # Replace NaN with 0
        self.entries = {}
        self.reviewed_by = tk.StringVar()

        # Add title rows to the DataFrame
        self.add_title_rows_to_dataframe()

        # Upper frame with logo, corresponding_value, selected_month, and reviewed_by
        upper_frame = ctk.CTkFrame(self)
        upper_frame.pack(fill="x", padx=10, pady=9)

        # Load and display the logo after the main window is set up
        script_dir = os.path.dirname(os.path.abspath(__file__))
        logo_path = os.path.join(script_dir, "logo.png")

        self.logo_image = Image.open(logo_path)
        self.logo_image = self.logo_image.resize((220, 50), Image.LANCZOS)
        self.logo_image = ImageTk.PhotoImage(master=self, image=self.logo_image)
        
        logo_label = ctk.CTkLabel(upper_frame, image=self.logo_image, text="")
        logo_label.pack(side="left", padx=10)

        # Display corresponding_value and selected_month with reduced text size by 1
        details_frame = ctk.CTkFrame(upper_frame)
        details_frame.pack(side="left", padx=20, pady=10)  # Added padding

        # Program label and value on the same line
        program_label = ctk.CTkLabel(details_frame, text=f"Program: ", font=("Arial bold", 11))
        program_label.grid(row=0, column=0, sticky='w', padx=5)
        program_value_label = ctk.CTkLabel(details_frame, text=corresponding_value, font=("Arial", 11))
        program_value_label.grid(row=0, column=1, sticky='w', padx=5)

        # Month label and value on the same line, below the Program line
        month_label = ctk.CTkLabel(details_frame, text=f"Month: ", font=("Arial bold", 11))
        month_label.grid(row=1, column=0, sticky='w', padx=5, pady=(5, 0))
        month_value_label = ctk.CTkLabel(details_frame, text=selected_month, font=("Arial", 11))
        month_value_label.grid(row=1, column=1, sticky='w', padx=5, pady=(5, 0))

        # Reviewed by text box
        reviewed_by_frame = ctk.CTkFrame(upper_frame)
        reviewed_by_frame.pack(side="right", padx=10)

        reviewed_by_label = ctk.CTkLabel(reviewed_by_frame, text="Reviewed by:", font=("Arial", 12))
        reviewed_by_label.pack(side="top")
        reviewed_by_entry = ctk.CTkEntry(reviewed_by_frame, textvariable=self.reviewed_by, width=200)
        reviewed_by_entry.pack(side="top", pady=5)

        self.frame = ctk.CTkFrame(self, fg_color="#302c2c")
        self.frame.pack(fill="both", expand=True, padx=20, pady=20)  # Center the frame within the main window

        self.table = ctk.CTkScrollableFrame(self.frame, fg_color="#302c2c")
        self.table.pack(fill="both", expand=True, padx=(30, 0))  # Keep the table as it was inside the frame

        self.build_table()

        button_frame = ctk.CTkFrame(self.frame)
        button_frame.pack(fill="x", pady=10)

        self.update_button = ctk.CTkButton(button_frame, text="Update", command=self.update_all_totals, fg_color="#5fa35f", width=100)
        self.submit_button = ctk.CTkButton(button_frame, text="Submit", command=self.submit, width=100)

        button_frame.grid_columnconfigure(0, weight=1)
        button_frame.grid_columnconfigure(1, weight=1)

        self.update_button.grid(row=0, column=0, padx=5, pady=5, sticky='ew')
        self.submit_button.grid(row=0, column=1, padx=5, pady=5, sticky='ew')

        # Initialize reviewed_by_value to ensure it captures the input value
        self.reviewed_by_value = ""

    def add_title_rows_to_dataframe(self):
        # Create a list of tuples where each tuple contains a title and its insertion index
        title_rows = [
            ("Account Management", 0),
            ("Other Variable Fees", self.dataframe[self.dataframe['Item'] == "Documentation (additional B.U.s, brands, processes, etc.)"].index[0]),
            ("Warehouse Fees", self.dataframe[self.dataframe['Item'] == "Receiving minimum fee (Pallet / Sku)"].index[0]),
            ("Courier", self.dataframe[self.dataframe['Item'] == "Carrier Pass through Costs (Estimate, actuals will be billed) ATS ambient"].index[0])
        ]

        # Insert titles in reverse order to maintain correct positions
        for title, index in sorted(title_rows, key=lambda x: x[1], reverse=True):
            title_row = pd.DataFrame({"Item": [title], "RATES": [None], "MULTIPLE": [None], "TOTAL": [None]})
            self.dataframe = pd.concat([self.dataframe.iloc[:index], title_row, self.dataframe.iloc[index:]]).reset_index(drop=True)

    def build_table(self):
        for i, column in enumerate(self.dataframe.columns):
            label = ctk.CTkLabel(self.table, text=column)
            label.grid(row=0, column=i, padx=5, pady=5)

        for row_index, row in self.dataframe.iterrows():
            for col_index, value in enumerate(row):
                if pd.isna(value):  # Check if the value is NaN (title rows will have NaN values)
                    label = ctk.CTkLabel(self.table, text=row["Item"], anchor='center', fg_color="#4d4d4d")
                    label.grid(row=row_index + 1, column=0, columnspan=len(self.dataframe.columns), padx=5, pady=5, sticky='ew')
                    break
                elif col_index == 0:  # Item Description
                    label = ctk.CTkLabel(self.table, text=str(value)[:60], anchor='w')  # Display only first 30 characters
                    label.grid(row=row_index + 1, column=col_index, padx=5, pady=5, sticky='w')
                    self.table.columnconfigure(col_index, minsize=150)  # Set a minimum width for the Item column
                elif col_index == 1:  # Rates
                    label = ctk.CTkLabel(self.table, text=f"{value:.2f}" if value != 0 else "0.00")
                    label.grid(row=row_index + 1, column=col_index, padx=5, pady=5)
                elif col_index == 2:  # Multiple
                    entry = ctk.CTkEntry(self.table)
                    entry.insert(0, f"{value:.2f}" if value != 0 else "0.00")
                    entry.grid(row=row_index + 1, column=col_index, padx=5, pady=5)
                    entry.bind("<FocusOut>", self.update_total(row_index, entry))
                    entry.bind("<Return>", self.update_total(row_index, entry))  # Update on pressing Enter key
                    self.entries[(row_index, col_index)] = entry
                else:  # Total
                    label = ctk.CTkLabel(self.table, text=f"{value:.2f}" if value != 0 else "0.00")
                    label.grid(row=row_index + 1, column=col_index, padx=5, pady=5)

    def update_total(self, row_index, entry):
        def callback(event):
            try:
                item_description = self.dataframe.at[row_index, 'Item']
                print(f"Updating row: {row_index}, Item: {item_description}")

                if pd.isna(self.dataframe.at[row_index, 'RATES']):  # Check if the row is a title row
                    print(f"Skipping title row during update_total: {item_description}")
                    return

                multiple = float(entry.get()) if entry.get() else 0.0  # Ensure float and handle empty input
                rate = float(self.dataframe.iloc[row_index, 1])  # Assuming "RATES" is the second column
                total = round(rate * multiple, 2)  # Ensure 2 decimal places for "Total"
                self.dataframe.at[row_index, 'MULTIPLE'] = multiple
                self.dataframe.at[row_index, 'TOTAL'] = total

                # Update the corresponding labels in the table
                self.update_labels(row_index + 1, total)
            except ValueError:
                print(f"Error: Invalid input for 'Multiple' at row {row_index}")

        return callback

    def update_labels(self, row_index, total):
        for col_index, value in enumerate(self.dataframe.iloc[row_index - 2]):
            if col_index == 3:  # "Total" column
                total_label = self.table.grid_slaves(row=row_index, column=col_index)[0]
                total_label.configure(text=f"{total:.2f}")

    def update_all_totals(self):
        for (row_index, col_index), entry in self.entries.items():
            item_description = self.dataframe.at[row_index, 'Item']
            print(f"Processing row: {row_index}, Item: {item_description}")

            if pd.isna(self.dataframe.at[row_index, 'RATES']):  # Check if the row is a title row
                print(f"Skipping title row during update_all_totals: {item_description}")
                continue

            multiple = float(entry.get()) if entry.get() else 0.0  # Ensure float and handle empty input
            rate = float(self.dataframe.iloc[row_index, 1])  # Assuming "RATES" is the second column
            total = round(rate * multiple, 2)  # Ensure 2 decimal places for "Total"
            self.dataframe.at[row_index, 'MULTIPLE'] = multiple
            self.dataframe.at[row_index, 'TOTAL'] = total
            self.update_labels(row_index + 1, total)

    def submit(self):
        try:
            self.update_all_totals()
            # Remove title rows before saving
            self.dataframe = self.dataframe.dropna(subset=['RATES'])
            self.dataframe['MULTIPLE'] = self.dataframe['MULTIPLE'].astype(float).fillna(0)
            self.dataframe['TOTAL'] = self.dataframe['TOTAL'].astype(float).fillna(0)
            self.reviewed_by_value = self.reviewed_by.get()  # Ensure this captures the input value
            print("Updated DataFrame before closing the editor:n", self.dataframe)
            print("Reviewed by (inside submit):", self.reviewed_by_value)  # Print inside submit method
            self.quit()
            self.destroy()
        except Exception as e:
            print(f"Error: {e}")

# Display the DataFrame editor for user input
app = DataFrameEditor(template, corresponding_value, selected_month)
app.mainloop()

updated_template = app.dataframe
reviewed_by = app.reviewed_by_value

I have a similar script that works fine in another implementation, using the same environment. Strangely, for the code I’ve posted here, I’ve had to change the way the logo.png is loaded by setting “master=self” – otherwise, it wouldn’t recognize the file in the directory. I feel like that is related, but I’m not sure why the issue occured.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật