pyqt5 QLabel显示网络图片

分享一个QLabel显示网络图片的方。
看网上基本都是使用requests来请求的,这会有个问题如果将请求放入主线程页面会直接卡死,那么肯定pass,如果将请求放入QThread中,网络图片只有10~20个还可以凑合,如果需要加载上百个网络图片,很有可能因为线程过多而堵塞,最大的问题就是慢,这个也可以pass了。
如果将requests异步,你会发现图片是一个一个的蹦出来的,也不太好看。

有缺点的一些方法

具体看代码细节吧

直接通过请求获取网络图片

def get_image_content(url: str) -> QPixmap:image = QPixmap()headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.0.0'}try:response = requests.get(url, headers=headers)image.loadFromData(response.content)return imageexcept Exception as e:return image# label = QLabel()
# label.setPixmap(get_image_content(
#     'https://image.baidu.com/search/detail?ct=503316480&z=undefined&tn=baiduimagedetail&ipn=d&word=csdn&step_word=&lid=11776445228125483707&ie=utf-8&in=&cl=2&lm=-1&st=undefined&hd=undefined&latest=undefined&copyright=undefined&cs=181147288,2457056291&os=2182694500,281061618&simid=181147288,2457056291&pn=2&rn=1&di=46137345&ln=1914&fr=&fmq=1713437873349_R&fm=&ic=undefined&s=undefined&se=&sme=&tab=0&width=undefined&height=undefined&face=undefined&is=0,0&istype=0&ist=&jit=&bdtype=11&spn=0&pi=0&gsm=1e&objurl=https%3A%2F%2Fimg-blog.csdnimg.cn%2Ff2dc93498ac14647869750e19fa0fdae.png&rpstart=0&rpnum=0&adpicid=0&nojc=undefined&dyTabStr=MCwxLDMsMiw2LDQsNSw4LDcsOQ%3D%3D'))

QThread查看网络图片

class GetImageThread(QThread):imageChanged = pyqtSignal(QPixmap)def __init__(self, parent=None):super().__init__(parent)self._urls = []self._imageDataList = []self._headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.0.0'}def run(self):for index, url in enumerate(self._urls):image = QPixmap()try:response = requests.get(url, headers=self._headers)image.loadFromData(response.content)self.imageChanged.emit(image)except Exception as e:self.imageChanged.emit(image)def setUrls(self, urls: list):self._urls = urlsdef urls(self):return self._urlsdef setHeaders(self, headers: dict = {}):self._headers.update(headers)

QThread+asyncio异步请求

请求后你会发现,QThread用不到1s就结束了,但是异步的返回值需要5s后才能接受到,很明显不符合需求

class GetImgAsyncThread(QThread):imgChanged = pyqtSignal(QPixmap)errorChange = pyqtSignal(str)def __init__(self, parent=None):super().__init__(parent)self._urlsData = []self._headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.0.0'}def run(self):try:for index, response in enumerate(asyncio.run(self.async_response())):  # type: int, requests.Responseimage = QPixmap()image.loadFromData(response.content)self.imgChanged.emit(image)response.close()except Exception as e:self.errorChange.emit(str(e))async def async_request(self, method, url, **kwargs):response = await asyncio.to_thread(requests.request, method, url, headers=self._headers,**kwargs)  # type: requests.Responsereturn responseasync def async_response(self):task = []for urlData in self._urlsData:func_task: asyncio.Task[dict] = asyncio.create_task(self.async_request(**urlData))func_response = await func_tasktask.append(func_response)return taskdef setUrlsData(self, urlsData: list) -> None:"""[{'method': 'get', 'url': 'http://127.0.0.1:8888'}]:param urlsData: :return: """self._urlsData = urlsDatadef getUrlsData(self):return self._urlsDatadef setHeaders(self, headers: dict = {}):self._headers.update(headers)

这些方法都有些缺点,还有就是比较麻烦,每次都需要反复调用

推荐使用的方法

先分享一个ImageLabel的组件,它会让你显示图片更加丝滑

from functools import singledispatch, update_wrapper
from typing import Unionfrom PyQt5.Qt import *class singledispatchmethod:"""Single-dispatch generic method descriptor.Supports wrapping existing descriptors and handles non-descriptorcallables as instance methods."""def __init__(self, func):if not callable(func) and not hasattr(func, "__get__"):raise TypeError(f"{func!r} is not callable or a descriptor")self.dispatcher = singledispatch(func)self.func = funcdef register(self, cls, method=None):"""generic_method.register(cls, func) -> funcRegisters a new implementation for the given *cls* on a *generic_method*."""return self.dispatcher.register(cls, func=method)def __get__(self, obj, cls=None):def _method(*args, **kwargs):if args:method = self.dispatcher.dispatch(args[0].__class__)else:method = self.funcfor v in kwargs.values():if v.__class__ in self.dispatcher.registry:method = self.dispatcher.dispatch(v.__class__)if method is not self.func:breakreturn method.__get__(obj, cls)(*args, **kwargs)_method.__isabstractmethod__ = self.__isabstractmethod___method.register = self.registerupdate_wrapper(_method, self.func)return _method@propertydef __isabstractmethod__(self):return getattr(self.func, '__isabstractmethod__', False)class ImageLabel(QLabel):""" Image labelConstructors------------* ImageLabel(`parent`: QWidget = None)* ImageLabel(`image`: str | QImage | QPixmap, `parent`: QWidget = None)"""clicked = pyqtSignal()@singledispatchmethoddef __init__(self, parent: QWidget = None):super().__init__(parent)self.image = QImage()self.setBorderRadius(0, 0, 0, 0)self._postInit()@__init__.registerdef _(self, image: str, parent=None):self.__init__(parent)self.setImage(image)self._postInit()@__init__.registerdef _(self, image: QImage, parent=None):self.__init__(parent)self.setImage(image)self._postInit()@__init__.registerdef _(self, image: QPixmap, parent=None):self.__init__(parent)self.setImage(image)self._postInit()def _postInit(self):passdef _onFrameChanged(self, index: int):self.image = self.movie().currentImage()self.update()def setBorderRadius(self, topLeft: int, topRight: int, bottomLeft: int, bottomRight: int):""" set the border radius of image """self._topLeftRadius = topLeftself._topRightRadius = topRightself._bottomLeftRadius = bottomLeftself._bottomRightRadius = bottomRightself.update()def setImage(self, image: Union[str, QPixmap, QImage] = None):""" set the image of label """self.image = image or QImage()if isinstance(image, str):reader = QImageReader(image)if reader.supportsAnimation():self.setMovie(QMovie(image))else:self.image = reader.read()elif isinstance(image, QPixmap):self.image = image.toImage()self.setFixedSize(self.image.size())self.update()def scaledToWidth(self, width: int):if self.isNull():returnh = int(width / self.image.width() * self.image.height())self.setFixedSize(width, h)if self.movie():self.movie().setScaledSize(QSize(width, h))def scaledToHeight(self, height: int):if self.isNull():returnw = int(height / self.image.height() * self.image.width())self.setFixedSize(w, height)if self.movie():self.movie().setScaledSize(QSize(w, height))def isNull(self):return self.image.isNull()def mouseReleaseEvent(self, e):super().mouseReleaseEvent(e)self.clicked.emit()def setPixmap(self, pixmap: QPixmap):self.setImage(pixmap)def pixmap(self) -> QPixmap:return QPixmap.fromImage(self.image)def setMovie(self, movie: QMovie):super().setMovie(movie)self.movie().start()self.image = self.movie().currentImage()self.movie().frameChanged.connect(self._onFrameChanged)def paintEvent(self, e):if self.isNull():returnpainter = QPainter(self)painter.setRenderHints(QPainter.Antialiasing)path = QPainterPath()w, h = self.width(), self.height()# top linepath.moveTo(self.topLeftRadius, 0)path.lineTo(w - self.topRightRadius, 0)# top right arcd = self.topRightRadius * 2path.arcTo(w - d, 0, d, d, 90, -90)# right linepath.lineTo(w, h - self.bottomRightRadius)# bottom right arcd = self.bottomRightRadius * 2path.arcTo(w - d, h - d, d, d, 0, -90)# bottom linepath.lineTo(self.bottomLeftRadius, h)# bottom left arcd = self.bottomLeftRadius * 2path.arcTo(0, h - d, d, d, -90, -90)# left linepath.lineTo(0, self.topLeftRadius)# top left arcd = self.topLeftRadius * 2path.arcTo(0, 0, d, d, -180, -90)# draw imageimage = self.image.scaled(self.size() * self.devicePixelRatioF(), Qt.IgnoreAspectRatio, Qt.SmoothTransformation)painter.setPen(Qt.NoPen)painter.setClipPath(path)painter.drawImage(self.rect(), image)@pyqtProperty(int)def topLeftRadius(self):return self._topLeftRadius@topLeftRadius.setterdef topLeftRadius(self, radius: int):self.setBorderRadius(radius, self.topRightRadius, self.bottomLeftRadius, self.bottomRightRadius)@pyqtProperty(int)def topRightRadius(self):return self._topRightRadius@topRightRadius.setterdef topRightRadius(self, radius: int):self.setBorderRadius(self.topLeftRadius, radius, self.bottomLeftRadius, self.bottomRightRadius)@pyqtProperty(int)def bottomLeftRadius(self):return self._bottomLeftRadius@bottomLeftRadius.setterdef bottomLeftRadius(self, radius: int):self.setBorderRadius(self.topLeftRadius, self.topRightRadius, radius, self.bottomRightRadius)@pyqtProperty(int)def bottomRightRadius(self):return self._bottomRightRadius@bottomRightRadius.setterdef bottomRightRadius(self, radius: int):self.setBorderRadius(self.topLeftRadius, self.topRightRadius, self.bottomLeftRadius, radius)

显示网络图片

在上面基础上添加了图片阴影,网络图片的显示
诸所周知C++运行非常快,那么很简单,将所有的请求都扔给C++就好,那么不得不使用Qt自带的一个请求管理器了,使用QNetworkAccessManager可以轻松的实现那些壁纸 软件的效果,需要注意的是QNetworkAccessManager也是多线程操作,你可以在finished中做任何事情,完全不会影响页面的运行

# coding: utf-8
from typing import Unionfrom PyQt5.QtCore import QUrl, Qt, pyqtSignal
from PyQt5.QtGui import QPixmap, QColor, QImage, QImageReader, QMovie
from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkReply, QNetworkRequest
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QApplication, QGraphicsDropShadowEffectclass WebImageLabel(ImageLabel):finished = pyqtSignal()def _postInit(self):self.shadowEffect = Noneself._shadowVisible = Falseself.networkAccessManager = QNetworkAccessManager(self)self.networkAccessManager.finished.connect(self.__on_finished_connect)self.setBorderRadius(5, 5, 5, 5)def setWebUrl(self, url: Union[str, QUrl], headers: dict = None):if isinstance(url, str):url = QUrl(url)request = QNetworkRequest(url)request.setAttribute(QNetworkRequest.FollowRedirectsAttribute, True)self.__initHeaders(request, headers)self.networkAccessManager.get(request)self.update()def __initHeaders(self, request: QNetworkRequest, headers: dict = None):if headers is None:returnfor item in headers.items():request.setRawHeader(item[0].encode(), item[1].encode())def __on_finished_connect(self, reply: QNetworkReply):if reply.error() == QNetworkReply.NoError:pixmap = QPixmap()pixmap.loadFromData(reply.readAll().data())self.setPixmap(pixmap)else:self.setPixmap(QPixmap())self.finished.emit()def setImage(self, image: Union[str, QPixmap, QImage] = None):""" set the image of label """self.image = image or QImage()if isinstance(image, str):reader = QImageReader(image)if reader.supportsAnimation():self.setMovie(QMovie(image))else:self.image = reader.read()elif isinstance(image, QPixmap):self.image = image.toImage()# self.setFixedSize(self.image.size())self.update()def setShadowEffect(self, blurRadius=30, offset=(0, 0), color=QColor(0, 0, 0, 100)):"""为对话框添加阴影"""self.shadowEffect = QGraphicsDropShadowEffect(self)self.shadowEffect.setBlurRadius(blurRadius)self.shadowEffect.setOffset(*offset)self.shadowEffect.setColor(color)self.setGraphicsEffect(None)self.setGraphicsEffect(self.shadowEffect)def isShadowVisible(self):return self._shadowVisibledef setShadowVisible(self, b: bool):self._shadowVisible = bif self._shadowVisible:self.setShadowEffect()else:self.setGraphicsEffect(None)del self.shadowEffectself.shadowEffect = None

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/443.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vue 3 项目构建与效率提升:vite-plugin-vue-setup-extend 插件应用指南

一、Vue3项目创建 前提是已安装Node.js(点击跳转Node官网) npm create vuelatest这一指令将会安装并执行 create-vue,它是 Vue 官方的项目脚手架工具。你将会看到一些诸如 TypeScript 和测试支持之类的可选功能提示: ✔ Projec…

2024-03-23青少年软件编程(Python语言)等考(一级)解析

2024-03-23青少年软件编程(Python语言)等级考试试卷(一级)解析一、单选题(共25题,共50分) 1.下列哪个命令,可以将2024转换成2024 呢?( A ) A. str(2024) B. int(2024) C. float(2024) D. bool(2024)将数字转换成字符串用到的是str() 语句。 2.猴子摘了一包桃子,第一…

WPS的bug问题(解决方法->换成office吧):表格数据和透视图数据不一致问题,多次尝试确定该bug

1.软件版本 2.问题描述 我在原始表中对其中一列进行筛选,选择95%以上这个选项值,343个数据。 在筛选了95%以上这个选项之后,我的另一列的值全部是no,343个数据。 然后进行透视图之后,在绘制的图形中发现&#xff0c…

腾讯面试准备-2024.3.25

腾讯面试准备-2024.3.25 腾讯面试准备-2024.3.25自我介绍C11/14/17新特性C11新特性C14新特性C17新特性 struct和class的区别进程状态现代的流媒体通信协议栈流媒体协议详解extern "C"程序从编译到执行的过程进程、线程、协程进程线程协程 如何实现一个信号与槽系统&a…

Linux错误(3)Linux里IP套接字sendmsg出现EPERM错误

Linux错误(3)之Linux里IP套接字sendmsg出现EPERM错误 Author: Once Day Date: 2024年2月21日 漫漫长路才刚刚开始… 全系列文章可参考专栏: Mermaid使用指南_Once_day的博客-CSDN博客 参考文档: c - How to fix EPERM error when trying to use sendto() with Ethernet so…

2024_GAMES101作业环境配置Mac(intel)_VSCode_Clion

目录 VSCodeClionCMakeList.txt VSCode brew install cmake 更换下载源为阿里云下载 opencv,不然会很慢 cd "$(brew --repo)" git remote -v cd "$(brew --repo)" git remote set-url origin https://mirrors.aliyun.com/homebrew/brew.git…

linux中 关于操作Tomcat、Apache、Nginx、Mysql 的操作命令

a. 控制Apache 的操作命令 # 启动Apache命令 service httpd start # 重新 启动Apache命令 service httpd restart # 停止Apache命令 service httpd stop # 启动Apache命令 service httpd statusb. 控制Tomcat的操作命令 # 启动Tomcat命令 sh startup.sh# 停止Tomcat命令 s…

Ubuntu 24.04 LTS (Noble Numbat) 下载

Ubuntu 24.04 LTS (Noble Numbat) 下载 Ubuntu 24.04 LTS 开启 Beta 测试, 正式版即将发布 请访问原文链接:Ubuntu 24.04 LTS (Noble Numbat),查看最新版。原创作品,转载请保留出处。 作者主页:sysin.org Ubuntu 24.04 LTS 首个…

如果出现这7个现象,别犹豫,是时候更换你的海外仓系统了

不知不觉,即使是曾经让你觉得很有用的海外仓系统也出现了问题。 曾经看似可以简化海外仓运营的管理系统,现在却难以满足你的需求。你是否注意到你的仓库管理效率低下的情况已经开始蔓延,甚至影响了公司的盈利? 仓库日常的管理工…

力扣(leetcode) 42. 接雨水 (带你逐步思考)

力扣(leetcode) 42. 接雨水 (带你逐步思考) 链接:https://leetcode.cn/problems/trapping-rain-water/ 难度:hard 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多…

鸿蒙开发踩坑与理解

基于 studio dev3.1,api 9 总结:现在的鸿蒙,感觉就像是用eclipse开发android的时候的android4.0或者4.0以下 持续更新中… 申请next,可能没通过? 没下文了。可能华为还不希望普通开发者进行开发吧。 兼容性问题 鸿蒙4.0,华为mate40E当前版本有黑屏、卡顿问题,客服说a…

【正点原子Linux连载】 第三十三章 Linux CAN驱动实验 摘自【正点原子】ATK-DLRK3568嵌入式Linux驱动开发指南

1)实验平台:正点原子ATK-DLRK3568开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id731866264428 3)全套实验源码手册视频下载地址: http://www.openedv.com/docs/boards/xiaoxitongban 第三十…

https通信流程

HTTPS通信流程通常包括以下几个关键步骤: 客户端发起请求:客户端(通常是Web浏览器)向服务器发起HTTPS连接请求,并连接到服务器的443端口(HTTPS的默认端口)。SSL/TLS握手:在数据传输…

Word目录格式的编辑记录

1、整体风格 鼠标右键,编辑域 选择目录,风格可以根据自己的喜好选择古典、优雅、正式等 2、字段、段落样式调整 更新整个目录 加载出样式侧框,选中某一级目录,侧框会定位到其样式 然后修改对应的样式,比如字体和段…

vscode自动生成返回值的快捷键

vscode中类似idea的altenter功能,可以添加返回值 idea中是Introduce local variable, vscode中按下command.(句号) 然后选extract to local variable或者 Assign statement to new local variable都行, 光标在分号前如图: 光标在…

如何安装和使用Yarn管理JavaScript依赖

在JavaScript开发中,依赖管理是一个至关重要的环节。Yarn是一个强大的包管理工具,旨在提供快速、可靠和安全的依赖解决方案。本文将介绍如何安装和使用Yarn,让你轻松管理JavaScript项目的依赖。 1. 安装Yarn 首先,我们需要在系统…

探索直播+电商系统中台架构:连接消费者与商品的智能纽带

随着直播电商的崛起,电商行业进入了全新的智能时代。直播形式的互动性和即时性为消费者提供了全新的购物体验,而电商平台则为商品的展示、销售和配送提供了强大的支持。在这一背景下,直播电商系统中台架构成为了连接消费者与商品的智能纽带&a…

Java基于微信小程序的电影院订票系统,附源码

博主介绍:✌IT徐师兄、7年大厂程序员经历。全网粉丝15W、csdn博客专家、掘金/华为云//InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇&#x1f3…

C语言简单的数据结构:双向链表的实现

目录: 1.双向链表的结构和初始化1.1双向链表的结构1.2双向链表的初始化 2.双向链表的相关操作2.1双向链表的尾插、打印和头插2.11双向链表的尾插2.12双向链表的打印2.13双向链表的头插 2.2双向链表的尾删和头删2.21双向链表的尾删2.22双向链表的头删 2.3双向链表查找…

前后端系统开发之——文章管理

原文地址:前后端系统开发之——文章管理 - Pleasure的博客 下面是正文内容: 前言 主要使用的技术:前端使用的是Vue.js,后端使用的是SpringBoot。如不雷同可以直接跳过了。 文章管理是这个系统最主要的一个功能也是最常规的一个功…