How to get result from corfirmation dialog - python

I have problem with the results of my pop-up window. Below I have shown part of my code to understand the problem.
It's a kind of pop-up window where the user makes some choice in the GUI. After this it should show a window where there will be the question "Are you sure?", and two buttons "Yes" and "No".
The problem is that when I test the code below (before and after the msg.show()), I have the same value set as False.
Why doesnt it work like this:
Before function -> False
Show my window and wait to click the button
If I clicked button "Yes", then give True, else False
How I can handle this properly? Is there another approach?
from PyQt4 import QtCore, QtGui
from Message import Ui_Message
import sys
class MessageBox(QtGui.QDialog):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent=None)
self.msg = Ui_Message()
self.msg.setupUi(self)
self.confirmed=False
self.declined=False
QtCore.QObject.connect(self.msg.NoButton, QtCore.SIGNAL(("clicked()")), self.Declined)
QtCore.QObject.connect(self.msg.YesButton, QtCore.SIGNAL(("clicked()")), self.Confirmed)
def Confirmed(self):
self.confirmed = True
MessageBox.close(self)
return True
def Declined(self):
self.declined = True
MessageBox.close(self)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
msg = MessageBox()
print('Befor show window',msg.confirmed)
msg.show()
print('After show window', msg.confirmed)
sys.exit(app.exec_())

Your example doesn't work, because you are printing "After show window" before the window has closed. It is the exec() method that blocks, not the show() method, so your example would need to be written like this:
app = QtGui.QApplication(sys.argv)
msg = MessageBox()
print('Before show window', msg.confirmed)
msg.show()
app.exec_() # this blocks, waiting for close
print('After show window', msg.confirmed)
sys.exit()
However, a much more realistic example showing how to use a dialog to confirm an action would be something like this:
import sys
from PyQt4 import QtCore, QtGui
class MessageBox(QtGui.QDialog):
def __init__(self, parent=None):
super(MessageBox, self).__init__(parent)
self.yesButton = QtGui.QPushButton('Yes')
self.noButton = QtGui.QPushButton('No')
layout = QtGui.QGridLayout(self)
layout.addWidget(QtGui.QLabel('Are you sure?'), 0, 0)
layout.addWidget(self.yesButton, 1, 0)
layout.addWidget(self.noButton, 1, 1)
self.yesButton.clicked.connect(self.accept)
self.noButton.clicked.connect(self.reject)
class Window(QtGui.QWidget):
def __init__(self):
super(Window, self).__init__()
self.button = QtGui.QPushButton('Do Something')
self.button.clicked.connect(self.handleButton)
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.button)
def handleButton(self):
if self.confirmSomething():
print('Yes')
else:
print('No')
def confirmSomething(self):
msg = MessageBox(self)
result = msg.exec_() == QtGui.QDialog.Accepted
msg.deleteLater()
return result
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = Window()
window.show()
app.exec_()

Related

check if button clicked or not in pyqt5

Hello guys I want to check if the button clicked or not
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
loadUi("app.ui", self)
self.setWindowIcon(QIcon('discord.png'))
self.setWindowFlag(Qt.WindowMinimizeButtonHint, False)
self.setWindowFlag(Qt.WindowMaximizeButtonHint, False)
self.setFixedSize(self.size())
self.regis = self.findChild(QPushButton, "pushButton")
self.regis.clicked.connect(self.connectt)
self.cl = self.findChild(QPushButton, "pushButton_2")
self.show()
QApplication.processEvents()
def connectt(self):
ID = self.findChild(QLineEdit, "lineEdit")
RP = Presence(ID.text())
RP.connect()
print("connected")
self.statusBar.showMessage('connected')
if self.cl.clicked():
print("disconnected")
app = QApplication(sys.argv)
UIWindow = MainWindow()
app.exec_()
I tried to use self.cl.clicked() but it didn't work!
but I got this error :
if self.cl.clicked():
^^^^^^^^^^^^^^^^^
TypeError: native Qt signal is not callable
can anyone help me, please
You don't need your "if self.cl.clicked():
Assuming "regis" is your button, this line :
self.regis.clicked.connect(self.connectt)
makes it that as soon as you click your "regis" button, the whole "connectt" function will execute.
And if "cl" is another button, your code makes no sense to me, because what your doing is you verify if your "cl" button is clicked when you click your "regis" button (basically clicking two buttons at the same time, which feels strange in my opinion). Maybe you should think about another way to do what you're trying to do.
Let me know if this answered your question.
Edit:
You can use the codeblock like:
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
loadUi("app.ui", self)
self.setWindowIcon(QIcon('discord.png'))
self.setWindowFlag(Qt.WindowMinimizeButtonHint, False)
self.setWindowFlag(Qt.WindowMaximizeButtonHint, False)
self.setFixedSize(self.size())
self.pushButton.clicked.connect(self.pushButtonOperations)
self.pushButton_2.clicked.connect(self.pushButton_2Operations)
self.cl = self.findChild(QPushButton, "pushButton_2")
self.show()
QApplication.processEvents()
def pushButtonOperations(self):
ID = self.findChild(QLineEdit, "lineEdit")
RP = Presence(ID.text())
RP.connect()
print("connected")
self.statusBar.showMessage('connected')
def pushButton_2Operations(self):
print("disconnected")
app = QApplication(sys.argv)
UIWindow = MainWindow()
app.exec_()

Is there any way to make mouse events completely ignore windows in PyQt5?

I have tried to use setAttribute(Qt.Qt.WA_TransparentForMouseEvents),but mouse also can't pierce through Qtwindow.
I want make mouse event penetrate Qtwindow,like I have clicked mouse's right button at a Qtwindow which is located in Windows10 Desktop,then it will trigger win10 contextmenu.
Would a transparent window suit your needs?
from PyQt5 import QtCore, QtWidgets, QtGui
class Overlay(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.setAttribute(QtCore.Qt.WA_TransparentForMouseEvents)
self.setAttribute(QtCore.Qt.WA_TranslucentBackground, True)
self.setWindowFlags(QtCore.Qt.FramelessWindowHint)
layout = QtWidgets.QHBoxLayout(self)
label = QtWidgets.QLabel('Transparent and propagating')
label.setFont(QtGui.QFont('Arial', 26))
label.setStyleSheet("background-color : white")
layout.addWidget(label)
self.show()
if __name__ == '__main__':
app = QtWidgets.QApplication([])
form = Overlay()
app.exec_()
I tried to figure out a way to directly transmit clicks to the desktop. The closest related question gave me some ideas, but ultimately I was not able to get it working, the clicks never reach the desktop. Maybe you can still get some ideas from this:
from PyQt5 import QtWidgets, QtGui
import win32api, win32con
from ctypes import windll
class Overlay(QtWidgets.QWidget):
def __init__(self):
super().__init__()
layout = QtWidgets.QHBoxLayout(self)
label = QtWidgets.QLabel('Click to Desktop')
label.setFont(QtGui.QFont('Arial', 26))
label.setStyleSheet("background-color : white")
layout.addWidget(label)
# make window partially transparent to see where you are clicking
self.setWindowOpacity(0.5)
# get handle to desktop as described in linked question
hProgman = windll.User32.FindWindowW("Progman", 0)
hFolder = windll.User32.FindWindowExW(hProgman, 0, "SHELLDLL_DefView", 0)
self.desktop = windll.User32.FindWindowExW(hFolder, 0, "SysListView32", 0)
self.show()
def mousePressEvent(self, event):
# catch mouse event to route it to desktop
x = event.globalPos().x()
y = event.globalPos().y()
lParam = win32api.MAKELONG(x, y)
# left click on desktop (left button down + up, => should be replaced by event.button() pseudo switch case once working)
windll.User32.SendInput(self.desktop, win32con.WM_LBUTTONDOWN, win32con.MK_LBUTTON, lParam)
windll.User32.SendInput(self.desktop, win32con.WM_LBUTTONUP, 0, lParam)
# display position for debugging (position gets displayed, but nothing gets clicked)
print(f'clicked on desktop at position {x} and {y}')
if __name__ == '__main__':
app = QtWidgets.QApplication([])
form = Overlay()
app.exec_()
class main(QWidget):
def __init__(self):
super().__init__()
self.setWindowFlags(Qt.Popup|Qt.WindowDoesNotAcceptFocus|Qt.WindowTransparentForInput)
self.setAttribute(Qt.WA_AlwaysStackOnTop, True)

How to get a PyQt5 QPushButton to do different commands on different button clicks

I wish to have the QPushButton do different things on different clicks. One the first click it should execute one command and on the next click, it should execute the other command. I've tried to make a program to do it but it only executes one command, not the other
my code I:
import PyQt5.QtWidgets as pyqt
import sys
ongoing = False
class Stuff(pyqt.QWidget):
def __init__(self):
super().__init__()
self.windows()
def windows(self):
w = pyqt.QWidget()
layout = pyqt.QGridLayout()
self.setLayout(layout)
button = pyqt.QPushButton('click me', w)
layout.addWidget(button)
if not ongoing:
button.clicked.connect(click_one)
else:
button.clicked.connect(click_two)
self.show()
w.show()
def click_one():
global ongoing
print('one')
ongoing = not ongoing
def click_two():
global ongoing
print('two')
ongoing = not ongoing
if __name__ == '__main__':
app = pyqt.QApplication(sys.argv)
x = Stuff()
app.exec_()
What should I do to fix this?
Since the value of ongoing is False when the class is initialized, the button's clicked signal gets connected to click_one(). Connect the button to an initial slot and then call the desired function based on the value of ongoing.
class Stuff(pyqt.QWidget):
def __init__(self):
super().__init__()
self.windows()
def windows(self):
w = pyqt.QWidget()
layout = pyqt.QGridLayout()
self.setLayout(layout)
button = pyqt.QPushButton('click me', w)
layout.addWidget(button)
button.clicked.connect(on_click)
self.show()
w.show()
def on_click():
global ongoing
if not ongoing:
click_one()
else:
click_two()
I suggest rewriting the code with the functions and ongoing variable belonging to the class. The QWidget assigned to variable w seems redundant because the QPushButton is then added to the layout of the class, so its parent gets changed anyways.
class Stuff(pyqt.QWidget):
def __init__(self):
super().__init__()
self.ongoing = False
self.windows()
def windows(self):
layout = pyqt.QGridLayout(self)
button = pyqt.QPushButton('click me')
layout.addWidget(button)
button.clicked.connect(self.on_click)
self.show()
def on_click(self):
self.click_one() if not self.ongoing else self.click_two()
self.ongoing = not self.ongoing
def click_one(self):
print('one')
def click_two(self):
print('two')
Also you might be interested in using a checkable button.

How do I make a context menu for each item in a QListWidget?

I'm working on a QGIS plugin, where the UI is made with PyQt. I have a QListWidget and a function that fills it. I'd like to add a context menu for each item with only one option: to open another window.
I'm having trouble searching for info, since most of it works only on PyQt4 and I'm using version 5. The QListWidget that I want to add a context menu on is ds_list_widget. Here's some of the relevant code.
FORM_CLASS, _ = uic.loadUiType(os.path.join(
os.path.dirname(__file__), 'dialog_base.ui'))
class Dialog(QDialog, FORM_CLASS):
def __init__(self, parent=None):
...
self.p_list_widget = self.findChild(QListWidget, 'projects_listWidget')
self.p_list_widget.itemClicked.connect(self.project_clicked)
self.ds_list_widget = self.findChild(QListWidget, 'datasets_listWidget')
self.ds_list_widget.itemClicked.connect(self.dataset_clicked)
...
def project_clicked(self, item):
self.fill_datasets_list(str(item.data(Qt.UserRole)))
self.settings.setValue('projectIdValue', str(item.data(Qt.UserRole)))
def fill_datasets_list(self, project_id):
self.ds_list_widget.clear()
dataset_list = self.anotherClass.fetch_dataset_list(project_id)
for dataset in dataset_list:
#Query stuff from remote
...
item = QListWidgetItem(ds_name, self.ds_list_widget)
item.setIcon(self.newIcon(ds_img))
item.setData(Qt.UserRole, ds_id)
self.ds_list_widget.addItem(item)
self.ds_list_widget.setIconSize(self.iconSize)
Since your list-widget is created by Qt Designer, it is probably easiest to install an event-filter on it and trap the context-menu event. With that in place, the rest is quite straightforward - here is a simple demo:
import sys
from PyQt5 import QtCore, QtWidgets
class Dialog(QtWidgets.QDialog):
def __init__(self, parent=None):
super(Dialog, self).__init__()
self.listWidget = QtWidgets.QListWidget()
self.listWidget.addItems('One Two Three'.split())
self.listWidget.installEventFilter(self)
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.listWidget)
def eventFilter(self, source, event):
if (event.type() == QtCore.QEvent.ContextMenu and
source is self.listWidget):
menu = QtWidgets.QMenu()
menu.addAction('Open Window')
if menu.exec_(event.globalPos()):
item = source.itemAt(event.pos())
print(item.text())
return True
return super(Dialog, self).eventFilter(source, event)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Dialog()
window.setGeometry(600, 100, 300, 200)
window.show()
sys.exit(app.exec_())
PS:
You should also note that code like this:
self.p_list_widget = self.findChild(QListWidget, 'projects_listWidget')
is completely unnecessary. All the widgets from Qt Designer are automatically added as attributes to the form class using the object-name. So your code can be simplified to this:
self.projects_listWidget.itemClicked.connect(self.project_clicked)
self.datasets_listWidget.itemClicked.connect(self.dataset_clicked)
there is no need to use findChild.
In addition to the answer above, you can also set multiple QAction() submenu items to do multiple things. As you would a normal menu.
One way is to edit your eventFilter so that menu.exec() becomes a variable:
def eventFilter(self, source, event):
if (event.type() == QtCore.QEvent.ContextMenu and source is self.listWidget):
menu = QtWidgets.QMenu()
open_window_1 = QAction("Open Window 1")
open_window_2 = QAction("Open Window 2")
menu.addAction(open_window_1)
menu.addAction(open_window_2)
menu_click = menu.exec(event.globalPos())
try:
item = source.itemAt(event.pos())
except Exception as e:
print(f"No item selected {e}")
if menu_click == open_window_1 :
print("Opening Window 1...")
# Your code here
if menu_click == open_window_2 :
print("Opening Window 2...")
# Your code here
# and so on... You can now add as many items as you want
return True
return super(Dialog, self).eventFilter(source, event)

PyQt Make parent GUI wait till child GUI is closed

I am new to pyqt.I am trying to invoke a child GUI when a button is clicked in the parent GUI. In this process, parent GUI has to wait for the child GUI to be closed by the user after selecting some inputs. But this is not happening, Parent GUI does execute the next lines after which the child GUI has been invoked. Below is the code where I am passing an argument to child GUI from parent GUI. The child GUI will return value based on OK/Cancel button click
Code:
import sys
from PyQt4 import QtGui,QtCore,Qt
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class Child(QtGui.QWidget):
def __init__(self,switches=None):
super(Child,self).__init__()
self.swwidget = QtGui.QWidget()
self.swlayout = QtGui.QGridLayout()
switches = ['abc1','def1']
switches.sort()
self.switches = switches
def switchesUI(self):
self.swwidget.setWindowModality(QtCore.Qt.ApplicationModal)
self.swl = len(self.switches)
self.sw = {}
self.addsw = []
print ("I am in switchesUI")
#Add the switches to layout dynamically
for i in range(self.swl):
self.sw[i] = QtGui.QCheckBox(self.switches[i])
self.swlayout.addWidget(self.sw[i],i,0)
self.swbuttonbox = QtGui.QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel);
self.swbuttonbox.setOrientation(QtCore.Qt.Horizontal)
self.swlayout.addWidget(self.swbuttonbox)
self.swwidget.setWindowTitle('Switches')
self.swwidget.setLayout(self.swlayout)
self.swwidget.show()
self.connect(self.swbuttonbox,QtCore.SIGNAL("accepted()"),self.swaccept)
self.connect(self.swbuttonbox,QtCore.SIGNAL("rejected()"),self.swreject)
def swaccept(self):
for i in range(self.swl):
if self.sw[i].isChecked():
self.addsw.append(self.switches[i])
self.swwidget.close()
return self.addsw
def swreject(self):
self.swwidget.close()
return None
class Parent(QtGui.QWidget):
def __init__(self):
super(Parent,self).__init__()
QtGui.QWidget.__init__(self)
self.button = QtGui.QPushButton('Test', self)
self.layout = QtGui.QVBoxLayout(self)
self.layout.addWidget(self.button)
self.assw = ['Test1','Test2']
self.CH = Child(self.assw)
self.connect(self.button,SIGNAL("clicked()"),self.popup)
print ("Child GUI closed")
def popup(self):
self.CH.switchesUI()
def main():
app = QtGui.QApplication(sys.argv)
form = Parent()
form.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
After the button "Test" is clicked, a child GUI will pop-up. I don't want the statement "Child GUI Closed" to be printed till the child GUI is closed.
Can someone suggest me how to achieve this functionality ?
You have to handle closeEvent to perform operations when a window wants to close, also since your Child class inherits from QWidget which means it's a QWidget itself you dont need to create another one with self.swwidget
import sys
from PyQt4 import QtGui,QtCore,Qt
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class Child(QtGui.QWidget):
def __init__(self,switches=None):
super(Child,self).__init__()
# self.swwidget = QtGui.QWidget() # you don't need to do this you can add all the properties to self
self.swlayout = QtGui.QGridLayout()
switches = ['abc1','def1']
switches.sort()
self.switches = switches
def switchesUI(self):
self.setWindowModality(QtCore.Qt.ApplicationModal)
self.swl = len(self.switches)
self.sw = {}
self.addsw = []
print ("I am in switchesUI")
#Add the switches to layout dynamically
for i in range(self.swl):
self.sw[i] = QtGui.QCheckBox(self.switches[i])
self.swlayout.addWidget(self.sw[i],i,0)
self.swbuttonbox = QtGui.QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel);
self.swbuttonbox.setOrientation(QtCore.Qt.Horizontal)
self.swlayout.addWidget(self.swbuttonbox)
self.setWindowTitle('Switches')
self.setLayout(self.swlayout)
self.show()
self.connect(self.swbuttonbox,QtCore.SIGNAL("accepted()"),self.swaccept)
self.connect(self.swbuttonbox,QtCore.SIGNAL("rejected()"),self.swreject)
def swaccept(self):
for i in range(self.swl):
if self.sw[i].isChecked():
self.addsw.append(self.switches[i])
self.close()
return self.addsw
def swreject(self):
self.close()
return None
def closeEvent(self, event):
print ("Child GUI closed")
class Parent(QtGui.QWidget):
def __init__(self):
super(Parent,self).__init__()
QtGui.QWidget.__init__(self)
self.button = QtGui.QPushButton('Test', self)
self.layout = QtGui.QVBoxLayout(self)
self.layout.addWidget(self.button)
self.assw = ['Test1','Test2']
self.CH = Child(self.assw)
self.connect(self.button,SIGNAL("clicked()"),self.popup)
def popup(self):
self.CH.switchesUI()
def main():
app = QtGui.QApplication(sys.argv)
form = Parent()
form.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()

Categories