• 締切済み

tkinterのFrame他で画像を循環表示する

pythonのtkinterモジュールを使って画像表示するのに下記のようなコードをコピペで作りました。しかしこのコードではクリックコマンドの動作に関する関数を備えていないため動きません。後ろのcanvasを使ったコードに示したような関数を組み込むにはどうすればいいのでしょうか。お教えください。 #Frameの例 import tkinter as tk from tkinter import Frame, Label from PIL import Image, ImageTk import sys, os root = tk.Tk() root.title("Image in Frame Example") root.geometry("600x450") # Optional: set window size frame = Frame(root, width=500, height=400, bg="white") frame.pack(pady=20) # Adjust padding as necessary dir_name = "GUI" image_data = [os.path.join(dir_name, file) for file in os.listdir(dir_name)\ if ".png" in file or ".PNG" in file or ".jpg" in file or ".JPG" in file or ".jpeg" in file or ".JPEG" in file or ".gif" in file or ".GIF" in file] image = Image.open(image_data[7]) original_size =image.size if image.size[0] <= image.size[1]: h1 = 400 img =image.resize((int(h1/original_size[1]*original_size[0]), h1), Image.LANCZOS) elif image.size[0] > image.size[1]: w1 = 500 img =image.resize(( w1,int(w1/original_size[0]*original_size[1])), Image.LANCZOS) photo_image = ImageTk.PhotoImage(img) image_label = Label(frame, image=photo_image) image_label.pack() root.mainloop() #canvasの例 import tkinter as tk from PIL import Image, ImageTk import sys, os class Application(tk.Frame): def __init__(self, master = None): super().__init__(master) self.master.title("画像の表示") self.master.geometry("540x440") self.canvas = tk.Canvas(self.master) self.canvas.pack(expand = True, fill = tk.BOTH) self.update() canvas_width = self.canvas.winfo_width() - 20 canvas_height = self.canvas.winfo_height() - 40 dir_name = "GUI" image_data = [os.path.join(dir_name, file) for file in os.listdir(dir_name)\ if ".png" in file or ".PNG" in file or ".jpg" in file or ".JPG" in file or ".jpeg" in file or ".JPEG" in file or ".gif" in file or ".GIF" in file] pil_image = Image.open(image_data[9]) original_size =pil_image.size if pil_image.size[0] <= pil_image.size[1]: h1 = canvas_height img =pil_image.resize((int(h1/original_size[1]*original_size[0]), h1), Image.LANCZOS) elif pil_image.size[0] > pil_image.size[1]: w1 = canvas_width img =pil_image.resize(( w1,int(w1/original_size[0]*original_size[1])), Image.LANCZOS) self.photo_image = ImageTk.PhotoImage(image= img) self.canvas.create_image( canvas_width / 2 + 10, canvas_height / 2, image=self.photo_image ) btn=tk.Button(text='Click',command="") btn.pack(ipadx=10,ipady=5) if __name__ == "__main__": root = tk.Tk() app = Application(master = root) app.mainloop() #クリック動作に関する関数を含む例 import tkinter as tk index=0 #画像のindexはグローバルで管理する def btn_click(): global index index=(index+1) % len(photos) canvas.delete('p1') canvas.create_image(320,213,image=photos[index],tag='p1') root=tk.Tk() root.geometry('700x560') root['bg']='lightgrey' canvas=tk.Canvas(root,width=640,height=426,bd=0, highlightthickness=0, relief='ridge') canvas.pack(pady=20) photos=[ tk.PhotoImage(file='GUI/s.png'), tk.PhotoImage(file='GUI/frog2.png'), tk.PhotoImage(file='GUI/k05.png'), ] canvas.create_image(320,213,image=photos[index],tag='p1') btn=tk.Button(text='Click',command=btn_click) btn.pack(ipadx=10,ipady=5) root.mainloop() TkEasyGUIのcanvasで出来ないかと思いましたがなんかそこまでの部品が見当たらないようなので他を探してみたところtkinterでの例が見受けられたので早速画像のアスペクト比を維持して表示する方法をcanvasを含めいろいろ組み込んでみましたが、いざ循環表示の処でお手上げです。なおFrameの場合適正なボタン配置が分かりませんでした。 私みたいな半端な者には、サイトによって様々な方法が紹介されていても同じpythonの文法として理解できないのが現状です。よろしくお願いします。

みんなの回答

回答No.1

あなたの取り組んでいる問題について、少しでもお手伝いできれば幸いです。Tkinterで画像を循環表示するためには、ボタンのクリックイベントによって表示する画像を切り替える機能を実装する必要があります。以下は、Frameを使用したサンプルコードで、ボタンをクリックすると画像が循環するようにしています。 ```python import tkinter as tk from tkinter import Frame, Label, Button from PIL import Image, ImageTk import sys, os class ImageCycleApp: def __init__(self, root): self.root = root self.root.title("Image in Frame Example") self.root.geometry("600x500") # Optional: set window size self.frame = Frame(self.root, width=500, height=400, bg="white") self.frame.pack(pady=20) # Adjust padding as necessary # Load images dir_name = "GUI" self.image_data = [os.path.join(dir_name, file) for file in os.listdir(dir_name) if file.lower().endswith(('.png', '.jpg', '.jpeg', '.gif'))] self.photos = [self.load_image(image_path) for image_path in self.image_data] self.index = 0 self.image_label = Label(self.frame, image=self.photos[self.index]) self.image_label.pack() self.button = Button(self.root, text='Click', command=self.cycle_image) self.button.pack() def load_image(self, image_path): image = Image.open(image_path) original_size = image.size if image.size[0] <= image.size[1]: h1 = 400 img = image.resize((int(h1 / original_size[1] * original_size[0]), h1), Image.LANCZOS) else: w1 = 500 img = image.resize((w1, int(w1 / original_size[0] * original_size[1])), Image.LANCZOS) return ImageTk.PhotoImage(img) def cycle_image(self): self.index = (self.index + 1) % len(self.photos) self.image_label.config(image=self.photos[self.index]) if __name__ == "__main__": root = tk.Tk() app = ImageCycleApp(root) root.mainloop() ``` このコードでは、`ImageCycleApp`クラスで画像のリストを管理し、ボタンをクリックするごとに表示される画像を切り替えています。このサンプルを基に、あなたの具体的な要件に合わせて調整してみてください。質問があれば、いつでもお気軽にどうぞ。 ------------------------------------------------ こちらの回答はAIエージェント「あい」による参考回答です。 有識者からの回答も是非お待ちしています。 OKWAVEのAIに対する取り組みについてはこちらをご確認ください。 https://staffblog.okwave.jp/2023/06/07/10415/

turu575
質問者

お礼

ボタンがアスペクト比の違いで画像に合わせて配置されるようになるのは気になるがスムーズに切り替わる。

turu575
質問者

補足

ボタン位置を固定で配置して下記コードのように多少内容を変えて試みたが、画像の配置について未だ分からないままです。左右はデフォルトでセンター配置になるが上下のセンター指定の方法が分からない。 import tkinter as tk from tkinter import Frame, Label, Button from PIL import Image, ImageTk import sys, os class ImageCycleApp: def __init__(self, root): self.root = root self.root.title("Image in Frame Example") self.root.geometry("850x720") # Optional: set window size self.frame = Frame(self.root, width=720, height=540,background="red") self.frame.pack(pady=10) # Adjust padding as necessary SCRIPT_DIR = os.path.dirname(__file__) # 実行ファイルのパスを取得 SAVE_FILE = os.path.join(SCRIPT_DIR, "notepad-save-data.txt") with open(SAVE_FILE, "r", encoding="utf-8") as f: s = f.read() self.image_data=s.split(";") self.photos = [self.load_image(image_path) for image_path in self.image_data] self.index = 0 self.image_label = Label(self.frame, image=self.photos[self.index]) self.image_label.pack() self.button1 = Button(self.root, text='▷', command=self.cycle_image).place(x=420,y=680) self.button2 = Button(self.root, text='◁', command=self.cycle_image2).place(x=370,y=680) self.button3 = Button(self.root, text='□', command=self.cycle_image3).place(x=390,y=680) self.button4 = Button(self.root, text='close', command=self.main).place(x=800,y=680) def load_image(self, image_path): image = Image.open(image_path) original_size = image.size if image.size[0] <= image.size[1]: h1 = 540 img = image.resize((int(h1 / original_size[1] * original_size[0]), h1), Image.LANCZOS) else: w1 = 720 img = image.resize((w1, int(w1 / original_size[0] * original_size[1])), Image.LANCZOS) return ImageTk.PhotoImage(img) def cycle_image(self): self.index = (self.index + 1) % len(self.photos) self.image_label.config(image=self.photos[self.index]) def cycle_image2(self): self.index = (self.index - 1) % len(self.photos) self.image_label.config(image=self.photos[self.index]) def cycle_image3(self): self.index = 0 self.image_label.config(image=self.photos[0]) def main(self): self.root.destroy() import imx_03 sys.exit(0) if __name__ == "__main__": root = tk.Tk() app = ImageCycleApp(root) root.mainloop() このファイルは、別のファイルでTkEasyGUIを使い複数の画像ファイルを指定してテキストファイルを経由して表示することを目的としたものです。また、直接ファイルパスのリストの受け渡しをsubprocessモジュールを使うことによって別途ファイルで表示できるようにまでなりましたが、肝心の表示方法でとどまったままです。

関連するQ&A