PythonProgrammi
PythonProgrammi

Reputation: 23443

How to add a scrollbar to window made with tkinter

A simple quiz game

I got this code and I need scrollbars, I tried to search how to add it on stackoverflow (ScrolledWindow with tix...) but I still can't get something that works properly. Could someone help me?

from tkinter import *
from random import randint

root = Tk()
root.title("Quiz")
root.geometry("400x300")


class Window:

    def __init__(self, question, answer):
        self.text = [question, answer]
        self.createLabel()
        # self.createText()
        self.createEntry()
        self.createButton()

    def retrieve_input(self):
        # inputValue = self.textBox.get("1.0", "end-1c")
        # print(inputValue)
        if self.mystring.get() == self.text[1]:
            print("Esatto. è " + self.text[1])
            self.left['text'] = "Esatto"

    def createLabel(self):
        self.labelframe = LabelFrame(root, text="Domanda:")
        self.labelframe.pack(fill="both", expand="yes")
        self.left = Label(self.labelframe, text=self.text[0])
        self.left.pack()

    def createText(self):
        self.textBox = Text(height=1)
        self.textBox.pack()

    def createEntry(self):
        self.mystring = StringVar()
        self.myentry = Entry(root, textvariable=self.mystring).pack()

    def createButton(self):
        self.but = Button(text="Click", command=self.retrieve_input)
        self.but.pack()


for i in range(10):
    one = randint(1, 10)
    two = randint(1, 10)
    Window("Quanto fa " + str(one) + "+" + str(two) + "?", str(one + two))

root.mainloop()

output

enter image description here

Upvotes: 4

Views: 5672

Answers (1)

furas
furas

Reputation: 142631

With ScrolledFrame it can look like this

enter image description here

  • I renamed Window into Question because it makes more sense
  • I use self.question and self.answer instead of self.text = [question, answer] to make it more readable.
  • I put classes and functions before root = tk.Tk() to make it more readable.
  • I use import tkinter as tk instead of from tkinter import * to make it more readable.

Question gets inner frame from ScrolledFrame and use as parent for LabelFrame. Other widgets use labelframe as parent.

BTW: you had entry = Entry(..).pack() which assign None to entry because pack()/grid()/place() returns None. I put pack() in next line and now I can get text directly from Entry (without StringVar)

Code

import tkinter as tk
from random import randint

# --- classes ---

class ScrolledFrame(tk.Frame):

    def __init__(self, parent, vertical=True, horizontal=False):
        super().__init__(parent)

        # canvas for inner frame
        self._canvas = tk.Canvas(self)
        self._canvas.grid(row=0, column=0, sticky='news') # changed

        # create right scrollbar and connect to canvas Y
        self._vertical_bar = tk.Scrollbar(self, orient='vertical', command=self._canvas.yview)
        if vertical:
            self._vertical_bar.grid(row=0, column=1, sticky='ns')
        self._canvas.configure(yscrollcommand=self._vertical_bar.set)

        # create bottom scrollbar and connect to canvas X
        self._horizontal_bar = tk.Scrollbar(self, orient='horizontal', command=self._canvas.xview)
        if horizontal:
            self._horizontal_bar.grid(row=1, column=0, sticky='we')
        self._canvas.configure(xscrollcommand=self._horizontal_bar.set)

        # inner frame for widgets
        self.inner = tk.Frame(self._canvas, bg='red')
        self._window = self._canvas.create_window((0, 0), window=self.inner, anchor='nw')

        # autoresize inner frame
        self.columnconfigure(0, weight=1) # changed
        self.rowconfigure(0, weight=1) # changed

        # resize when configure changed
        self.inner.bind('<Configure>', self.resize)
        self._canvas.bind('<Configure>', self.frame_width)

    def frame_width(self, event):
        # resize inner frame to canvas size
        canvas_width = event.width
        self._canvas.itemconfig(self._window, width = canvas_width)

    def resize(self, event=None): 
        self._canvas.configure(scrollregion=self._canvas.bbox('all'))

class Question:

    def __init__(self, parent, question, answer):
        self.parent = parent
        self.question = question
        self.answer = answer
        self.create_widgets()

    def get_input(self):
        value = self.entry.get()
        print('value:', value)
        if value == self.answer:
            print("Esatto. è " + self.answer)
            self.label['text'] = "Esatto"

    def create_widgets(self):
        self.labelframe = tk.LabelFrame(self.parent, text="Domanda:")
        self.labelframe.pack(fill="both", expand=True)

        self.label = tk.Label(self.labelframe, text=self.question)
        self.label.pack(expand=True, fill='both')

        self.entry = tk.Entry(self.labelframe)
        self.entry.pack()

        self.button = tk.Button(self.labelframe, text="Click", command=self.get_input)
        self.button.pack()

# --- main ---

root = tk.Tk()
root.title("Quiz")
root.geometry("400x300")

window = ScrolledFrame(root)
window.pack(expand=True, fill='both')

for i in range(10):
    one = randint(1, 10)
    two = randint(1, 10)
    Question(window.inner, "Quanto fa {} + {} ?".format(one, two), str(one + two))

root.mainloop()

Upvotes: 5

Related Questions