Set List Widget Icon from Multiple URL
-
I am trying to create a news app but I am facing a issue that I can't seem to find the solution for.
from PyQt5 import QtCore, QtGui, QtWidgets import json import requests class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(1194, 767) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.side_bar_background = QtWidgets.QLabel(self.centralwidget) self.side_bar_background.setGeometry(QtCore.QRect(-10, -10, 171, 801)) self.side_bar_background.setStyleSheet("background-color: rgb(42, 72, 120);") self.side_bar_background.setText("") self.side_bar_background.setObjectName("side_bar_background") self.main_background = QtWidgets.QLabel(self.centralwidget) self.main_background.setGeometry(QtCore.QRect(80, -10, 1211, 791)) self.main_background.setStyleSheet("background-color: rgb(255, 247, 212);\n" "border-radius: 40px;") self.main_background.setText("") self.main_background.setObjectName("main_background") self.label = QtWidgets.QLabel(self.centralwidget) self.label.setGeometry(QtCore.QRect(270, 410, 521, 161)) self.label.setText("") self.label.setObjectName("label") self.search_bar = QtWidgets.QLineEdit(self.centralwidget) self.search_bar.setGeometry(QtCore.QRect(170, 30, 311, 41)) self.search_bar.setFocusPolicy(QtCore.Qt.WheelFocus) self.search_bar.setStyleSheet("background-color: white;\n" "color: rgb(26, 46, 75);\n" "font: 12pt \"Century Gothic\";\n" "border: 2px rgb(255, 255, 255);\n" "border-radius: 10px;\n" "") self.search_bar.setObjectName("search_bar") self.spacer = QtWidgets.QLabel(self.centralwidget) self.spacer.setGeometry(QtCore.QRect(150, 30, 41, 41)) self.spacer.setLayoutDirection(QtCore.Qt.LeftToRight) self.spacer.setStyleSheet("background-color: white;\n" "border: 2px rgb(255, 255, 255);\n" "border-radius: 10px;\n" "\n" "\n" "\n" "") self.spacer.setText("") self.spacer.setPixmap(QtGui.QPixmap("../../../Downloads/icons/search_bar_icon.png")) self.spacer.setObjectName("spacer") self.search_button = QtWidgets.QPushButton(self.centralwidget) self.search_button.setGeometry(QtCore.QRect(470, 30, 41, 41)) self.search_button.setFocusPolicy(QtCore.Qt.WheelFocus) self.search_button.setStyleSheet("QPushButton\n" "{\n" " background-color: white;\n" " border: 2px rgb(255, 255, 255);\n" " border-radius: 10px;\n" " \n" "}\n" "\n" "QPushButton:pressed\n" "{\n" " background-color: rgb(238, 238, 238);\n" "}\n" "\n" "\n" "") self.search_button.setText("") icon = QtGui.QIcon() icon.addPixmap(QtGui.QPixmap("../icons/search-line.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.search_button.setIcon(icon) self.search_button.setIconSize(QtCore.QSize(50, 50)) self.search_button.setFlat(False) self.search_button.setObjectName("search_button") self.home_icon = QtWidgets.QPushButton(self.centralwidget) self.home_icon.setGeometry(QtCore.QRect(24, 20, 41, 41)) self.home_icon.setFocusPolicy(QtCore.Qt.WheelFocus) self.home_icon.setStyleSheet("QPushButton\n" "{\n" " background-color: rgb(42, 72, 120);\n" " border: 2px rgb(255, 255, 255);\n" " border-radius: 10px;\n" " \n" "}\n" "\n" "\n" "QPushButton:pressed\n" "{\n" " background-color: rgb(33, 58, 95);\n" "}\n" "\n" "QPushButton:hover {\n" " \n" " background-color: rgb(33, 58, 95);\n" "\n" "}\n" "") self.home_icon.setText("") icon1 = QtGui.QIcon() icon1.addPixmap(QtGui.QPixmap("../icons/newspaper.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.home_icon.setIcon(icon1) self.home_icon.setIconSize(QtCore.QSize(50, 50)) self.home_icon.setFlat(False) self.home_icon.setObjectName("home_icon") self.search_tab = QtWidgets.QPushButton(self.centralwidget) self.search_tab.setGeometry(QtCore.QRect(20, 160, 41, 41)) self.search_tab.setFocusPolicy(QtCore.Qt.WheelFocus) self.search_tab.setStyleSheet("QPushButton\n" "{\n" " background-color: rgb(42, 72, 120);\n" " border: 2px rgb(255, 255, 255);\n" " border-radius: 10px;\n" " \n" "}\n" "\n" "\n" "QPushButton:pressed\n" "{\n" " background-color: rgb(33, 58, 95);\n" "}\n" "\n" "QPushButton:hover {\n" " \n" " background-color: rgb(33, 58, 95);\n" "\n" "}\n" "") self.search_tab.setText("") icon2 = QtGui.QIcon() icon2.addPixmap(QtGui.QPixmap("../icons/side_tab_search.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.search_tab.setIcon(icon2) self.search_tab.setIconSize(QtCore.QSize(50, 50)) self.search_tab.setFlat(False) self.search_tab.setObjectName("search_tab") self.category_tab = QtWidgets.QPushButton(self.centralwidget) self.category_tab.setGeometry(QtCore.QRect(20, 260, 41, 41)) self.category_tab.setFocusPolicy(QtCore.Qt.WheelFocus) self.category_tab.setStyleSheet("QPushButton\n" "{\n" " background-color: rgb(42, 72, 120);\n" " border: 2px rgb(255, 255, 255);\n" " border-radius: 10px;\n" " \n" "}\n" "\n" "\n" "QPushButton:pressed\n" "{\n" " background-color: rgb(33, 58, 95);\n" "}\n" "\n" "QPushButton:hover {\n" " \n" " background-color: rgb(33, 58, 95);\n" "\n" "}\n" "") self.category_tab.setText("") icon3 = QtGui.QIcon() icon3.addPixmap(QtGui.QPixmap("../icons/news_items.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.category_tab.setIcon(icon3) self.category_tab.setIconSize(QtCore.QSize(50, 50)) self.category_tab.setFlat(False) self.category_tab.setObjectName("category_tab") self.media_tab = QtWidgets.QPushButton(self.centralwidget) self.media_tab.setGeometry(QtCore.QRect(20, 360, 41, 41)) self.media_tab.setFocusPolicy(QtCore.Qt.WheelFocus) self.media_tab.setStyleSheet("QPushButton\n" "{\n" " background-color: rgb(42, 72, 120);\n" " border: 2px rgb(255, 255, 255);\n" " border-radius: 10px;\n" " \n" "}\n" "\n" "\n" "QPushButton:pressed\n" "{\n" " background-color: rgb(33, 58, 95);\n" "}\n" "\n" "QPushButton:hover {\n" " \n" " background-color: rgb(33, 58, 95);\n" "\n" "}\n" "") self.media_tab.setText("") icon4 = QtGui.QIcon() icon4.addPixmap(QtGui.QPixmap("../icons/media_tab.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.media_tab.setIcon(icon4) self.media_tab.setIconSize(QtCore.QSize(50, 50)) self.media_tab.setFlat(False) self.media_tab.setObjectName("media_tab") self.weather_tab = QtWidgets.QPushButton(self.centralwidget) self.weather_tab.setGeometry(QtCore.QRect(20, 460, 41, 41)) self.weather_tab.setFocusPolicy(QtCore.Qt.WheelFocus) self.weather_tab.setStyleSheet("QPushButton\n" "{\n" " background-color: rgb(42, 72, 120);\n" " border: 2px rgb(255, 255, 255);\n" " border-radius: 10px;\n" " \n" "}\n" "\n" "\n" "QPushButton:pressed\n" "{\n" " background-color: rgb(33, 58, 95);\n" "}\n" "\n" "QPushButton:hover {\n" " \n" " background-color: rgb(33, 58, 95);\n" "\n" "}\n" "") self.weather_tab.setText("") icon5 = QtGui.QIcon() icon5.addPixmap(QtGui.QPixmap("../icons/weather_icon.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.weather_tab.setIcon(icon5) self.weather_tab.setIconSize(QtCore.QSize(50, 50)) self.weather_tab.setFlat(False) self.weather_tab.setObjectName("weather_tab") self.listWidget = QtWidgets.QListWidget(self.centralwidget) self.listWidget.setGeometry(QtCore.QRect(100, 90, 1071, 661)) self.listWidget.setStyleSheet("font: 15pt \"MS Shell Dlg 2\";") self.listWidget.setIconSize(QtCore.QSize(200, 200)) self.listWidget.setObjectName("listWidget") item = QtWidgets.QListWidgetItem() icon6 = QtGui.QIcon() icon6.addPixmap(QtGui.QPixmap("apple.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) item.setIcon(icon6) self.listWidget.addItem(item) self.side_bar_background.raise_() self.label.raise_() self.main_background.raise_() self.spacer.raise_() self.search_bar.raise_() self.search_button.raise_() self.home_icon.raise_() self.search_tab.raise_() self.category_tab.raise_() self.media_tab.raise_() self.weather_tab.raise_() self.listWidget.raise_() MainWindow.setCentralWidget(self.centralwidget) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) self.addItem() def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) self.search_bar.setPlaceholderText(_translate("MainWindow", " Search any word or phrase")) __sortingEnabled = self.listWidget.isSortingEnabled() self.listWidget.setSortingEnabled(False) item = self.listWidget.item(0) item.setText(_translate("MainWindow", "News Example")) self.listWidget.setSortingEnabled(__sortingEnabled) # go through each item and clear the title/info for the ones the picture isn't working on def addItem(self): api_key = '4dbc17e007ab436fb66416009dfb59a8' news_call = json.loads(requests.get(f'https://newsapi.org/v2/everything?domains=wsj.com&apiKey={api_key}').text) result = len(news_call['articles']) call_store = {} count = 0 for i in range(result - 1): item = QtWidgets.QListWidgetItem(self.listWidget) icon = QtGui.QIcon() image = news_call['articles'][i]['urlToImage'] title = news_call['articles'][i]['title'] descri = news_call['articles'][i]['description'] if image != None: r = requests.get(image).content with open("image.png", 'wb+') as handler: handler.write(r) icon.addPixmap(QtGui.QPixmap('image.png'), QtGui.QIcon.Normal, QtGui.QIcon.Off) item.setIcon(icon) item.setText(title) """#another method if image != None: response = requests.get(image) ic = QtGui.QPixmap() ic.loadFromData(response.content) icon = QtGui.QIcon(ic) icon.addPixmap(QtGui.QPixmap(ic), QtGui.QIcon.Normal, QtGui.QIcon.Off) item.setIcon(icon) item.setText(title)""" if __name__ == "__main__": import sys app = QtWidgets.QApplication(sys.argv) MainWindow = QtWidgets.QMainWindow() ui = Ui_MainWindow() ui.setupUi(MainWindow) MainWindow.show() sys.exit(app.exec_())
My apprach was to get images/icon to ListWidget is to request every URL and add that to the Listwidget icon but the problem here is since I am requesting every image that takes around 30-1min to complete the whole request and have the image added to each title.
I did see another approach using QNetworkAccessManager but I am not sure how to apply that to my program. Pls help
are there any other approach?
-
The rule of dumb is to always think asynchronously when dealing with UI.
requests.get()is a synchronous function, e.g. it blocks the UI thread.grequestsis an asynchronous alternative.However, the best approach here is to use
QNetworkAccessManager. Keep in mind to always use the "Qt approach" unless it doesn't exist (it usually does ;-)).Anyway, here's a starting point:
def addItem(self): api_key = '4dbc17e007ab436fb66416009dfb59a8' self.manager = QtNetwork.QNetworkAccessManager() self.manager.finished[QtNetwork.QNetworkReply].connect(self.onFetchArticlesFinished) self.manager.get(QtNetwork.QNetworkRequest(QtCore.QUrl(f'https://newsapi.org/v2/everything?domains=wsj.com&apiKey={api_key}'))) def onFetchArticlesFinished(self, response): if response.error() != QtNetwork.QNetworkReply.NetworkError.NoError: raise Exception(f"The following error occurred while fetching articles: {response.error()}") news_call = json.loads(response.readAll().data()) result = len(news_call['articles']) # Redirect manager response self.manager.finished[QtNetwork.QNetworkReply].disconnect(self.onFetchArticlesFinished) self.manager.finished[QtNetwork.QNetworkReply].connect(self.onFetchArticleImageFinished) for i in range(result - 1): item = QtWidgets.QListWidgetItem(self.listWidget) image_url = news_call['articles'][i]['urlToImage'] title = news_call['articles'][i]['title'] # descri = news_call['articles'][i]['description'] item.setText(title) # Use a placeholder while image is downloaded item.setIcon(QtGui.QIcon(QtGui.QPixmap('./placeholder.png'))) # Build image request request = QtNetwork.QNetworkRequest(QtCore.QUrl(image_url)) # Save item index in request request.setAttribute(QtNetwork.QNetworkRequest.Attribute.User, i) # Start download self.manager.get(request) def onFetchArticleImageFinished(self, response): if response.error() != QtNetwork.QNetworkReply.NetworkError.NoError: raise Exception(f"The following error occurred while downloading '{response.url().toString()}': {response.error()}") # Create pixmap from response content pixmap = QtGui.QPixmap() pixmap.loadFromData(response.readAll()) # Retrieve item index from request item_index = response.request().attribute(QtNetwork.QNetworkRequest.Attribute.User) # Update item icon self.listWidget.item(item_index).setIcon(QtGui.QIcon(pixmap))And here's the placeholder.png.
The result:
