视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
使用wxpython实现的一个简单图片浏览器实例
2020-11-27 14:38:18 责编:小采
文档

上次我爬了n多图片,但是浏览的时候有一个问题。

图片浏览器的浏览一般都是按名称排的,而我对图片的命名是按照数字递增的。比如3总是会排在10后面,也就无法快速地浏览图片了。

所以,出于方便自己查阅图片,也出于学习,决定做一个自己的图片浏览器。

目标:浏览目录,通过滚轮不断显示同一个文件夹下的图片,并自定义排序。

步骤0:要实现图形界面,我使用wxPython。

至于如何安装和简单地使用wxpython,可以到网上检索,一大堆资料。
以下步骤默认你已经知道如何生成一个自己的frame。

步骤1:浏览目录。

这个功能就是类似于打开“我的电脑”,然后不断地进入文件夹和返回。
通过几种尝试,我决定使用listbox。

我初始化一个app。用一个frame实现目录的功能,其上只有一个listbox;用另一个frame实现图片展示的功能,两个frame通过app进行信息的传递。

代码如下:


for _dir in os.listdir(dir):
#do something

其中像os.path.split()、os.path.splitext()、os.path.isdir()等,都是很常用的一些方法。

显示目录就是一个不断地获取你选择的目录,进入目录,读取其下目录,清空listbox,显示目录,更改工作路径的过程。

显示目录的时候,自定义排序功能就来了。通过对图片名称进行处理,转为数字,排序,然后再重新组装回去,从而达到按数字递增的效果。

代码如下:


self.list.Bind(wx.EVT_LISTBOX_DCLICK, self.OnDClick)

同时通过以上方法为listbox绑定了双击事件。若是双击目录则进入目录,否则显示通过app展示图片。

同时这个frame需要具备两个方法,就是获取上一张或下一张图片,为了后续app的调用。

步骤2:显示图片

这个图片展示一开始感觉挺麻烦的,但是弄懂了之后就很简单了。

我用一个frame展示图片。

frame上面空白,有一个wx.StaticBitmap,之后显示图片的时候只需要往这个staticbitmap写bitmap就可以了。一开始我是不断地新建staticbitmap,导致了一些可以看到但是那时候不知道为什么的原因。

然后在这个frame上检测鼠标滚轮事件,通过向上或向下滚轮调用app的GetNextImage和GetPreImage方法并将获得的图片显示出来。

还有图片的大小,我先规定了一个最大值和最小值,将图片约束在一定的范围内。

代码如下:


bmp = image.Scale(size[0], size[1]).ConvertToBitmap()
self.bmp.SetSize(size)#bmp是staticbitmap
self.bmp.SetBitmap(bmp)

但是一个小窗口看图片很不爽,于是将图片窗口全屏化。

代码如下:


self.ShowFullScreen(True, style=wx.FULLSCREEN_ALL)

全屏化就要考虑怎么退出了。我通过按键发送消息,命令窗口关闭或显示。若显示则关闭(其实只是隐藏),若隐藏则显示。注意这个事件要绑定到app上面。

代码如下:


self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)

然后图片需要能够放大和缩小。于是我再次通过按键触发。放大或缩小只需要通过改变staticbitmap的最大值并让bmp适应那个size就可以了。

由于全屏了,那么需要能够移动图片。移动的时候也只需要移动staticbitmap就行了。

代码如下:


#注意这里要将事件绑定到staticbitmap上面
self.bmp.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
self.bmp.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
self.bmp.Bind(wx.EVT_MOTION, self.OnMotion)

至此,大概要点都讲完了,下面是全部代码。仔细查阅会发现一些新的用法,

不过这个图片浏览器估计只是够我用,不过其实用起来已经挺爽的了, 全屏的图片展示,还可以随便移动图片,快捷键很方便地退出全屏。

里面还有一些不完善的地方需要改进,希望能跟大家多多交流~

感谢这期间被我大量参考资料的作者们。

代码如下:


#!/usr/bin/env Python
#coding=utf-8

#filename : PictureBrowser.py
#date : 2012-10-11

import wx
import os
import sys
import string

#你有H盘吗?没有的话在这个初始化函数里修改加载的初始路径
class PBDirFrame(wx.Frame):
def __init__(self, app):
wx.Frame.__init__(self, None, -1, "选择文件夹", size=(250,500))

self.app = app

#设置字体
font = wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.NORMAL, False, 'Courier New')
self.SetFont(font)

#文件夹listbox
self.list = wx.ListBox(self, -1, (0,0), (200,600), '', wx.LB_SINGLE)
self.list.Bind(wx.EVT_LISTBOX_DCLICK, self.OnDClick)

#加载当前文件夹
#curdir = os.getcwd()#在这里修改初始路径,这个是当前工作路径
curdir = 'H:\'
os.chdir(curdir)
self.LoadDir(curdir)

#绑定事件
self.Bind(wx.EVT_CLOSE, self.OnClose)



#显示窗口
self.Show()

def OnClose(self, event):
self.Destroy()
self.app.Close()

#listbox双击事件
def OnDClick(self, event):
if self.list.GetSelection()==0:#判断是否选择了返回上一层文件夹
path = os.getcwd()
pathinfo = os.path.split(path)
dir = pathinfo[0]
else:#获得需要进入的下一层文件夹
dir = self.list.GetStringSelection()

if os.path.isdir(dir):#进入文件夹
self.LoadDir(dir)
elif os.path.splitext(dir)[-1]=='.jpg':#显示图片
self.app.ShowImage(dir)

#加载文件夹,如果你想定义自己的排序,那么修改这个方法吧~
def LoadDir(self, dir):
#不是目录则不进行操作
if not os.path.isdir(dir):
return

self.list.Clear()#清空
self.list.Append('...')#添加返回上一层文件夹标志

dirs = []
jpgs = []
nnjpgs = []
for _dir in os.listdir(dir):
if os.path.isdir(dir+os.path.sep+_dir):
dirs.append(_dir)
else:
info = os.path.splitext(_dir)
if info[-1]=='.jpg':
if info[0].isdigit():
jpgs.append(string.atoi(info[0]))#转化为数字
else:
nnjpgs.append(_dir)
jpgs.sort()
for _jpgs in jpgs:
self.list.Append(str(_jpgs)+'.jpg')
for _nnjpgs in nnjpgs:
self.list.Append(_nnjpgs)
for _dirs in dirs:
self.list.Append(_dirs)

os.chdir(dir)#设置工作路径

#获得下一张要显示的图片
def GetNextImage(self):
index = self.list.GetSelection()
i = index
while i+1 i += 1
if os.path.splitext(self.list.GetString(i))[-1]=='.jpg':
break
if i index = i
self.list.SetSelection(index)
return self.list.GetStringSelection()

#获得上一张图片
def GetPreImage(self):
index = self.list.GetSelection()
i = index
while i-1>0:
i -= 1
if os.path.splitext(self.list.GetString(i))[-1]=='.jpg':
break
if i>0:
index = i

self.list.SetSelection(index)
return self.list.GetStringSelection()


class PBPicFrame(wx.Frame):

max_width = 400
max_height = 600

def __init__(self, app):
wx.Frame.__init__(self, None, -1, "显示图片", size=(400,400))#, style=wx.SIMPLE_BORDER)

#是否要移动图片的标志
self.bmoved = False

self.app = app

#staticbitmap
self.bmp = wx.StaticBitmap(self, 0, wx.NullBitmap, (0,0), (400,400))


self.Bind(wx.EVT_MOUSEWHEEL, self.OnChangeImage)
self.bmp.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
self.bmp.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
self.bmp.Bind(wx.EVT_MOTION, self.OnMotion)
self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)

self.ShowFullScreen(True, style=wx.FULLSCREEN_ALL)
self.Hide()


def ShowImage(self, path):
if os.path.splitext(path)[-1]!='.jpg':
return
self.bmppath = path
image = wx.Image(path, wx.BITMAP_TYPE_JPEG)
bmp = image.ConvertToBitmap()
size = self.GetSize(bmp)
bmp = image.Scale(size[0], size[1]).ConvertToBitmap()
self.bmp.SetSize(size)
self.bmp.SetBitmap(bmp)
self.Show()

def GetSize(self, bmp):
width = bmp.GetWidth()
height = bmp.GetHeight()
if width>self.max_width:
height = height*self.max_width/width
width = self.max_width
if height>self.max_height:
width = width*self.max_height/height
height = self.max_height
size = width, height
return size

def OnChangeImage(self, event):
rotation = event.GetWheelRotation()
if rotation<0:
self.app.ShowNextImage()
else:
self.app.ShowPreImage()

def OnLeftDown(self, event):
self.pos = event.GetX(), event.GetY()
self.bmoved = True

def OnLeftUp(self, event):
self.bmoved = False

def OnMotion(self, event):
if not self.bmoved:
return
pos = event.GetX(), event.GetY()
dx = pos[0]-self.pos[0]
dy = pos[1]-self.pos[1]
pos = self.bmp.GetPosition()
pos = pos[0]+dx, pos[1]+dy
self.bmp.SetPosition(pos)

def OnKeyDown(self, event):
keycode = event.GetKeyCode()
if keycode == 49:#数字1放大
self.SizeUp()
elif keycode == 50:#数字2缩小
self.SizeDown()
event.Skip()#这个貌似很重要,要同时触发app上的快捷键

def SizeUp(self):
self.max_width += 50
self.max_height += 75
self.ShowImage(self.bmppath)
def SizeDown(self):
self.max_width -= 50
self.max_height -= 75
self.ShowImage(self.bmppath)

class PBApp(wx.App):

#redirect=False将信息输出到dos界面
def __init__(self, redirect=False):
wx.App.__init__(self, redirect)

def OnInit(self):

#显示文件夹列表界面
self.dirframe = PBDirFrame(self)

#显示图片界面
self.picframe = PBPicFrame(self)

#绑定事件
self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
return True

def ShowImage(self, path):
#print 'showing app img', path
self.picframe.ShowImage(path)
self.picframe.SetFocus()

def ShowNextImage(self):
path = self.dirframe.GetNextImage()
self.ShowImage(path)

def ShowPreImage(self):
path = self.dirframe.GetPreImage()
self.ShowImage(path)

def OnKeyDown(self, event):
keycode = event.GetKeyCode()
#print keycode
if keycode == 27:# ESC键
#切换图片窗体的显示和隐藏
if self.picframe.IsShown():
self.picframe.Hide()
else:
self.picframe.Show()

def Close(self):
self.picframe.Close()


def main():
app = PBApp()
app.MainLoop()

if __name__=='__main__':
main()

下载本文
显示全文
专题