用Python PyQt写一个在线预览图片的GUI

这篇文章是我之前几篇文章的续篇:
用python写一个百度贴吧客户端

在爬完网上一篇帖子,并得到其中的所有图片链接后,写一个GUI来实现在线预览是一个很自然的想法, 相当于实现一个python版的图片浏览器, 通过这个练习,可以让我们更熟悉PyQt这个库。

这里我用的是PyQt4。

以下是我的写的程序,可以实现以下几个功能。

预览图片:

  1. 实现鼠标左键单击即可下翻至下一张图片,鼠标右键单击则是返回前一张图片。

  2. 利用本地Cache来解决反复读取的问题。 比如说对同样的两张图片我们想来回比较,我们没必要每次都重新下载。我们可以将图片保存到本地,当以后调用同一张图片时,直接从本地读取缓存来加速。如果我们不想让外界看到缓存的图片,则可以对其进行加密 (尚未实现)。

  3. 对动图gif的支持。普通的 jpg 和 Png 格式,利用QLable 即可以显示,但是对于gif,我们则必须利用QMovie来让其动起来。

由于我刚接触这个库,仍然在学习,所以写的不妥或者冗余的地方,希望大家指出。


# coding=utf-8
import sys
import pycurl
import os
import time
from StringIO import StringIO
import re
from PyQt4 import QtGui,QtCore
from PyQt4.QtGui import *
from PyQt4.QtCore import *



# class definition
class Pic_Label(QtGui.QLabel):
    def __init__(self):
        super(Pic_Label,self).__init__()
        self.setFrameStyle(QtGui.QFrame.StyledPanel)
        self.cache_map={}

    def paintEvent(self, event):

        if self.extention !="gif":
            size = self.size()
            painter = QtGui.QPainter(self)
            point = QtCore.QPoint(0,0)
            scaledPix = self.pixmap.scaled(size, Qt.KeepAspectRatio, transformMode = Qt.SmoothTransformation)
            # start painting the label from left upper corner
            point.setX((size.width() - scaledPix.width())/2)
            point.setY((size.height() - scaledPix.height())/2)
            #print point.x(), ' ', point.y()
            painter.drawPixmap(point, scaledPix)
        else:
            QLabel.paintEvent(self, event)



    def mouseReleaseEvent(self,ev):
        #self.emit(SIGNAL('clicked()'))
        if ev.button() == Qt.RightButton:
            self.emit(SIGNAL("RightClick"))
        else:
            self.emit(SIGNAL("LeftClick"))



    def set_image(self,pic_url,index):

        if (index in self.cache_map) == False:
            self.cache_map[index]=False
        self.pixmap = QtGui.QPixmap()
        self.retrieve_from_url_cache(pic_url,index)
        


    def retrieve_from_url_cache(self,pic_url,index):

        try:
            self.extention=re.search(r"\.(\w+)$", pic_url).group(1)
        except:
            self.extention="jpg"
        cache_pic_name="Pic_"+str(index)+"."+self.extention
        cache_pic_path=os.getcwd()+"\Cache_Pic\\"+cache_pic_name



        if self.cache_map[index]==True:
            if self.extention =="gif":
                movie = QtGui.QMovie(cache_pic_path)
                self.setMovie(movie)
                movie.start()

            else:
                #print "Cached!" + cache_pic_path
                if self.pixmap.load(cache_pic_path) == False:
                #print "use jpg to try again"
                    if self.pixmap.load(cache_pic_path)== False:
                    #last resort, try again
                        self.retrieve_from_url(pic_url,index,cache_pic_path)
                self.setPixmap(self.pixmap)  # udpate immediately


        else:
            if self.extention =="gif":
                data=self.retrieve_from_url(pic_url,index,cache_pic_path)
                self.pixmap.loadFromData(data)
                f = open(cache_pic_path, 'wb')
                f.write(data)
                f.close()
                movie = QtGui.QMovie(cache_pic_path)
                self.setMovie(movie)
                movie.start()

            else:
                data=self.retrieve_from_url(pic_url,index,cache_pic_path)
                self.pixmap.loadFromData(data)
                self.pixmap.save(cache_pic_path)
                self.setPixmap(self.pixmap)  # udpate immediately


    def retrieve_from_url(self,pic_url,index,file_path):
        c = pycurl.Curl()
        c.setopt(pycurl.PROXY, 'http://192.168.87.15:8080')
        c.setopt(pycurl.PROXYUSERPWD, 'LL66269:')
        c.setopt(pycurl.PROXYAUTH, pycurl.HTTPAUTH_NTLM)
        buffer = StringIO()
        c.setopt(pycurl.URL, pic_url)
        c.setopt(c.WRITEDATA, buffer)
        c.perform()
        c.close()  
        data = buffer.getvalue()
        self.cache_map[index]=True
        return data

        


    def setMovie(self,movie):
        QLabel.setMovie(self, movie)
        s=movie.currentImage().size()
        self._movieWidth = s.width()
        self._movieHeight = s.height()



class Example(QtGui.QWidget):


    def __init__(self,thread_url_list):
        super(Example, self).__init__()
        
        self.url_list=thread_url_list
        self.current_pic_index=0

        cwd = os.getcwd()
        #print cwd
        directory=cwd+"\Cache_Pic"
        #print directory
        if not os.path.exists(directory):
            os.makedirs(directory)


        self.initUI()

        # making subfolderss to cache pictures



    def initUI(self):


        layout = QtGui.QGridLayout()
        self.label = Pic_Label()
        self.label.set_image(self.url_list[0],0)


        #self.label = QLabel()
        #movie = QtGui.QMovie("Cache_Pic/Pic_0.gif")
        #self.label.setMovie(movie)
        #movie.start()


        layout.addWidget(self.label)
        layout.setRowStretch(0,1)
        layout.setColumnStretch(0,1)
      
        #self.connect(self.label,SIGNAL('clicked()'),self.fun_next)
        self.connect(self.label,SIGNAL("LeftClick"),self.fun_next)
        self.connect(self.label,SIGNAL("RightClick"),self.fun_prev)


        #b1=QtGui.QPushButton("next")
        #b2=QtGui.QPushButton("prev")
        #b1.clicked.connect(self.fun_next)
        #b2.clicked.connect(self.fun_prev)
        #layout.addWidget(b1)
        #layout.addWidget(b2)


        self.setLayout(layout)
        self.setGeometry(300, 300, 500, 500)
        self.setWindowTitle('Picture Viewer')
        self.show()



        # Connect button to image updating 






    def fun_next(self):
        if self.current_pic_index < len(self.url_list)-1:
            self.current_pic_index=self.current_pic_index+1
        else:
            self.current_pic_index=0

        self.label.set_image(self.url_list[self.current_pic_index],self.current_pic_index)
        sys.stdout.write('\r')
        sys.stdout.write("[ %d ] out of (%d)" % (self.current_pic_index+1,len(self.url_list)))
        sys.stdout.flush()




    def fun_prev(self):
        if self.current_pic_index > 0:
            self.current_pic_index=self.current_pic_index-1
        else:
            self.current_pic_index=len(self.url_list)-1

        self.label.set_image(self.url_list[self.current_pic_index],self.current_pic_index)
        sys.stdout.write('\r')
        sys.stdout.write("[ %d ] out of (%d)" % (self.current_pic_index+1,len(self.url_list)))
        sys.stdout.flush()


    
def view_image():
    url_list=['https://i.imgur.com/waprhO3.gif','http://static.cnbetacdn.com/article/2017/0831/7f11d5ec94fa123.png','http://static.cnbetacdn.com/article/2017/0831/1b6595175fb5486.jpg']
    viewer_app = QtGui.QApplication(sys.argv)
    ex = Example(url_list)
    sys.exit(viewer_app.exec_())


view_image()


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容