2

Fairly new to Tkinter. I've looked in numerous posts about this issue, but none fixed it for me. I'm trying to create a simple GUI, in which I have a canvas which displays an image. The canvas is scrollable, but the scrollbars won't stretch to the size of the canvas.

Following is the relevant part of my code. there is no code here actually displaying the image, the image is given by an openFileDialog, but the scrollbars remain the same with the image.

from Tkinter import *
import Image
import ImageTk
import numpy as np
import tkFileDialog
import os as os

class DIP(Frame):
    def __init__(self, parent):
        Frame.__init__(self, parent) 
        self.parent = parent        
        self.initUI()
        self.isOpenedYet = False

    def initUI(self):
        self.parent.title("Viewer")
        self.pack(fill = BOTH, expand = 1)

        menubar = Menu(self.parent)
        self.parent.config(menu = menubar)

        vsframe = Frame(self, width=500, height=500)
        vsframe.grid(row = 1, column = 2, columnspan = 2, sticky = "nw")
        hsframe = Frame(self, width=500, height=500)
        hsframe.grid(row = 2, column = 1, rowspan = 2, sticky = "nw")
        self.canv = Canvas(self, relief=SUNKEN)
        self.canv.config(width=500, height=500)
        self.canv.config(highlightthickness=0)
        self.sbarV = Scrollbar(vsframe, orient=VERTICAL)
        self.sbarH = Scrollbar(hsframe, orient=HORIZONTAL)
        self.sbarV.config(command=self.canv.yview)
        self.sbarH.config(command=self.canv.xview)

        self.canv.config(yscrollcommand=self.sbarV.set)
        self.canv.config(xscrollcommand=self.sbarH.set)

        self.sbarV.pack(expand = YES, fill=BOTH)
        self.sbarH.pack(expand = YES, fill=BOTH)

        self.label2 = Label(self, border = 5)
        self.label2.grid(row = 0, column = 1)
        self.canv.grid(row = 1, column = 1, sticky = "nw")

        #Open Image Menu
        fileMenu = Menu(menubar)
        fileMenu.add_command(label = "Open", command = self.onOpen)
        menubar.add_cascade(label = "File", menu = fileMenu)

        #menu for algorithms
        basicMenu = Menu(menubar)
        basicMenu.add_command(label = "Super Resolution-stub", command = self.SuperRes)
        menubar.add_cascade(label = "Algorithms", menu = basicMenu)

What am I missing?

Ysch
  • 752
  • 2
  • 9
  • 24

2 Answers2

2

There are a couple things that are going on here.

First, you don't need to put the scrollbars in separate frames. They can (and normally should) go in the same frame as the canvas.

Second, your scroll frames don't have the right "sticky" values. A vertical scrollbar needs to "stick" to both the top and bottom of the area it is given, and a horizontal one needs to "stick" to the left and right of the area it is given. Also, your canvas should "stick" to all sides of its area so that it fills the area.

Third, you aren't giving any weights to your rows and columns, so they don't resize the way you might expect. In your case, you want to give the row and column that contains the canvas a weight of 1 (one), so it takes up all of the extra space in the GUI.

Taking all that advice together, here's how to possibly get what you are wanting:

def initUI(self):
    self.parent.title("Viewer")
    self.pack(fill = BOTH, expand = 1)

    menubar = Menu(self.parent)
    self.parent.config(menu = menubar)

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

    self.canv = Canvas(self, relief=SUNKEN)
    self.canv.config(width=500, height=500)
    self.canv.config(highlightthickness=0)
    self.sbarV = Scrollbar(self, orient=VERTICAL)
    self.sbarH = Scrollbar(self, orient=HORIZONTAL)

    self.sbarV.config(command=self.canv.yview)
    self.sbarH.config(command=self.canv.xview)

    self.canv.config(yscrollcommand=self.sbarV.set)
    self.canv.config(xscrollcommand=self.sbarH.set)

    self.sbarV.grid(row=1, column=2, sticky="ns")
    self.sbarH.grid(row=2, column=1, sticky="ew")

    self.label2 = Label(self, border = 5, text="label 2")
    self.label2.grid(row = 0, column = 1)
    self.canv.grid(row = 1, column = 1, sticky = "nsew")

    ...

By the way, here's a tip for debugging problems like this: give each "large" widget (frames, canvases, text widgets) a distinctive background color during development. For example, give "self" a background of blue, the canvas a background of pink, and so on. It becomes much easier to see where each item is going and how they resize relative to each other. Without this, it can sometimes be hard to know if some white space on the screen belongs to the main window, a child window, etc.

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • Thanks, sovled it already with petem's help, but your answer is exactly what I did, so thanks. Definitely going to use the bg color tip.. – Ysch Feb 26 '14 at 18:40
0

You don't need a frame for your scrollbars. Remove those and add the scrollbars to the Canvas widget:

self.sbarV = Scrollbar(self.canv, orient=VERTICAL)
self.sbarH = Scrollbar(self.canv, orient=HORIZONTAL)

Then, use .grid() for your scrollbars. It's not a good idea to mix pack and grid. Use the sticky option in your grid to sticky the scrollbars to the extent of the Canvas.

self.sbarV.grid(column=1, sticky=N+S)
self.sbarH.grid(row=1, sticky=E+W)

Doing that should fix it, everything else looks right.

More: http://effbot.org/zone/tkinter-scrollbar-patterns.htm

atlasologist
  • 3,824
  • 1
  • 21
  • 35
  • Thanks for the reply. I tried it before, but then the canvas shrinks to match the scrollbars, sticking to the NW corner... – Ysch Feb 26 '14 at 18:05
  • I don't think it's a good idea to embed the scrollbars in the canvas -- anything you draw on the canvas might end up under the scrollbar. Also, the way the OP mixes pack and grid is perfectly fine. You can (and should!) mix them in an app, just not in the same widget. – Bryan Oakley Feb 26 '14 at 18:12
  • Finally got it! I passed self to the scrollbars instead of self.canvas. Thanks for the pointers in the direction. – Ysch Feb 26 '14 at 18:18
  • Good call. Yonadav, here's a good reference for exactly what you're trying to do: http://stackoverflow.com/questions/7727804/python-and-tkinter-using-scrollbars-on-a-canvas – atlasologist Feb 26 '14 at 18:19