I have a QMainWindow object that regularly calls QDialogs, but the visibility of the frameless QDialog boxes is very low when over another window. I am trying to add a dark overlay onto the MainWindow whenever a QDialog is called, but regardless if I use QGraphicsOpacityEffect or set a stylesheet, it never shows up.
Specifications: Windows 11 Environment, Python3.11, PyQt5
Here is using QGraphicsOpacityEffect function:
def darken_window(self):
self.overlay = QWidget(self)
self.overlay.setGeometry(self.geometry())
self.overlay.setWindowModality(Qt.ApplicationModal)
opacity_effect = QGraphicsOpacityEffect()
opacity_effect.setOpacity(0.5)
self.overlay.setGraphicsEffect(opacity_effect)
self.overlay.show()
Here it is using setStyleSheet:
def darken_window(self):
self.overlay = QWidget(self)
self.overlay.setGeometry(self.geometry())
self.overlay.setStyleSheet("background-color: rgba(255,0,0,128);")
self.overlay.setWindowModality(Qt.ApplicationModal)
self.overlay.show()
Here is the full code for the mainWindow:
class MainWindow(QMainWindow):
"""
Main application window with title, banner, result widgets and navigation buttons
Parameters:
None
"""
def __init__(self):
super().__init__()
self.results = empty_results
self.img_states = (
QPixmap(resource_path("images/failure.png")).scaled(50, 50),
QPixmap(resource_path("images/success.png")).scaled(50, 50),
QPixmap(resource_path("images/pending.png")).scaled(50, 50),
QPixmap(resource_path("images/blanked.png")).scaled(50, 50),
QPixmap(resource_path("images/warning.png")).scaled(50, 50))
self.setWindowTitle("D-NA")
self.setGeometry(100, 100, 500, 700)
self.central_widget = QWidget(self)
self.setCentralWidget(self.central_widget)
self.setMouseTracking(True)
self.center()
layout = QVBoxLayout(self.central_widget)
image_label = QLabel(self)
image = QPixmap(resource_path("images/banner.png"))
image_label.setPixmap(image)
image_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
layout.addWidget(image_label)
self.result_labels: dict = {}
for key, result in self.results.items():
h_layout = QHBoxLayout()
result_widget = HoverWidget(key.upper(), self.img_states[3], result)
layout.addWidget(result_widget)
layout.addLayout(h_layout)
self.result_labels[key] = [result_widget]
button_layout = QHBoxLayout()
self.analyse_button = QPushButton("Analyze", self)
self.report_button = QPushButton("Show Report", self)
self.close_button = QPushButton("Close", self)
self.analyse_button.clicked.connect(self.analyse_pressed)
self.report_button.clicked.connect(self.report_pressed)
self.close_button.clicked.connect(self.close_pressed)
button_layout.addWidget(self.analyse_button)
button_layout.addWidget(self.report_button)
button_layout.addWidget(self.close_button)
layout.addLayout(button_layout)
self.report_button.setEnabled(False)
self.show()
self.initialize()
self.populate_devices()
def center(self):
qr = self.frameGeometry()
cp = QDesktopWidget().availableGeometry().center()
qr.moveCenter(cp)
self.move(qr.topLeft())
def initialize(self):
login = LoginScreen()
result = self.darken_window(login)
if result == QDialog.Accepted:
self.username, self.session, self.account_id = login.getData()
def darken_window(self, dialog):
self.overlay = QWidget(self)
self.overlay.setGeometry(self.geometry())
self.overlay.setStyleSheet("background-color: rgba(255,0,0,128);")
print(self.overlay.styleSheet())
self.overlay.setWindowModality(Qt.ApplicationModal)
self.overlay.show()
result = dialog.exec_()
self.overlay.close()
return result
def populate_devices(self):
self.events = list_available_events(f'{url}incl/list_elements.php', self.session, self.account_id)
popup_window = EventSelection(self.events)
result = popup_window.exec_()
if result == QDialog.Accepted:
event_ids = popup_window.getData()
self.devices = list_available_devices(f'{url}incl/list_elements.php', self.session, event_ids)
popup_window = PopUpWindow("Info", f'Found {len(self.devices) if self.devices else 0} units in the {len(event_ids)} selected events',
(int(self.x() + self.width()/2),
int(self.y() + self.height()/2)), 1000)
popup_window.show()
def update_result(self, name: str, value: int, result: int):
self.result_labels[name][0].progress_bar.setValue(value)
self.result_labels[name][0].image_label.setPixmap(self.img_states[result])
def analyse_pressed(self):
if self.worker is not None:
popup_window = PopUpYesNo("Clear results and analyze again?")
result = popup_window.exec_()
if result != QDialog.Accepted:
return
self.worker = None
self.worker = Worker(empty_results, url, self.session, self.account_id, self.devices)
self.worker.update_result_signal.connect(self.update_result)
self.worker.finished.connect(self.worker_finished)
self.report_button.setEnabled(False)
self.analyse_button.setEnabled(False)
for i in empty_results.keys():
self.result_labels[i][0].progress_bar.setValue(0)
self.result_labels[i][0].image_label.setPixmap(self.img_states[3])
self.worker.start()
def report_pressed(self):
text = generate_report(self.username, self.results)
self.popup_window = ResultsWindow(text, self)
self.popup_window.show()
def close_pressed(self):
sys.exit()
def worker_finished(self):
if self.worker is not None:
self.results = self.worker.get_results()
self.worker.exit()
self.report_button.setEnabled(True)
self.analyse_button.setEnabled(True)
I tried to change the color of the overlay to see it better, but it doesn't help. Nothing I've tried darkens the main window.
Any help would be greatly appreciated.
EDIT: This might be relevant, so I added the login screen QDialog below.
Also add that I am using qdarktheme which overrides the PyQt themes, but I tried with it both enabled and disabled, with the same results, so I don't expect my problem comes from there.
class LoginScreen(QDialog):
"""
Simple login screen implementation to login
Use getData() to retrieve username, session and account ID
Parameters:
None
"""
def __init__(self):
super().__init__()
self.setWindowTitle("D-NA")
self.setWindowFlags(Qt.WindowType.Tool | Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint)
self.setGeometry(100, 100, 300, 100)
self.center()
layout = QVBoxLayout()
image_label = QLabel(self)
image = QPixmap(resource_path("images/login.png"))
image_label.setPixmap(image)
image_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
layout.addWidget(image_label)
layout.addSpacing(10)
username_layout = QHBoxLayout()
self.username_label = QLabel("Username:", self)
self.username_input = QLineEdit(self)
username_layout.addWidget(self.username_label)
username_layout.addWidget(self.username_input)
layout.addLayout(username_layout)
password_layout = QHBoxLayout()
self.password_label = QLabel("Password:", self)
self.password_input = QLineEdit(self)
self.password_input.setEchoMode(QLineEdit.Password)
password_layout.addWidget(self.password_label)
password_layout.addWidget(self.password_input)
layout.addLayout(password_layout)
remember_layout = QHBoxLayout()
remember_layout.setContentsMargins(0,0,int(self.width()/2),0)
self.remember_check = QCheckBox()
self.remember_label = QLabel("Remember me", self)
remember_layout.addWidget(self.remember_check)
remember_layout.addWidget(self.remember_label)
layout.addLayout(remember_layout)
button_layout = QHBoxLayout()
self.login_button = QPushButton("Login", self)
self.login_button.clicked.connect(self.login)
self.close_button = QPushButton("Close", self)
self.close_button.clicked.connect(self.close)
button_layout.addWidget(self.login_button)
button_layout.addWidget(self.close_button)
layout.addLayout(button_layout)
try:
with open(f'{os.path.expanduser("~")}/.login_info', 'r') as file:
self.username_input.setText(file.readline().strip())
self.password_input.setFocus()
self.remember_check.setChecked(True)
except:
pass
self.setLayout(layout)
self.password_input.returnPressed.connect(self.login)
self.popup_widget = None
def closeEvent(self, event):
sys.exit()
def getData(self):
return self.username, self.session, self.account_id
def center(self):
qr = self.frameGeometry()
cp = QDesktopWidget().availableGeometry().center()
qr.moveCenter(cp)
self.move(qr.topLeft())
def login(self):
self.username = self.username_input.text()
password = self.password_input.text()
self.session, self.account_id = create_https_session(f'{url}admin/gate.php', self.username, password)
if self.session is not None:
if self.remember_check.isChecked():
with open(f'{os.path.expanduser("~")}/.login_info', 'w+') as file:
file.write(self.username)
self.accept()
self.hide()
else:
self.popup_widget = PopUpWindow("Error", self.account_id,
(int(self.x() + self.width()/2),
int(self.y() + self.height()/2)), 1000)
self.popup_widget.show()
self.password_input.clear()
Thanks to @musicamante in the comments, I finally realized I was setting it as a relative geometry, outside the frame itself.
Thank you so much, I feel like an idiot, but it works!
Basically, I should have used
self.overlay.setGeometry(self.rect())
instead ofself.geometry()
and that fixed it!Thanks again!