【ChatGPT】画像ビューワのPythonプログラムを作る

今回はChatGPTを利用して、画像ビューワのPythonプログラムを作ってみます。

ChatGPTを利用してプログラムを作成すれば、素早く簡単に欲しい機能を追加したり、機能を提案してもらったりしながらプログラムを作成することができます。

まずは簡単にプロンプトを投げてみる

シンプルに「フォルダ内の画像を表示する画像ビューワのPythonプログラムを作る」ようにお願いしました。

出力されたコード

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

class ImageViewer(tk.Tk):
    def __init__(self):
        super().__init__()

        self.title("Image Viewer")
        self.geometry("800x600")
        
        self.current_image_index = 0
        self.images = []

        self.label = tk.Label(self)
        self.label.pack()

        self.open_folder_button = tk.Button(self, text="Open Folder", command=self.open_folder)
        self.open_folder_button.pack()

        self.prev_button = tk.Button(self, text="Previous", command=self.show_previous)
        self.prev_button.pack(side=tk.LEFT)

        self.next_button = tk.Button(self, text="Next", command=self.show_next)
        self.next_button.pack(side=tk.RIGHT)

    def open_folder(self):
        folder_path = filedialog.askdirectory()
        if folder_path:
            self.images = [
                os.path.join(folder_path, file) for file in os.listdir(folder_path)
                if file.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.bmp'))
            ]
            self.current_image_index = 0
            self.show_current_image()

    def show_current_image(self):
        if self.images:
            image_path = self.images[self.current_image_index]
            image = Image.open(image_path)
            image.thumbnail((800, 600), Image.ANTIALIAS)
            photo = ImageTk.PhotoImage(image)
            self.label.config(image=photo)
            self.label.image = photo

    def show_previous(self):
        if self.images:
            self.current_image_index -= 1
            if self.current_image_index < 0:
                self.current_image_index = len(self.images) - 1
            self.show_current_image()

    def show_next(self):
        if self.images:
            self.current_image_index += 1
            if self.current_image_index >= len(self.images):
                self.current_image_index = 0
            self.show_current_image()

if __name__ == "__main__":
    viewer = ImageViewer()
    viewer.mainloop()

実行結果

このように、簡単な指示で画像ビューワを作ることできました。

「Previous」「Next」で画像を変更することができます。

機能を追加する

一気に10枚ずつ表示するようにお願いしてみました。

出力されたコード

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

class ImageViewer(tk.Tk):
    def __init__(self):
        super().__init__()

        self.title("Image Viewer")
        self.geometry("1600x1200")

        self.current_image_index = 0
        self.images = []

        self.labels = []
        for i in range(2):
            for j in range(5):
                label = tk.Label(self)
                label.grid(row=i, column=j)
                self.labels.append(label)

        self.open_folder_button = tk.Button(self, text="Open Folder", command=self.open_folder)
        self.open_folder_button.grid(row=2, column=2)

        self.prev_button = tk.Button(self, text="Previous", command=self.show_previous)
        self.prev_button.grid(row=3, column=0)

        self.next_button = tk.Button(self, text="Next", command=self.show_next)
        self.next_button.grid(row=3, column=4)

    def open_folder(self):
        folder_path = filedialog.askdirectory()
        if folder_path:
            self.images = [
                os.path.join(folder_path, file) for file in os.listdir(folder_path)
                if file.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.bmp'))
            ]
            self.current_image_index = 0
            self.show_current_images()

    def show_current_images(self):
        for i, label in enumerate(self.labels):
            image_index = self.current_image_index + i
            if image_index < len(self.images):
                image_path = self.images[image_index]
                image = Image.open(image_path)
                image.thumbnail((300, 300), Image.ANTIALIAS)
                photo = ImageTk.PhotoImage(image)
                label.config(image=photo)
                label.image = photo
            else:
                label.config(image=None)
                label.image = None

    def show_previous(self):
        if self.images:
            self.current_image_index -= 10
            if self.current_image_index < 0:
                self.current_image_index = 0
            self.show_current_images()

    def show_next(self):
        if self.images:
            self.current_image_index += 10
            if self.current_image_index >= len(self.images):
                self.current_image_index -= 10
            self.show_current_images()

if __name__ == "__main__":
    viewer = ImageViewer()
    viewer.mainloop()

実行結果

出力されたコードは問題なく実行でき、10枚ずつ表示されるようになりました。

追加機能の提案をしてもらう

便利な追加機能の提案をお願いしてみました。

どれも便利そうです。今回はスライドショーの機能追加をお願いしてみました。

出力されたコード

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

class ImageViewer(tk.Tk):
    def __init__(self):
        super().__init__()

        self.title("Image Viewer")
        self.geometry("800x600")

        self.current_image_index = 0
        self.images = []
        self.is_slideshow_running = False
        self.slideshow_interval = 3000  # 3 seconds

        self.label = tk.Label(self)
        self.label.pack()

        self.open_folder_button = tk.Button(self, text="Open Folder", command=self.open_folder)
        self.open_folder_button.pack()

        self.prev_button = tk.Button(self, text="Previous", command=self.show_previous)
        self.prev_button.pack(side=tk.LEFT)

        self.next_button = tk.Button(self, text="Next", command=self.show_next)
        self.next_button.pack(side=tk.RIGHT)

        self.slideshow_button = tk.Button(self, text="Start Slideshow", command=self.toggle_slideshow)
        self.slideshow_button.pack(side=tk.RIGHT)

    def open_folder(self):
        folder_path = filedialog.askdirectory()
        if folder_path:
            self.images = [
                os.path.join(folder_path, file) for file in os.listdir(folder_path)
                if file.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.bmp'))
            ]
            self.current_image_index = 0
            self.show_current_image()

    def show_current_image(self):
        if self.images:
            image_path = self.images[self.current_image_index]
            image = Image.open(image_path)
            image.thumbnail((800, 600), Image.ANTIALIAS)
            photo = ImageTk.PhotoImage(image)
            self.label.config(image=photo)
            self.label.image = photo

    def show_previous(self):
        if self.images:
            self.current_image_index -= 1
            if self.current_image_index < 0:
                self.current_image_index = len(self.images) - 1
            self.show_current_image()

    def show_next(self):
        if self.images:
            self.current_image_index += 1
            if self.current_image_index >= len(self.images):
                self.current_image_index = 0
            self.show_current_image()

    def toggle_slideshow(self):
        if not self.is_slideshow_running:
            self.is_slideshow_running = True
            self.slideshow_button.config(text="Stop Slideshow")
            self.start_slideshow()
        else:
            self.is_slideshow_running = False
            self.slideshow_button.config(text="Start Slideshow")

    def start_slideshow(self):
        if self.is_slideshow_running:
            self.show_next()
            self.after(self.slideshow_interval, self.start_slideshow)

if __name__ == "__main__":
    viewer = ImageViewer()
    viewer.mainloop()

実行結果

「Start Slideshow」ボタンが追加され、スライドショーを見ることができるようになりました。

追加の修正依頼

スライドショー中は「Stop Sllideshow」でスライドショーを停止できました。ただ、10個ずつの表示がなくなってしまったので、それを復活させるようにお願いしてみました。

修正されたコード

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

class ImageViewer(tk.Tk):
    def __init__(self):
        super().__init__()

        self.title("Image Viewer")
        self.geometry("1600x1200")

        self.current_image_index = 0
        self.images = []
        self.is_slideshow_running = False
        self.slideshow_interval = 3000  # 3 seconds

        self.labels = []
        for i in range(2):
            for j in range(5):
                label = tk.Label(self)
                label.grid(row=i, column=j)
                self.labels.append(label)

        self.open_folder_button = tk.Button(self, text="Open Folder", command=self.open_folder)
        self.open_folder_button.grid(row=2, column=2)

        self.prev_button = tk.Button(self, text="Previous", command=self.show_previous)
        self.prev_button.grid(row=3, column=0)

        self.next_button = tk.Button(self, text="Next", command=self.show_next)
        self.next_button.grid(row=3, column=4)

        self.slideshow_button = tk.Button(self, text="Start Slideshow", command=self.toggle_slideshow)
        self.slideshow_button.grid(row=3, column=2)

    def open_folder(self):
        folder_path = filedialog.askdirectory()
        if folder_path:
            self.images = [
                os.path.join(folder_path, file) for file in os.listdir(folder_path)
                if file.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.bmp'))
            ]
            self.current_image_index = 0
            self.show_current_images()

    def show_current_images(self):
        if not self.is_slideshow_running:
            for i, label in enumerate(self.labels):
                image_index = self.current_image_index + i
                if image_index < len(self.images):
                    image_path = self.images[image_index]
                    image = Image.open(image_path)
                    image.thumbnail((300, 300), Image.ANTIALIAS)
                    photo = ImageTk.PhotoImage(image)
                    label.config(image=photo)
                    label.image = photo
                else:
                    label.config(image=None)
                    label.image = None

    def show_previous(self):
        if self.images and not self.is_slideshow_running:
            self.current_image_index -= 10
            if self.current_image_index < 0:
                self.current_image_index = 0
            self.show_current_images()

    def show_next(self):
        if self.images and not self.is_slideshow_running:
            self.current_image_index += 10
            if self.current_image_index >= len(self.images):
                self.current_image_index -= 10
            self.show_current_images()

    def toggle_slideshow(self):
        if not self.is_slideshow_running:
            self.is_slideshow_running = True
            self.slideshow_button.config(text="Stop Slideshow")
            self.start_slideshow()
        else:
            self.is_slideshow_running = False
            self.slideshow_button.config(text="Start Slideshow")
            self.show_current_images()

    def start_slideshow(self):
        if self.is_slideshow_running:
            self.show_next()
            self.after(self.slideshow_interval, self.start_slideshow)

if __name__ == "__main__":
    viewer = ImageViewer()
    viewer.mainloop()

実行結果

スライドショーボタンは復活しましたが、スライドショーが実行できませんでした。

さらに追加の修正依頼

スライドショーが実行できないことをChatGPTに伝えてみました。

さらに修正されたコード

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

class ImageViewer(tk.Tk):
    def __init__(self):
        super().__init__()

        self.title("Image Viewer")
        self.geometry("1600x1200")

        self.current_image_index = 0
        self.images = []
        self.is_slideshow_running = False
        self.slideshow_interval = 3000  # 3 seconds

        self.labels = []
        for i in range(2):
            for j in range(5):
                label = tk.Label(self)
                label.grid(row=i, column=j)
                self.labels.append(label)

        self.open_folder_button = tk.Button(self, text="Open Folder", command=self.open_folder)
        self.open_folder_button.grid(row=2, column=2)

        self.prev_button = tk.Button(self, text="Previous", command=self.show_previous)
        self.prev_button.grid(row=3, column=0)

        self.next_button = tk.Button(self, text="Next", command=self.show_next)
        self.next_button.grid(row=3, column=4)

        self.slideshow_button = tk.Button(self, text="Start Slideshow", command=self.toggle_slideshow)
        self.slideshow_button.grid(row=3, column=2)

    def open_folder(self):
        folder_path = filedialog.askdirectory()
        if folder_path:
            self.images = [
                os.path.join(folder_path, file) for file in os.listdir(folder_path)
                if file.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.bmp'))
            ]
            self.current_image_index = 0
            self.show_current_images()

    def show_current_images(self, is_slideshow=False):
        if not self.is_slideshow_running or is_slideshow:
            for i, label in enumerate(self.labels):
                image_index = self.current_image_index + i
                if image_index < len(self.images):
                    image_path = self.images[image_index]
                    image = Image.open(image_path)
                    image.thumbnail((300, 300), Image.ANTIALIAS)
                    photo = ImageTk.PhotoImage(image)
                    label.config(image=photo)
                    label.image = photo
                else:
                    label.config(image=None)
                    label.image = None

    def show_previous(self):
        if self.images and not self.is_slideshow_running:
            self.current_image_index -= 10
            if self.current_image_index < 0:
                self.current_image_index = 0
            self.show_current_images()

    def show_next(self):
        if self.images and not self.is_slideshow_running:
            self.current_image_index += 10
            if self.current_image_index >= len(self.images):
                self.current_image_index -= 10
            self.show_current_images()

    def toggle_slideshow(self):
        if not self.is_slideshow_running:
            self.is_slideshow_running = True
            self.slideshow_button.config(text="Stop Slideshow")
            self.start_slideshow()
        else:
            self.is_slideshow_running = False
            self.slideshow_button.config(text="Start Slideshow")
            self.show_current_images()

    def start_slideshow(self):
        if self.is_slideshow_running:
            self.show_current_images(is_slideshow=True)
            self.current_image_index += 1
            if self.current_image_index >= len(self.images):
                self.current_image_index = 0
            self.after(self.slideshow_interval, self.start_slideshow)

if __name__ == "__main__":
    viewer = ImageViewer()
    viewer.mainloop()

実行結果

スライドショーは実行できるようになりましたが、スライドショー中も10枚ずつの表示になってしまいました。

さらに追加の修正依頼

スライドショー中は1枚ずつの表示になるようにお願いしました。

さらに修正されたコード

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

class ImageViewer(tk.Tk):
    def __init__(self):
        super().__init__()

        self.title("Image Viewer")
        self.geometry("1600x1200")

        self.current_image_index = 0
        self.images = []
        self.is_slideshow_running = False
        self.slideshow_interval = 3000  # 3 seconds

        self.labels = []
        for i in range(2):
            for j in range(5):
                label = tk.Label(self)
                label.grid(row=i, column=j)
                self.labels.append(label)

        self.open_folder_button = tk.Button(self, text="Open Folder", command=self.open_folder)
        self.open_folder_button.grid(row=2, column=2)

        self.prev_button = tk.Button(self, text="Previous", command=self.show_previous)
        self.prev_button.grid(row=3, column=0)

        self.next_button = tk.Button(self, text="Next", command=self.show_next)
        self.next_button.grid(row=3, column=4)

        self.slideshow_button = tk.Button(self, text="Start Slideshow", command=self.toggle_slideshow)
        self.slideshow_button.grid(row=3, column=2)

    def open_folder(self):
        folder_path = filedialog.askdirectory()
        if folder_path:
            self.images = [
                os.path.join(folder_path, file) for file in os.listdir(folder_path)
                if file.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.bmp'))
            ]
            self.current_image_index = 0
            self.show_current_images()

    def show_current_images(self, is_slideshow=False):
        if not self.is_slideshow_running or is_slideshow:
            for i, label in enumerate(self.labels):
                if is_slideshow and i > 0:
                    label.config(image=None)
                    label.image = None
                    continue

                image_index = self.current_image_index + i
                if image_index < len(self.images):
                    image_path = self.images[image_index]
                    image = Image.open(image_path)
                    image.thumbnail((300, 300), Image.ANTIALIAS)
                    photo = ImageTk.PhotoImage(image)
                    label.config(image=photo)
                    label.image = photo
                else:
                    label.config(image=None)
                    label.image = None

    def show_previous(self):
        if self.images and not self.is_slideshow_running:
            self.current_image_index -= 10
            if self.current_image_index < 0:
                self.current_image_index = 0
            self.show_current_images()

    def show_next(self):
        if self.images and not self.is_slideshow_running:
            self.current_image_index += 10
            if self.current_image_index >= len(self.images):
                self.current_image_index -= 10
            self.show_current_images()

    def toggle_slideshow(self):
        if not self.is_slideshow_running:
            self.is_slideshow_running = True
            self.slideshow_button.config(text="Stop Slideshow")
            self.start_slideshow()
        else:
            self.is_slideshow_running = False
            self.slideshow_button.config(text="Start Slideshow")
            self.show_current_images()

    def start_slideshow(self):
        if self.is_slideshow_running:
            self.show_current_images(is_slideshow=True)
            self.current_image_index += 1
            if self.current_image_index >= len(self.images):
                self.current_image_index = 0
            self.after(self.slideshow_interval, self.start_slideshow)

if __name__ == "__main__":
    viewer = ImageViewer()
    viewer.mainloop()

実行結果

スライドショーの画像が小さいですが、スライドショーのときは一枚だけ表示することができるようになりました。このあとは画像を大きくして中央に表示するように指示したりすることなどが考えられそうです。

まとめ

欲しい機能を追加しながらプログラムを作成することができました。

追加機能の提案までしてもらうことができました。

思うような結果が得られない場合も、改善してほしいところをお願いすることで少しずつ改善することができました。

工数の削減や機能を簡単に色々追加して使い心地を試してみるといったことにも使えそうです。

あなたもぜひ、ChatGPTに聞きながらプログラムを作成してみてください。