QListWidget not updating
-
Hi,
I'm adding items to a QlistIdget by Iterating through a list, each element has certain info to display and a link to an image to download.
It's working fine my only problem is that it takes too long.
What happens is that all items are shown at once. Which means that depending on the size of the list and my data, it may take minutes to show everything.
I already have an idea for the network issue but I still can't fix the everything shown at once issue.
I'm using python and qt5. -
@Iliass
Sounds like you are doing this in blocking loop if you mean "all items are shown at once [at the end]"? Do not do that. Either add each item to the list when it arrives (however you determine that) via a signal, or use aQTimer
to add a certain number at a time from some list of pending items to add which you have created. -
def search(self): // this is how I create my list self.listWidget.clear() self.gogo.keywordSetter(self.lineEdit.text()) self.gogo.linkSetter() self.gogo.resultsGetter() // iterating through the list for x in self.gogo.resultsContainer: self.listWidget.update() // an attempt to update the list (doesn't work lol) #print(x[2]) url = x[2] // unnecessary print(url) // just to check // reuesting the image req = Request(url, headers={'User-Agent': 'Mozilla/5.0'}) webpage = urlopen(req).read() pixmap = QPixmap() pixmap.loadFromData(webpage) icon = QIcon(pixmap) //creating the item item = QListWidgetItem(icon, x[1]) size = QSize() size.setHeight(100) size.setWidth(400) item.setSizeHint(size) #item.iconSize(QSize(100, 400)) self.listWidget.addItem(item)
here it is
Thanks in advance -
@Iliass
So the slowness comes from requesting data from a web page, is that where the delay is? You must not write a Qt UI program this way. Do something like: create a repeatingQTimer
, each time it expires go get one new item and add that.Even that may be too slow, if one web request takes a while. I do not know what
Request()
orurlopen()
are/do, maybe some synchronous Python routines? Use Qt's QNetworkAccessManager Class to do your web accesses, then you can use its asynchronous signals & slots to fetch data without blocking the UI. -
Not just because of the slowness. Because even when removing the icon and the requests it still waits until the loop is finished to add everything.
What's bothering is not how much it takes for each item but for everything.
If I could display one item at a time the wait between each item wouldn't bother me.
I'll give a try to QNetwork. I'll ask here while I can but can you add an Icon to an item after it was already added? -
@Iliass
Yes you can/change an icon any time.You must not write code which "waits" for anything to happen in an event-driven UI like Qt. It is a change in the approach required compared to traditional/sequential/synchronous coding. Your UI should normally be sitting doing "nothing", just in its event loop. When something happens --- like data arriving from somewhere --- you respond to it by updating the UI and then return to allowing the event loop to run. Any time you might have a while loop which fetches data and displays it that is not the best approach, you want the UI to respond to data arriving, not requesting and then waiting for it in any kind of loop.
-
@JonB
That's very instructive thanks. I have been messing around with qt for a few weeks and this is the first time I hear this (probably my fault lol)
So, If I understood it right I should first fetch all the relevant data before entering the loop.
Then using signals to add each element?
At the end of day what my program does is that it just displays search results with a thumbnail.One way to do it would be to create the list, add all the items use addItems instead of addItem then go through the ListWidget again and use signals to add the thumbnails?
I can't post so I'll just edit
def resultsGetter4(self,window): #self.resultsContainer = [] resultsContainerTemp = [] r = requests.get(self.resultsLink) resultsContainerTemp = BeautifulSoup(r.content,'html.parser') resultsContainerTemp = resultsContainerTemp.find("div", attrs = {"class" : "film_list-wrap"}).findAll("div", attrs = {"class" : "flw-item"}) for element in resultsContainerTemp: animeInfoContainer = element.find("img") asnimeLinkContainer = element.find("a") #anime = (asnimeLinkContainer['href'],animeInfoContainer['alt'],animeInfoContainer['data-src']) url = animeInfoContainer['data-src'] req = Request(url, headers={'User-Agent': 'Mozilla/5.0'}) webpage = urlopen(req).read() pixmap = QPixmap() pixmap.loadFromData(webpage) icon = QIcon(pixmap) item = QListWidgetItem(icon, animeInfoContainer['alt']) size = QSize() size.setHeight(100) size.setWidth(400) item.setSizeHint(size) #item.iconSize(QSize(100, 400)) window.listWidget.addItem(item) #self.resultsContainer.append(anime) #print(self.resultsContainer)
This is an alternative way that I had tried yesterday.
-
@Iliass said in QListWidget not updating:
So, If I understood it right I should first fetch all the relevant data before entering the loop.
Not really, because (from what you say) that may take a long time to fetch them all and you don't like waiting?
I suggested maybe one-at-a-time if you stick with your Python web functions, where each time is called from a
QTimer
. Or if you change over toQNetworkAccessManager
for the web retrieval that can be left to fetch things and emit a signal each time one arrives.I'm afraid this is all very fundamental to using Qt (or other event-driven approach), and I do not have time to write up a lecture course for you :) Maybe someone else wants to explain in more detail. I don't see that you have used a signal/slot in your code. If you have not done so already, take the time to study https://doc.qt.io/qt-5/signalsandslots.html in detail; you must grasp this concept to do anything useful in Qt.