Pythonic将用户定义的图像添加到tkinter帧中的方法

时间:2017-05-02 18:20:43

标签: python image tkinter resize

我试图让一个框架显示一个通过filedialog打开的图像。我当前的方法使用“image1path”初始化Step1中的帧,然后我想将其更新为用户指定的某个“image2path”。我试图通过Data.currentJPEG属性执行此操作。

  1. 有没有更好的方法不涉及初始化“虚拟”图像?
  2. 如果这是正确的方法,为什么我在底部注释掉的行返回:“'str'对象没有属性'_bind'”当Step1不是字符串时。我认为Step1是允许self.bind在startPage上工作的原因。这不是更新帧中图像的正确方法吗?
  3. 奖金方面的问题:如果我在开始页面行中改变权重= 100到权重= 1,为什么打开.jpg按钮的位置比例尺呢?
  4. 可以找到此代码结构here

    可以通过这种方式调整图像大小here

    我尝试使用的方法遵循this answer,其中按下按钮时会调用新函数来更新图像。但是,我认为我遇到了问题,因为我的图像也使用了调整大小功能。

                import os
                import tkinter as tk
                from PIL import Image, ImageTk
                from tkinter import filedialog
    
                image1path='mainGraphic.jpg'
    
                cwd = os.getcwd()
    
                # where opened file data with be stored
                class Data():
                    # this sets initial values for the class attributes 
                    def __init__(self):
                        self.currentJPEG=image1path
    
                class program(tk.Tk):
                    def __init__(self,*args,**kwargs):
                        tk.Tk.__init__(self,*args,**kwargs)
    
                        self.title('program name')
    
                        container = tk.Frame(self)
                        container.pack(side="top", fill="both", expand=True)
                        container.grid_rowconfigure(0, weight=1)
                        container.grid_columnconfigure(0, weight=1)
    
                        # frames are laid ontop of each other, startPage shown first
                        self.frames = {}
                        for Frame in (StartPage, Step1):
                            frame = Frame(container, self)
                            self.frames[Frame] = frame
                            frame.grid(row = 0, column = 0, sticky="nsew")
                            frame.columnconfigure(0, weight=1)
                            frame.rowconfigure(0, weight=1)
    
                        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)
    
                        # scale rows and columns (make button scaling negligible) 
                        self.rowconfigure(0,weight=0)
                        self.rowconfigure(1,weight=100) #bonus question refers to these 2 lines
                        self.columnconfigure(0,weight=100) 
    
                        # button to open an image in Step 1,
                             # must pass program so app.showframe is available,
                             # must pass Step1 so the image attributes are available?
                        button = tk.Button(self, text='Open .jpg File in new frame',
                                            command=lambda: Step1.openJPEG(program))
                        button.grid(row=0, column=0, sticky='ew')
    
                        # add the main graphic
                        self.canvas = tk.Canvas(self,bg='black')
                        self.canvas.grid(row=1, column=0, sticky='nsew')
                        self.img_copy = Image.open(image1path)
                        self.image = None #this is overriden every time the image is redrawn so there is no need to make it yet
                        self.bind("<Configure>",self.resizeImage)
    
                    def resizeImage(self,event):
                        origin = (0,0)
                        size = (event.width, event.height)
                        if self.bbox("bg") != origin + size:
                            self.canvas.delete("bg")
                            self.image = self.img_copy.resize(size)
                            self.background_image = ImageTk.PhotoImage(self.image)
                            self.canvas.create_image(*origin,anchor="nw",image=self.background_image,tags="bg")
                            self.canvas.tag_lower("bg","all")
    
                class Step1(tk.Frame):
    
                    def __init__(self, parent, controller):
                        tk.Frame.__init__(self, parent)
    
                        # give even weight to each subframe
                        self.rowconfigure(0, weight=1)
                        self.columnconfigure(0, weight=100)
                        self.columnconfigure(1, weight=100)
    
                        # Frame1, this is on the left and empty
                        frame1 = tk.Frame(self, bg="grey")
                        frame1.grid(row=0, column=0, sticky='nsew')
    
                        # Frame2, this is where image preview is
                        frame2 = tk.Frame(self, bg="grey")
                        frame2.grid(row=0, column=1, sticky='nsew')    
    
                        # scale rows and columns with equal weight
                        frame2.rowconfigure(0,weight=1)
                        frame2.columnconfigure(0,weight=100)
                        frame2.columnconfigure(1,weight=100)
    
                        # initialize where image preview will be in frame2
                        self.canvas = tk.Canvas(frame2,bg='black')
                        self.canvas.grid(row=0, column=1, sticky='nsew')
                        self.img_copy = Image.open(Data.currentJPEG)
                        self.image = None 
                        self.bind("<Configure>",self.resizeImage)
    
                    def resizeImage(self,event):
                        origin = (0,0)
                        size = (event.width, event.height) # these need to get height/width of their frame, not Step1
                        if self.bbox("bg") != origin + size:
                            self.canvas.delete("bg")
                            self.image = self.img_copy.resize(size)
                            self.background_image = ImageTk.PhotoImage(self.image)
                            self.canvas.create_image(*origin,anchor="nw",image=self.background_image,tags="bg")
                            self.canvas.tag_lower("bg","all")
    
                    # update the image in frame2 using opened jpeg image
                    def openJPEG(program):
                        filePath = filedialog.askopenfilename(initialdir=cwd,
                                                              filetypes=(("JPEG",".jpg"),("All Files","*.*")),
                                                              title="Open JPEG")
                        try:
                            with open(filePath) as image: #***need a better 'try' statement for only jpeg is opened'
                                app.show_frame(Step1)
                        except:
                            print('could not open image')
                            return
    
                        ## update image preview from mainGraphic to opened JPEG; these lines aren't working
                        Data.currentJPEG=filePath
                        #Step1.img_copy = Image.open(Data.currentJPEG)
                        #Step1.image = None
                        #Step1.bind("<Configure>",Step1.resizeImage)
    
                # initalize data class
                Data=Data()
                # run program
                app = program()
    

1 个答案:

答案 0 :(得分:0)

如果你想做的只是让你的用户手动选择一个文件,然后让你的tkinter GUI显示它,你只需要ButtonCanvas

<强>代码

from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import matplotlib.image as mpimg
from tkinter import filedialog
import tkinter as tk
import os

class program(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)

        # Create a button to load a jpg
        self.button = tk.Button(self, text="Load image", command=self.openJPEG)
        self.button.pack()

        # Create a canvas on which to show the jpg
        self.frame = tk.Frame(self)
        self.frame.pack(fill=tk.BOTH, expand=1)
        self.create_canvas()

    def openJPEG(self):
        # Display a dialog for the user to select a jpg file, 
        filePath = filedialog.askopenfilename(initialdir=os.getcwd(),
                                              filetypes=(("JPEG",".jpg"),
                                                         ("All Files","*.*")),
                                              title="Open JPEG")
        # Show the selected jpg on the canvas
        img = mpimg.imread(filePath)
        self.ax1.imshow(img)
        self.canvas1.draw()

    def create_canvas(self):
        """ Add a canvas to plot images """        
        self.fig1 = Figure(frameon=False, figsize=(6, 4.5))
        self.canvas1 = FigureCanvasTkAgg(self.fig1, master=self.frame)
        self.canvas1.get_tk_widget().pack(fill=tk.BOTH, expand=1)
        self.ax1 = self.fig1.add_axes([0, 0, 1, 1])
        self.ax1.axis('off')

# Run program
app = program()
app.mainloop()

如果您想保留多个类结构,则必须更好地利用GUI的根部分(在子帧中称为controller)来进行不同的通信帧。请参阅以下代码以帮助您入门:

import os
import tkinter as tk
from PIL import Image, ImageTk
from tkinter import filedialog

# where opened file data with be stored
class Data():
    # this sets initial values for the class attributes 
    def __init__(self):
        self.currentJPEG=""

class program(tk.Tk):
    def __init__(self, Data):
        tk.Tk.__init__(self)
        self.Data = Data
        container = tk.Frame(self)
        container.pack(fill="both", expand=True)

        # frames are laid ontop of each other, startPage shown first
        self.frames = {}
        for Frame in (StartPage, Step1):
            frame = Frame(container, self)
            self.frames[Frame] = frame
            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)
        self.controller = controller

        # button to open an image in Step 1,
        button = tk.Button(self, text='Open .jpg File in new frame',
                           command= self.openJPEG)
        button.grid(row=0, column=0, sticky='ew')

        # add empty canvas
        self.canvas = tk.Canvas(self,bg='black')
        self.canvas.grid(row=1, column=0, sticky='nsew')

    def openJPEG(self):
        self.openJPEG
        filePath = filedialog.askopenfilename(initialdir=os.getcwd(),
                                              filetypes=(("JPEG",".jpg"),
                                                         ("All Files","*.*")),
                                              title="Open JPEG")
        # Update the image in Step1 frame
        self.controller.Data.currentJPEG = filePath
        self.controller.frames[Step1].show_current_image()
        # Show Step1 frame
        self.controller.show_frame(Step1)

class Step1(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller

        # Frame2, this is where image preview is
        frame2 = tk.Frame(self, bg="grey")
        frame2.grid(row=0, column=1, sticky='nsew')    

        # initialize where image preview will be in frame2
        self.canvas = tk.Canvas(frame2,bg='black')
        self.canvas.grid(row=0, column=1, sticky='nsew')

    def show_current_image(self):
        self.image = Image.open(self.controller.Data.currentJPEG)
        self.background_image = ImageTk.PhotoImage(self.image)
        self.canvas.create_image(0, 0, anchor="nw", image=self.background_image, 
                                 tags="bg")

# initalize data class
Data = Data()
# run program
app = program(Data)
app.mainloop()