我正在嘗試覆寫 PySide2 中 QStatusBar 的 clearMessage 插槽/方法。
我有一個繼承自 QStatusBar 的自定義類,它重新實作了 showMessage 和 clearMessage 方法。
class MyStatus(QtWidgets.QStatusBar):
def showMessage(self, *args, **kwargs):
super(MyStatus, self).showMessage(*args, **kwargs)
print('Showing message')
def clearMessage(self, *args, **kwargs):
super(MyStatus, self).clearMessage(*args, **kwargs)
print('Clearing message')
根據我可以為 QStatusBar 找到的 c 源代碼,showMessage使用超時引數呼叫時,應在計時器到期時呼叫 clearMessage 槽:
void QStatusBar::showMessage(const QString &message, int timeout)
{
Q_D(QStatusBar);
if (timeout > 0) {
if (!d->timer) {
d->timer = new QTimer(this);
connect(d->timer, SIGNAL(timeout()), this, SLOT(clearMessage()));
}
d->timer->start(timeout);
} else if (d->timer) {
delete d->timer;
d->timer = nullptr;
}
if (d->tempItem == message)
return;
d->tempItem = message;
hideOrShow();
}
雖然訊息在計時器結束時清除,但我在方法中添加的列印行沒有被列印,這讓我相信:
- 它仍在執行基類的 clearMessage 方法
- 也許我找到的源代碼是針對不同版本的 Qt,而 PySide2 5.12.6 根本不呼叫該方法
我需要確保在訊息被清除的任何時候都會呼叫我的自定義 clearMessage,無論是手動(當前很好)還是通過計時器或其他原因。
我可以重新實作我自己的 Qtimer 并確保我正在捕獲任何其他可能呼叫 clearMessage 的方法,但我想知道我是否遺漏了一些明顯的東西,這會阻止我正確覆寫該方法。
uj5u.com熱心網友回復:
clearMessage()未列為virtual,這意味著覆寫對“內部”行為沒有影響,并且僅在從您的代碼中顯式呼叫時才會起作用。
由于clearMessage()實際上僅從創建的 QTimer 從 Qt 呼叫showMessage(),因此可能的解決方法是檢查呼叫基本實作后創建的最新QTimer 子物件,斷開其timeout信號并再次將其連接到您的插槽:
class MyStatusBar(QStatusBar):
def showMessage(self, message, timeout=0):
super().showMessage(message, timeout)
if timeout:
timer = self.findChildren(QTimer)[-1]
timer.timeout.disconnect()
timer.timeout.connect(self.clearMessage)
def clearMessage(self):
super().clearMessage()
print('my clearMessage')
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setStatusBar(MyStatusBar(self))
請注意,只有當您從不使用作為子類的子類創建的其他計時器時,上述代碼才能正常作業。如果您這樣做,您可能會不由自主地重新連接它們。拿這個案例:
def showMessage(self, message, timeout=0):
super().showMessage(message, timeout)
if timeout:
timer = self.findChildren(QTimer)[-1]
timer.timeout.disconnect()
timer.timeout.connect(self.clearMessage)
anotherTimer = QTimer(self, interval=3000,
timeout=self.myFunction)
anotherTimer.start()
def myFunction(self):
print('my custom function')
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setStatusBar(MyStatusBar(self))
self.statusBar().showMessage('Hello 1', 5000)
QTimer.singleShot(2000,
lambda: self.statusBar().showMessage('Hello 2', 5000))
以上將導致以下序列:
- 顯示一條訊息 5 秒;
- 啟動一個將在 3 秒后超時的計時器;
myFunction()叫做;- 啟動后2秒,
showMessage()呼叫一個新的; - 覆寫找到最后一個計時器(這是新
anotherTimer的),斷開它,然后將其連接到clearMessage();
雖然上面的案例顯然沒有多大意義,但最好考慮一下任意創建其他計時器的可能性;解決方案非常簡單:為內部計時器設定一個物件名稱,并在呼叫基本實作之前對其進行檢查。
showMessage()d->timer如果前一個不存在,總是創建一個新的計時器,否則它只是更新它,保持現有連接不變,所以如果沒有設定我們的物件名稱的前一個計時器,我們設定它,以便我們可以showMessage()在之前呼叫時找到它它的超時并且不再重新連接任何計時器。
請注意,我還添加了Qt.FindDirectChildrenOnly標志以避免找到來自其他物件的 QTimers 的可能性(例如使用addWidget()or時addPermanentWidget())。
def showMessage(self, message, timeout=0):
if timeout:
oldTimer = self.findChild(QTimer, 'clearMessageTimer',
Qt.FindDirectChildrenOnly)
super().showMessage(message, timeout)
if timeout and not oldTimer:
# there was no previously set timer
timer = self.findChildren(
QTimer, Qt.FindDirectChildrenOnly)[-1]
timer.setObjectName('clearMessageTimer')
timer.timeout.disconnect()
timer.timeout.connect(self.clearMessage)
clearMessage()出于顯而易見的原因,這是基于始終在其覆寫中呼叫的基本實作的假設。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/526189.html
