一半君的总结纸

听话只听一半君

给QLineEdit textChanged添加延迟效果

一般我们用QLineEdit的时候,会把textChanged连到slot上,但带来一个附带的问题是,如果你的slot是刷新tableview,或者是执行耗时较长的操作的时候,如果每次按下按键都去执行slot,可能会造成ui卡住,或者是进行了无意义的刷新,脑残解决法如下

class DelayedExecutionTimer(QObject):  # source: https://wiki.qt.io/Delay_action_to_wait_for_user_interaction
    triggered = pyqtSignal(str)

    def __init__(self, parent):
        super(DelayedExecutionTimer, self).__init__(parent)
        # The minimum delay is the time the class will wait after being triggered before emitting the triggered() signal
        # (if there is no key press for this time: trigger)
        self.minimumDelay = 700
        self.minimumTimer = QTimer(self)
        self.minimumTimer.timeout.connect(self.timeout)

    def timeout(self):
        self.minimumTimer.stop()
        self.triggered.emit(self.string)

    def trigger(self, string):
        self.string = string
        self.minimumTimer.stop()
        self.minimumTimer.start(self.minimumDelay)

用的时候:

def __textChangeTriggered(text):
    print 'textChange trigged:', text

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    w = QtGui.QLineEdit()

    filter_delay = DelayedExecutionTimer(w)
    w.textChanged[str].connect(filter_delay.trigger)
    filter_delay.triggered[str].connect(__textChangeTriggered)

    w.show()
    sys.exit(app.exec_())

其效果是当textChanged 信号发生时,__textChangeTriggered 并不会马上执行,而是会有一定的延迟,只要用户还在输入,minimumTimer就会被不断的stop,并重新初始化,直到用户停止输入,再经过minimumDelay之后,slot才会被执行

略微修改版:(忘了哪里找来的了)

class DelayedExecutionTimer(QtCore.QObject):
    triggered = QtCore.pyqtSignal(str)

    def __init__(self, maxDelay=2000, minDelay=500, parent=None):
        super(DelayedExecutionTimer, self).__init__(parent)
        # The min delay is the time the class will wait after being triggered before emitting the triggered() signal
        # (if there is no key press for this time: trigger)
        self.minDelay = minDelay
        self.maxDelay = maxDelay
        self.minTimer = QtCore.QTimer(self)
        self.maxTimer = QtCore.QTimer(self)
        self.minTimer.timeout.connect(self.timeout)
        self.maxTimer.timeout.connect(self.timeout)

    def timeout(self):
        self.minTimer.stop()
        self.maxTimer.stop()
        self.triggered.emit(self.string)

    def trigger(self, string):
        self.string = string
        if not self.maxTimer.isActive():
            self.maxTimer.start(self.maxDelay)
        self.minTimer.stop()
        self.minTimer.start(self.minDelay)

这个修改版的不同之处在于又加入了一个maxTimer,当maxDelay的时间到了的时候,即使用户正在输入,slot也会被执行,这个意义在于如果用户一直在打字,我们偶尔也希望slot执行一下下,不要一直等待输入完成

参考:
https://wiki.qt.io/Delay_action_to_wait_for_user_interaction
TreeNote – An intuitive outliner for personal knowledge and task management
Diaoul/Dobby

Advertisements

2 responses to “给QLineEdit textChanged添加延迟效果

  1. wen 十一月 14, 2016 @ 6:36 下午

    Timer.stop() 下面最好加 一行 Timer.deleteLater(), 不然每调用一次都会创建一次新的QtCore.QTimer,前台你输入正爽的时候,后台不知不觉累积创建了N多QtCore.QTimer,
    (不太确定python的垃圾回收机制能否回收不用的QtCore.QTimer,手动自己关掉更安全)

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s

%d 博主赞过: