2

我想编写一个程序,在不同的对话框中向用户询问一系列问题。每个框一次显示一个,如果单击下一步按钮,则转到下一个框。我的问题是我是否为每个对话框创建一个类,并在单击下一步按钮后调用下一个类?或者有更优雅的解决方案吗?

4

2 回答 2

3

我的建议是构建一个包含当前问题的基类,然后当用户回答一个问题并进入下一个问题时,基类会更新新的当前问题的显示。您不需要在任何时候销毁小部件(退出应用程序时除外),您还可以在创建新小部件之前重用小部件。

让我将你的问题的格式简化为这个:每个问题都包含一个问题描述和一组答案,用户可以在其中选择一个答案。这些简化可以删除,但我设置它们是为了提供一个初始代码来处理问题。这是这样做的起点(我对命名的想象力很弱):

import random
import Tkinter
import ttk

# Make 5 "questions" with varied number of answers to pick from.
QUESTION = [u"Question %d" % (i + 1) for i in range(5)]
QOPTS = []
k = 1
for _ in QUESTION:
    num_opts = random.randint(3, 6)
    QOPTS.append([u"text %d" % (k + i) for i in range(num_opts)])
    k += num_opts


class Question:
    def __init__(self, master):
        self._common_var = Tkinter.StringVar()

        self._title = None
        self._lframe = None
        self._rb = []
        self._make_gui(master)

    def get_answer(self):
        return self._common_var.get()

    def reset_answer(self):
        self._common_var.set("")

    def _make_gui(self, master):
        self._title = ttk.Label(master, padding=(0, 6, 0, 0))
        self._title.grid(in_=master, padx=6, row=0, column=0, sticky='ew')

        self._lframe = ttk.Labelframe(master)
        self._lframe.grid(in_=master, padx=6, row=1, column=0, sticky='nsew')

    def update_gui(self, question, options):
        self._title['text'] = question
        for i, opt in enumerate(options):
            if i < len(self._rb):
                if not self._rb[i].grid_info():
                    self._rb[i].grid()
                self._rb[i]['text'] = opt
            else:
                rb = ttk.Radiobutton(self._lframe, text=opt, value=i,
                        variable=self._common_var)
                rb.grid(in_=self._lframe, row=i, column=0, sticky='w')
                self._rb.append(rb)
        # Deal with i < total.
        for k in xrange(i + 1, len(self._rb)):
            self._rb[k].grid_remove()



class Base:
    def __init__(self, frame, q, o):
        self.master = frame

        self.question = None
        self.curr_question = 0
        self.q = q
        self.o = o
        self._make_gui(frame)
        self._update_gui()

    def next_question(self):
        answer = self.question.get_answer()
        try:
            answer = int(answer)
        except ValueError:
            print "Question not answered, stay here."
            return
        print "Answer for question %d: %d" % (self.curr_question, answer)
        self.question.reset_answer()

        self.curr_question += 1
        self._update_gui()

    def _make_gui(self, frame):
        self.question = Question(frame)
        frame.columnconfigure(0, weight=1)
        frame.rowconfigure(1, weight=1)

        btn = [(u"Next", self.next_question)]
        self._btn = []
        for i, (text, cmd) in enumerate(btn):
            # Assumption: the Question instance always uses the rows 0 and 1.
            b = ttk.Button(frame, text=text, command=cmd)
            b.grid(in_=frame, padx=6, pady=6, row=2, column=i, sticky='e')
            self._btn.append(b)

    def _update_gui(self):
        if self.curr_question == len(self.q):
            print "Done"
            self.master.quit()
            return
        elif self.curr_question == len(self.q) - 1:
            for btn in self._btn:
                # No next question
                btn['text'] = u"Finish"

        self.question.update_gui(self.q[self.curr_question],
                self.o[self.curr_question])


root = Tkinter.Tk()
root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)
root.geometry('300x250')
frame = ttk.Frame(root)
frame.grid(sticky='nsew')
Base(frame, QUESTION, QOPTS)
root.mainloop()

这是您将获得的 GUI:

在此处输入图像描述 在此处输入图像描述

于 2012-12-21T02:40:08.880 回答
0

你确定你必须为对话框创建一个类吗?Tkinter 内置对话框类不好吗?您可以为函数提供 Dialogs 的迭代器next(),每个 Next 按钮在单击时都会调用该迭代器。你的意思是这样的吗?

于 2012-12-14T09:33:26.147 回答