2016-03-10 237 views
0

我正在创建一个GUI,它应该在主窗口左侧显示一些小部件(例如按钮和比例尺)(或由'root=tk.Tk()'创建的'root'和右侧的图表。该图将使用matplotlib和FigureCanvasTkAgg()后端创建(类似于发现的here)。以下是我迄今为止编写的代码。Tkinter和Matplotlib:创建的画布的相对位置FigureCanvasTkAgg

import tkMessageBox, tkFileDialog 
import sys 
# Tkinter is for python 2; tkinter is for python 3 
if sys.version_info[0] < 3: 
    import Tkinter as tk 
else: 
    import tkinter as tk 


class MainApp(tk.Frame): 

    def __init__(self, parent): 
     tk.Frame.__init__(self, parent) 
     self.parent = parent 
     self.parent.title('App') 
     # call the widgets 
     self.okButton() 
     self.quitButton() 
     self.readDataButton() 
     self.clearDataButton() 
     self.velScale() 
     self.canvas() 

    # print messages on the screen 
    def printMessage(self): 
     if (self.data): 
      print("Data is loaded and accessible from here (printMessage()).") 
     else: 
      print('No data loaded...') 

    ### OK button 
    def okButton(self): 
     self.okButton = tk.Button(self, text='Test', command=self.printMessage) 
     self.okButton.grid() 

    ### Quit button 
    def quitButton(self): 
     self.quitButton = tk.Button(self, text='Quit', command=self.confirmQuit) 
     self.quitButton.grid() 
    # confirm quitting 
    def confirmQuit(self): 
     answer = tkMessageBox.askyesno(title="App", message="Do you really want to quit?") 
     if (answer): 
      self.quit() 

    # Read data button 
    def readDataButton(self): 
     self.data = None 
     self.readDataButton = tk.Button(self, text='Import data', command=self.readData) 
     self.readDataButton.grid() 
    # reading data 
    def readData(self): 
     import os 
     fullPath = dataList = tkFileDialog.askopenfilename(initialdir='path/to/initialdir') 
     dataDir = os.path.split(fullPath)[0]+'/' 
     self.data = readData(fullPath) 

    # Clear data from current session 
    def clearDataButton(self): 
     self.clearData = tk.Button(self, text='Clear data', command=self.confirmClearData) 
     self.clearData.grid() 
    # confirm clearing data 
    def confirmClearData(self): 
     answer = tkMessageBox.askyesno(title="App", message="Are you sure you want to clear the loaded data?") 
     if (answer): 
      self.data = None 
      tkMessageBox.showwarning(title="App", message="Data has been deleted.") 

    # Velocity scale 
    def velScale(self): 
     self.velVar = tk.StringVar() 
     velLabel = tk.Label(self, text="Scale value:", textvariable=self.velVar) 
     velLabel.grid(row=4, column=0, columnspan=2, sticky=tk.W+tk.E) 
     velScale = tk.Scale(self, from_=-500, to=+500, orient=tk.HORIZONTAL, resolution=20, 
         sliderlength=20, showvalue=0, 
         length=200, width=20, 
         command=self.onVelScale) 
     velScale.grid(row=5, column=0) 
    # update velLabel 
    def onVelScale(self, val): 
     self.velVar.set("Scale value: {:+0.0f}".format(float(val))) 

    # Canvas 
    def canvas(self): 
     import matplotlib 
     import matplotlib.pyplot as plt 
     matplotlib.use("TkAgg") 
     from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg 
     from matplotlib.figure import Figure 

     self.f = Figure(figsize=(4,2)) 
     self.a = self.f.add_subplot(111) 
     self.a.plot([1,2,3,4,5,6,7,8],[5,6,1,3,8,9,3,5]) 

     self.canvas = FigureCanvasTkAgg(self.f, master=self.parent) 
     self.canvas.show() 
     self.canvas.get_tk_widget().pack() 

     self.toolbar = NavigationToolbar2TkAgg(self.canvas, self.parent) 
     self.toolbar.update() 
     self.canvas._tkcanvas.pack() 



if __name__ == "__main__": 
    root = tk.Tk() 
    root.geometry("800x600+10+10") 
    root.resizable(0, 0) 
    MainApp(root).pack(side=tk.TOP) 
    root.mainloop() 

结果是这样的:Screenshot of the App's main window。使用.grid()作为按钮和比例小部件按预期工作(我可以通过指定rowcolumn将它们放置在任何地方)。但是,我不能在画布部分具有相同的行为。似乎只有.pack()将与画布一起工作(并且结果显示在上面的链接中)。

有没有人有关于如何解决这个问题的任何想法?或者我错过了什么?

谢谢你的任何建议。

+0

首先,我不认为你需要调用'show'当你'网格'的数字,但其次你有一些代码可以在python 2或3中使用'tkinter',但你没有改变你为filedialogs或消息框输入,这些也在2和3之间变化。 –

+0

嗨,@JamesKent!感谢您的意见。我已经改变了代码来相应地导入'tkMessageBox'和'tkFileDialog'到正在使用的Python版本。关于你对'.grid()'的评论,你能否详细说明一下? ;) – mairan

回答

0

我与python3.3的工作,我已经改变了你的代码是:

import sys 
import matplotlib 
import matplotlib.pyplot as plt 
matplotlib.use("TkAgg") 
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg 
from matplotlib.figure import Figure 
# Tkinter is for python 2; tkinter is for python 3 
if sys.version_info[0] < 3: 
    import Tkinter as tk 
    import tkMessageBox, tkFileDialog 

else: 
    import tkinter as tk 
    from tkinter import messagebox as tkMessageBox 
    from tkinter import filedialog as tkFileDialog 

class MainApp(tk.Frame): 

    def __init__(self, parent): 
     tk.Frame.__init__(self, parent) 
     self.parent = parent 
     self.parent.title('App') 
     # call the widgets 
     self.okButton() 
     self.quitButton() 
     self.readDataButton() 
     self.clearDataButton() 
     self.velScale() 
     self.canvas() 

    # print messages on the screen 
    def printMessage(self): 
     if (self.data): 
      print("Data is loaded and accessible from here (printMessage()).") 
     else: 
      print('No data loaded...') 

    ### OK button 
    def okButton(self): 
     self.okButton = tk.Button(self, text='Test', command=self.printMessage) 
     self.okButton.grid(column=1, row=1, sticky="nesw") 

    ### Quit button 
    def quitButton(self): 
     self.quitButton = tk.Button(self, text='Quit', command=self.confirmQuit) 
     self.quitButton.grid(column=1, row=2, sticky="nesw") 
    # confirm quitting 
    def confirmQuit(self): 
     answer = tkMessageBox.askyesno(title="App", message="Do you really want to quit?") 
     if (answer): 
      self.quit() 

    # Read data button 
    def readDataButton(self): 
     self.data = None 
     self.readDataButton = tk.Button(self, text='Import data', command=self.readData) 
     self.readDataButton.grid(column=1, row=3, sticky="nesw") 
    # reading data 
    def readData(self): 
     import os 
     fullPath = dataList = tkFileDialog.askopenfilename(initialdir='path/to/initialdir') 
     dataDir = os.path.split(fullPath)[0]+'/' 
     self.data = readData(fullPath) 

    # Clear data from current session 
    def clearDataButton(self): 
     self.clearData = tk.Button(self, text='Clear data', command=self.confirmClearData) 
     self.clearData.grid(column=1, row=4, sticky="nesw") 
    # confirm clearing data 
    def confirmClearData(self): 
     answer = tkMessageBox.askyesno(title="App", message="Are you sure you want to clear the loaded data?") 
     if (answer): 
      self.data = None 
      tkMessageBox.showwarning(title="App", message="Data has been deleted.") 

    # Velocity scale 
    def velScale(self): 
     self.velVar = tk.StringVar() 
     velLabel = tk.Label(self, text="Scale value:", textvariable=self.velVar) 
     velLabel.grid(row=4, column=0, columnspan=2, sticky=tk.W+tk.E) 
     velScale = tk.Scale(self, from_=-500, to=+500, orient=tk.HORIZONTAL, resolution=20, 
         sliderlength=20, showvalue=0, 
         length=200, width=20, 
         command=self.onVelScale) 
     velScale.grid(column=1, row=5, sticky="nesw") 
    # update velLabel 
    def onVelScale(self, val): 
     self.velVar.set("Scale value: {:+0.0f}".format(float(val))) 

    # Canvas 
    def canvas(self): 
     self.f = Figure(figsize=(4,2)) 
     self.a = self.f.add_subplot(111) 
     self.a.plot([1,2,3,4,5,6,7,8],[5,6,1,3,8,9,3,5]) 

     self.canvas = FigureCanvasTkAgg(self.f, master=self) 
     self.canvas.get_tk_widget().grid(column=2, row=1, rowspan=5, sticky="nesw") 

     self.toolbar = NavigationToolbar2TkAgg(self.canvas, self.parent) 

if __name__ == "__main__": 
    root = tk.Tk() 
    root.geometry("800x600+10+10") 
    root.resizable(0, 0) 
    MainApp(root).pack(side=tk.TOP) 
    root.mainloop() 

显示我的意思不是左右调用show我也动了你的matplotlib进口到该文件的顶部并改变了其他进口,以适应蟒蛇2/3,这似乎对我来说很好,你能澄清它没有做的,你期望它做什么吗? (如果这仍然无法正常工作)

+0

谢谢,詹姆斯肯特。现在我明白了。然而,使用'.grid()'的问题仍然存在:使用'row'和'column'作为参数,我仍然不能将按钮/比例小部件放在左边,而绘图区域放在右边。 – mairan

+0

我不能相信我错过了它,问题在于你试图放置情节的地方,你应该把它放到框架中,而是你试图把它放到框架的父亲,因为框架是包装和情节是网格化它进入一个无尽的循环试图找出在哪里放置一切,试试上面修改后的代码。 –

+0

就是这样,@詹姆斯肯特!现在可以使用'row'和'column'选项通过'.grid()'控制它们。谢谢! ;) – mairan

0

你没有得到一个有错误的画布()函数和调用FigureCanvasTkAgg帆布

+1

谢谢,安德烈!当我有机会时,我会给它一个镜头。 – mairan

+0

处理与matplotlib,画布和网格类似的问题,并看到与导致我问题的变量相同的命名函数。 –