Question

I have the following code and am wondering if there is a way to make this more efficient. The setCurrentItem() and scrollToItem() functions seem to slow the process down considerable. Also, I would like to see the items show up in the list as they are added instead of all at once after the loop has completed. Any help or discussion would be greatly appreaciated.

import sys
from math import *
#from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import (Qt, SIGNAL, QSize)
from PyQt4.QtGui import (QApplication, QDialog, QLabel, QListWidget, QListWidgetItem,     QPushButton, QScrollArea, QTextDocument, QVBoxLayout)
from time import localtime, strftime
import time

class LogDlg(QDialog):

  def __init__(self, parent=None):
    super(LogDlg, self).__init__(parent)
    self.resize(450, 380)

    self.log1 = QListWidget()
    self.log2 = QListWidget()
    lbl = QLabel()
    lbl_2 = QLabel()
    lbl.setText("Communications Log")
    lbl_2.setText("Command/Data Log")
    self.pushButton = QPushButton()
    self.pushButton.setMaximumSize(QSize(110, 24))
    self.pushButton.setObjectName("pushButton")

    self.pushbutton = QPushButton
    self.pushButton.setText("Start Log Loop")
    layout = QVBoxLayout()
    layout.addWidget(self.pushButton)
    layout.addWidget(lbl)
    layout.addWidget(self.log1)
    layout.addWidget(lbl_2)
    layout.addWidget(self.log2)
    self.setLayout(layout)
    self.setWindowTitle("Transaction Logs")
    self.connect(self.pushButton,SIGNAL("clicked()"),self.logLoop) 
    self.time = time.time()

  def logLoop(self):
    for i in range(1000):
        print i
        self.addLog("This is a test","c",True)      

  def timeStamp(self):
    now = time.time()
    localtime = time.localtime(now)
    milliseconds = '%02d' % int((now - int(now)) * 100)
    val = time.strftime('%H:%M:%S.', localtime) + milliseconds
    return val

  def clearUi(self):
    self.log1.clear()
    self.log2.clear()

  def addLog(self, data, type="c", ts=False):
#        pass
    t = self.timeStamp()
    if ts == True:
        data = t + " " + data
    if type == "c":
        self.listItem1 = QListWidgetItem()
        self.listItem1.setText(data)
        self.log1.addItem(self.listItem1)
#        self.log1.scrollToItem(self.listItem1)
        self.log1.setCurrentItem(self.listItem1)


    elif type == "d":
        self.listItem2 = QListWidgetItem()
        self.listItem2.setText(data)
        self.log2.addItem(self.listItem2)
#        self.log2.scrollToItem(self.listItem2)
        self.log2.setCurrentItem(self.listItem2)


app = QApplication(sys.argv)
form = LogDlg()
form.open()
app.exec_()
Was it helpful?

Solution

Your issue doesn't have anything to do with .scrollToItem or .setCurrentItem. The loop in logLoop method doesn't give any chance for the Qt event loop to update things. One way to solve it is, give the Qt a chance to update the GUI with QApplication.processEvents(). So if you modify the logLoop as following, you should see the items as they are added:

  def logLoop(self):
    for i in range(1000):
        print i
        self.addLog("This is a test","c",True)
        QApplication.processEvents()

This is useful to some degree. If the time between processEvents is small enough you'll get a responsive UI. But once things get more complicated and the time to complete tasks for each segment increases, you'll need to delegate that piece of code to a separate thread (QThread) in order to keep the GUI responsive.

One other issue is, things will get slower once you have a large number of items in the QListWidget. You may notice that adding the 25th item is faster than 925th item. That's because QListWidget (or QTableWidget/QTreeWidget) doesn't scale well. If you are going to have large number of items, model/view framework (QListView/QTableView/QTreeView) should be your choice.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top