-1

I have been working on a quizzing application recently and now I have come to making the GUI. I want to make it so that I can have a scroll bar for scrolling horizontally, whereas the vertical scroll bar would show up if the GUI length is greater than a certain length. Alas, I'm only a Tkinter beginner and am unable to figure out scrollbars. Please help me. Here is the code for the GUI:

    def run(self):
        self.root1 = tk.Tk()
        self.root1.protocol("WM_DELETE_WINDOW", self.cont)
        self.root1.resizable(False, False)
        self.root1.title(TITLE)
        QAS_SEQUENCED = qasSequenced
        ANSWERS = list(QAS_SEQUENCED.values())
        QUESTIONS = list(QAS_SEQUENCED.keys())
        print(QUESTIONS)
        print(ANSWERS)
        global ANSWER_FIELDS
        ANSWER_FIELDS = []
        ANSWER_FIELDS.clear()
        self.REPLIES_AA = []
        qColumnIndex = 1 #Current Column (Qs relative)
        qColumnIndex_ALIGN = 1
        numColumns = int(len(QUESTIONS)/10) #Num columns (Qs total)
        ROW = 0
        QUESTION = ""
        for i in range(0, len(QUESTIONS)):
            QUESTION_TMP = QUESTIONS[i]
            QUESTION = ""
            QUESTION_NEWLINE_INDEX = int(len(QUESTION_TMP)/40)
            QUESTION_NEWLINE_INDEX_USE = 1
            for ii in range(0, len(QUESTION_TMP)):
                QUESTION_TMP = str(QUESTION_TMP)
                if (ii+1) >= 40*QUESTION_NEWLINE_INDEX_USE or QUESTION_TMP[ii] == "`":
                    QUESTION += ("\n")
                    if not QUESTION_TMP[ii] == "`":
                        QUESTION += str(QUESTION_TMP[ii])
                    QUESTION_NEWLINE_INDEX_USE += 1
                else:
                    QUESTION += str(QUESTION_TMP[ii])
            QUESTION = str(QUESTION)
            ANSWERS[i] = str(ANSWERS[i])
            print('Setting up question ' + str(i+1))
            print('Question: ' + QUESTION + ' Answer: ' + ANSWERS[i] + "\n")
            if ROW > 10:
                qColumnIndex += 1
                qColumnIndex_ALIGN += 2
                ROW = 0
            QUESTION_TMP = tk.Label(self.root1)
            QUESTION_TMP.config(text=QUESTION)
            QUESTION_TMP.grid(row=ROW,column=(qColumnIndex_ALIGN-1))
            ANSWER_TEMP_ASF = tk.Entry(self.root1)
            ANSWER_TEMP_ASF.grid(row=ROW,column=(qColumnIndex_ALIGN))
            ANSWER_FIELDS.append(ANSWER_TEMP_ASF)
            ROW += 1
        if len(QUESTIONS) <= 10:
            self.submitButton = tk.Button(self.root1,text='SUBMIT ANSWERS',command=self.submitClick)
            self.submitButton.grid(row=(len(QUESTIONS)+1),column=1)
        else:
            self.submitButton = tk.Button(self.root1, text='SUBMIT ANSWERS', command=self.submitClick)
            self.submitButton.grid(row=(len(QUESTIONS)+1),column=1)
        self.root1.mainloop()
Syscall
  • 19,327
  • 10
  • 37
  • 52
Geetansh G
  • 17
  • 7
  • Please try to reduce this code down to a [mcve]. If the question is about scrollbars, we don’t all of the code dealing with the quiz features. – Bryan Oakley Mar 22 '20 at 04:00
  • @Brian Oakley the _**"run"_** method is the GUI creator of the application. Please refer to that if needed. There is no quizzing logic in the above-listed code except the answer field handling in the submit method. – Geetansh G Mar 22 '20 at 05:21
  • Right, _except the answer field handling_, which should be removed because it's irrelevant to the question being asked.It would also help if you explained why you think you need threading. For a simple quiz program, that seems like a lot of overhead. – Bryan Oakley Mar 22 '20 at 06:08
  • Read [Adding a scrollbar to a group of widgets in Tkinter](https://stackoverflow.com/a/3092341/7414759) – stovfl Mar 22 '20 at 10:13
  • @BryanOakley I require the threading because I run an external loop where all the quiz logic happens such as loading the questions, sequencing them, and saving the results. Or at least I think I need the threading; as I mentioned above, I am new to Tkinter and saw multiple people use this method to run external loops, therefore I did so as well. Also, I minimized the amount of code. – Geetansh G Mar 22 '20 at 21:26
  • @stovfl I have read that post already, however, I am not using "**Frame**" at all, instead, I'm using threading because I need an external loop. Can you help me translate the code for threading in that case? – Geetansh G Mar 22 '20 at 21:29
  • @GeetanshG ***"Tkinter scrollbar"***: You question is about `Scrollbar`. If you use a `Thread` to gather data that's irrelevant. ***"not using "Frame" at all"***: All `tkinter Toplevel` widgets provide a `Frame` interface. How do you think will your layout using `.grid(...` work? So go ahead and implement the solution from the given link. – stovfl Mar 22 '20 at 21:36
  • You would probably need a few thousand questions before the computations required would warrant using threads. I recommend you first get the code working without threads, and then add threads only when you learn that you need them. – Bryan Oakley Mar 22 '20 at 21:53
  • Please include some sample data, or a function that generates sample data. It looks like your data is just a dictionary, which should be easy for you to mock up. – Bryan Oakley Mar 22 '20 at 21:54
  • @BryanOakley I have developed this application with threading from the beginning; intending for an external loop to do all the computation. The only solution that worked for me was the one with threading. I am unable to simply remove the threading as the application no longer works ( have already attempted to do so upon multiple occasions) – Geetansh G Mar 22 '20 at 23:31

1 Answers1

0

Read Adding a scrollbar to a group of widgets in Tkinter -@stovfl

I read the above mentioned article and made a few, simple changes to my code. They go as followed:

def onFrameConfigure(self, canvas):
        '''Reset the scroll region to encompass the inner frame'''
        self.canvas.configure(scrollregion=self.canvas.bbox("all"))

    def run(self):
        self.root1 = tk.Tk()
        self.root1.protocol("WM_DELETE_WINDOW", self.cont)
        self.root1.resizable(True, True)
        self.root1.title(TITLE)
        self.canvas = tk.Canvas(self.root1, borderwidth=0)
        self.frame = tk.Frame(self.canvas)
        self.vsb = tk.Scrollbar(self.root1, orient="vertical", command=self.canvas.yview)
        self.xsb = tk.Scrollbar(self.root1, orient="horizontal",command=self.canvas.xview)
        self.canvas.configure(yscrollcommand=self.vsb.set,xscrollcommand=self.xsb.set)
        self.vsb.pack(side="right", fill="y")
        self.xsb.pack(side="bottom",fill="x")
        self.canvas.pack(side="left", fill="both", expand=True)
        self.canvas.create_window((6,6),window=self.frame, anchor="nw")
        self.frame.bind("<Configure>", lambda event, canvas=self.canvas: self.onFrameConfigure(self.canvas))
        QAS_SEQUENCED = qasSequenced
        ANSWERS = list(QAS_SEQUENCED.values())
        QUESTIONS = list(QAS_SEQUENCED.keys())

        print('SETUP Frame')

        print(QUESTIONS)
        print(ANSWERS)

        global ANSWER_FIELDS
        ANSWER_FIELDS = []
        ANSWER_FIELDS.clear()

        self.REPLIES_AA = []
        print('Set self.REPLIES_AA')

        qColumnIndex = 1 #Current Column (Qs relative)
        qColumnIndex_ALIGN = 1
        numColumns = int(len(QUESTIONS)/10) #Num columns (Qs total)
        ROW = 0

        QUESTION = ""

        for i in range(0, len(QUESTIONS)):
            QUESTION_TMP = QUESTIONS[i]
            QUESTION = ""
            QUESTION_NEWLINE_INDEX = int(len(QUESTION_TMP)/40)
            QUESTION_NEWLINE_INDEX_USE = 1

            for ii in range(0, len(QUESTION_TMP)):
                QUESTION_TMP = str(QUESTION_TMP)
                if (ii+1) >= 40*QUESTION_NEWLINE_INDEX_USE or QUESTION_TMP[ii] == "`":
                    QUESTION += ("\n")
                    if not QUESTION_TMP[ii] == "`":
                        QUESTION += str(QUESTION_TMP[ii])
                    QUESTION_NEWLINE_INDEX_USE += 1
                else:
                    QUESTION += str(QUESTION_TMP[ii])

            QUESTION = str(QUESTION)
            ANSWERS[i] = str(ANSWERS[i])

            print('Setting up question ' + str(i+1))
            print('Question: ' + QUESTION + ' Answer: ' + ANSWERS[i] + "\n")

            if ROW > 10:
                qColumnIndex += 1
                qColumnIndex_ALIGN += 2
                ROW = 0

            QUESTION_TMP = tk.Label(self.frame)
            QUESTION_TMP.config(text=QUESTION)
            QUESTION_TMP.grid(row=ROW,column=(qColumnIndex_ALIGN-1))

            ANSWER_TEMP_ASF = tk.Entry(self.frame)
            ANSWER_TEMP_ASF.grid(row=ROW,column=(qColumnIndex_ALIGN))
            ANSWER_FIELDS.append(ANSWER_TEMP_ASF)
            ROW += 1
        if len(QUESTIONS) <= 10:
            self.submitButton = tk.Button(self.frame,text='SUBMIT ANSWERS',command=self.submitClick)
            self.submitButton.grid(row=(len(QUESTIONS)+1),column=1)
        else:
            self.submitButton = tk.Button(self.frame, text='SUBMIT ANSWERS', command=self.submitClick)
            self.submitButton.grid(row=(len(QUESTIONS)+1),column=1)
        self.root1.mainloop()

These modifications did just as I wanted and now I am really happy about the outcome of this GUI!

Thank you to all that responded and helped.

Geetansh G
  • 17
  • 7