'PySide2: QMessageBox resizes when informatve text is changed obscuring progress bar
I have a custom QMessageBox with a progress bar. When I change the info text of the message box (using method setInformativeText), the window resizes automatically and hides the progress bar.
See below for a working example. The version I use is: PySide2==5.12.0.
How can I prevent the message box from resizing?
When the info text hasn't been changed the message box looks like:
After I change the info text, I get:
Working example:
#!/usr/bin/env python
import time
from PySide2.QtWidgets import (
QAction, QMessageBox, QAbstractButton, QProgressBar, qApp, QPlainTextEdit, QDialog,
QPushButton, QVBoxLayout, QApplication,
)
from PySide2.QtCore import QThread, Qt, Signal as Signal, QStandardPaths
from PySide2.QtGui import QIcon
class ShowMessageBox(QThread):
SLEEPTIME = 0.2
started = Signal()
finished = Signal()
def __init__(
self, text, parent=None, minimum_time=1.0, maximum_time=120.0,
cancel=False, callback=None):
super().__init__(parent=parent)
self.message_box = QMessageBox(parent=parent)
self.message_box.setText(str(text))
if cancel:
self.message_box.setStandardButtons(QMessageBox.Cancel)
else:
self.message_box.setStandardButtons(QMessageBox.NoButton)
self.callback = callback
self.progress_bar = None
self.started.connect(self.message_box.show)
self.finished.connect(self.message_box.accept)
if cancel and callback:
self.message_box.buttonClicked['QAbstractButton *'].connect(callback)
self.message_box.buttonClicked['QAbstractButton *'].connect(
self.button_clicked)
self.must_run = False
self.time_left = minimum_time
self.time_stop = maximum_time
self.start()
time.sleep(0.01)
qApp.processEvents()
def set_running(self, must_run):
self.must_run = must_run
time.sleep(0.01)
qApp.processEvents()
def run(self):
self.must_run = True
self.started.emit()
while (self.must_run or self.time_left) and self.time_stop:
time.sleep(self.SLEEPTIME)
if self.time_left > 0:
self.time_left -= self.SLEEPTIME
if self.time_left < 0.0:
self.time_left = 0.0
if self.time_stop > 0:
self.time_stop -= self.SLEEPTIME
if self.time_stop < 0.0:
self.time_stop = 0.0
self.finished.emit()
def button_clicked(self, button_or_id):
if isinstance(button_or_id, QAbstractButton):
self.set_running(False)
time.sleep(0.01)
qApp.processEvents()
def add_progress_bar(self, progress_max):
# add a progress bar if we have none
if progress_max and not self.progress_bar:
self.progress_bar = QProgressBar()
self.progress_bar.setMinimum(0)
self.progress_bar.setMaximum(progress_max)
layout = self.message_box.layout()
layout.addWidget(self.progress_bar, 5, 1)
self.progress_bar.setValue(0)
# remove progress bar if we have one
if progress_max == 0 and self.progress_bar:
self.progress_bar.deleteLater()
self.progress_bar.setParent(None)
self.progress_bar = None
time.sleep(0.01)
qApp.processEvents()
def set_progress_bar(self, progress):
if self.progress_bar:
self.progress_bar.setValue(progress)
time.sleep(0.01)
qApp.processEvents()
def set_text(self, text):
self.message_box.setText(str(text))
time.sleep(0.01)
qApp.processEvents()
def set_info_text(self, text):
self.message_box.setInformativeText(str(text))
time.sleep(0.01)
qApp.processEvents()
def process_events(process_time):
val = 0.0
while val < process_time:
qApp.processEvents() # todo:test
time.sleep(0.01) # todo:test
val += 0.01
def main():
app = QApplication()
mbox = ShowMessageBox('some normal text...', cancel=True, maximum_time=10)
process_events(1)
mbox.set_info_text('some info text...')
process_events(1)
# add a progress bar with a maximum value of 20; corresponds to 100%
mbox.add_progress_bar(20)
val = 0
while val <= 20:
process_events(0.2)
mbox.set_progress_bar(val)
val += 1
# change info text to show effect on progress bar
if val == 10:
mbox.set_info_text('changed info text...')
app.exec_()
if __name__ == "__main__":
main()
Solution 1:[1]
I couldn't get it to work using method setInformativeText without resizing issues.
I managed to work around the issue by appending the additional text to the main text, as suggested in Qt5 - Resizing a QMessageBox
My updated (working) code is:
#!/usr/bin/env python
import time
from PySide2.QtWidgets import (
QAction, QMessageBox, QAbstractButton, QProgressBar, qApp, QPlainTextEdit, QDialog,
QPushButton, QVBoxLayout, QApplication,
)
from PySide2.QtCore import QThread, Qt, Signal as Signal, QStandardPaths
from PySide2.QtGui import QIcon
class ShowMessageBox(QThread):
SLEEPTIME = 0.2
started = Signal()
finished = Signal()
def __init__(
self, text, parent=None, minimum_time=1.0, maximum_time=120.0,
cancel=False, callback=None):
super().__init__(parent=parent)
# trac:970:I couldn't get self.message_box.setInformativeText to work
# so used '\n' to delimit main text and info text, see:
# https://web.archive.org/web/20190910202435/http://apocalyptech.com/linux/qt/qmessagebox/
self.message_box = QMessageBox(parent=parent)
self.set_text(text)
if cancel:
self.message_box.setStandardButtons(QMessageBox.Cancel)
else:
self.message_box.setStandardButtons(QMessageBox.NoButton)
self.callback = callback
self.progress_bar = None
self.started.connect(self.message_box.show)
self.finished.connect(self.message_box.accept)
if cancel and callback:
self.message_box.buttonClicked['QAbstractButton *'].connect(callback)
self.message_box.buttonClicked['QAbstractButton *'].connect(
self.button_clicked)
self.must_run = False
self.time_left = minimum_time
self.time_stop = maximum_time
self.start()
def set_running(self, must_run):
self.must_run = must_run
def run(self):
self.must_run = True
self.started.emit()
while (self.must_run or self.time_left) and self.time_stop:
time.sleep(self.SLEEPTIME)
if self.time_left > 0:
self.time_left -= self.SLEEPTIME
if self.time_left < 0.0:
self.time_left = 0.0
if self.time_stop > 0:
self.time_stop -= self.SLEEPTIME
if self.time_stop < 0.0:
self.time_stop = 0.0
self.finished.emit()
def button_clicked(self, button_or_id):
if isinstance(button_or_id, QAbstractButton):
self.set_running(False)
def add_progress_bar(self, progress_max):
# add a progress bar if we have none
if progress_max and not self.progress_bar:
self.progress_bar = QProgressBar()
self.progress_bar.setMinimum(0)
self.progress_bar.setMaximum(progress_max)
layout = self.message_box.layout()
# line up progress bar with main text in column 1
layout.addWidget(self.progress_bar, 5, 1)
# set initial value
self.set_progress_bar(0)
# remove progress bar if we have one
if progress_max == 0 and self.progress_bar:
self.progress_bar.deleteLater()
self.progress_bar.setParent(None)
self.progress_bar = None
def set_progress_bar(self, progress):
if self.progress_bar:
self.progress_bar.setValue(progress)
# force update of message box in GUI
time.sleep(0.01)
qApp.processEvents()
def set_text(self, text):
self.main_text = str(text)
self.output_text()
def set_info_text(self, text):
self.info_text = str(text)
self.output_text()
def output_text(self):
try:
text = self.main_text
except AttributeError:
self.main_text = ''
text = self.main_text
try:
if self.info_text:
text = text + '\n' + self.info_text
except AttributeError:
self.info_text = ''
self.message_box.setText(text)
# force update of message box in GUI
time.sleep(0.01)
qApp.processEvents()
def main():
app = QApplication()
mbox = ShowMessageBox('some normal text...', cancel=True, maximum_time=10)
mbox.set_info_text('some info text...')
time.sleep(1.5)
# add a progress bar with a maximum value of 20; corresponds to 100%
mbox.add_progress_bar(20)
val = 0
while val <= 20:
# sleeping mimics application processing
time.sleep(0.2)
mbox.set_progress_bar(val)
val += 1
# change informative text while progress meter is active
if val == 10:
mbox.set_info_text('changed info text...')
app.exec_()
if __name__ == "__main__":
main()
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | NZD |


