最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

基于python制作簡(jiǎn)單的相冊(cè)瀏覽小工具

 更新時(shí)間:2025年10月10日 09:34:26   作者:學(xué)習(xí)&實(shí)踐愛(ài)好者  
這篇文章主要為大家詳細(xì)介紹了如何基于python制作一個(gè)簡(jiǎn)單的相冊(cè)瀏覽小工具,并且支持網(wǎng)格視圖和單圖視圖兩種視圖模式,下面小編就為大家詳細(xì)介紹一下吧

用python制作相冊(cè)瀏覽小工具

近日,歡度國(guó)慶、中秋節(jié)雙節(jié),朋友們應(yīng)拍了一些相片,故用python制作相冊(cè)瀏覽小工具試用。

依賴庫(kù):tkinter(通常 Python 自帶)和Pillow(圖像處理庫(kù)),后者,需安裝。

安裝命令:pip install pillow

程序支持兩種視圖模式,可通過(guò)頂部控制欄的【網(wǎng)格視圖/單圖視圖】按鈕切換:

單圖視圖:默認(rèn)模式,一次顯示一張圖片,支持圖片瀏覽及圖片顯示方式操作。

網(wǎng)格視圖:以縮略圖網(wǎng)格形式顯示所有圖片,便于快速查找;點(diǎn)擊任意縮略圖可切換到單圖視圖并顯示該圖片。

遠(yuǎn)行效果

完整源碼

import tkinter as tk
from tkinter import filedialog, messagebox, ttk
from PIL import Image, ImageTk, ImageFilter
import os
import random
import math
from typing import List, Tuple, Optional, Dict

class AestheticPhotoAlbum:
    """相冊(cè)瀏覽,支持單圖查看和多圖網(wǎng)格瀏覽模式"""
    
    def __init__(self, root: tk.Tk):
        # 初始化主窗口
        self.root = root
        self.root.title("相冊(cè)瀏覽")
        self.root.geometry("1300x800")
        self.root.configure(bg="#f0f0f0")
        
        # 圖片相關(guān)變量
        self.image_files: List[str] = []
        self.current_index: int = 0
        self.original_image: Optional[Image.Image] = None
        self.processed_image: Optional[Image.Image] = None
        self.displayed_image: Optional[Image.Image] = None
        self.photo_directory: str = ""
        self.transitioning: bool = False
        self.rotation_angle: int = 0
        self.cropping: bool = False
        self.crop_start: Optional[Tuple[int, int]] = None
        self.crop_rect: Optional[int] = None
        self.thumbnail_cache: Dict[str, ImageTk.PhotoImage] = {}
        self.view_mode: str = "single"  # 視圖模式:single(單圖) 或 grid(網(wǎng)格)
        self.slideshow_running: bool = False
        
        # 布局常量
        self.grid_spacing: int = 10  # 調(diào)整間距
        self.thumb_size: Tuple[int, int] = (240,100) # 縮略圖尺寸
        self.control_padx: int = 10
        self.control_pady: int = 5
        
        # 創(chuàng)建UI組件
        self._create_widgets()
        
        # 綁定事件
        self._bind_events()
        
    def _font_config(self) -> None:
        """配置字體以支持中文顯示"""
        default_font = ('SimHei', 10)
        self.root.option_add("*Font", default_font)
        
    def _bind_events(self) -> None:
        """綁定各種事件處理"""
        # 鍵盤事件
        self.root.bind('<Left>', lambda e: self.prev_image() if self.view_mode == "single" else None)
        self.root.bind('<Right>', lambda e: self.next_image() if self.view_mode == "single" else None)
        self.root.bind('<Escape>', lambda e: self.root.quit())
        self.root.bind('<r>', lambda e: self.rotate_clockwise() if self.view_mode == "single" else None)
        self.root.bind('<R>', lambda e: self.rotate_counterclockwise() if self.view_mode == "single" else None)
        
        # 窗口大小變化事件
        self.root.bind('<Configure>', self._on_window_resize)
        
    def _create_widgets(self) -> None:
        """創(chuàng)建所有UI組件"""
        self._font_config()
        self._create_top_controls()
        self._create_display_area()
        self._create_bottom_controls()
        
    def _create_top_controls(self) -> None:
        """創(chuàng)建頂部控制欄"""
        top_frame = tk.Frame(self.root, bg="#ffffff", height=60)
        top_frame.pack(fill=tk.X, padx=10, pady=10)
        top_frame.pack_propagate(False)  # 固定高度
        
        # 選擇文件夾按鈕
        self.select_btn = tk.Button(
            top_frame, text="圖片文件夾", 
            command=self.select_directory,
            bg="#4a90e2", fg="white",
            padx=self.control_padx, pady=self.control_pady, 
            relief=tk.FLAT, cursor="hand2"
        )
        self.select_btn.pack(side=tk.LEFT, padx=self.control_padx)
        
        # 視圖切換按鈕
        view_frame = tk.Frame(top_frame, bg="#ffffff")
        view_frame.pack(side=tk.LEFT, padx=self.control_padx)
        
        self.view_mode_btn = tk.Button(
            view_frame, text="網(wǎng)格視圖", 
            command=self.toggle_view_mode,
            bg="#673ab7", fg="white",
            padx=self.control_padx, pady=2, 
            relief=tk.FLAT, cursor="hand2", 
            state=tk.DISABLED
        )
        self.view_mode_btn.pack(side=tk.LEFT)
        
        # 編輯工具框架
        self.edit_frame = tk.Frame(top_frame, bg="#ffffff")
        self.edit_frame.pack(side=tk.LEFT, padx=self.control_padx)
        self._create_edit_controls()
        
        # 特效按鈕
        effects_frame = tk.Frame(top_frame, bg="#ffffff")
        effects_frame.pack(side=tk.LEFT, padx=self.control_padx)
        
        self.effect_var = tk.StringVar(value="原圖")
        effects = ["原圖", "柔化", "黑白", "復(fù)古", "銳化"]
        effect_menu = tk.OptionMenu(effects_frame, self.effect_var, *effects, command=self.apply_effect)
        effect_menu.config(bg="#f8f9fa", relief=tk.FLAT)
        effect_menu.pack()
        
        # 重置按鈕
        self.reset_btn = tk.Button(
            top_frame, text="重置圖片", 
            command=self.reset_image,
            bg="#f0ad4e", fg="white",
            padx=self.control_padx, pady=self.control_pady, 
            relief=tk.FLAT, cursor="hand2", 
            state=tk.DISABLED
        )
        self.reset_btn.pack(side=tk.LEFT, padx=self.control_padx)

        # 使用幫助         
        self.help_btn = tk.Button(
            top_frame, text="幫助",     
            command=self.show_help,
            bg="#7f8c8d", fg="white",
            padx=self.control_padx, pady=self.control_pady, 
            relief=tk.FLAT, cursor="hand2"
        )
        self.help_btn.pack(side=tk.RIGHT, padx=self.control_padx)

        # 狀態(tài)標(biāo)簽
        self.status_label = tk.Label(
            top_frame, text="請(qǐng)選擇圖片文件夾", 
            bg="#ffffff", fg="#666666"
        )
        self.status_label.pack(side=tk.RIGHT, padx=20)
        
    def _create_edit_controls(self) -> None:
        """創(chuàng)建編輯控制按鈕(旋轉(zhuǎn)、翻轉(zhuǎn))"""
        # 旋轉(zhuǎn)按鈕
        rotate_frame = tk.Frame(self.edit_frame, bg="#ffffff")
        rotate_frame.pack(side=tk.LEFT, padx=5)
        
        tk.Label(rotate_frame, text="旋轉(zhuǎn):", bg="#ffffff").pack(side=tk.TOP)
        self.rotate_cw_btn = tk.Button(
            rotate_frame, text="順時(shí)針", 
            command=self.rotate_clockwise,
            bg="#f8f9fa", fg="#333333",
            padx=5, pady=2, relief=tk.FLAT,
            cursor="hand2", state=tk.DISABLED
        )
        self.rotate_cw_btn.pack(side=tk.LEFT)
        
        self.rotate_ccw_btn = tk.Button(
            rotate_frame, text="逆時(shí)針", 
            command=self.rotate_counterclockwise,
            bg="#f8f9fa", fg="#333333",
            padx=5, pady=2, relief=tk.FLAT,
            cursor="hand2", state=tk.DISABLED
        )
        self.rotate_ccw_btn.pack(side=tk.LEFT)
        
        # 翻轉(zhuǎn)按鈕
        flip_frame = tk.Frame(self.edit_frame, bg="#ffffff")
        flip_frame.pack(side=tk.LEFT, padx=5)
        
        tk.Label(flip_frame, text="翻轉(zhuǎn):", bg="#ffffff").pack(side=tk.TOP)
        self.flip_h_btn = tk.Button(
            flip_frame, text="水平", 
            command=self.flip_horizontal,
            bg="#f8f9fa", fg="#333333",
            padx=5, pady=2, relief=tk.FLAT,
            cursor="hand2", state=tk.DISABLED
        )
        self.flip_h_btn.pack(side=tk.LEFT)
        
        self.flip_v_btn = tk.Button(
            flip_frame, text="垂直", 
            command=self.flip_vertical,
            bg="#f8f9fa", fg="#333333",
            padx=5, pady=2, relief=tk.FLAT,
            cursor="hand2", state=tk.DISABLED
        )
        self.flip_v_btn.pack(side=tk.LEFT)
       
    def _create_display_area(self) -> None:
        """創(chuàng)建圖片顯示區(qū)域(支持滾動(dòng))"""
        # 創(chuàng)建帶滾動(dòng)條的容器
        self.scroll_frame = tk.Frame(self.root)
        self.scroll_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
        
        # 垂直滾動(dòng)條
        self.vscrollbar = ttk.Scrollbar(self.scroll_frame)
        self.vscrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
        # 水平滾動(dòng)條
        self.hscrollbar = ttk.Scrollbar(self.scroll_frame, orient=tk.HORIZONTAL)
        self.hscrollbar.pack(side=tk.BOTTOM, fill=tk.X)
        
        # 單圖模式顯示區(qū)域
        self.display_frame = tk.Frame(
            self.scroll_frame, bg="#e9ecef", 
            relief=tk.FLAT, bd=1
        )
        self.display_frame.pack(fill=tk.BOTH, expand=True)
        
        # 網(wǎng)格視圖容器
        self.grid_frame = tk.Frame(self.scroll_frame, bg="#e9ecef")
        
        # 單圖模式畫(huà)布
        self.canvas = tk.Canvas(
            self.display_frame, bg="#e9ecef", 
            highlightthickness=0, cursor="cross"
        )
        self.canvas.pack(fill=tk.BOTH, expand=True)
        
        # 配置滾動(dòng)條
        self.canvas.configure(yscrollcommand=self.vscrollbar.set, xscrollcommand=self.hscrollbar.set)
        self.vscrollbar.configure(command=self.canvas.yview)
        self.hscrollbar.configure(command=self.canvas.xview)
        
    def _create_bottom_controls(self) -> None:
        """創(chuàng)建底部控制欄"""
        bottom_frame = tk.Frame(self.root, bg="#ffffff", height=60)
        bottom_frame.pack(fill=tk.X, padx=10, pady=10)
        bottom_frame.pack_propagate(False)  # 固定高度
        
        # 導(dǎo)航按鈕
        self.prev_btn = tk.Button(
            bottom_frame, text="上一張", 
            command=self.prev_image,
            bg="#f8f9fa", fg="#333333",
            padx=15, pady=5, relief=tk.FLAT,
            cursor="hand2", state=tk.DISABLED
        )
        self.prev_btn.pack(side=tk.LEFT, padx=20)
        
        # 圖片計(jì)數(shù)器
        self.counter_label = tk.Label(
            bottom_frame, text="0/0", 
            bg="#ffffff", fg="#333333",
            font=('SimHei', 12)
        )
        self.counter_label.pack(side=tk.LEFT, padx=20)
        
        # 下一張按鈕
        self.next_btn = tk.Button(
            bottom_frame, text="下一張", 
            command=self.next_image,
            bg="#f8f9fa", fg="#333333",
            padx=15, pady=5, relief=tk.FLAT,
            cursor="hand2", state=tk.DISABLED
        )
        self.next_btn.pack(side=tk.LEFT, padx=20)
        
        # 幻燈片播放按鈕
        self.slideshow_btn = tk.Button(
            bottom_frame, text="開(kāi)始幻燈片", 
            command=self.toggle_slideshow,
            bg="#5cb85c", fg="white",
            padx=15, pady=5, relief=tk.FLAT,
            cursor="hand2", state=tk.DISABLED
        )
        self.slideshow_btn.pack(side=tk.RIGHT, padx=20)
        
    def toggle_view_mode(self) -> None:
        """切換視圖模式(單圖/網(wǎng)格)"""
        if self.view_mode == "single":
            self.view_mode = "grid"
            self.view_mode_btn.config(text="單圖視圖")
            self.display_frame.pack_forget()
            self.grid_frame.pack(fill=tk.BOTH, expand=True)
            # 強(qiáng)制更新布局,使 winfo_width 能獲取正確寬度
            self.grid_frame.update_idletasks()  
            self._update_grid_view()
            # 隱藏編輯工具
            self.edit_frame.pack_forget()
            self.reset_btn.pack_forget()
            # 更改鼠標(biāo)樣式
            self.canvas.config(cursor="arrow")
        else:
            self.view_mode = "single"
            self.view_mode_btn.config(text="網(wǎng)格視圖")
            self.grid_frame.pack_forget()
            self.display_frame.pack(fill=tk.BOTH, expand=True)
            self._load_and_display_image()
            # 顯示編輯工具
            self.edit_frame.pack(side=tk.LEFT, padx=self.control_padx)
            self.reset_btn.pack(side=tk.LEFT, padx=self.control_padx)
        
        # 更新按鈕狀態(tài)
        self._update_button_states()
        
    def _update_grid_view(self) -> None:
        """更新網(wǎng)格視圖,顯示所有圖片縮略圖"""
        # 清空現(xiàn)有內(nèi)容
        for widget in self.grid_frame.winfo_children():
            widget.destroy()
                
        if not self.image_files:
            return
                
        # 優(yōu)先獲取網(wǎng)格容器的實(shí)際寬度(若已渲染)
        frame_width = self.grid_frame.winfo_width()
        # 若寬度為0(容器未渲染完成),則使用窗口寬度作為默認(rèn)
        if frame_width == 0:
            frame_width = self.root.winfo_width() - 100  
        #cols = max(1, frame_width // (self.thumb_size[0] + self.grid_spacing))
        available_width = frame_width - 20 #將上句改為兩句, 減去容器左右邊緣的額外間距
        cols = max(1, available_width // (self.thumb_size[0] + self.grid_spacing))    
        rows = math.ceil(len(self.image_files) / cols)
        
        # 創(chuàng)建縮略圖并添加到網(wǎng)格
        for i, filename in enumerate(self.image_files):
            row = i // cols
            col = i % cols
            
            # 創(chuàng)建縮略圖容器
            thumb_frame = tk.Frame(
                self.grid_frame, 
                width=self.thumb_size[0], 
                height=self.thumb_size[1] + 30,  # 額外空間顯示文件名
                bg="#ffffff",
                relief=tk.RAISED,
                bd=1
            )
            thumb_frame.grid(
                row=row, column=col,
                padx=self.grid_spacing//2,
                pady=self.grid_spacing//2,
                sticky="nsew"
            )
            thumb_frame.grid_propagate(False)
            
            # 加載或獲取緩存的縮略圖
            try:
                if filename not in self.thumbnail_cache:
                    file_path = os.path.join(self.photo_directory, filename)
                    with Image.open(file_path) as img:
                        img.thumbnail(self.thumb_size, Image.Resampling.LANCZOS)
                        self.thumbnail_cache[filename] = ImageTk.PhotoImage(img)
                
                # 顯示縮略圖
                thumb_label = tk.Label(thumb_frame, image=self.thumbnail_cache[filename], bg="#ffffff")
                thumb_label.pack(pady=5)
                
                # 顯示文件名(簡(jiǎn)短版本)
                short_name = filename[:15] + "..." if len(filename) > 18 else filename
                name_label = tk.Label(
                    thumb_frame, 
                    text=short_name, 
                    bg="#ffffff",
                    wraplength=self.thumb_size[0] - 10,
                    justify=tk.CENTER
                )
                name_label.pack(pady=2)
                
                # 添加點(diǎn)擊事件
                def on_thumb_click(index: int) -> callable:
                    def handler(event=None) -> None:
                        self.current_index = index
                        self.toggle_view_mode()
                        self._update_counter()
                    return handler
                
                thumb_frame.bind("<Button-1>", on_thumb_click(i))
                thumb_label.bind("<Button-1>", on_thumb_click(i))
                name_label.bind("<Button-1>", on_thumb_click(i))
                
                # 設(shè)置鼠標(biāo)樣式為手型
                thumb_frame.config(cursor="hand2")
                thumb_label.config(cursor="hand2")
                name_label.config(cursor="hand2")
                
            except Exception as e:
                # 出錯(cuò)時(shí)顯示錯(cuò)誤信息而非崩潰
                error_label = tk.Label(
                    thumb_frame, 
                    text=f"無(wú)法加載\n{filename[:10]}...", 
                    bg="#ffebee",
                    fg="#b71c1c",
                    wraplength=self.thumb_size[0] - 10
                )
                error_label.pack(expand=True)
                print(f"加載縮略圖錯(cuò)誤: {filename}, {str(e)}")
        
        # 配置網(wǎng)格權(quán)重
        for i in range(cols):
            self.grid_frame.grid_columnconfigure(i, weight=1)
        for i in range(rows):
            self.grid_frame.grid_rowconfigure(i, weight=1)
    
    def _on_window_resize(self, event: tk.Event) -> None:
        """窗口大小變化時(shí)的處理函數(shù)"""
        # 避免初始化時(shí)的無(wú)效調(diào)用和非主窗口事件
        if event.widget != self.root or self.transitioning:
            return
            
        # 根據(jù)當(dāng)前視圖模式刷新
        if self.view_mode == "single" and self.processed_image:
            self.apply_effect(self.effect_var.get())
        elif self.view_mode == "grid" and self.image_files:
            # 延遲更新網(wǎng)格,避免頻繁觸發(fā)
            self.root.after(100, self._update_grid_view)
                
    def select_directory(self) -> None:
        """選擇圖片文件夾"""
        directory = filedialog.askdirectory(title="圖片文件夾")
        if directory:
            self.photo_directory = directory
            self._load_images()
            self.status_label.config(text=f"當(dāng)前文件夾: {os.path.basename(directory)}")
            self.thumbnail_cache.clear()  # 清除緩存的縮略圖
            
    def _load_images(self) -> None:
        """加載文件夾中的圖片"""
        supported_formats = ('.jpg', '.jpeg', '.png', '.gif', '.bmp', '.jfif', '.webp')
        self.image_files = [
            f for f in os.listdir(self.photo_directory)
            if f.lower().endswith(supported_formats)
        ]
        
        if not self.image_files:
            messagebox.showinfo("提示", "所選文件夾中沒(méi)有圖片文件")
            return
            
        # 啟用所有按鈕
        self._enable_all_controls()
        
        # 顯示第一張圖片
        self.current_index = 0
        self._update_counter()
        self._load_and_display_image()
        
    def _enable_all_controls(self) -> None:
        """啟用所有控制按鈕"""
        self.prev_btn.config(state=tk.NORMAL)
        self.next_btn.config(state=tk.NORMAL)
        self.slideshow_btn.config(state=tk.NORMAL)
        self.rotate_cw_btn.config(state=tk.NORMAL)
        self.rotate_ccw_btn.config(state=tk.NORMAL)
        self.flip_h_btn.config(state=tk.NORMAL)
        self.flip_v_btn.config(state=tk.NORMAL)
        self.reset_btn.config(state=tk.NORMAL)
        self.view_mode_btn.config(state=tk.NORMAL)
        
    def _update_button_states(self) -> None:
        """根據(jù)當(dāng)前視圖模式更新按鈕狀態(tài)"""
        if self.view_mode == "grid":
            # 網(wǎng)格模式下禁用單圖操作按鈕
            self.prev_btn.config(state=tk.DISABLED)
            self.next_btn.config(state=tk.DISABLED)
            self.slideshow_btn.config(state=tk.DISABLED)
            self.rotate_cw_btn.config(state=tk.DISABLED)
            self.rotate_ccw_btn.config(state=tk.DISABLED)
            self.flip_h_btn.config(state=tk.DISABLED)
            self.flip_v_btn.config(state=tk.DISABLED)
            self.reset_btn.config(state=tk.DISABLED)
        else:
            # 單圖模式下啟用相關(guān)按鈕
            self.prev_btn.config(state=tk.NORMAL)
            self.next_btn.config(state=tk.NORMAL)
            self.slideshow_btn.config(state=tk.NORMAL)
            self.rotate_cw_btn.config(state=tk.NORMAL)
            self.rotate_ccw_btn.config(state=tk.NORMAL)
            self.flip_h_btn.config(state=tk.NORMAL)
            self.flip_v_btn.config(state=tk.NORMAL)
            self.reset_btn.config(state=tk.NORMAL)
    
    def _load_and_display_image(self) -> None:
        """加載并顯示當(dāng)前圖片"""
        if not self.image_files:
            return
            
        # 獲取當(dāng)前圖片路徑
        current_file = self.image_files[self.current_index]
        file_path = os.path.join(self.photo_directory, current_file)
        
        try:
            # 打開(kāi)圖片,重置所有處理狀態(tài)
            self.original_image = Image.open(file_path)
            self.processed_image = self.original_image.copy()
            self.rotation_angle = 0
            self.cropping = False
            self.crop_rect = None
            
            # 應(yīng)用默認(rèn)效果
            self.apply_effect(self.effect_var.get())
            
        except Exception as e:
            messagebox.showerror("錯(cuò)誤", f"無(wú)法打開(kāi)圖片: {str(e)}")
            # 移除無(wú)法打開(kāi)的圖片
            self.image_files.pop(self.current_index)
            if not self.image_files:
                self.status_label.config(text="沒(méi)有可用的圖片文件")
                self._disable_all_controls()
                return
                
            # 調(diào)整索引
            self.current_index = min(self.current_index, len(self.image_files) - 1)
            self._update_counter()
            self._load_and_display_image()
    
    def _disable_all_controls(self) -> None:
        """禁用所有控制按鈕"""
        self.prev_btn.config(state=tk.DISABLED)
        self.next_btn.config(state=tk.DISABLED)
        self.slideshow_btn.config(state=tk.DISABLED)
        self.rotate_cw_btn.config(state=tk.DISABLED)
        self.rotate_ccw_btn.config(state=tk.DISABLED)
        self.flip_h_btn.config(state=tk.DISABLED)
        self.flip_v_btn.config(state=tk.DISABLED)
        self.reset_btn.config(state=tk.DISABLED)
        self.view_mode_btn.config(state=tk.DISABLED)
            
    def apply_effect(self, effect: str) -> None:
        """應(yīng)用圖片效果"""
        if not self.processed_image:
            return
            
        # 復(fù)制處理過(guò)的圖片以便應(yīng)用效果
        img = self.processed_image.copy()
        
        # 應(yīng)用選定的效果
        if effect == "柔化":
            img = img.filter(ImageFilter.GaussianBlur(radius=2))
        elif effect == "黑白":
            img = img.convert("L")
        elif effect == "復(fù)古":
            # 復(fù)古效果
            r, g, b = img.split()
            r = r.point(lambda i: i * 0.9)
            g = g.point(lambda i: i * 0.7)
            b = b.point(lambda i: i * 0.5)
            img = Image.merge("RGB", (r, g, b))
        elif effect == "銳化":
            img = img.filter(ImageFilter.SHARPEN)
        
        # 調(diào)整圖片大小以適應(yīng)窗口,保持比例
        self.displayed_image = self._resize_image(img)
        
        # 在畫(huà)布上顯示圖片
        self.tk_image = ImageTk.PhotoImage(image=self.displayed_image)
        self.canvas.delete("all")
        
        # 計(jì)算居中位置
        canvas_width = self.display_frame.winfo_width()
        canvas_height = self.display_frame.winfo_height()
        img_width = self.displayed_image.width
        img_height = self.displayed_image.height
        
        self.img_x = max(0, (canvas_width - img_width) // 2)
        self.img_y = max(0, (canvas_height - img_height) // 2)
        
        self.canvas.create_image(self.img_x, self.img_y, anchor=tk.NW, image=self.tk_image)
        
        # 更新?tīng)顟B(tài)標(biāo)簽顯示當(dāng)前文件名
        current_file = self.image_files[self.current_index]
        self.status_label.config(text=f"當(dāng)前圖片: {current_file}")
        
    def _resize_image(self, img: Image.Image) -> Image.Image:
        """調(diào)整圖片大小以適應(yīng)窗口,保持比例"""
        # 獲取窗口可用尺寸
        max_width = self.display_frame.winfo_width() - 40  # 留出邊距
        max_height = self.display_frame.winfo_height() - 40
        
        # 如果窗口還沒(méi)初始化,使用默認(rèn)尺寸
        if max_width <= 0 or max_height <= 0:
            max_width = 1100
            max_height = 600
            
        # 計(jì)算縮放比例
        width_ratio = max_width / img.width
        height_ratio = max_height / img.height
        scale_ratio = min(width_ratio, height_ratio)
        
        # 如果圖片小于最大尺寸,則不縮放
        if scale_ratio >= 1:
            return img
            
        # 計(jì)算新尺寸
        new_width = int(img.width * scale_ratio)
        new_height = int(img.height * scale_ratio)
        
        # 調(diào)整大小,使用高質(zhì)量縮放
        return img.resize((new_width, new_height), Image.Resampling.LANCZOS)
    
    # 旋轉(zhuǎn)和翻轉(zhuǎn)功能
    def rotate_clockwise(self) -> None:
        """順時(shí)針旋轉(zhuǎn)90度"""
        if not self.processed_image or self.view_mode != "single":
            return
            
        self.rotation_angle = (self.rotation_angle + 90) % 360
        self.processed_image = self.processed_image.rotate(-90, expand=True)
        self.apply_effect(self.effect_var.get())
    
    def rotate_counterclockwise(self) -> None:
        """逆時(shí)針旋轉(zhuǎn)90度"""
        if not self.processed_image or self.view_mode != "single":
            return
            
        self.rotation_angle = (self.rotation_angle - 90) % 360
        self.processed_image = self.processed_image.rotate(90, expand=True)
        self.apply_effect(self.effect_var.get())
    
    def flip_horizontal(self) -> None:
        """水平翻轉(zhuǎn)圖片"""
        if not self.processed_image or self.view_mode != "single":
            return
            
        self.processed_image = self.processed_image.transpose(Image.Transpose.FLIP_LEFT_RIGHT)
        self.apply_effect(self.effect_var.get())
    
    def flip_vertical(self) -> None:
        """垂直翻轉(zhuǎn)圖片"""
        if not self.processed_image or self.view_mode != "single":
            return
            
        self.processed_image = self.processed_image.transpose(Image.Transpose.FLIP_TOP_BOTTOM)
        self.apply_effect(self.effect_var.get())
    
    
    def reset_image(self) -> None:
        """重置圖片到原始狀態(tài)"""
        if self.original_image and self.view_mode == "single":
            self.processed_image = self.original_image.copy()
            self.rotation_angle = 0
            self.cropping = False
            self.crop_rect = None
            self.canvas.config(cursor="arrow")
            self.apply_effect(self.effect_var.get())
        
    def prev_image(self) -> None:
        """顯示上一張圖片"""
        if not self.image_files or self.transitioning or self.view_mode != "single":
            return
            
        self.transitioning = True
        self.current_index = (self.current_index - 1) % len(self.image_files)
        self._update_counter()
        self._load_and_display_image()
        self.transitioning = False
        
    def next_image(self) -> None:
        """顯示下一張圖片"""
        if not self.image_files or self.transitioning or self.view_mode != "single":
            return
            
        self.transitioning = True
        self.current_index = (self.current_index + 1) % len(self.image_files)
        self._update_counter()
        self._load_and_display_image()
        self.transitioning = False
        
    def _update_counter(self) -> None:
        """更新圖片計(jì)數(shù)器"""
        self.counter_label.config(text=f"{self.current_index + 1}/{len(self.image_files)}")
        
    def toggle_slideshow(self) -> None:
        """切換幻燈片播放狀態(tài)"""
        if self.view_mode != "single":
            return
            
        if self.slideshow_running:
            self.slideshow_running = False
            self.slideshow_btn.config(text="開(kāi)始幻燈片", bg="#5cb85c")
        else:
            self.slideshow_running = True
            self.slideshow_btn.config(text="停止幻燈片", bg="#d9534f")
            self._run_slideshow()
            
    def _run_slideshow(self) -> None:
        """運(yùn)行幻燈片"""
        if self.slideshow_running and self.image_files and self.view_mode == "single":
            # 隨機(jī)切換效果增加美感
            effects = ["原圖", "柔化", "黑白", "復(fù)古", "銳化"]
            self.effect_var.set(random.choice(effects))
            self.next_image()
            # 3-5秒后切換到下一張
            self.root.after(random.randint(3000, 5000), self._run_slideshow)

    def show_help(self) -> None:
        """顯示使用幫助窗口"""
        # 創(chuàng)建幫助窗口
        help_window = tk.Toplevel(self.root)
        help_window.title("使用幫助")
        help_window.geometry("800x600")
        help_window.configure(bg="#f0f0f0")
        help_window.resizable(True, True)
        
        # 添加滾動(dòng)條
        scrollbar = ttk.Scrollbar(help_window)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
        # 創(chuàng)建文本區(qū)域
        help_text = tk.Text(
            help_window, 
            wrap=tk.WORD, 
            bg="#ffffff", 
            padx=20, 
            pady=20,
            font=('SimHei', 10),
            yscrollcommand=scrollbar.set
        )
        help_text.pack(fill=tk.BOTH, expand=True)
        scrollbar.config(command=help_text.yview)
        
        # 幫助內(nèi)容
        help_content = """
    # 相冊(cè)瀏覽使用幫助

    ## 一、基本介紹
    這是一款圖片瀏覽與簡(jiǎn)單編輯工具,支持單圖查看和網(wǎng)格縮略圖瀏覽兩種模式,可對(duì)圖片進(jìn)行旋轉(zhuǎn)、翻轉(zhuǎn)及特效處理。


    ## 二、核心功能

    ### 1. 文件夾操作
    - 點(diǎn)擊頂部【圖片文件夾】按鈕,選擇存放圖片的文件夾
    - 支持格式:.jpg、.jpeg、.png、.gif、.bmp、.jfif、.webp
    - 選擇后自動(dòng)加載所有圖片,默認(rèn)顯示第一張


    ### 2. 視圖模式切換
    - 【網(wǎng)格視圖】:以縮略圖網(wǎng)格展示所有圖片,便于快速查找
      - 網(wǎng)格會(huì)根據(jù)窗口大小自動(dòng)調(diào)整列數(shù)
      - 點(diǎn)擊任意縮略圖可切換到單圖模式并顯示該圖片
    - 【單圖視圖】:顯示單張高清圖片,支持圖片瀏覽及圖片顯示方式操作


    ### 3. 圖片瀏覽(單圖模式)
    - 【上一張】/【下一張】按鈕:切換圖片(支持鍵盤←/→箭頭)
    - 底部計(jì)數(shù)器:顯示當(dāng)前位置(如"1/20")
    - 【開(kāi)始幻燈片】:自動(dòng)播放圖片,點(diǎn)擊按鈕可停止


    ### 4. 圖片顯示方式(單圖模式)
    - **旋轉(zhuǎn)**:
      - 【順時(shí)針】(快捷鍵r):順時(shí)針旋轉(zhuǎn)90°
      - 【逆時(shí)針】(快捷鍵R):逆時(shí)針旋轉(zhuǎn)90°
    - **翻轉(zhuǎn)**:
      - 【水平】:水平鏡像翻轉(zhuǎn)
      - 【垂直】:垂直鏡像翻轉(zhuǎn)
    - **特效**:通過(guò)下拉菜單選擇(原圖/柔化/黑白/復(fù)古/銳化)
    - **重置圖片**:恢復(fù)當(dāng)前圖片到初始狀態(tài)


    ## 三、快捷鍵
     快捷鍵      功能 
     ← 左箭頭  上一張圖片 
     → 右箭頭  下一張圖片 
     Esc        退出程序 
     r          順時(shí)針旋轉(zhuǎn) 
     R          逆時(shí)針旋轉(zhuǎn) 


    ## 四、注意事項(xiàng)
    1. 所有編輯操作僅臨時(shí)生效,不會(huì)修改原圖文件
    2. 首次加載大量圖片時(shí),網(wǎng)格視圖可能需要短暫加載時(shí)間
    3. 若圖片加載失敗,網(wǎng)格中會(huì)顯示"無(wú)法加載"提示
        """
        
        # 插入并格式化內(nèi)容
        help_text.insert(tk.END, help_content)
        help_text.config(state=tk.DISABLED)  # 設(shè)置為只讀
        
        # 居中顯示窗口
        help_window.update_idletasks()
        width = help_window.winfo_width()
        height = help_window.winfo_height()
        x = (self.root.winfo_width() // 2) - (width // 2) + self.root.winfo_x()
        y = (self.root.winfo_height() // 2) - (height // 2) + self.root.winfo_y()
        help_window.geometry(f"{width}x{height}+{x}+{y}")

if __name__ == "__main__":
    root = tk.Tk()
    app = AestheticPhotoAlbum(root)
    root.mainloop()

到此這篇關(guān)于基于python制作簡(jiǎn)單的相冊(cè)瀏覽小工具的文章就介紹到這了,更多相關(guān)python相冊(cè)瀏覽內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 使用python刪除nginx緩存文件示例(python文件操作)

    使用python刪除nginx緩存文件示例(python文件操作)

    這篇文章主要介紹了使用python刪除nginx緩存文件示例(python文件操作),需要的朋友可以參考下
    2014-03-03
  • 基于Python+smtplib實(shí)現(xiàn)郵件自動(dòng)發(fā)送功能

    基于Python+smtplib實(shí)現(xiàn)郵件自動(dòng)發(fā)送功能

    工作中總有各種郵件需要定期發(fā)送,手動(dòng)操作不僅繁瑣還容易忘記,Python的smtplib庫(kù)完美解決這個(gè)痛點(diǎn),幾行代碼就能搞定郵件自動(dòng)發(fā)送,還能加上附件、HTML格式美化、定時(shí)任務(wù)等花樣玩法,所以本文介紹了基于Python+smtplib實(shí)現(xiàn)郵件自動(dòng)發(fā)送功能,需要的朋友可以參考下
    2025-09-09
  • python閉包的實(shí)例詳解

    python閉包的實(shí)例詳解

    在本篇文章里小編給大家整理的是一篇關(guān)于python閉包的實(shí)例詳解內(nèi)容,有興趣的朋友們可以學(xué)習(xí)下。
    2021-10-10
  • django 將自帶的數(shù)據(jù)庫(kù)sqlite3改成mysql實(shí)例

    django 將自帶的數(shù)據(jù)庫(kù)sqlite3改成mysql實(shí)例

    這篇文章主要介紹了django 將自帶的數(shù)據(jù)庫(kù)sqlite3改成mysql實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-07-07
  • 在Python中操作字典之clear()方法的使用

    在Python中操作字典之clear()方法的使用

    這篇文章主要介紹了在Python中操作字典之clear()方法的使用,是Python入門的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2015-05-05
  • pydev debugger: process 10341 is connecting無(wú)法debu的解決

    pydev debugger: process 10341 is co

    這篇文章主要介紹了pydev debugger: process 10341 is connecting無(wú)法debu的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • 解決keras backend 越跑越慢問(wèn)題

    解決keras backend 越跑越慢問(wèn)題

    這篇文章主要介紹了解決keras backend 越跑越慢問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-06-06
  • Python+OpenCV編寫(xiě)車輛計(jì)數(shù)器系統(tǒng)

    Python+OpenCV編寫(xiě)車輛計(jì)數(shù)器系統(tǒng)

    本文,我們將使用歐幾里德距離跟蹤和輪廓的概念在 Python 中使用 OpenCV 構(gòu)建車輛計(jì)數(shù)器系統(tǒng),文中的示例代碼講解詳細(xì),感興趣的可以了解一下
    2022-05-05
  • Python?OpenCV獲取圖片的基本參數(shù)信息

    Python?OpenCV獲取圖片的基本參數(shù)信息

    在圖像處理領(lǐng)域,了解圖像的基本信息是必不可少的第一步,本文主要介紹了如何使用Python?OpenCV獲取圖片的基本參數(shù)信息,感興趣的小伙伴可以了解下
    2024-11-11
  • python實(shí)現(xiàn)超市掃碼儀計(jì)費(fèi)

    python實(shí)現(xiàn)超市掃碼儀計(jì)費(fèi)

    這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)超市掃碼儀計(jì)費(fèi),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-05-05

最新評(píng)論

栖霞市| 师宗县| 孟州市| 南涧| 津市市| 陕西省| 清原| 满洲里市| 吴堡县| 辽宁省| 同德县| 外汇| 富宁县| 合江县| 馆陶县| 萨嘎县| 泊头市| 雷州市| 长葛市| 宁津县| 温宿县| 永福县| 定结县| 桐城市| 顺义区| 宜章县| 勃利县| 石城县| 公安县| 东光县| 天门市| 咸丰县| 铅山县| 琼结县| 界首市| 临江市| 宁南县| 郯城县| 西充县| 临西县| 沙坪坝区|