简体   繁体   中英

Tkinter scrollbar doesn't fill frame

I'm trying to make a GUI that changes based on the user's resolution. I'm still fairly new to Python but I have managed to accomplish this somewhat. I am struggling to find why the scrollbar(s) do not use all of the space given to them. This leads to the frame behind them being visible.

root = Tk()

screen_height = root.winfo_screenheight()
screen_width = root.winfo_screenwidth()

h = (screen_height / 800)
w = (screen_width / 1300)

frame = ['topleft', 'topmid', 'topright',
     'bottomleft', 'bottommid']
multiplier = [300, 200, 800, 500, 100]
height = [0,
      Decimal(h*(multiplier[0]))
      .quantize(Decimal('1.'), rounding=ROUND_UP),
      Decimal(h*(multiplier[1]))
      .quantize(Decimal('1.'), rounding=ROUND_UP),
      Decimal(h*(multiplier[2]))
      .quantize(Decimal('1.'), rounding=ROUND_UP),
      Decimal(h*(multiplier[3]))
      .quantize(Decimal('1.'), rounding=ROUND_UP),
      Decimal(h*(multiplier[4]))
      .quantize(Decimal('1.'), rounding=ROUND_UP)
     ]
width = [0,
     Decimal(w*(multiplier[0]))
     .quantize(Decimal('1.'), rounding=ROUND_UP),
     Decimal(w*(multiplier[1]))
     .quantize(Decimal('1.'), rounding=ROUND_UP),
     Decimal(w*(multiplier[2]))
     .quantize(Decimal('1.'), rounding=ROUND_UP),
     Decimal(w*(multiplier[3]))
     .quantize(Decimal('1.'), rounding=ROUND_UP),
     Decimal(w*(multiplier[4]))
     .quantize(Decimal('1.'), rounding=ROUND_UP),
     Decimal(w*(multiplier[4]))
     .quantize(Decimal('1.'), rounding=ROUND_UP),
    ]

topleft = Frame(root,
            bg = 'black', bd='3',
            height = height[1], width = width[1],
            relief='flat'
            ).grid(row = height[0], column = width[0],
                   rowspan = height[1], columnspan = width[1])
topmid = Frame(root,
           bg = 'yellow', bd='3',
           height = height[2], width = width[2],
           relief='flat'
           ).grid(row = height[0], column = width[1],
                  rowspan = height[2], columnspan = width[2])
bottommid = Frame(root,
              bg = 'pink', bd ='3',
              height = height[5], width = width[5],
              relief='flat'
              ).grid(row = height[2], column = width[1],
                     rowspan = height[5], columnspan = width[5])
bottomright = Frame(root,
                bg = 'blue', bd='3',
                height = height[5], width = width[5],
                relief='flat'
                ).grid(row = height[2], column = width[1]+width[5],
                       rowspan = height[5], columnspan = width[5])

class file_selector:
def __init__(self):
    global fs_scrollbar, fs_listbox, check
    bottomleft = Frame(root,
               bg = 'white', bd='3',
               height = height[4], width = width[4],
               relief='flat'
               ).grid(row= height[1], column= width[0],
                      rowspan= height[4], columnspan= width[4])

    self.fs_scrollbar = Scrollbar(bottomleft,
                          orient = VERTICAL
                          )

    self.fs_listbox = Listbox(bottomleft,
                      bg = 'white',
                      relief = 'flat',
                      yscrollcommand = self.fs_scrollbar.set
                      )

    self.check = print(self.fs_listbox.curselection())

    self.fs_listbox.bind('<ButtonRelease-1>', self.check)

    self.fs_scrollbar['command'] = self.fs_listbox.yview

    file_selector.widgets(self)

def widgets(self):        

    self.fs_scrollbar.grid(row = height[1], column = (width[4]-(width[4]*Decimal(0.05)).quantize(Decimal('1.'), rounding=ROUND_UP)),
                           rowspan = height[4], columnspan = ((width[4]*Decimal(0.05)).quantize(Decimal('1.'), rounding=ROUND_UP)),
                           sticky= N+E+S+W
                           )

    for file in os.listdir(os.curdir):
        if file.endswith(".txt"):
            self.fs_listbox.insert(END, file)

    self.fs_listbox.grid(row = height[1], column = width[0],
                         rowspan = height[4], columnspan = (width[4]-(width[4]*Decimal(0.05)).quantize(Decimal('1.'), rounding=ROUND_UP)),
                         sticky = N+E+S+W
                         )



class text_editor:
def __init__(self):
    global te_scrollbar, te_text
    topright = Frame(root,
             bg = 'red', bd='3',
             height = height[3], width = width[3],
             relief='flat'
             ).grid(row=height[0], column= width[4],
                    rowspan= height[3], columnspan= width[3])

    self.te_scrollbar = Scrollbar(topright,
                                  orient = VERTICAL
                                  )

    self.te_text = Text(topright,
                bg = 'white',
                yscrollcommand = self.te_scrollbar.set
                )

    self.te_scrollbar['command'] = self.te_text.yview

    text_editor.widgets(self)

def widgets(self):
    with open('test1.txt', 'r') as self.file:
         self.file = self.file.read()

    self.te_scrollbar.grid(row = height[0], column = (width[4]+width[3]-(width[3]*Decimal(0.05)).quantize(Decimal('1.'), rounding=ROUND_UP)),
                           rowspan = height[3], columnspan = ((width[3]*Decimal(0.05)).quantize(Decimal('1.'), rounding=ROUND_UP)),
                           sticky = N+S
                           )

    self.te_text.insert(END, self.file)

    self.te_text.grid(row = height[0], column = width[4],
                      rowspan = height[3], columnspan = (width[3]-(width[3]*Decimal(0.05)).quantize(Decimal('1.'), rounding=ROUND_UP)),
                      sticky = N+E+S+W
                      )

file_selector()
text_editor()

Sorry in advance for the poor code, Tkinter isn't very well documented (and i'm not very good at it).

You don't need to be making all of those calculations -- tkinter is very good at computing geometry for you.

You're making a couple of very common mistakes in your use of grid. When there is extra space in a container (eg: Frame), grid will allocate extra space to rows and columns with a positive "weight". By default, grid rows and columns have a weight of 0 (zero), meaning they don't get any extra space.

As a rule of thumb, every frame for which the internal widgets use grid needs to have at least one row and one column with a positive weight. You do that with the grid_rowconfigure and grid_columnconfigure commands. In your case you need to give at least one row (probably the bottom row) a weight of 1 (one).

You also have another very common problem. Consider this line of code and others similar to it:

topleft = Frame(...).grid(...)

The above will always set topleft to None because that is what grid returns. Therefore, any widget you think is going into topleft is actually going into the root window since specifying None as a parent or master is the same as supplying the root window.

In my opinion, however, you have even bigger problems. Using one grid for an entire application with multiple widgets is extremely difficult to get right. Instead, you need to take a "divide and conquer" approach.

For example, your GUI clearly has two main regions: a left side and a right side. So I would start by making two frames, one for each side. With that, any grid or pack commands on the right won't affect the grid or pack commands on the left, and vise versa.

It also appears that the left side is divided into two sections: the top part with the colored frames, and a bottom part which is a listbox and a scrollbar. I recommend dividing the left side in half. Again, the use of grid or pack in the bottom left won't affect the use of grid or pack in the top left. This will make solving your layout problems much, much easier.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM