0

I created a GUI that represents json file as buttons. I want to make the json structure scrollable. I was able to make it scroll but only up until the middle of the file

import tkinter as tk
import json

class JSONGUI():
    json_example = '{"event":{"name":"test","time":"today"}}'
    s = '{"success": "true", "status": 200, "message": "Hello"}'
    json_example2 = """{
    "glossary": {
        "title": "example glossary",
        "GlossDiv": {
            "title": "S",
            "GlossList": {
                "GlossEntry": {
                    "ID": "SGML",
                    "SortAs": "SGML",
                    "GlossTerm": "Standard Generalized Markup Language",
                    "Acronym": "SGML",
                    "Abbrev": "ISO 8879:1986",
                    "GlossDef": {
                        "para": "A meta-markup language, used to create markup languages such as DocBook.",
                        "GlossSeeAlso": ["GML", "XML"]
                    },
                    "GlossSee": "markup"
                }
            }
        }
    }
}"""

    def __init__(self):
        json_dict = json.loads(self.json_example2)
        #window
        self.window = tk.Tk()
        self.window.title('JSON GUI')
        # self.window.state('zoomed')
        self.window.geometry('500x100')

        #frame
        self.frame = tk.Frame(self.window)
        self.frame.grid(column=0, row=0, sticky='W')
        self.frame.grid_propagate(False)

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

        #scrollbar
        myscrollbar = tk.Scrollbar(self.window, orient="vertical", command=self.canvas.yview)
        myscrollbar.grid(column=1, row=0, sticky='ns')
        self.canvas.configure(yscrollcommand=myscrollbar.set)

        #json_frame
        self.frame_json = tk.Frame(self.canvas)
        self.canvas.create_window((0, 0), window=self.frame_json, anchor='nw')

        #logic add buttons
        self.loop_dict(json_dict, 0, 0)

        #others
        self.frame.config(width=450, height=50)
        self.frame_json.update_idletasks()
        self.canvas.config(scrollregion=self.canvas.bbox("all"))

        #mainloop
        self.window.mainloop()

    def test_function(self):
        print('button pressed')

    def loop_dict(self, json_dict, l, c):
        for x in json_dict:
            tk.Button(self.frame_json, text=x, command=self.test_function).grid(row=l, column=c, sticky='W')
            l += 1
            if isinstance(json_dict.get(x), dict):
                c += 1
                l = self.loop_dict(json_dict.get(x), l, c)
            if isinstance(json_dict.get(x), list):
                c += 1
                l = self.loop_list(json_dict.get(x), l, c)
        return l

    def loop_list(self, json_list, l, c):
        tk.Label(self.frame_json, text='list').grid(row=l, column=c, sticky='W')
        l += 1
        for x in json_list:
            if isinstance(x, dict):
                c += 1
                l = self.loop_dict(self, x, l, c)
        return l


enter image description here enter image description here

So i am able to scroll but cant scroll further then is shown in the second picture. I noticed if i changed the width and height i was able to scroll a little bit further. What is causing this ? And how can i scroll all the way down ?

aprox
  • 15
  • 2

3 Answers3

0

I tried running your code on my computer, but it didn't work. My guess about the issue you are having is probably due your configuration of the scrollbar itself. Try something like this! It worked on a early project I did a few months ago.

scroll_bar = Scrollbar(root)

scroll_bar.pack( side = RIGHT,
            fill = Y )

mylist = Listbox(root, 
             yscrollcommand = scroll_bar.set)

scroll_bar.config(command = mylist.yview)
Thomas_Hang5
  • 1
  • 1
  • 1
0

You should use .pack() manager. Also, you need to replace all the widgets with .grid() to .pack() as they don't go well with each other.

You cannot use both pack and grid on widgets that which have same master. The first one will adjust the size of the widget. The other will see the change, and resize everything to fit it's own constraints. The first will see these changes and resize everything again to fit its constraints. The other will see the changes, and so on ad infinitum. They will be stuck in an eternal struggle for supremacy.

    def __init__(self):
        self.window = tk.Tk()
        self.window.title('JSON GUI')
        # self.window.state('zoomed')
        self.window.geometry('500x100')

        #frame
        self.frame = tk.Frame(self.window)
        self.frame.pack(fill=tk.Y,side=tk.LEFT)
 

        #canvas
        self.canvas = tk.Canvas(self.frame)
        self.canvas.pack(fill=tk.BOTH,expand=1)

        #scrollbar
        myscrollbar = tk.Scrollbar(self.window, orient="vertical", command=self.canvas.yview)
        myscrollbar.pack(fill="y",side=tk.RIGHT)
        self.canvas.configure(yscrollcommand=myscrollbar.set)

        #json_frame
        self.frame_json = tk.Frame(self.canvas)
        self.canvas.create_window((0, 0), window=self.frame_json, anchor='nw')

Sample Output:

enter image description here

0

Part of the problem is that you have layout code sprinkled all throughout the code which makes it hard to visualize the layout. The second part of your problem is that you're using grid, but you never tell grid what to do with unallocated space (ie: space left over when the window is bigger than the widgets inside).

Having to configure the weight of rows and columns is one of the downsides to using grid. When you only have widgets arranged in a row or column, pack is usually the better choice simply because it requires fewer lines of code.

In your case, the root window has only two widgets: the canvas, and the scrollbar. Since you only have two widgets arranged in a horizontal arrangement, I recommend you remove the use of grid and instead use pack like so:

myscrollbar.pack(side="right", fill="y")
self.frame.pack(side="left", fill="both", expand=True)

If you prefer using grid, then you must take care to set a weight for column 0 so that it is given all unallocated space. You should do that for the row as well. As you can see, using grid in this case requires twice as many lines of code, but other than that it works just as well.

self.frame.grid(row=0, column=0, sticky="nsew")
myscrollbar.grid(row=0, column=1, sticky="ns")

self.window.grid_rowconfigure(0, weight=1)
self.window.grid_columnconfigure(0, weight=1)

That alone solves the scrolling problem. However, it exposes another problem, which is that the canvas isn't filling its window. This is also due to not assigning weight to any columns or rows, and can also be more easily solved with pack since it is the only widget inside its parent.

self.canvas.pack(fill="both", expand=True)

Again, you can use grid instead of pack, but you have to take care of setting row and column weights.

self.canvas.grid(column=0, row=0, sticky='news')
self.frame.grid_rowconfigure(0, weight=1)
self.frame.grid_columnconfigure(0, weight=1)
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685