Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/user-interface/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
User interface 图像查看器-标准gui控件,自底向上还是什么?_User Interface_Image - Fatal编程技术网

User interface 图像查看器-标准gui控件,自底向上还是什么?

User interface 图像查看器-标准gui控件,自底向上还是什么?,user-interface,image,User Interface,Image,我需要制作一个基本图像查看器。 主要关注的是如何实现(在gui组件和图像处理方面)诸如:缩小、滚动和“手动工具”等功能 实现这一目标似乎有几种选择,主要是在图形界面框架上的责任程度不同于手动实现 对我来说显而易见的两个解决方案是: 1)使用某些图像处理库的功能自行调整图像可见部分的大小和裁剪。然后在某个窗口/控件上以重写的onPaint()方法绘制图像(或其部分)。需要编写滚动条更新(使用“手动工具”时)和操作(直接使用时)代码 2)包含图像的超大控件(StaticBitmap或其他任何控件)放

我需要制作一个基本图像查看器。 主要关注的是如何实现(在gui组件和图像处理方面)诸如:缩小、滚动和“手动工具”等功能

实现这一目标似乎有几种选择,主要是在图形界面框架上的责任程度不同于手动实现

对我来说显而易见的两个解决方案是:

1)使用某些图像处理库的功能自行调整图像可见部分的大小和裁剪。然后在某个窗口/控件上以重写的onPaint()方法绘制图像(或其部分)。需要编写滚动条更新(使用“手动工具”时)和操作(直接使用时)代码

2)包含图像的超大控件(StaticBitmap或其他任何控件)放在自动滚动的窗口中。然后需要弄清楚如何将图像坐标转换为滚动坐标

这两种方法看起来都很尴尬。有什么好办法可以干净利落地做吗?还是我觉得丑陋只是唯一的出路

我将Python与wxPython/wxWidgets和PIL一起使用,但问题在很大程度上是语言和平台独立的


欢迎使用示例代码和指向(不太臃肿的内容)源代码的链接。

这里有一个教程可能会有所帮助

实际上我并没有看所有的视频,所以我不能说它能很好地解决你的具体问题


还有,杰夫·阿特伍德(Jeff Atwood)的一篇博客文章,介绍了如何编写恐怖代码。它说明了什么时候应该花时间编写自己的代码,什么时候应该只使用第三方解决方案。

我实际上刚刚用wxPython和PIL制作了一个简单的图像查看器。我不想,但我很难找到一个像我想要的那样简单的查看器。不管怎样,我从一个应用程序开始,并努力开发了一个应用程序,可以缩放、旋转和浏览文件夹中的所有图像。回家后,如果你愿意,我可以发布完整的代码。

我是新来的,搜索了一段时间后,我仍然找不到上传文件的方法。哦,好吧,这是帖子里的代码。对于非描述性变量名和缺少注释,我们深表歉意。我想您要了解的主要功能是processPicture和showPicture

编辑:只是重申一下,我是从年的例子开始的

导入wx、操作系统、字符串、系统
从PIL导入图像
#滚轮和+/-进行放大/缩小。f切换全屏。r旋转。
#m将PIL模式从低质量(快速)更改为高质量(慢速)。
#1000x1000以下的图像自动显示为高质量图像。
#拖动时按下中键可移动图像,如箭头所示
#关键点(如果图像大于窗口)。
#鼠标左键和右键是下一个和上一个图像。
#没有加载图像的功能。当创建可执行文件时
#查看器是通过打开图像启动的。
#要从命令行运行此文件,请注释掉第55行并取消注释
#第54行,然后执行“viewer.py sampleImage”
#有几行特定于Windows。他们(可能)都有
#与路径有关,即“/”vs“\”。
类ImageFrame(wx.Frame):
定义初始化(自):
wx.Frame.\uuuu init\uuuuu(self,None,title=“viewer”)
自我中心()
self.Size=(450450)
self.imageBox=wx.Window(self)
self.vbox=wx.BoxSizer(wx.VERTICAL)
self.CreateStatusBar(5)
自我设置状态宽度([-1,70,50,50,30])
self.cursor=wx.StockCursor(wx.cursor\u箭头)
self.moveCursor=wx.StockCursor(wx.CURSOR\u大小)
self.vbox.Add(self.imageBox,比例=1,标志=wx.EXPAND)
self.SetSizer(self.vbox)
self.Show()
self.sbm=0
self.sbmList=[]
self.name=“”
self.url=“”
self.dir=''
自系数=1.0
自旋转=0
self.width=0
self.height=0
self.count=0
self.size=0
self.numopics=0
self.mc=False
self.fs=False
self.mode=0
self.SetStatusText(str(self.mode),4)
如果len(sys.argv)==2:
#self.url=os.getcwd()+'\\'+sys.argv[1]
self.url=sys.argv[1]
self.name=self.url.split('\\')[len(self.url.split('\\'))-1]
self.dir=self.url.replace('\\'+self.name',)
self.loadDirectory(self.dir)
self.processPicture()
self.imageBox.Bind(wx.EVT_大小,lambda EVT:self.rescale(EVT,1))
self.imageBox.Bind(wx.EVT\u鼠标滚轮,self.zoom)
self.imageBox.Bind(wx.EVT\u KEY\u DOWN,self.keyEvent)
self.imageBox.Bind(wx.EVT\u MIDDLE\u UP,self.endDrag)
self.imageBox.setbackgroundcolor((0,0,0,0))
self.imageBox.Bind(wx.EVT_LEFT_DOWN,self.next)
self.imageBox.Bind(wx.EVT\u RIGHT\u DOWN,self.prev)
def nameFromUrl(self,url):
name=url.split(“\\”)
name=name[len(name)-1]
返回名称
def processPicture(自身,系数=0):
img=Image.open(self.url)
self.width=img.size[0]
自身高度=外形尺寸[1]
ogHeight=自我高度
ogWidth=self.width
xWin=self.imageBox.Size[0]
yWin=self.imageBox.Size[1]
winRatio=1.0*xWin/yWin
imgRatio=1.0*self.width/self.height
self.factor=因子*因子
如果系数==0:
自我系数=1
模式=0
如果(ogWidth self.imageBox.Size[0]:
比较=boxPos[0]-imgPos[0]
如果比较self.imageBox.Size[1]:
比较=boxPos[1]-imgPos[1]
如果比较self.imageBox.Size[0]:
比较=imgPos[0]+self.sbm.Size[0]-boxPos[0]-self.imageBox.Size[0]
如果比较self.imageBox.Size[1]:
比较=imgPos[1]+s
import wx, os, string, sys
from PIL import Image

# Scroll wheel and +/- do zoom in/out. f toggles full screen. r rotates.
# m changes PIL mode from low quality (fast) to high quality (slow).
# Images under 1000x1000 are automatically on high quality.
# Middle button down while dragging moves image around, as do arrow
# keys (if image is bigger than window).
# Left and right mouse buttons are next and previous image.

# There is no functionality to load an image. When an executeable is made, the
# viewer is started by opening an image with it. 
# To run this file from command line, comment out line 55 and uncomment 
# line 54, then do "viewer.py sampleImage"

# There are several lines that are Windows specific. They (probably) all have
# to do with paths, i.e, "/" vs "\". 



class ImageFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self,None,title = "viewer")
        self.Centre()
        self.Size = (450,450)
        self.imageBox = wx.Window(self)
        self.vbox = wx.BoxSizer(wx.VERTICAL)
        self.CreateStatusBar(5) 
        self.SetStatusWidths([-1, 70, 50, 50, 30])
        self.cursor = wx.StockCursor(wx.CURSOR_ARROW)
        self.moveCursor = wx.StockCursor(wx.CURSOR_SIZING)
        self.vbox.Add(self.imageBox,proportion=1,flag = wx.EXPAND)
        self.SetSizer(self.vbox)
        self.Show()
        self.sbm = 0
        self.sbmList = []
        self.name = ''
        self.url = ''
        self.dir = ''
        self.factor = 1.0
        self.rotation = 0
        self.width = 0
        self.height = 0
        self.count = 0
        self.size = 0
        self.numOfPics = 0
        self.mc = False
        self.fs = False
        self.mode = 0
        self.SetStatusText(str(self.mode), 4)
        if len(sys.argv) == 2:
            #self.url = os.getcwd() + '\\' + sys.argv[1]
            self.url = sys.argv[1]
            self.name = self.url.split('\\')[len(self.url.split('\\'))-1]
            self.dir = self.url.replace('\\' + self.name,'')
            self.loadDirectory(self.dir)
            self.processPicture()
        self.imageBox.Bind(wx.EVT_SIZE, lambda evt: self.rescale(evt,1))
        self.imageBox.Bind(wx.EVT_MOUSEWHEEL,self.zoom)
        self.imageBox.Bind(wx.EVT_KEY_DOWN, self.keyEvent)
        self.imageBox.Bind(wx.EVT_MIDDLE_UP, self.endDrag)
        self.imageBox.SetBackgroundColour((0,0,0,0))
        self.imageBox.Bind(wx.EVT_LEFT_DOWN, self.next)
        self.imageBox.Bind(wx.EVT_RIGHT_DOWN, self.prev)

    def nameFromUrl(self,url):
        name = url.split('\\')
        name = name[len(name)-1]
        return name

    def processPicture(self, factor = 0):

        img = Image.open(self.url)
        self.width = img.size[0]
        self.height = img.size[1]
        ogHeight = self.height
        ogWidth = self.width
        xWin = self.imageBox.Size[0]
        yWin = self.imageBox.Size[1]
        winRatio = 1.0*xWin/yWin
        imgRatio = 1.0*self.width/self.height

        self.factor = factor*self.factor
        if factor == 0:
            self.factor = 1
        mode = 0
        if (ogWidth <=1000 and ogHeight <= 1000) or self.mode == 1:
            mode = 1

        if imgRatio >= winRatio: #match widths
            self.width = self.factor*xWin
            self.height = self.factor*xWin/imgRatio
            img = img.resize((int(self.width),int(self.height)),mode)
        else:   #match heights
            self.height = self.factor*yWin
            self.width = self.factor*yWin*imgRatio
            img = img.resize((int(self.width),int(self.height)),mode)

        label = str(int(100*self.width/ogWidth))
        name = self.nameFromUrl(self.url)
        index = self.sbmList.index(name)
        self.SetStatusText(name, 0)
        self.SetStatusText(str(ogWidth) + 'x' + str(ogHeight), 1)
        self.SetStatusText(label + '%', 2)
        self.SetStatusText(str(index+1) + '/' + str(self.numOfPics), 3)

        if self.rotation % 360 != 0:
            img = img.rotate(self.rotation)
            self.width = img.size[0]
            self.height = img.size[1]

        wximg = wx.EmptyImage(img.size[0],img.size[1])
        wximg.SetData(img.convert("RGB").tostring())
        wximg.SetAlphaData(img.convert("RGBA").tostring()[3::4])

        self.showPicture(wximg)

    def showPicture(self,img):
        bmp = wx.BitmapFromImage(img)
        x = (self.imageBox.Size[0] - self.width)/2.0
        y = (self.imageBox.Size[1] - self.height)/2.0
        tmp = wx.StaticBitmap(self.imageBox,wx.ID_ANY,bmp,(x,y))
        tmp.Bind(wx.EVT_LEFT_DOWN, self.next)
        tmp.Bind(wx.EVT_RIGHT_DOWN, self.prev)
        tmp.Bind(wx.EVT_MOTION, self.drag)
        tmp.Bind(wx.EVT_MIDDLE_UP, self.endDrag)
        tmp.SetBackgroundColour((180,180,180,180))
        if self.sbm:
            self.sbm.Destroy()
        self.sbm = tmp
        self.imageBox.Refresh()

    def loadDirectory(self,dir):
        self.sbmList = []
        for image in os.listdir(dir):
            if image.lower().endswith('jpg') or image.lower().endswith('png') or image.lower().endswith('jpeg') or image.lower().endswith('gif') or image.lower().endswith('bmp'):
                self.sbmList.append(image)
        self.numOfPics = len(self.sbmList)

    def next(self,event):
        if self.name in self.sbmList:
            n = self.sbmList.index(self.name)
            if n == len(self.sbmList) - 1:
                n = -1
            self.name = self.sbmList[n + 1]
            self.url = self.dir + '\\' + self.name
            self.rotation = 0
            self.processPicture()

    def prev(self,event):
        if self.name in self.sbmList:
            n = self.sbmList.index(self.name)
            if n == 0:
                n = len(self.sbmList)
            self.name = self.sbmList[n - 1]
            self.url = self.dir + '\\' + self.name 
            self.rotation = 0
            self.processPicture()

    def rescale(self,event,factor):
        if self.url and self.GetStatusBar(): #close is seen as a size event.
            self.processPicture(factor)

    def zoom(self,event):
        factor = 1.25
        if event.GetWheelRotation() < 0:
                factor = 0.8
        self.rescale(event,factor)

    def keyEvent(self,event):
        code = event.GetKeyCode()
        if code == 43: #plus
            self.rescale(event,1.25)
        elif code == 45: #minus
            self.rescale(event,0.8)
        elif code == 82 and self.url: #r
            self.rotation = self.rotation + 90
            self.processPicture(1)
        elif code == 70: #f
            self.toggleFS()
        elif (code == 314 or code == 315 or code == 316 or code == 317) and self.sbm:
            #left, up, right, down
            self.scroll(code)
        elif code == 77: #m
            if self.mode == 0:
                self.mode = 1
            else:
                self.mode = 0
            self.SetStatusText(str(self.mode), 4)
            self.processPicture(1)


    def scroll(self,code):
        boxPos = self.imageBox.GetScreenPositionTuple()
        imgPos = self.sbm.GetScreenPositionTuple()
        delta = 20
        if code == 314 and self.width > self.imageBox.Size[0]:
            compare = boxPos[0] - imgPos[0]
            if compare <= delta:
                delta = max(compare,0)
            self.imageBox.ScrollWindow(delta,0)
        if code == 315 and self.height > self.imageBox.Size[1]:
            compare = boxPos[1] - imgPos[1]
            if compare <= delta:
                delta = max(compare,0)
            self.imageBox.ScrollWindow(0,delta)
        if code == 316 and self.width > self.imageBox.Size[0]:
            compare =  imgPos[0] + self.sbm.Size[0] - boxPos[0] - self.imageBox.Size[0]
            if compare <= delta:
                delta = max(compare,0)
            self.imageBox.ScrollWindow(-delta,0)
        if code == 317 and self.height > self.imageBox.Size[1]:
            compare =  imgPos[1] + self.sbm.Size[1] - boxPos[1] - self.imageBox.Size[1]
            if compare <= delta:
                delta = max(compare,0)
            self.imageBox.ScrollWindow(0,-delta)

    def drag(self,event):
        if event.MiddleIsDown():
            if not self.mc:
                self.SetCursor(self.moveCursor)
                self.mc = True
            boxPos = self.imageBox.GetScreenPositionTuple()
            imgPos = self.sbm.GetScreenPositionTuple()
            if self.count == 0:
                self.x = event.GetX()
                self.y = event.GetY()
            self.count = self.count + 1
            if self.count > 1:
                deltaX = event.GetX() - self.x
                deltaY = event.GetY() - self.y
                if imgPos[0] >= boxPos[0] and deltaX > 0:
                    deltaX = 0
                if imgPos[0] + self.width <= boxPos[0] + self.imageBox.Size[0] and deltaX < 0:
                    deltaX = 0
                if imgPos[1] >= boxPos[1] and deltaY > 0:
                    deltaY = 0
                if imgPos[1] + self.height <= boxPos[1] + self.imageBox.Size[1] and deltaY < 0:
                    deltaY = 0
                self.imageBox.ScrollWindow(2*deltaX,2*deltaY)
                self.count = 0

    def endDrag(self,event):
        self.count = 0
        self.SetCursor(self.cursor)
        self.mc = False

    def toggleFS(self):
        if self.fs:
            self.ShowFullScreen(False)
            self.fs = False
        else:
            self.ShowFullScreen(True)
            self.fs = True




app = wx.App(redirect = False)
frame = ImageFrame()
app.MainLoop()