You need to enable JavaScript to run this app. 如何在Tkinter按钮点击事件中从GUI类调用测验逻辑类的方法
优惠活动
大模型
产品
解决方案
定价
更多

如何在Tkinter按钮点击事件中从GUI类调用测验逻辑类的方法

核心实现逻辑

你当前的代码存在类实例隔离、属性引用错误、基础容器未创建三类核心问题,可通过「主GUI类组合调用测验逻辑类」的方式实现需求,不需要用继承,耦合度更低。

  • 主GUI类提前创建所有页面容器,给触发测验开始的按钮绑定页面切换方法
  • 页面切换方法中完成容器切换后,直接将当前主GUI实例作为参数传给测验类,完成测验逻辑初始化
  • 测验类内部通过传入的主GUI实例操作窗口、容器等UI元素,不需要单独调用全局实例
修正后可运行代码
import tkinter as tk
from tkinter import tix 
from tkinter import ttk
import json
import tkinter.messagebox
import sqlite3

# 主GUI类
class Main:
    def __init__(self):
        self.root = tix.Tk()
        self.root.title("Quiz App")
        self.root.geometry("850x600+500+200")
        self.root.resizable(False,False)
        # 提前创建两个页面容器
        self.frame2 = tk.Frame(self.root)
        self.frame3 = tk.Frame(self.root)
        # frame2示例内容:登录页,你可以替换成自己的原有逻辑
        tk.Label(self.frame2, text="用户名:").grid(row=0, column=0, padx=10, pady=10)
        self.entry1 = tk.Entry(self.frame2)
        self.entry1.grid(row=0, column=1, padx=10, pady=10)
        tk.Label(self.frame2, text="密码:").grid(row=1, column=0, padx=10, pady=10)
        self.entry2 = tk.Entry(self.frame2, show="*")
        self.entry2.grid(row=1, column=1, padx=10, pady=10)
        # 登录按钮点击触发切换到测验页
        tk.Button(self.frame2, text="开始测验", command=self.frame2to3).grid(row=2, column=0, columnspan=2, pady=20)
        self.frame2.pack(fill="both", expand=True)

    # 切换到测验页并初始化测验逻辑
    def frame2to3(self):
        # 这里可以加用户名密码存入SQLite的逻辑,你可以自己补充
        self.frame2.pack_forget()
        self.frame3.pack(fill="both", expand=True)
        # 传入当前主GUI实例初始化测验类
        self.quiz = Quiz(main_gui=self)

    def clearfunc1(self):
        self.entry1.delete(0, 'end')
        self.entry2.delete(0, 'end')

    def clearfunc2(self):
        self.entry3.delete(0, 'end')
        self.entry4.delete(0, 'end')

    def close(self):
        if tkinter.messagebox.askyesno("Quiz App","Are you sure you want to exit?") > 0:
            self.root.destroy()
            return

# 测验逻辑类
class Quiz:
    # 接收主GUI实例参数
    def __init__(self, main_gui):
        self.main_gui = main_gui
        self.q_no = 0
        self.opt_selected = tk.IntVar()
        self.opts = self.radio_buttons()
        self.display_question()
        self.display_options()
        self.buttons()
        self.data_size = len(question)
        self.correct = 0

    def display_result(self):
        wrong_count = self.data_size - self.correct
        correct_text = f"Correct: {self.correct}"
        wrong_text = f"Wrong: {wrong_count}"
        score = int(self.correct/self.data_size*100)
        result = f"Score: {score}%"
        show_result = tk.Label(self.main_gui.frame3, text=f"{result}\n{correct_text}\n{wrong_text}")
        show_result.place(x=30, y=300)

    def check_ans(self, q_no):
        if self.opt_selected.get() == answer[q_no]:
            return True

    def next_btn(self):
        if self.check_ans(self.q_no):
            self.correct += 1
        self.q_no += 1
        if self.q_no == self.data_size:
            self.display_result()
            # 答题结束后禁用下一题按钮
            self.next_button.config(state="disabled")
        else:
            self.display_question()
            self.display_options()

    def buttons(self):
        self.next_button = tk.Button(self.main_gui.frame3, text = "下一题" , command=self.next_btn)
        self.next_button.place(x=780,y=550)
        self.exitButton3 = tk.Button(self.main_gui.frame3,text="Exit", command = self.main_gui.close)
        self.exitButton3.place(x=250,y=140)

    def display_options(self):
        val = 0
        self.opt_selected.set(0)
        for option in options[self.q_no]:
            self.opts[val]['text'] = option
            val += 1

    def display_question(self):
        # 先清空旧的问题标签
        for widget in self.main_gui.frame3.winfo_children():
            if isinstance(widget, tk.Label) and widget.winfo_y() == 90:
                widget.destroy()
        ques_no = tk.Label(self.main_gui.frame3, text=question[self.q_no])
        ques_no.place(x=30,y=90)

    def radio_buttons(self):
        q_list =[]
        y_pos = 150
        while len(q_list) < 4:
            radio_btn = tk.Radiobutton(self.main_gui.frame3, text = "", variable=self.opt_selected,value = len(q_list)+1)
            q_list.append(radio_btn)
            radio_btn.place(x=100,y=y_pos)
            y_pos += 30
        return q_list

if __name__ == "__main__":
    # 读取JSON题目数据
    with open('data1.json') as f:
        data1 = json.load(f)
    question = data1['question']
    options = data1['options']
    answer = data1['answer']
    # 启动主GUI
    app = Main()
    app.root.mainloop()
补充说明
  • 你可以在frame2to3方法中补充用户名密码写入SQLite的逻辑,直接用sqlite3库操作即可
  • 示例代码中给frame2加了基础的登录表单,你可以替换成自己原有UI逻辑
  • 原有代码中存在的变量名冲突、属性引用错误、页面元素残留问题都已经修复

内容的提问来源于stack exchange,提问作者akash_s93

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.14 20:24:01