how to check if PyQt window exists - python

I have an application in development using PyQt4.
This app will popup a window on particular events in the application.
I want to know if the popup window which was popped up exists on the next event i wan to display the message on the same window rather tan creating another window.
For example you can consider a messaging application. where when we get a message the window will popup. and if we receive the message again from same user the message will be appended to that window itself.
My scenario is also the same.
Anyone have any idea on this...?

All you have to do is keep a reference to the popup window and then reset the text as necessary.
Here's a simple demo:
from PyQt4 import QtGui, QtCore
class Window(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.button = QtGui.QPushButton('ShowTime!', self)
self.button.clicked.connect(self.handleButton)
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.button)
self._dialog = None
def handleButton(self):
if self._dialog is None:
self._dialog = QtGui.QMessageBox(self)
self._dialog.setWindowTitle('Messages')
self._dialog.setModal(False)
pos = self.pos()
pos.setX(pos.x() + self.width() + 10)
self._dialog.move(pos)
self._dialog.setText(
'The time is: %s' % QtCore.QTime.currentTime().toString())
self._dialog.show()
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())

Related

PyQt - how to rerender window

I am new to PyQt and Qt at all and I have a problem with window rendering or updating or how to call it. Problem is that when I call QWidget.show(), none of added components after are displayed. Here is a simple code, where in init(), there is called self.show(). First QLabel item is displayed and the second one is not. What am I doing wrong?
Code:
from PyQt6.QtWidgets import QApplication, QWidget, QLabel
import sys
class MyGui(QWidget):
box = {}
def __init__(self) -> None:
super().__init__()
self.setFixedSize(200, 400)
self.setStyleSheet("background-color:#000000")
self.box["top"] = QLabel(self)
self.box["top"].setFixedSize(200, 200)
self.box["top"].setStyleSheet("background-color:red")
self.box["top"].move(0,0)
self.show()
self.box["botom"] = QLabel(self)
self.box["botom"].setFixedSize(200, 200)
self.box["botom"].setStyleSheet("background-color:green")
self.box["botom"].move(0,200)
if __name__ == "__main__":
app = QApplication(sys.argv)
my_app = MyGui()
my_app.show()
try:
sys.exit(app.exec())
except SystemExit:
print("Closing window..")
Screenshots of GUI window:
With self.show()
Without self.show()

How to create an independent non-modal dialog

I'm trying to extend this solution Non modal dialog
from PyQt5 import QtWidgets
dialog = None
class Dialog(QtWidgets.QDialog):
def __init__(self, *args, **kwargs):
super(Dialog, self).__init__(*args, **kwargs)
self.setWindowTitle('A floating dialog')
self.resize(250,250)
class Window(QtWidgets.QWidget):
def __init__(self):
QtWidgets.QWidget.__init__(self)
button = QtWidgets.QPushButton('Open Dialog', self)
button.clicked.connect(self.handleOpenDialog)
self.resize(300, 200)
self._dialog = None
global dialog
dialog = Dialog(self)
dialog.show()
def handleOpenDialog(self):
if self._dialog is None:
self._dialog = QtWidgets.QDialog(self)
self._dialog.resize(200, 100)
self._dialog.exec_()
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
win = Window()
win.show()
sys.exit(app.exec_())
Apology if title wasn't relevant. I want to have a dialog/window that is independent of all existing window/dialogs, and can be always interacted with, i.e. GUI loop of application window/any dialogs doesn't block this non-model dialog. For simplicity, I have used global variable dialog in above code snippet which will hold the non-modal dialog instance.
When above program is run, the main window appears along-with the non-modal dialog, and both dialogs are user interactive, but when the button is clicked, the GUI loop of self._dialog starts, and user can no longer interact with the floating dialog, and application window. What I want is to be able to interact with dialog but not with Window
I want behavior similar to the example below:
I opened help dialog from main window, then I opened a non-modal dialog which appears on top of the main window, and can not interact with the main window, but still doesn't block help dialog/window and allows user to interact with this non-modal window i.e. the help dialog in the example.
When a dialog is opened with exec(), it will default to being application-modal. This means it will block all other windows in the application, regardless of whether they're parented to other windows or not. To make a dialog modal for only one window, it must be parented to that window and also have its modality explicitly set to window-modal.
For a dialog to be fully non-modal with respect to all other windows (and any of their modal dialogs), it must have no parent and then be opened with show(). However, a side-effect of this is that it won't be automatically closed when the main-window is closed. To work around this, it can be explicitly closed in the closeEvent() of the main-window.
Here is a simple demo that implements all of the above:
import sys
from PyQt5 import QtCore, QtWidgets
class Window(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle('Main Window')
self.setGeometry(400, 100, 300, 200)
self._help_dialog = None
self._other_dialog = None
self.buttonHelp = QtWidgets.QPushButton('Open Help')
self.buttonHelp.clicked.connect(self.handleOpenHelp)
self.buttonDialog = QtWidgets.QPushButton('Open Dialog')
self.buttonDialog.clicked.connect(self.handleOpenDialog)
layout = QtWidgets.QHBoxLayout(self)
layout.addWidget(self.buttonDialog)
layout.addWidget(self.buttonHelp)
self.handleOpenHelp()
def handleOpenDialog(self):
if self._other_dialog is None:
self._other_dialog = QtWidgets.QDialog(self)
self._other_dialog.setWindowModality(QtCore.Qt.WindowModal)
self._other_dialog.setWindowTitle('Other Dialog')
self._other_dialog.resize(200, 100)
self._other_dialog.exec_()
def handleOpenHelp(self):
if self._help_dialog is None:
self._help_dialog = QtWidgets.QDialog()
self._help_dialog.setWindowTitle('Help Dialog')
self._help_dialog.setGeometry(750, 100, 250, 250)
self._help_dialog.show()
def closeEvent(self, event):
if self._help_dialog is not None:
self._help_dialog.close()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())

Increasing avaliable space in main window

I am trying to create an application using pyqt python.Application's Main window is filled with many dock widgets, some dock widgets are just used to list certain string data. These widgets are occupying more space.
the drawer to the left in the image is my interest. That drawer opens on mouse click.
Is there any way I could hide these widgets to the side of main window and open when mouse is hovered over it?
or if you know any pyqt UI element which could do this. please suggest.
The logic is to detect the desired event and show the widget, in the following example the click on the QGraphicsView is detected and then the QDockWidget that was initially hidden is shown.
from PyQt5 import QtCore, QtGui, QtWidgets
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.dock_widget = QtWidgets.QDockWidget()
self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.dock_widget)
list_widgets = QtWidgets.QListWidget()
list_widgets.addItems(["item{}".format(i) for i in range(100)])
self.dock_widget.setWidget(list_widgets)
self.scene = QtWidgets.QGraphicsScene(self)
self.view = QtWidgets.QGraphicsView(self.scene)
it = self.scene.addRect(QtCore.QRectF(0, 0, 300, 400))
it.setBrush(QtGui.QColor("white"))
self.view.viewport().installEventFilter(self)
self.setCentralWidget(self.view)
self.dock_widget.hide()
self.resize(640, 480)
for i in range(4):
self.menuBar().addAction("Action{}".format(i))
def eventFilter(self, obj, event):
if obj is self.view.viewport():
if event.type() == QtCore.QEvent.MouseButtonPress:
self.dock_widget.show()
return super().eventFilter(obj, event)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())

Python: How detect text in a plainTextEdit and only then enable a button?

in my Qt application I have a plainTextEdit box into which I expect the user to enter the serial number of the hardware for which he wants the python/Qt application to generate a report. So, the HW Serial Number is a must input for my application, if he doesn't enter that then I don't want to enable the Report Generate pushButton.
How can I detect that he has entered some text in the box? Then enable the button?
How to detect if he completely erases what he has entered? Then disable the button?
Connect to the textChanged() signal of QPlainTextEdit. This will be fired whenever the text changes. You can then access the contents of the QPlainTextEdit through toPlainText() and use it to decide whether to enable or disable the button.
Here's a simple example:
import sys
from PySide import QtCore, QtGui
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self, parent)
widget = QtGui.QWidget()
self.edit = QtGui.QPlainTextEdit()
QtCore.QObject.connect(self.edit, QtCore.SIGNAL('textChanged()'), self.handleTextChange)
self.button = QtGui.QPushButton('Generate Report')
self.button.setEnabled(False)
layout = QtGui.QVBoxLayout(widget)
layout.addWidget(self.edit)
layout.addWidget(self.button)
self.setCentralWidget(widget)
#QtCore.Slot()
def handleTextChange(self):
self.button.setDisabled(self.edit.toPlainText() == '')
app = QtGui.QApplication(sys.argv)
main = MainWindow()
main.show()
sys.exit(app.exec_())

Replace CentralWidget in MainWindow

I'm kinda new to PySide.I have a main window object which shows one widget at a time. I've been trying to change the central widget of the QMainWindow class in order to replace the visible Widget in the window when pressing a button. The problem is that the button pressed is in the Widget class, not in the main window class.
say...
class App(QtGui.QMainWindow):
def __init__(self):
super(App, self).__init__()
self.initUI()
def initUI(self):
self.statusBar().showMessage('Listo.') #Status Bar
self.login_screen = LoginScreen()
self.logged_in_screen = LoggedInScreen()
self.setCentralWidget(self.login_screen)
self.setGeometry(300, 300, 450, 600) #Window Size
self.setWindowTitle('PyTransactio - Client') #Window Title
self.setWindowIcon(QtGui.QIcon('icon.png')) #App Icon
self.show()
The pressed button is in the login_screen instance. The method called when the button is clicked is inside the LoginScreen class:
def login(self):
""" Send login data to the server in order to log in """
#Process
self.setParent(None)
Setting the parent widget to None removes the widget (login_screen) from the main window. What should I do in order to get another widget (e.g. logged_in_screen) as the central widget of the main window when the loginButton (inside the login_screen widget) is pressed?
Maybe the login method should be inside the main window class? If so, how can I connect the buttons pressed in login_screen with the main window's method?
You may use a QStackedWidget as central widget and add both the log-in screen and "logged-in" screen to it.
An example usage:
from PyQt4 import QtCore, QtGui
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.central_widget = QtGui.QStackedWidget()
self.setCentralWidget(self.central_widget)
login_widget = LoginWidget(self)
login_widget.button.clicked.connect(self.login)
self.central_widget.addWidget(login_widget)
def login(self):
logged_in_widget = LoggedWidget(self)
self.central_widget.addWidget(logged_in_widget)
self.central_widget.setCurrentWidget(logged_in_widget)
class LoginWidget(QtGui.QWidget):
def __init__(self, parent=None):
super(LoginWidget, self).__init__(parent)
layout = QtGui.QHBoxLayout()
self.button = QtGui.QPushButton('Login')
layout.addWidget(self.button)
self.setLayout(layout)
# you might want to do self.button.click.connect(self.parent().login) here
class LoggedWidget(QtGui.QWidget):
def __init__(self, parent=None):
super(LoggedWidget, self).__init__(parent)
layout = QtGui.QHBoxLayout()
self.label = QtGui.QLabel('logged in!')
layout.addWidget(self.label)
self.setLayout(layout)
if __name__ == '__main__':
app = QtGui.QApplication([])
window = MainWindow()
window.show()
app.exec_()
If you do not want to use this widget, then I think you'll have to call QMainWindow.setCentralWidget every time you change the central widget.
As to where the login method should be, it depends. Probably you could define a simple interface for your mainwindow to add/remove/show specific central widgets, and call it from the login method of LoginScreen. In this way the LoginScreen class does not have to know about implementation details such as if the central widget is actually a QStackedWidget or this thing is done in an other way.
You can use QMainWindow.setCentralWidget to do this (repeatedly):
#! /usr/bin/env python3
from PySide import QtGui
from PySide import QtCore
import sys
app = QtGui.QApplication(sys.argv)
mw = QtGui.QMainWindow()
w2 = QtGui.QWidget()
pb = QtGui.QPushButton('push me', w2)
l1 = QtGui.QLabel('orig')
l2 = QtGui.QLabel('changed')
mw.setCentralWidget(l1)
pb.clicked.connect(lambda: mw.setCentralWidget(l2))
mw.show()
w2.show()
sys.exit(app.exec_())

Categories

Resources