2017-05-02 1 views
0

Ich versuche, ein Bild anzuzeigen, ein Bild, das durch filialialog geöffnet ist. Meine aktuelle Methode initialisiert den Frame in Step1 mit "image1path", und dann möchte ich ihn auf einen vom Benutzer angegebenen "image2path" updaten. Ich versuche dies über das Attribut Data.currentJPEG zu erreichen.Pythonic Weg, um benutzerdefinierte Bild in Tkinter Rahmen hinzufügen

  1. Gibt es eine bessere Möglichkeit, die nicht mit einem "Dummy" Image zu initialisieren?
  2. Wenn dies der richtige Weg ist, warum kommen meine auskommentierten Zeilen unten zurück: "'str' Objekt hat kein Attribut '_bind'", wenn Step1 keine Zeichenkette ist. Ich dachte Step1 war, was es ermöglichte, dass self.bind auf der startPage arbeitete. Ist das nicht die richtige Methode, um das Bild im Bild zu aktualisieren?
  3. Bonus Seite Frage: wenn ich Gewicht = 100 zu Gewicht = 1 in den Start-Seitenzeilen ändern, warum skaliert die Open .jpg Taste überhaupt?

Dieser Code kann Struktur here

Ändern der Größe eines Bildes auf diese Weise gefunden zu verwenden, können here

Die Methode, die ich versuchen, folgt gefunden werden this answer, wo eine neue Funktion, die aufgerufen wird, wenn die Taste gedrückt wird Das aktualisiert das Bild. Ich glaube jedoch, dass ich auf Probleme stoße, weil mein Bild auch die Größenänderungsfunktion verwendet.

  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() 

Antwort

0

Wenn alles, was Sie tun möchten, ist Ihre Benutzer manuell lassen eine Datei auswählen, und dann haben Ihre tkinter GUI es anzuzeigen, benötigen Sie nur ein Button und ein Canvas.

-Code:

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() 

Wenn Sie Ihre mehrere Klassen Struktur behalten möchten, werden Sie eine bessere Nutzung des Root-Teil Ihrer GUI machen müssen (controller in Ihrem Subrahmen genannt) zu kommunizieren zwischen den verschiedenen Frames. Sehen Sie den folgenden Code, um loszulegen:

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() 
+0

Das funktioniert gut, aber können Sie zeigen, wie Sie eine Taste verwenden, um openJPEG aus einer anderen Klasse auszuführen? In meinem Fall ist diese Schaltfläche für das Öffnen von Bildern auf der Startseite vorhanden, aber das Bild sollte im Rahmen von Schritt 1 geöffnet werden. Ich würde denken, Sie würden verwenden: command = Step1.openJPEG, aber das scheint nicht der Fall zu sein. Ich brauche auch Controller für den Frame-Switch übergeben werden. – theMostVersatileSnake

+0

Ich habe meiner Antwort eine überarbeitete Version Ihres Codes hinzugefügt, um Ihnen zu zeigen, wie Sie zwischen verschiedenen Teilen Ihrer GUI in verschiedenen Klassen kommunizieren können, indem Sie eine gemeinsame "Controller" -Klasse verwenden. – Josselin

+1

Ich beginne, diese Struktur ein bisschen besser zu verstehen. Können Sie unter Schritt 1 "self.controller = controller" näher erläutern? Ich dachte Controller wurde vererbt nur mit __init __ (selbst, Eltern, Controller). Vielen Dank für Ihre Hilfe! – theMostVersatileSnake

Verwandte Themen