如何正确填写输入字段,以及如何使根在需要时出现

问题描述 投票:0回答:1

所以,我正在 Python (Tkinter) 上创建一个数据库。一切都很顺利,直到我意识到当我尝试通过选择产品自动填充输入字段时,这些字段填充得不好。问题是,输入字段由树视图上的内容填充,我不知道如何制作,以便从 JOSN 文件中收集信息(树视图上的成本不会同时显示) ,因为有 2 个不同的选项,具体取决于您选择的选项是显示的选项,并且应用程序将计算增益和裕度)。另一件事是我有一个菜单窗口,在登录完成之前我无法让根不出现,所以你打开了两个窗口,这不太好(这更适合外观,但仍然如此)。我使用Python 3.13.0

对于填充的输入字段,我真的不知道该怎么办,我迷失了方向,这几天一直在抓耳挠腮。

对于我尝试在代码末尾使用

root.withdraw()
的菜单,它可以工作,但是当我完成登录时,“数据库”(主应用程序)不会打开。

(如果您看到我可以更改的内容,即使与问题无关,我也会很感激,我不是编程专业人士)

import tkinter as tk
from tkinter import messagebox, ttk
import json
import os

class User:
    def __init__(self, username, password):
        self.username = username
        self.password = password

    def to_dict(self):
        return {
            "username": self.username,
            "password": self.password
        }

    @classmethod
    def from_dict(cls, data):
        return cls(data['username'], data['password'])

    @staticmethod
    def save_users(users):
        with open('users.json', 'w') as f:
            json.dump([user.to_dict() for user in users], f)

    @staticmethod
    def load_users():
        if os.path.exists('users.json'):
            with open('users.json', 'r') as f:
                return [User.from_dict(item) for item in json.load(f)]
        return []

class Product:
    def __init__(self, name, price, cost_lb, cost_pm, weight, store_prices=None):
        self.name = name
        self.price = price
        self.cost_lb = cost_lb
        self.cost_pm = cost_pm
        self.weight = weight
        self.store_prices = store_prices if store_prices is not None else {}

    def gain(self, use_cost_lb=True):
        return self.price - (self.cost_lb if use_cost_lb else self.cost_pm)

    def margin(self, use_cost_lb=True):
        gain = self.gain(use_cost_lb)
        return (gain / self.price) * 100 if self.price > 0 else 0

    def to_dict(self):
        return {
            "name": self.name,
            "price": self.price,
            "cost_lb": self.cost_lb,
            "cost_pm": self.cost_pm,
            "weight": self.weight,
            "store_prices": self.store_prices
        }

    @classmethod
    def from_dict(cls, data):
        return cls(data['name'], data['price'], data['cost_lb'], data['cost_pm'], data['weight'], data.get('store_prices', {}))

class Store:
    def __init__(self):
        self.products = []
        self.load_products()

    def add_product(self, name, price, cost_lb, cost_pm, weight):
        product = Product(name, price, cost_lb, cost_pm, weight)
        self.products.append(product)
        self.save_products()

    def delete_product(self, name):
        self.products = [product for product in self.products if product.name != name]
        self.save_products()

    def update_product(self, name, price=None, cost_lb=None, cost_pm=None, weight=None):
        for product in self.products:
            if product.name == name:
                if price is not None:
                    product.price = price
                if cost_lb is not None:
                    product.cost_lb = cost_lb
                if cost_pm is not None:
                    product.cost_pm = cost_pm
                if weight is not None:
                    product.weight = weight
                break
        self.save_products()

    def save_products(self):
        with open('products.json', 'w') as f:
            json.dump([product.to_dict() for product in self.products], f)

    def load_products(self):
        if os.path.exists('products.json'):
            with open('products.json', 'r') as f:
                self.products = [Product.from_dict(item) for item in json.load(f)]
       
class StoreApp:
    def __init__(self, root):
        self.root = root
        self.root.title("RenoCart")
        self.store = Store()
        self.users = User.load_users()  # Load existing users
        self.current_user = None  # Track the currently logged-in user

        self.show_menu()

    def center_window(self, window, width, height):
        screen_width = window.winfo_screenwidth()
        screen_height = window.winfo_screenheight()
        
        x = (screen_width // 2) - (width // 2)
        y = (screen_height // 2) - (height // 2)
        
        window.geometry(f"{width}x{height}+{x}+{y}")

    def show_menu(self):
        self.clear_frame()
        menu_window = tk.Toplevel(self.root)
        menu_window.title("Main Menu")
        self.center_window(menu_window, 210, 250)


        title_label = tk.Label(menu_window, text="RenoCart", font=("Helvetica", 16))
        title_label.pack(pady=10)

        # Login button
        login_button = tk.Button(menu_window, text="Login", command=self.open_login_window)  # Changed this line
        login_button.pack(pady=5)

        # Sign-up button
        signup_button = tk.Button(menu_window, text="Sign Up", command=self.signup_user)
        signup_button.pack(padx=7.5)

        # Quit Button
        quit_button = tk.Button(menu_window, text="Close", command=self.root.quit)
        quit_button.pack(pady=10)

    def signup_user(self):
        signup_window = tk.Toplevel(self.root)
        signup_window.title("Sign up")
        signup_window.geometry("300x200")  
        self.center_window(signup_window, 210, 220)

        # Username label and entry
        username_label = tk.Label(signup_window, text="Username:")
        username_label.pack()
        username_entry = tk.Entry(signup_window)
        username_entry.pack()

        # Password label and entry
        password_label = tk.Label(signup_window, text="Password:")
        password_label.pack()
        password_entry = tk.Entry(signup_window, show="*")
        password_entry.pack()

        # Code for signup
        code_label = tk.Label(signup_window, text="Sign Up Code:")
        code_label.pack()
        code_entry = tk.Entry(signup_window)
        code_entry.pack(pady=5)

        # Sign Up button
        signup_button = tk.Button(signup_window, text="Sign Up", command=lambda: self.signup(username_entry.get(), password_entry.get(), code_entry.get()))
        signup_button.pack(pady=10)

        # Back to menu button
        back_button = tk.Button(signup_window, text="Back", command=self.show_menu)
        back_button.pack()

    def signup (self, username, password, code):
        required_code = "1234"  # The required code for sign-up
        if code != required_code:
            tk.messagebox.showerror("Error", "Invalid sign-up code.")
            return

        if any(user.username == username for user in self.users):
            tk.messagebox.showerror("Error", "Username already exists.")
            return

        new_user = User(username, password)
        self.users.append(new_user)
        User.save_users(self.users)

        tk.messagebox.showinfo("Success", "User signed up successfully!")

    def clear_frame(self):
        # Remove all widgets from the frame
        for widget in self.root.winfo_children():
            widget.destroy()

    def open_login_window(self):
        login_window = tk.Toplevel(self.root)
        login_window.title("Login")
        login_window.geometry("300x200")     
        self.center_window(login_window, 210, 220)  

        # Username Entry
        username_label = tk.Label(login_window, text="Username:")
        username_label.pack(pady=5)
        username_entry = tk.Entry(login_window)
        username_entry.pack(pady=5)

        # Password Entry
        password_label = tk.Label(login_window, text="Password:")
        password_label.pack(pady=5)
        password_entry = tk.Entry(login_window, show="*")
        password_entry.pack(pady=5)

        # Login Button
        login_button = tk.Button(login_window, text="Login", command=lambda: self.login_user(username_entry.get(), password_entry.get(), login_window))
        login_button.pack(pady=10)

        # Cancel Button
        cancel_button = tk.Button(login_window, text="Cancel", command=login_window.destroy)
        cancel_button.pack(pady=5)

    def login_user(self, username, password, login_window):
        users = User.load_users()  # Load users from the JSON file
        for user in users:
            if user.username == username and user.password == password:
                tk.messagebox.showinfo("Success", "Login successful!")
                login_window.destroy()  # Close the login window
                self.access_app()  # Proceed to the next screen
                return
        tk.messagebox.showerror("Error", "Invalid username or password.")

    def access_app(self):
        self.clear_frame()  
        self.create_widgets()       

    def create_widgets(self):
        # Input
        self.name_var = tk.StringVar()
        self.price_var = tk.DoubleVar()
        self.cost_lb_var = tk.DoubleVar()
        self.cost_pm_var = tk.DoubleVar()
        self.weight_var = tk.DoubleVar()
        self.cost_type = tk.StringVar(value="L&B")
        self.search_var = tk.StringVar()
        self.weight_unit = tk.StringVar(value="lbs")

        tk.Label(self.root, text="Name:").grid(row=0, column=0)
        tk.Entry(self.root, textvariable=self.name_var).grid(row=0, column=1)
        tk.Button(self.root, text="Add", command=self.add_product).grid(row=0, column=2)

        tk.Label(self.root, text="Price:").grid(row=1, column=0)
        tk.Entry(self.root, textvariable=self.price_var).grid(row=1, column=1)
        tk.Button(self.root, text="Delete", command=self.delete_product).grid(row=1, column=2)

        tk.Label(self.root, text="L&B Cost:").grid(row=2, column=0)
        tk.Entry(self.root, textvariable=self.cost_lb_var).grid(row=2, column=1)
        tk.Button(self.root, text="Update", command=self.update_product).grid(row=2, column=2)

        tk.Label(self.root, text="Pont-Masson Cost:").grid(row=3, column=0)
        tk.Entry(self.root, textvariable=self.cost_pm_var).grid(row=3, column=1)

        tk.Label(self.root, text="Weight (lbs):").grid(row=4, column=0)
        tk.Entry(self.root, textvariable=self.weight_var).grid(row=4, column=1)

        # Weight unit selection
        tk.Label(self.root, text="Weight Unit:").grid(row=4, column=2)
        tk.OptionMenu(self.root, self.weight_unit, "lbs", "kg").grid(row=4, column=3)

        # Cost type selection
        tk.Label(self.root, text="Select Cost Type for Margin:").grid(row=5, column=0, columnspan=2)
        tk.OptionMenu(self.root, self.cost_type, "L&B", "Pont-Masson").grid(row=6, column=0, columnspan=2)

        # Search
        tk.Label(self.root, text="Search:").grid(row=7, column=0)
        tk.Entry(self.root, textvariable=self.search_var).grid(row=7, column=1)
        tk.Button(self.root, text="Search", command=self.search_products).grid(row=7, column=2)

        # Refresh button
        tk.Button(self.root, text="Refresh", command=self.show_products).grid(row=8, column=0, columnspan=3, sticky="w")

        # Clear button
        tk.Button(self.root, text="Clear", command=self.clear_selection).grid(row=3, column=2)

        # Compare Prices button
        tk.Button(self.root, text="Compare Prices", command=self.open_price_comparison).grid(row=8, column=3)

        # Treeview for displaying products
        self.tree = ttk.Treeview(self.root, columns=("Name", "Cost", "Price", "Gain", "Margin", "Weight"), show='headings')
        self.tree.heading("Name", text="Name")
        self.tree.heading("Cost", text="Cost")
        self.tree.heading("Price", text="Price")
        self.tree.heading("Gain", text="Gain")
        self.tree.heading("Margin", text="Margin (%)")
        self.tree.heading("Weight", text="Weight")

        # Column centering
        for col in ("Cost", "Price", "Gain", "Margin", "Weight"):
            self.tree.column(col, anchor='center')

        self.tree.grid(row=9, column=0, columnspan=5)

        self.tree.bind("<<TreeviewSelect>>", self.on_product_select)  # Bind selection event

        # Show products
        self.show_products()

    def add_product(self):
        name = self.name_var.get()
        try:
            price = self.price_var.get()
            cost_lb = self.cost_lb_var.get()
            cost_pm = self.cost_pm_var.get()
            weight = self.weight_var.get()

            if not name:
                raise ValueError("Product name cannot be empty.")
            if price < 0 or cost_lb < 0 or cost_pm < 0 or weight < 0:
                raise ValueError("Price and costs must be non-negative.")

            self.store.add_product(name, price, cost_lb, cost_pm, weight)
            self.clear_entries()
            self.show_products()
        except ValueError as e:
            messagebox.showerror("Error", str(e))

    def delete_product(self):
        selected_item = self.tree.selection()
        if not selected_item:
            messagebox.showwarning("Select Product", "Please select a product to delete.")
            return
        item_id = selected_item[0]
        product_name = self.tree.item(item_id, "values")[0]

        confirm_delete = messagebox.askyesno("Confirm Delete", f"Are you sure you want to delete '{product_name}'?")
        if confirm_delete:
            self.store.delete_product(product_name)
            messagebox.showinfo("Success", f"Product '{product_name}' deleted.")
            self.clear_entries()
            self.show_products()

    def update_product(self):
        selected_item = self.tree.selection()
        if not selected_item:
            messagebox.showwarning("Select Product", "Please select a product to update.")
            return
        item_id = selected_item[0]
        product_name = self.tree.item(item_id, "values")[0]
        
        price = self.price_var.get() or None
        cost_lb = self.cost_lb_var.get() or None
        cost_pm = self.cost_pm_var.get() or None
        weight = self.weight_var.get() or None
        
        self.store.update_product(product_name, price, cost_lb, cost_pm, weight)
        messagebox.showinfo("Success", f"Product '{product_name}' updated.")
        self.clear_entries()
        self.show_products()

    def show_products(self):

        for item in self.tree.get_children():
            self.tree.delete(item)
        for product in self.store.products:
            use_cost_lb = self.cost_type.get() == "L&B"
            cost = product.cost_lb if use_cost_lb else product.cost_pm
            gain = product.gain(use_cost_lb)
            margin = product.margin(use_cost_lb)

            # Convert weight based on selection
            weight_display = product.weight
            if self.weight_unit.get() == "kg":
                weight_display = weight_display * 0.453592  # Convert lbs to kg

            self.tree.insert("", "end", values=(
                product.name,
                f"${cost:.2f}",
                f"${product.price:.2f}",
                f"${gain:.2f}",
                f"{margin:.2f}%",
                f"{weight_display:.2f} {self.weight_unit.get()}"
            ))

    def search_products(self):
        search_term = self.search_var.get().lower()
        for item in self.tree.get_children():
            self.tree.delete(item)
        for product in self.store.products:
            if search_term in product.name.lower():
                use_cost_lb = self.cost_type.get() == "L&B"
                cost = product.cost_lb if use_cost_lb else product.cost_pm
                gain = product.gain(use_cost_lb)
                margin = product.margin(use_cost_lb)

                weight_display = product.weight
                if self.weight_unit.get() == "kg":
                    weight_display = weight_display * 0.453592

                self.tree.insert("", "end", values=(
                    product.name,
                    f"${cost:.2f}",
                    f"${product.price:.2f}",
                    f"${gain:.2f}",
                    f"{margin:.2f}%",
                    f"{weight_display:.2f} {self.weight_unit.get()}"
                ))

    def clear_entries(self):
        self.name_var.set("")
        self.price_var.set(0)
        self.cost_lb_var.set(0)
        self.cost_pm_var.set(0)
        self.weight_var.set(0)

    def clear_selection(self):
        self.tree.selection_remove(self.tree.selection())  # Deselect any selected item
        self.clear_entries()

    def on_product_select(self, event):
        selected_item = self.tree.selection()
        if not selected_item:
            return

        item_id = selected_item[0]
        product_data = self.tree.item(item_id, "values")

        # Order of values in product_data is (Name, Cost, Price, Gain, Margin, Weight)
        self.name_var.set(product_data[0])  # Set product name
        self.cost_lb_var.set(float(product_data[1][1:]))  # L&B Cost (remove '$' sign)
        self.price_var.set(float(product_data[2][1:]))    # Price (remove '$' sign)
        self.cost_pm_var.set(float(product_data[1][1:]))  # Pont-Masson Cost (remove '$' sign)
        self.weight_var.set(float(product_data[5].split()[0]))  # Weight (extract value)

    def open_price_comparison(self):
        selected_item = self.tree.selection()
        if not selected_item:
            messagebox.showwarning("Select Product", "Please select a product to compare prices.")
            return
        item_id = selected_item[0]
        product_name = self.tree.item(item_id, "values")[0]
        product = next((p for p in self.store.products if p.name == product_name), None)
        if product:
            PriceComparisonWindow(self.root, product)

class PriceComparisonWindow:
    def __init__(self, parent, product):
        self.top = tk.Toplevel(parent)
        self.top.title(f"Price Comparison for {product.name}")
        self.product = product
        
        # Store labels and entry fields for each store
        self.store_vars = {
            "Rona": tk.DoubleVar(value=self.product.store_prices.get("Rona", 0)),
            "Home Depot": tk.DoubleVar(value=self.product.store_prices.get("Home Depot", 0)),
            "Patrick Morin": tk.DoubleVar(value=self.product.store_prices.get("Patrick Morin", 0)),
            "BMR": tk.DoubleVar(value=self.product.store_prices.get("BMR", 0)),
        }

        tk.Label(self.top, text="Store Prices").grid(row=0, column=0, columnspan=2)

        for idx, (store, var) in enumerate(self.store_vars.items()):
            tk.Label(self.top, text=store).grid(row=idx + 1, column=0)
            entry = tk.Entry(self.top, textvariable=var)
            entry.grid(row=idx + 1, column=1)
            entry.bind("<KeyRelease>", self.update_price_info)  # Update on key release

        tk.Button(self.top, text="Save", command=self.save_prices).grid(row=len(self.store_vars) + 1, columnspan=2)

        # Labels for comparison results
        self.comparison_labels = {}
        for idx, store in enumerate(self.store_vars.keys()):
            label = tk.Label(self.top, text="")
            label.grid(row=len(self.store_vars) + 2 + idx, columnspan=2)
            self.comparison_labels[store] = label

        # Label for cheapest store
        self.cheapest_store_label = tk.Label(self.top, text="", font=('Arial', 10, 'bold'))
        self.cheapest_store_label.grid(row=len(self.store_vars) + len(self.comparison_labels) + 2, columnspan=2)

        # Label for most expensive store
        self.most_expensive_store_label = tk.Label(self.top, text="", font=('Arial', 10, 'bold'))
        self.most_expensive_store_label.grid(row=len(self.store_vars) + len(self.comparison_labels) + 3, columnspan=2)

        self.update_price_info()

    def save_prices(self):
        for store, var in self.store_vars.items():
            self.product.store_prices[store] = var.get()
        messagebox.showinfo("Success", "Prices saved successfully.")
        self.update_price_info()

    def update_price_info(self, event=None):
        prices = {store: var.get() for store, var in self.store_vars.items()}

        # Update comparison labels
        for store, price in prices.items():
            if self.product.price < price:
                comparison_text = f"Your price is Lower than {store}"
            elif self.product.price > price:
                comparison_text = f"Your price is Higher than {store}"
            else:
                comparison_text = f"Your price is the Same as {store}"
            self.comparison_labels[store].config(text=comparison_text)

        # Calculate the cheapest store
        cheapest_store = min(prices, key=prices.get)
        cheapest_price = prices[cheapest_store]
        self.cheapest_store_label.config(text=f"Cheapest Store: {cheapest_store} - ${cheapest_price:.2f}")

        # Calculate the most expensive store
        most_expensive_store = max(prices, key=prices.get)
        most_expensive_price = prices[most_expensive_store]
        self.most_expensive_store_label.config(text=f"Most Expensive Store: {most_expensive_store} - ${most_expensive_price:.2f}")

if __name__ == "__main__":
    root = tk.Tk()
    app = StoreApp(root)
    root.mainloop()
python tkinter field tkinter-entry python-3.13
1个回答
0
投票

双窗口问题是由库架构引起的。库会自动创建根窗口以及在其之上构建的所有内容。如果删除它,关闭它,所有 gui 应用程序都可能会出现意外的行为。因此,您可以在根窗口内创建一个框架,并用登录屏幕元素填充它。用户登录后,删除或清除框架并通过第二阶段。

您的其他问题的解决方案就在这里。

此函数从给定产品的 json 文件中获取数据。

def get_product_data_db(self, product_name): 
    with open("products.json","r") as f:
        text = f.read()
        product_list = json.loads(text)

    for product in product_list:
        if(product["name"] == product_name):
            return product

你的 on_product_select 函数应该像这样完善。

def on_product_select(self, event):
    selected_item = self.tree.selection()
    if not selected_item:
        return

    item_id = selected_item[0]
    selected_product = self.tree.item(item_id, "values")

    product_data = self.get_product_data_db(selected_product[0])
    self.name_var.set(product_data["name"]) 
    self.cost_lb_var.set(product_data["cost_lb"])
    self.price_var.set(product_data["price"])
    self.cost_pm_var.set(product_data["cost_pm"])
    self.weight_var.set(product_data["weight"]) 

因此,您可以从文件夹中获取数据并单独分配它们。

© www.soinside.com 2019 - 2024. All rights reserved.