Python Forum
tkinter how to use whitespace with grid
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
tkinter how to use whitespace with grid
#1
Hi, I'm trying to write a gui application using tkinter and matplotlib. I am having trouble with the layout. I'm leaving all the buttons in one frame and the plot in another frame (ie optionsframe = tk.Frame(self), plotsframe = tk.Frame(self)) in a attempt to divide the window into 2 (unequal) parts. However I cannot get the matplotlib figure to scale I tried adding "plotsframe.grid_columnconfigure(0, weight=1 )plotsframe.grid_rowconfigure(0, weight=1)" but it doesn't work. can someone tell me how to use the whitespace? I'm leaving the code for the page in question below

# Plot
import matplotlib
import matplotlib.pyplot as plt
from matplotlib import style
from numpy import arange
from math import *
matplotlib.use("TkAgg")
style.use('fivethirtyeight')

from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure

## gui
import tkinter as tk
from tkinter import ttk

LARGE_FONT = ("Verdana", 12)
NORM_FONT = ("Verdana", 10)
SMALL_FONT = ("Verdana", 18)


## texts
Nsup= "Not supported yet! \n error: 010"

def popupmsg(msg):
    popup = tk.Tk()

    popup.wm_title("!")
    label = ttk.Label(popup, text= msg, font= NORM_FONT)
    label.pack(side="top", fill="x", pady=10)
    b1 = ttk.Button(popup, text="ok", command = popup.destroy)
    b1.pack()
    popup.mainloop()


#Plot
Y = [[]]
X = [[]]
Lines = 3
Sel = 1

def calc(ite, height, width):
    trans = ite*-500
    for i in arange(0,10, 0.05):
        # handle more plots
        if (len(X) <= ite):
            Y.append([])
            X.append([])
        # Maths
        a = (pi*i*20* width) - (90) + trans
        
        if a >= -90 and a <= 270:
            y = sin(radians(a)) + (i*1.1*(ite/100) + 1) + (height)
        else:
            y = i*1.1*(ite/100) + (height)
        

        # save datapoints
        X[ite].append(i)
        Y[ite].append(y)

def draw():
    for i in range(0, Lines):
        calc(i, i, i+1)


        
# baseline
class GUI(tk.Tk):

    def __init__(self, *args, **kwargs):  ## start up
        tk.Tk.__init__(self, *args, **kwargs) ## init tkinter
        tk.Tk.iconbitmap(self, default="icon.ico")
        tk.Tk.wm_title(self, "prog. Name")
        
        ## container
        container = tk.Frame(self)              #Frame = window
                    #              fills in space,  if there is white space fill
        container.pack(side="top", fill="both", expand = True)
                                # min size, priority
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)


        ## Menu bar
        menubar = tk.Menu(container)
        filemenu = tk.Menu(menubar, tearoff = 0)
        filemenu.add_command(label = "Save", command = lambda:popupmsg(Nsup))
        filemenu.add_separator()
        filemenu.add_command(label = "Exit", command = quit)

        newmenu = tk.Menu(menubar, tearoff = 1)
        newmenu.add_command(label = "Add line", command = lambda:popupmsg(Nsup))
        newmenu.add_command(label = "del line", command = lambda:popupmsg(Nsup))

        menubar.add_cascade(label="File", menu=filemenu) ## show it
        menubar.add_cascade(label="New", menu=newmenu)
        tk.Tk.config(self, menu=menubar)
        
        ## end Menu bar
        self.frames = {}

        for F in (StartPage, MainP):
            frame = F(container, self)
            self.frames[F] = frame
                                    # north, south, east, west
            frame.grid(row=0, column = 0, sticky="nsew")

        self.show_frame(StartPage)

    def show_frame(self, cont):
        frame = self.frames[cont]
        frame.tkraise()


class StartPage(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        label = ttk.Label(self, text= "Start page?", font= "LARGE_FONT") ## just defined the object
        label.grid(row=1, column = 1)

        button1 = ttk.Button(self, text="ok",
                            command=lambda: controller.show_frame(MainP) )
        button1.grid(row=2, column = 2)



        
class MainP(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
    
        f = Figure()
        a = f.add_subplot(111)
        
        draw()
        for i in range(len(X)):
            if i is not (Sel):
                a.plot(X[i],Y[i], color="black", linewidth = 0.6)
            if i is Sel:
                a.plot(X[i],Y[i], color="blue", linewidth = 1)
        ## set frame 
        optionsframe = tk.Frame(self)
        optionsframe.grid(row = 0, column = 0)
        ## withing options frame
        button1 = ttk.Button(optionsframe, text="+")
        button1.grid(row=1, column = 0)
        button2 = ttk.Button(optionsframe, text="-")
        button2.grid(row=1, column = 1)

        button1 = ttk.Button(optionsframe, text="<")
        button1.grid(row=2, column = 0)
        button2 = ttk.Button(optionsframe, text=">")
        button2.grid(row=2, column = 1)

        scaleframe = tk.Frame(optionsframe)
        scaleframe.grid(row = 3, column = 0)
        
        slabel1 = ttk.Label(scaleframe, text = "    Amp", font = "NORM_FONT")
        slabel1.grid(row = 3, column = 0)
        slabel2 = ttk.Label(scaleframe, text = "    Frq", font = "SMALL_FONT")
        slabel2.grid(row = 3, column = 1)
        slabel3 = ttk.Label(scaleframe, text = "    Inc", font = "NORM_FONT")
        slabel3.grid(row = 3, column = 2)
        
        scale1 = tk.Scale(scaleframe, from_=100, to=0.1)
        scale1.grid(row=4, column = 0)
        scale2 = tk.Scale(scaleframe, from_=100, to=0)
        scale2.grid(row=4, column = 1)
        scale3 = tk.Scale(scaleframe, from_=100, to=0)
        scale3.grid(row=4, column = 2)
        ## end
        
        #show the plot
        plotsframe = tk.Frame(self)
        plotsframe.grid(row = 0, column = 1)
        plotsframe.grid_columnconfigure(0, weight=1)
        plotsframe.grid_rowconfigure(0, weight=1)

        
        canvas = FigureCanvasTkAgg(f,plotsframe)
        canvas.show()
        canvas.get_tk_widget().grid(row=0, column=0, rowspan = 2, pady=20, padx=10, sticky='nsew')



        """
        #show the plot
        canvas = FigureCanvasTkAgg(f,self)
        canvas.show()
        canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand = True)

        # for matplotlib toolbar
        toolbar = NavigationToolbar2TkAgg(canvas, self)
        toolbar.update()
        canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand = True)
        """
        

app = GUI()
app.geometry("1280x720")
app.mainloop()
Reply
#2
first you don't show enough code to run what is controller?
where's you initial setup of parent?

If you're not too far into your project to change GUI packages, I'd look into wxpython
In tkinter is notoriously difficult to get your geometry correct.
In wxpython it's a snap see example here:
Reply
#3
sorry, I've uploaded the whole code, I'll take a look at wxpython.
Reply
#4
Sorry, forgot the link: https://python-forum.io/Thread-Perfectly...n-template
Reply
#5
thanks, I'm trying to switch over to wxpython. I'm having a few problems though, I am not being able to fit a matplotlib figure to a panel (it works when its the whole screen) can you help me out? also is there a way to get the size of the frame without having to set it in the int? here is the code that I've done so far

import wx

##mpl in wx
import wx.lib.agw.aui as aui
import matplotlib
matplotlib.use('WXAgg')
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.backends.backend_wx import NavigationToolbar2Wx
from matplotlib.figure import Figure

class Main(wx.Frame):
    def __init__(self, *args, **kwargs):
        dispX = wx.DisplaySize()[0]
        dispY = wx.DisplaySize()[1]
        super(Main, self).__init__(*args, **kwargs, size= (dispX, dispY))

        #frame starts in center of 
        ##self.Move((dispX/4, dispY/4))
        self.Show()

        self.basicGUI()

    def basicGUI(self, *args, **kwargs):
        dispX = wx.DisplaySize()[0]
        dispY = wx.DisplaySize()[1]
        lowestpos = dispY
        #menu bar
        menuBar = wx.MenuBar()
        ##panel
        panelLW = dispX*.2
        panelLH = lowestpos
        panelL = wx.Panel(self, id=wx.ID_ANY, size=(panelLW,lowestpos) )

        panelRW = dispX*.2 - panelLW
        panelRH = lowestpos
        panelR = wx.Panel(self)
        
        # menu options
        fileButton = wx.Menu()
        editButton = wx.Menu()
        helpButton = wx.Menu()
        
        # File options
        exitItem = fileButton.Append(wx.ID_EXIT, "E&xit", "Close Program")
        menuBar.Append(fileButton, '&File')
        # Edit options
        menuBar.Append(editButton, '&Edit')
        # Help options
        menuBar.Append(helpButton, '&Help')
        
        #call it
        self.SetMenuBar(menuBar)
        #what to do when click
        self.Bind(wx.EVT_MENU, self.Quit, exitItem)
        self.SetTitle("prog")
        self.Show(True)

        
        wx.TextCtrl(panelL, pos=(10,10), size=(panelLW-20 ,lowestpos-80))

        #matplotlib
        self._mgr = aui.AuiManager(self)
        self.figure = Figure()
        self.axes = self.figure.add_subplot(111)
        self.canvas = FigureCanvas(panelR, -1, self.figure)
        #self.sizer = wx.BoxSizer(wx.VERTICAL)
        #self.sizer.Add(panelR, 1, wx.LEFT | wx.TOP | wx.GROW)
        #self.SetSizer(panelR.sizer)
        panelL.Fit()
        #end
        
        self._mgr.Update()
        self.Show()
        
    def Quit(self, e):
        self.Close()
    def Conf(self, e):
        pass
        
def main():
    app = wx.App()
    Main(None)
    app.MainLoop()

main()
Reply
#6
This more than fills my screen.
What exactly is your goal, number of panes, and what goes where.
Reply
#7
I'd like to have 2 panels, similar to the example that you gave me, the left panel(now it's with a textbox) with a few buttons and sliders to manipulate the graph on the right panel. I'd like the plot to fill the right panel but it isn't showing.
Reply
#8
Ok, I'll play with it. You may not see results until tomorrow.
Reply
#9
OK,
This is almost there. For some reason the numpy plot is not plotting, but I'll leave that for you to fix.
Should just be a typo somewhere.
You'll also have to add back your buttons and binding, but the canvas is where you want it ...
import wx
import wx.aui as aui
import wx.lib.agw.aui as aui
import matplotlib
matplotlib.use('WXAgg')
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.figure import Figure
from numpy import arange, sin, pi


class Nutrition(wx.Frame):
    def __init__(self, parent, id=wx.ID_ANY, title="Matplotlib Example", pos=wx.DefaultPosition,
                 size=(1200, 675), style=wx.DEFAULT_FRAME_STYLE, name='TryMethods'):
        # ideal size: width = height x 1.77864583 or height = width / 1.77864583
        self.main_width = size[0]
        self.main_height = size[1]
        app = wx.App()
        wx.Frame.__init__(self, parent, id, title, pos, size, style)
        app.SetTopWindow(self)
        # self.pnl = pnl = MainPanel(self)
        self._mgr = aui.AuiManager(self)

        left_panel_width = self.main_width * .3  # This is 30% of main width
        left_panel_height = self.main_height * .75  # This is 75% of main height
        left_panel_sz = left_panel_width, left_panel_height  # combined for widget size

        right_panel_width = self.main_width - left_panel_width  # which is 70% of main width
        right_panel_height = left_panel_height  # Keep same height as left panel
        right_panel_sz = right_panel_width, right_panel_height


        self.left_panel = wx.Panel(self, id=wx.ID_ANY, size=left_panel_sz)
        self.right_panel = wx.Panel(self, id=wx.ID_ANY, size=right_panel_sz)


        hsizer = wx.BoxSizer(wx.HORIZONTAL)

        self.figure = Figure()
        self.axes = self.figure.add_subplot(111)
        self.canvas = FigureCanvas(self.right_panel, -1, self.figure)
        self.sizer = wx.BoxSizer(wx.VERTICAL)
        self.sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.EXPAND)
        hsizer.SetSizeHints(self.right_panel)
        self.right_panel.SetSizer(self.sizer)

        self._mgr.AddPane(self.left_panel, aui.AuiPaneInfo().Left())
        self._mgr.AddPane(self.right_panel, aui.AuiPaneInfo().Center())

        self._mgr.Update()
        self.Show()

        app.MainLoop()

    def draw(self):
        t = arange(0.0, 3.0, 0.01)
        s = sin(2 * pi * t)
        self.axes.plot(t, s)

def main():
    tm = Nutrition(None)
    tm.draw()

if __name__ == '__main__':
    main()
Click to enlarge:
   
Reply
#10
wow thanks man. ya it should plot nothing so far I'm only working on the gui later I'll actually get something in the graph that way thing wont get overcrowded. when I finish the code I'll add it here incase if someone wants to use it as a reference.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Centering and adding a push button to a grid window, TKinter Edward_ 15 4,666 May-25-2023, 07:37 PM
Last Post: deanhystad
  [Tkinter] Draw a grid of Tkinter Canvas Rectangles MrTim 5 7,867 May-09-2021, 01:48 PM
Last Post: joe_momma
  Tkinter grid columnspan being ignored mntfr 6 6,794 Feb-01-2019, 06:01 PM
Last Post: mntfr
  Widget placement issues with tkinter grid thread 1 mgtheboss 2 4,353 Jan-09-2018, 03:59 PM
Last Post: SmokerX

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020