首页 > 解决方案 > Tkinter 中 Matplotlib 图的滚动条

问题描述

我正在尝试让滚动条Tkinter用于matplotlib数字。滚动条不适应加载图像的宽度和高度,我不知道如何解决这个问题。任何帮助,将不胜感激。

图片

笑脸

最终结果:

问题

代码:

import os

from PIL import Image

import tkinter as tk
from tkinter import ttk, filedialog

import matplotlib as mpl
import matplotlib.pyplot as plt

mpl.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk

import numpy as np

from functools import partial

class AutoScrollbar(ttk.Scrollbar):

    def __init__(self,
                 parent,
                 *args,
                 **kwargs):
        '''
        '''
        self.parent = parent

        super().__init__(self.parent,
                         *args,
                         **kwargs)

    def set(self,
            low,
            high):
        '''
        '''
        if float(low) <= 0.0 and float(high) >= 1.0:
            self.tk.call('grid',
                         'remove',
                         self)
        else:
            self.grid()
        ttk.Scrollbar.set(self,
                          low,
                          high)

class DoubleScrollbarFrame(ttk.Frame):

    def __init__(self,
                 parent,
                 *args,
                 **kwargs):
        '''
        '''
        self.parent = parent

        super().__init__(self.parent,
                         *args,
                         **kwargs)

        #Set widgets to fill main window such that they are
        #all the same size
        self.columnconfigure(0, weight=1)
        self.rowconfigure(0, weight=1)

        self.create_widgets()
        self.position_widgets()

    def create_widgets(self):
        '''
        '''
        self.canvas = tk.Canvas(self)
        self.frame = ttk.Frame(self.canvas)
        self.scroll_x = AutoScrollbar(self,
                                      orient = tk.HORIZONTAL)
        self.scroll_y = AutoScrollbar(self,
                                      orient = tk.VERTICAL)
        self.sizegrip = ttk.Sizegrip(self)
        
        self.canvas.config(xscrollcommand = self.scroll_x.set,
                           yscrollcommand = self.scroll_y.set)
        self.scroll_x.config(command = self.canvas.xview)
        self.scroll_y.config(command = self.canvas.yview)
        
        self.canvas.create_window((0,0),
                                  window = self.frame,
                                  anchor = 'nw')
        
        self.frame.bind('<Configure>',
                        self.set_scrollregion)

    def position_widgets(self,
                         **kwargs):
        '''
        '''
        self.scroll_x.grid(row = 1,
                           column = 0,
                           sticky = 'ew')

        self.scroll_y.grid(row = 0,
                           column = 1,
                           sticky = 'ns')

        self.canvas.grid(row = 0,
                         column = 0,
                         sticky = 'nsew')

        self.sizegrip.grid(row = 1,
                           column = 1,
                           sticky = 'se')

        #NOTE: Do not use geometry manager with `self.frame`. This will
        # pass control from the canvas to grid and the canvas will then
        # no longer know how much to grow.
        
    def set_scrollregion(self,
                         event):
        '''
        '''
        self.canvas.configure(scrollregion = self.canvas.bbox('all'))

class Graph(ttk.Frame):

    def __init__(self,
                 parent,
                 axis_off = True,
                 *args,
                 **kwargs):
        '''
        '''
        self.parent = parent
        self.axis_off = axis_off

        super().__init__(self.parent,
                         *args,
                         **kwargs)

        #Set widgets to fill main window such that they are
        #all the same size
        self.columnconfigure(0, weight=1)
        self.rowconfigure(0, weight=1)

        self.create_widgets()
        self.position_widgets()

    def create_widgets(self):
        '''
        '''
        self.graph_container = DoubleScrollbarFrame(self)
        
        self.figure = plt.figure()
        self.figure.subplots_adjust(top = 1,
                                    right = 1,
                                    left= 0,
                                    bottom = 0,
                                    wspace = 0,
                                    hspace = 0)
            
        self.axis = self.figure.add_subplot(1,1,1)

        if self.axis_off:
            self.axis.set_axis_off()

        self.mpl_canvas = FigureCanvasTkAgg(self.figure,
                                            self.graph_container.frame)

        self.toolbar_frame = ttk.Frame(self)

        self.toolbar = NavigationToolbar2Tk(self.mpl_canvas,
                                            self.toolbar_frame)
        
    def position_widgets(self):
        '''
        '''
        self.toolbar.update()
        self.toolbar_frame.grid(row = 1,
                                column = 0,
                                sticky = 'sew')

        self.mpl_canvas.draw()
        self.mpl_canvas.get_tk_widget().grid(row = 0,
                                             column = 0,
                                             sticky = 'nsew')

        self.graph_container.grid(row = 0,
                                  column = 0,
                                  sticky = 'nsew')

    def load_image(self,
                   path):
        '''
        '''
        self.mpl_canvas.flush_events()
        self.axis.clear()
        
        self.image = Image.open(path)

        #NOTE: Dots per inch (dpi) in matplotlib should be used for
        # printing to paper media only. dpi is set at the time of
        # printing/scanning. Computer screen resolution is fixed by
        # the screen hardware and given in pixels per inch (ppi).
        # An image scanned at higher dpi will appear crisper on a
        # computer screen because of the difference in halftone/
        # dithering at each pixel, but the total size and number of
        # pixels in the image will be the same.
        # Matplotlib use 72 pixels per inch (ppi) for its figures by
        # default, and this cannot be changed. Thus, if you increase
        # dots per inch (dpi), the figure will appear bigger when
        # printed to screen (i.e. on the computer monitor) because
        # it will use more pixels to represent the same features.
        # When printed to paper media, however, the image will be
        # the same size regardless of dpi, but have finer halftoning/
        # dithering for an improved appearance.
        # Matplotlib sets sizes in terms of inches, so the scan dpi
        # must be known in order to get the physical size of the
        # image.
        if self.image.info.get('dpi'):
            self.scan_dpi, _ = self.image.info['dpi']
        else:
            self.scan_dpi = 100
        self.w_pel, self.h_pel = self.image.size

        self.graph_w_in = self.w_pel / self.scan_dpi
        self.graph_h_in = self.h_pel / self.scan_dpi
        self.graph_aspect_ratio = self.graph_h_in / self.graph_w_in

        self.zoom = 1
        
        self.figure.set_size_inches(self.graph_w_in * self.zoom,
                                    self.graph_h_in * self.zoom)
        
        self.image = np.array(self.image)
        
        self.axis.imshow(self.image)

        self.mpl_canvas.draw()

class FileBrowser(tk.Frame):

    def __init__(self,
                 parent,
                 path_type = 'file',
                 label_text = '',
                 file_types = (('*','All File Types...'),),
                 *args,
                 **kwargs):
        '''
        '''
        self.parent = parent
        self.path_type = path_type
        self.label_text = label_text
        self.file_types = file_types
        
        super().__init__(parent,
                         *args,
                         **kwargs)

        self.create_widgets()
        self.position_widgets()

    def create_widgets(self):
        '''
        '''
        self.label = tk.Label(self.parent,
                              text = self.label_text)

        self.path_entry = tk.Entry(self.parent,
                                   width = 50)

        self.button = ttk.Button(self.parent,
                                 text = 'Browse...',
                                 command = partial(self.open_file_dialog,
                                                   self.path_type,
                                                   self.file_types))

    def position_widgets(self):
        '''
        '''
        opts = {'padx': (5,5),
                'pady': (5,5)}
        
        self.label.grid(row = 0,
                        column = 0,
                        sticky = 'e',
                        **opts)
        self.path_entry.grid(row = 0,
                             column = 1,
                             sticky = 'w',
                             **opts)
        self.button.grid(row = 0,
                         column = 2,
                         sticky = 'w',
                         **opts)

    def open_file_dialog(self,
                         path_type,
                         file_types):
        '''
        '''
        init_dir = os.getcwd()

        if path_type == 'file':
             self.path = filedialog.askopenfilename(initialdir = init_dir,
                                                    title = 'Select file...',
                                                    filetypes = file_types)
        elif path_type == 'directory':
            self.path = filedialog.askdirectory(initialdir = init_dir,
                                                title = 'Select directory...')

        self.path_entry.delete(0,tk.END)
        self.path_entry.insert(0,self.path)

    def get_path(self):
        '''
        '''
        return self.path_entry.get()

class Loader(ttk.Frame):
    '''
    '''
    def __init__(self,
                 parent,
                 *args,
                 **kwargs):
        '''
        '''
        self.parent = parent

        super().__init__(self.parent,
                         *args,
                         **kwargs)

        #Set widgets to fill main window such that they are
        #all the same size
        self.columnconfigure(0, weight=1)
        self.rowconfigure(0, weight=1)

        self.create_widgets()
        self.position_widgets()

    def create_widgets(self):
        '''
        '''
        self.input_label_frame = ttk.LabelFrame(self,
                                                text = 'Input')
        self.output_label_frame = ttk.LabelFrame(self,
                                                 text = 'Output')
        
        self.create_file_browser(self.input_label_frame)
        self.create_ok_button(self.input_label_frame)

        self.create_output_window(self.output_label_frame)

    def create_file_browser(self,
                            label_frame):
        '''
        '''
        self.browser_frame = ttk.LabelFrame(label_frame,
                                            text = 'Select File')
        self.file_browser = FileBrowser(self.browser_frame,
                                        path_type = 'file',
                                        label_text = 'File:',
                                        file_types = (('*.tif', 'TIF'),
                                                      ('*.png', 'PNG'),))

    def create_ok_button(self,
                         label_frame):
        '''
        '''
        self.input_ok_button = ttk.Button(label_frame,
                                          text = 'OK',
                                          command = self.calibrate)

    def calibrate(self):
        '''
        '''
        path = self.file_browser.get_path()

        if path == '':
            messagebox.showerror(title = 'No File Selected',
                                 message = 'No file chosen. Please select file.')
            return

        _, ext = os.path.splitext(path)

        if ext.lower() not in ('.tif', '.png'):
            messagebox.showerror(title = 'File Is Not \"*.tif\" or \"*.png\"',
                                 message = 'File must be a \"*.tif\" or \"*.png\" image file. Please reselect file and try again.')

        img = plt.imread(path)

        self.graph.load_image(path)
        
    def create_output_window(self,
                             label_frame):
        '''
        '''
        self.output_frame = ttk.Frame(label_frame)
        self.graph = Graph(self.output_frame)

    def position_widgets(self,
                         **kwargs):
        '''
        '''
        #OK Button
        self.input_ok_button.grid(row = 4,
                                  column = 0,
                                  sticky = 'e')
        
        #Frames
        self.input_label_frame.grid(row = 0,
                                    column = 0,
                                    sticky = 'nsew')
        
        self.browser_frame.grid(row = 1,
                                column = 0,
                                sticky = 'nw')

        self.file_browser.grid(row = 0,
                               column = 0,
                               sticky = 'nsew')

        self.output_label_frame.grid(row = 0,
                                     column = 1,
                                     sticky = 'nw')

        self.graph.grid(row = 0,
                        column = 0,
                        sticky = 'nsew')

        self.output_frame.grid(row = 0,
                               column = 0,
                               sticky = 'nsew')


class MainApp(tk.Tk):

    def __init__(self,
                 title,
                 *args,
                 **kwargs):
        '''
        '''
        self._title = title

        super().__init__(*args,
                         **kwargs)

        #Set widgets to fill main window such that they are
        #all the same size
        self.rowconfigure(0, weight=1)
        self.columnconfigure(0, weight=1)

        #Set window title
        self.title(self._title)

        self.create_widgets()
        self.position_widgets()

    def create_widgets(self):
        '''
        '''
        self.loader = Loader(self)

    def position_widgets(self):
        '''
        '''
        self.loader.grid(row = 0,
                         column = 0,
                         sticky = 'nsew')

if __name__ == '__main__':

    #Create GUI
    root = MainApp('MainApp')

    #Run program
    root.mainloop()

标签: matplotlibtkinterscrollbar

解决方案


matplotlib人物是画布。因此,它的容器框架不会调整到它的大小,bbox("all")也不会工作。相反,我们必须更新大小以matplotlib canvas匹配figure大小和顶级大小。canvas scrollregionfigure

这是工作输出。

工作输出

回答

这是工作代码。

代码

import os

from PIL import Image

import tkinter as tk
from tkinter import ttk, filedialog

import matplotlib as mpl
import matplotlib.pyplot as plt

mpl.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk

import numpy as np

from functools import partial

#Matplotlib Default DPI
DEFAULT_DPI = 100

#Matplotlib Default PPI
DEFAULT_PPI = 72

class AutoScrollbar(ttk.Scrollbar):

    def __init__(self,
                 parent,
                 *args,
                 **kwargs):
        '''
        '''
        self.parent = parent

        super().__init__(self.parent,
                         *args,
                         **kwargs)

    def set(self,
            low,
            high):
        '''
        '''
        if float(low) <= 0.0 and float(high) >= 1.0:
            self.tk.call('grid',
                         'remove',
                         self)
        else:
            self.grid()
        ttk.Scrollbar.set(self,
                          low,
                          high)

class DoubleScrollbarFrame(ttk.Frame):

    def __init__(self,
                 parent,
                 *args,
                 **kwargs):
        '''
        '''
        self.parent = parent

        super().__init__(self.parent,
                         *args,
                         **kwargs)

        #Set widgets to fill main window such that they are
        #all the same size
        self.columnconfigure(0, weight=1)
        self.rowconfigure(0, weight=1)

        self.create_widgets()
        self.position_widgets()

    def create_widgets(self):
        '''
        '''
        self.canvas = tk.Canvas(self)
        self.frame = ttk.Frame(self.canvas)
        self.scroll_x = AutoScrollbar(self,
                                      orient = tk.HORIZONTAL)
        self.scroll_y = AutoScrollbar(self,
                                      orient = tk.VERTICAL)
        self.sizegrip = ttk.Sizegrip(self)
        
        self.canvas.config(xscrollcommand = self.scroll_x.set,
                           yscrollcommand = self.scroll_y.set)
        self.scroll_x.config(command = self.canvas.xview)
        self.scroll_y.config(command = self.canvas.yview)
        
        self.canvas.create_window((0,0),
                                  window = self.frame,
                                  anchor = 'nw')
        
        self.frame.bind('<Configure>',
                        self.set_scrollregion)

    def position_widgets(self,
                         **kwargs):
        '''
        '''
        self.scroll_x.grid(row = 1,
                           column = 0,
                           sticky = 'ew')

        self.scroll_y.grid(row = 0,
                           column = 1,
                           sticky = 'ns')

        self.canvas.grid(row = 0,
                         column = 0,
                         sticky = 'nsew')

        self.sizegrip.grid(row = 1,
                           column = 1,
                           sticky = 'se')

        #NOTE: Do not use geometry manager with `self.frame`. This will
        # pass control from the canvas to grid and the canvas will then
        # no longer know how much to grow.
        
    def set_scrollregion(self,
                         event):
        '''
        '''
        self.canvas.configure(scrollregion = self.canvas.bbox('all'))

class Graph(ttk.Frame):

    def __init__(self,
                 parent,
                 axis_off = True,
                 *args,
                 **kwargs):
        '''
        '''
        self.parent = parent
        self.axis_off = axis_off

        super().__init__(self.parent,
                         *args,
                         **kwargs)

        #Set widgets to fill main window such that they are
        #all the same size
        self.columnconfigure(0, weight=1)
        self.rowconfigure(0, weight=1)

        self.create_widgets()
        self.position_widgets()

    def create_widgets(self):
        '''
        '''
        self.figure = plt.figure()
        self.figure.subplots_adjust(top = 1,
                                    right = 1,
                                    left= 0,
                                    bottom = 0,
                                    wspace = 0,
                                    hspace = 0)
            
        self.axis = self.figure.add_subplot(1,1,1)

        if self.axis_off:
            self.axis.set_axis_off()

        self.canvas = tk.Canvas(self)
        self.frame = ttk.Frame(self.canvas)

        self.mpl_canvas = FigureCanvasTkAgg(self.figure,
                                            self.frame)

        self.mpl_canvas.draw()

        self.scroll_x = AutoScrollbar(self,
                                      orient = tk.HORIZONTAL)
        self.scroll_y = AutoScrollbar(self,
                                      orient = tk.VERTICAL)
        self.sizegrip = ttk.Sizegrip(self)
        
        self.canvas.config(xscrollcommand = self.scroll_x.set,
                           yscrollcommand = self.scroll_y.set)
        self.scroll_x.config(command = self.canvas.xview)
        self.scroll_y.config(command = self.canvas.yview)
        
        self.cwid = self.canvas.create_window((0,0),
                                              window = self.frame,
                                              anchor = 'nw')

        self.frame.bind('<Configure>',
                        self.set_scrollregion)

        self.toolbar_frame = ttk.Frame(self)

        self.toolbar = NavigationToolbar2Tk(self.mpl_canvas,
                                            self.toolbar_frame)

    def set_scrollregion(self,
                         event):
        '''
        '''
        w, h = self.figure.get_size_inches()
        w = int(w * DEFAULT_DPI)
        h = int(h * DEFAULT_DPI)
        scrollregion = (0,0,w,h)
        
        self.canvas.configure(scrollregion = scrollregion)
        
    def position_widgets(self):
        '''
        '''
        self.scroll_x.grid(row = 1,
                           column = 0,
                           sticky = 'ew')

        self.scroll_y.grid(row = 0,
                           column = 1,
                           sticky = 'ns')

        self.canvas.grid(row = 0,
                         column = 0,
                         sticky = 'nsew')

        self.mpl_canvas.get_tk_widget().grid(row = 0,
                                             column = 0,
                                             sticky = 'nsew')

        self.sizegrip.grid(row = 1,
                           column = 1,
                           sticky = 'se')

        #NOTE: Do not use geometry manager with `self.frame`. This will
        # pass control from the canvas to grid and the canvas will then
        # no longer know how much to grow.

        self.toolbar.update()
        self.toolbar_frame.grid(row = 2,
                                column = 0,
                                sticky = 'sew')

    def load_image(self,
                   path):
        '''
        '''
        self.mpl_canvas.flush_events()
        self.axis.clear()
        
        self.image = Image.open(path)

        #NOTE: Dots per inch (dpi) in matplotlib should be used for
        # printing to paper media only. dpi is set at the time of
        # printing/scanning. Computer screen resolution is fixed by
        # the screen hardware and given in pixels per inch (ppi).
        # An image scanned at higher dpi will appear crisper on a
        # computer screen because of the difference in halftone/
        # dithering at each pixel, but the total size and number of
        # pixels in the image will be the same.
        # Matplotlib use 72 pixels per inch (ppi) for its figures by
        # default, and this cannot be changed. Thus, if you increase
        # dots per inch (dpi), the figure will appear bigger when
        # printed to screen (i.e. on the computer monitor) because
        # it will use more pixels to represent the same features.
        # When printed to paper media, however, the image will be
        # the same size regardless of dpi, but have finer halftoning/
        # dithering for an improved appearance.
        # Matplotlib sets sizes in terms of inches, so the scan dpi
        # must be known in order to get the physical size of the
        # image.
        if self.image.info.get('dpi'):
            self.scan_dpi, _ = self.image.info['dpi']
        else:
            self.scan_dpi = DEFAULT_DPI # matplotlib default
            
        self.w_pel, self.h_pel = self.image.size

        self.graph_w_in = self.w_pel / self.scan_dpi
        self.graph_h_in = self.h_pel / self.scan_dpi        
        
        self.figure.set_size_inches(self.graph_w_in,
                                    self.graph_h_in)
        
        self.image = np.array(self.image)
        
        self.axis.imshow(self.image)

        self.mpl_canvas.get_tk_widget().configure(
            width = self.graph_w_in * DEFAULT_DPI,
            height = self.graph_h_in * DEFAULT_DPI)
        
        self.mpl_canvas.draw()
        self.canvas.update()

class FileBrowser(tk.Frame):

    def __init__(self,
                 parent,
                 path_type = 'file',
                 label_text = '',
                 file_types = (('*','All File Types...'),),
                 *args,
                 **kwargs):
        '''
        '''
        self.parent = parent
        self.path_type = path_type
        self.label_text = label_text
        self.file_types = file_types
        
        super().__init__(parent,
                         *args,
                         **kwargs)

        self.create_widgets()
        self.position_widgets()

    def create_widgets(self):
        '''
        '''
        self.label = tk.Label(self.parent,
                              text = self.label_text)

        self.path_entry = tk.Entry(self.parent,
                                   width = 50)

        self.button = ttk.Button(self.parent,
                                 text = 'Browse...',
                                 command = partial(self.open_file_dialog,
                                                   self.path_type,
                                                   self.file_types))

    def position_widgets(self):
        '''
        '''
        opts = {'padx': (5,5),
                'pady': (5,5)}
        
        self.label.grid(row = 0,
                        column = 0,
                        sticky = 'e',
                        **opts)
        self.path_entry.grid(row = 0,
                             column = 1,
                             sticky = 'w',
                             **opts)
        self.button.grid(row = 0,
                         column = 2,
                         sticky = 'w',
                         **opts)

    def open_file_dialog(self,
                         path_type,
                         file_types):
        '''
        '''
        init_dir = os.getcwd()

        if path_type == 'file':
             self.path = filedialog.askopenfilename(initialdir = init_dir,
                                                    title = 'Select file...',
                                                    filetypes = file_types)
        elif path_type == 'directory':
            self.path = filedialog.askdirectory(initialdir = init_dir,
                                                title = 'Select directory...')

        self.path_entry.delete(0,tk.END)
        self.path_entry.insert(0,self.path)

    def get_path(self):
        '''
        '''
        return self.path_entry.get()

class Loader(ttk.Frame):
    '''
    '''
    def __init__(self,
                 parent,
                 *args,
                 **kwargs):
        '''
        '''
        self.parent = parent

        super().__init__(self.parent,
                         *args,
                         **kwargs)

        #Set widgets to fill main window such that they are
        #all the same size
        self.columnconfigure(0, weight=1)
        self.rowconfigure(0, weight=1)

        self.create_widgets()
        self.position_widgets()

    def create_widgets(self):
        '''
        '''
        self.input_label_frame = ttk.LabelFrame(self,
                                                text = 'Input')
        self.output_label_frame = ttk.LabelFrame(self,
                                                 text = 'Output')
        
        self.create_file_browser(self.input_label_frame)
        self.create_ok_button(self.input_label_frame)

        self.create_output_window(self.output_label_frame)

    def create_file_browser(self,
                            label_frame):
        '''
        '''
        self.browser_frame = ttk.LabelFrame(label_frame,
                                            text = 'Select File')
        self.file_browser = FileBrowser(self.browser_frame,
                                        path_type = 'file',
                                        label_text = 'File:',
                                        file_types = (('*.tif', 'TIF'),
                                                      ('*.png', 'PNG'),))

    def create_ok_button(self,
                         label_frame):
        '''
        '''
        self.input_ok_button = ttk.Button(label_frame,
                                          text = 'OK',
                                          command = self.calibrate)

    def calibrate(self):
        '''
        '''
        path = self.file_browser.get_path()

        if path == '':
            messagebox.showerror(title = 'No File Selected',
                                 message = 'No file chosen. Please select file.')
            return

        _, ext = os.path.splitext(path)

        if ext.lower() not in ('.tif', '.png'):
            messagebox.showerror(title = 'File Is Not \"*.tif\" or \"*.png\"',
                                 message = 'File must be a \"*.tif\" or \"*.png\" image file. Please reselect file and try again.')

        img = plt.imread(path)

        self.graph.load_image(path)
        
    def create_output_window(self,
                             label_frame):
        '''
        '''
        self.output_frame = ttk.Frame(label_frame)
        self.graph = Graph(self.output_frame)

    def position_widgets(self,
                         **kwargs):
        '''
        '''
        #OK Button
        self.input_ok_button.grid(row = 4,
                                  column = 0,
                                  sticky = 'e')
        
        #Frames
        self.input_label_frame.grid(row = 0,
                                    column = 0,
                                    sticky = 'nsew')
        
        self.browser_frame.grid(row = 1,
                                column = 0,
                                sticky = 'nw')

        self.file_browser.grid(row = 0,
                               column = 0,
                               sticky = 'nsew')

        self.output_label_frame.grid(row = 0,
                                     column = 1,
                                     sticky = 'nw')

        self.graph.grid(row = 0,
                        column = 0,
                        sticky = 'nsew')

        self.output_frame.grid(row = 0,
                               column = 0,
                               sticky = 'nsew')


class MainApp(tk.Tk):

    def __init__(self,
                 title,
                 *args,
                 **kwargs):
        '''
        '''
        self._title = title

        super().__init__(*args,
                         **kwargs)

        #Set widgets to fill main window such that they are
        #all the same size
        self.rowconfigure(0, weight=1)
        self.columnconfigure(0, weight=1)

        #Set window title
        self.title(self._title)

        self.create_widgets()
        self.position_widgets()

    def create_widgets(self):
        '''
        '''
        self.loader = Loader(self)

    def position_widgets(self):
        '''
        '''
        self.loader.grid(row = 0,
                         column = 0,
                         sticky = 'nsew')

if __name__ == '__main__':

    #Create GUI
    root = MainApp('MainApp')

    #Run program
    root.mainloop()

推荐阅读