IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> Python + Tkinter:图片浏览器(一)——最小体积 -> 正文阅读

[Python知识库]Python + Tkinter:图片浏览器(一)——最小体积

作者:token keyword

前言

之前写过一篇关于图片浏览器的博文:Python + Tkinter:简易图片浏览器。由于仓促间完成,没有过多的琢磨和提炼,作品有些不尽人意。在使用过程中,觉得界面还不够清爽,做过一些改进。但一直没有更新。个人觉得还是图片浏览器,在视觉感官上,简洁纯粹的画面才是所追求的体验。

说明

布局方式

一开始是采用pack布局,格局简单,但是对于图片展示来说占用有限的初始空间。尝试使用绝对定位的place布局。place布局需要预设窗体大小,能做到精准设计。

图片展示

Tkinter库用于展示高清图片的容器主要有有两个:Label和Canvas。这里使用的是画布Canvas。

自动适应窗口

为了更好地展示高清图片,可能会调整窗口大小。显示图片的同时,需要考虑图片和按钮等组件自动适应窗口大小的变化的问题。

选择图片目录

一个具有良好用户体验的软件应该具有至少一个预设的初始化应用场景。同时,提供给用户自主选择的选项。

功能

图片导航

最基本的导航功能有三个:初始化、上一张和下一张。

浏览图库

初始化图片目录和重新选择图片目录。

窗口调整

窗口调整主要需要考虑的是:窗口居中、最大化、放大和缩小。在窗口调整时,也需要调整图片的大小:是放大还是缩小?通过监听窗口大小变化事件,及时原比例缩放图片是基本的要求。

模块

tkinter

PIL

os

自定义

imageutil.py

"""
@author: MR.N
@created: 2021-08-22 Sun. 21:54

"""
from PIL import Image, ImageTk

S_WIDTH = 560
S_HEIGHT = 640
SUB_WIDTH = 166
SUB_HEIGHT = 166
MIN_SUB_WIDTH = 16
MIN_SUB_HEIGHT = 16
I_WIDTH = S_WIDTH
I_HEIGHT = S_HEIGHT


def resize(path, scale=-1, screen_width=0, screen_height=0):
    image = Image.open(path)
    if scale == -1:
        if screen_width <= 0:
            screen_width = I_WIDTH
        if screen_height <= 0:
            screen_height = I_HEIGHT
        raw_width, raw_height = image.size[0], image.size[1]
        # max_width, max_height = I_WIDTH, I_HEIGHT
        max_width, max_height = raw_width, screen_height
        # '''
        min_width = max(raw_width, max_width)
        min_height = int(raw_height * min_width / raw_width)
        while min_height > screen_height:
            min_height = int(min_height * .9533)
        while min_height < screen_height:
            min_height += 1
        min_width = int(raw_width * min_height / raw_height)
        '''
        min_height = max(raw_width, max_width)
        min_width = int(raw_width * min_height / raw_height)
        '''
        while min_width > screen_width:
            min_width -= 1
        min_height = int(raw_height * min_width / raw_width)
    elif scale == 1:
        raw_width, raw_height = image.size[0], image.size[1]
        min_height = max(SUB_HEIGHT, max(I_HEIGHT, screen_height - 40) // 4)
        min_width = int(raw_width * min_height / raw_height)
    else:
        raw_width, raw_height = image.size[0], image.size[1]
        min_height = 18
        min_width = int(raw_width * min_height / raw_height)
    return image.resize((min_width, min_height))

imageviewer.py

# -*- coding: utf-8 -*-
"""
@file: imageviewer
@author: MR.N
@created: 2022/4/6 4月
@version: 1.0
@blog: https://blog.csdn.net/qq_21264377
"""

import tkinter as tk
from tkinter.filedialog import askdirectory
from imageutil import *
import os


def load_cache(media_dir=None):
    if media_dir is None:
        current_dir = os.path.abspath('.') + '/eming'
    else:
        current_dir = media_dir
        if not current_dir.startswith('/'):
            current_dir = os.path.abspath('.') + '/' + current_dir
    files = os.listdir(current_dir)
    temp = []
    for file in files:
        if os.path.isfile(current_dir + '/' + file):
            temp.append(current_dir + '/' + file)
    if len(temp) < 1:
        return []
    files.clear()
    for file in temp:
        # common picture medias
        if '.' in file and file.split('.')[-1].lower() in ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']:
            files.append(file)
    files.sort()
    return files


class MyWindow:
    BUTTON_SIZE_NORMAL = 32

    def __init__(self):
        self.window = tk.Tk()
        self.window.title('Gallery')
        self.window.config(bg='#111')
        self.frame_top_bar = tk.Frame(self.window)
        self.frame_photo = tk.Frame(self.window)
        self.window_width = 0
        self.window_height = 0
        self.window.geometry(
            f'{S_WIDTH}x{S_HEIGHT}+{(self.window.winfo_screenwidth() - S_WIDTH) // 2}+{(self.window.winfo_screenheight() - S_HEIGHT) // 2 - 18}')
        self.window.bind('<Configure>', self.window_resize)
        self.frame_top_bar.config(bg='#111111')

        self.photo_can = tk.Canvas(self.frame_photo)
        self.caches = load_cache('eming/img')
        self.cursor = 0
        if len(self.caches) > 0:
            self.photo = ImageTk.PhotoImage(
                resize(self.caches[self.cursor], screen_width=S_WIDTH, screen_height=S_HEIGHT))
            self.photo_can.create_image(
                ((S_WIDTH - self.photo.width()) // 2 - 36, (S_HEIGHT - self.photo.height()) // 2),
                anchor=tk.NW, image=self.photo)
        else:
            self.photo = None
        self.photo_can.config(bg='#111')
        self.photo_can.config(highlightthickness=0)
        # previous photo
        self.prev_button = tk.Button(self.window, text='?')
        self.prev_button.config(command=self.prev_photo)
        self.prev_button.config(font=('', 16))
        self.prev_button.place(x=0, y=(S_HEIGHT - self.BUTTON_SIZE_NORMAL) // 2, width=self.BUTTON_SIZE_NORMAL,
                               height=self.BUTTON_SIZE_NORMAL)
        self.photo_can.pack(side='left', expand='yes', fill='both', anchor='center')
        # next photo
        self.next_button = tk.Button(self.window, text='?')
        self.next_button.config(command=self.next_photo)
        self.next_button.config(font=('', 16))
        self.next_button.place(x=S_WIDTH - self.BUTTON_SIZE_NORMAL, y=(S_HEIGHT - self.BUTTON_SIZE_NORMAL) // 2,
                               width=self.BUTTON_SIZE_NORMAL, height=self.BUTTON_SIZE_NORMAL)
        # open gallery of photo(s) in another folder
        self.open_button = tk.Button(self.window, text='?')
        self.open_button.config(command=self.select_dir)
        self.open_button.config(font=('', 12))
        self.open_button.place(x=S_WIDTH - self.BUTTON_SIZE_NORMAL, y=0, width=self.BUTTON_SIZE_NORMAL,
                               height=self.BUTTON_SIZE_NORMAL)

        for button in [self.prev_button, self.next_button, self.open_button]:
            button.config(relief='ridge')
            button.config(fg='#fff')
            button.config(activeforeground='#f5f5f5')
            button.config(activebackground='#333')
            button.config(bg='#222')
            button.config(bd=0)
            button.config(highlightthickness=0)
            button.config(highlightcolor='#111')
            button.config(highlightbackground='#111')

        self.frame_top_bar.pack(side='bottom', expand='no', fill='x')
        self.frame_photo.pack(side='top', expand='yes', fill='both')

        self.first_load = True
        self.window.mainloop()

    def load_photo(self):
        if len(self.caches) > 0:
            if 0 <= self.cursor <= len(self.caches) - 1:
                width = self.photo_can.winfo_width() if self.photo_can.winfo_width() > 0 else S_WIDTH
                height = self.photo_can.winfo_height() if self.photo_can.winfo_height() > 0 else S_HEIGHT
                image = resize(self.caches[self.cursor], screen_width=width, screen_height=height)
                self.photo = ImageTk.PhotoImage(image)
                self.photo_can.create_image(
                    ((width - self.photo.width()) // 2,
                     (height - self.photo.height()) // 2),
                    anchor=tk.NW, image=self.photo)
                self.window.title(f'{self.caches[self.cursor].split("/")[-1]}')
        else:
            self.photo = None
        self.photo_can.update()

    def prev_photo(self):
        if len(self.caches) > 0:
            if self.cursor > 0:
                self.cursor -= 1
        self.load_photo()

    def next_photo(self):
        if len(self.caches) > 0:
            if self.cursor < len(self.caches) - 1:
                self.cursor += 1
        self.load_photo()

    def window_resize(self, event=None):
        if event is not None:
            # listen events of window resizing.
            if self.window_width != self.photo_can.winfo_width() or self.window_height != self.photo_can.winfo_height():
                if self.window_width != self.photo_can.winfo_width():
                    self.window_width = self.photo_can.winfo_width()
                if self.window_height != self.photo_can.winfo_height():
                    self.window_height = self.photo_can.winfo_height()
                # What happens here?
                if self.first_load:
                    self.first_load = False
                else:
                    self.prev_button.place(x=0, y=(self.photo_can.winfo_height() - self.BUTTON_SIZE_NORMAL) // 2,
                                           width=self.BUTTON_SIZE_NORMAL, height=self.BUTTON_SIZE_NORMAL)
                    self.next_button.place(x=self.photo_can.winfo_width() - self.BUTTON_SIZE_NORMAL,
                                           y=(self.photo_can.winfo_height() - self.BUTTON_SIZE_NORMAL) // 2,
                                           width=self.BUTTON_SIZE_NORMAL, height=self.BUTTON_SIZE_NORMAL)
                    self.open_button.place(x=self.photo_can.winfo_width() - self.BUTTON_SIZE_NORMAL,
                                           y=0,
                                           width=self.BUTTON_SIZE_NORMAL, height=self.BUTTON_SIZE_NORMAL)
                    self.load_photo()

    def select_dir(self):
        # Select the directory of photo(s).
        selected_dir = askdirectory()
        # Get () as return if selection is canceled or file dialog close.
        if selected_dir is not None and selected_dir != ():
            caches = load_cache(selected_dir)
            if len(caches) > 0:
                self.caches = caches
                self.cursor = 0
                self.load_photo()

    def __del__(self):
        self.window = None
        del self.window


def test():
    my_window = MyWindow()


if __name__ == '__main__':
    test()


界面

最小体积的Python + Tkinter图片浏览器

笔记

一个基本图片浏览器难点主要包含:
一)简洁合理的布局
二)图片容器、缩放、居中
三)图片导航
四)浏览图片目录
五)窗口自适应
“麻雀虽小五脏俱全”。完成以上几点基本功能,后续的扩展就更容易铺设。

  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2022-04-09 18:19:02  更:2022-04-09 18:22:20 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/28 22:42:30-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计