Showing and hiding multiple windows in PyQt5 - python

I'm working on a project with UI and I started to do it with PyQt5. So far I watched lots of videos read some tutorials and have progress on the project. Since PyQt is a binding of C++ for Python, there are not so many documents for complex UI with lots of windows.(or I couldn't find it and also looked examples of PyQt5). My project contains lots of windows. I'm trying to take some arguments from a user and due to user arguments optimization algorithm will work. So the project contain's these windows
Login Window(Qwidgets) {first view}
Login Sign up Window (Qwidgets) {if user don't have an account second view}
If user logs into system Tabwidget will be shown with 4 subtab view and these tabs will take arguments from a user. In this widget, there is already 2 subtab have already values that user can choose but also there are buttons which open new Qwidget class windows with OK and CANCEL button. One tab for choosing a file directory and I used QfileDialog class here. And last tab taking last arguments from a user and opening the file that user has chosen in 3rd tab.
After Tab view, I opened a Plotview, with the file that user have chosen, and in that window user by drawing some polygons giving argument on plot.{Im using Pyqtgraph library here}
Optimization Algorithm will work it's not connected with Pyqt
I have used Qt Designer mostly while designing UI. But later changed it adding some methods to take arguments from a user and for connecting other tabs or other windows.
By defining methods in the class (window) I can open other windows but I cant hide or close an already opened window. if I try to close them all process goes down but I want to make the only that window close. I have that problem in Login Signup window, popup windows for taking extra arguments from a user in 1st and 2nd tabview. My main starts with Login Window. After that in Loginwindow if login success it goes to tabview window. I have been successful by typing mainwindow.hide() and showing tabview window. But after that in all popup windows, I cant close the popup windows that takes arguments from a user.
Since the code is so long I will just put here interested parts.
class LoginUp(object):
def setupUi(self,LoginUp):
self.Buton1.clicked.connect(self.signup)
self.Buton2.clicked.connect(self.tabview)
def signup(self):
# here it shows but user cant close it by just clicking on OK button
# He must click on x button to close which I dont want.
self.signupshow = QtWidgets.QWidget()
self.ui = LoginSignUp()
self.ui.setupUi(self.signupshow)
self.signupshow.show()
def tabview(self): # Here its works
self.tabviewshow = QtWidgets.QWidget()
self.ui_tabview = TabView()
self.ui_tabview.setupUi(self.tabviewshow)
MainWindow.close()
self.tabviewshow.show()
class TabView(object):
def setupUi(self,Form):
self.button3.clicked.connect(self.addargument)
def addargument(self):
# same problem.. after that it popups window that user can give inputs but cant close the window AddArgument class
self.Add = QtWidgets.QWidget()
self.addargumentshow = AddArgument()
self.addargumentshow.setupUi(self.Add)
self.addargumentshow.show()
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QWidget()
ui = LoginUp()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())

One way to solve this is to use another class as a controller for all of the windows you want to show.
In each window you will send a signal when you want to switch windows and it is up to this controller class to decide how to handle the signal when received and decide which window to show. Any arguments that you need passed can be passed through the signals.
Here is a simplified complete working example.

Related

TortoiseHg hook with GUI

We are trying to write a mercurial pre-commit hook which should work with both commandline and TortoiseHg.
The idea of the hook is to connect to JIRA and get the list of activities assigned to the developer, and show the activities in a list from which the developer can choose one. The JIRA ID and summary will then be put in the commit comment.
Now, we have the basic parts of most of the functionality figured out, but are missing a way to show a list. We've tried to show a basic QtWidget with input field and a button (using PyQt4), and using the command line the window appears, we can enter text and press the button to print the text (or send it out with ui.status).
In TortoiseHg (version 2.7.1) it doesn't work that well. The hook fires and the window opens but it appears as if control is not properly passed on. The input field on the new window doesn't get active, we can't see when we type text, but when clicking the button the contents are printed to ui.status. More worringly is that TortoiseHg stops updating the graphics, so when the window is closed there is a blank spot in the TortoiseHg window and THG doesn't respond to any input. We have to use the process explorer to shoot it down.
Any hints as to how to write a hook which opens a window which we can interact with under TortoiseHg?
Hook definition:
pre-commit = python:e:\repos\SCM-TOOLS\hg-hooks\user.py:hook
Python code:
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class AppForm(QMainWindow):
def __init__(self, ui, parent=None):
QMainWindow.__init__(self, parent)
self.u = ui
self.create_main_frame()
def create_main_frame(self):
page = QWidget()
self.button = QPushButton('Test', page)
self.edit1 = QLineEdit()
vbox1 = QVBoxLayout()
vbox1.addWidget(self.edit1)
vbox1.addWidget(self.button)
page.setLayout(vbox1)
self.setCentralWidget(page)
self.connect(self.button, SIGNAL("clicked()"), self.clicked)
def clicked(self):
self.u.status (str(self.edit1.text()))
def hook(ui, repo, **kwargs):
app = QApplication(sys.argv)
form = AppForm(ui)
form.show()
app.exec_()
sys.exit(1)
Edit:
In addition to this working in TortoiseHg and from the commandline it should also work in Eclipse and IntelliJ, therefore the suggested TortoiseHg plugins are not a full solution.
This task would normally be handled differently in Tortoise products as they already have a defined issue tracker plugin interface. This is defined here.
From the user point of view, they get a new button on the commit window which presents them with a list of issues to choose from. This then adds the appropriate text to the commit message.
There are two tortoise issue tracker plugins for Jira: 1, 2
I know that they say that they are TortoiseSvn plugins but they should work for TortoiseHg too - we use the TurtleMine one with no issues.

PySide: hiding a dialog breaks the dialog.exec_()

In my project I have to show people a dialog which can accept or open another dialog.
I start the dialog by the usage of dialog.exec_() which also should make it possible to catch the QtGui.QDialog.Accepted and do some nice things after it.
While the first dialog opens the second dialog I try to hide the first dialog with self.hide() and I show it again with self.show() when the second dialog receives a QtGui.QDialog.Accepted.
This works fine, but after this the accept button of the first window does not return anything like QtGui.QDialog.Accepted
The thing is that it works fine until the usage of self.hide() and self.show() while opening the second window. Leaving the hiding option out makes it work without flaws.
How can I hide and show the dialog without breaking the dialog.exec_() which I need to know when the window gets accepted?
Abarnert's answer made me think again about my dialog designs. First I tried it again with non-modal dialogs, but this was not consistent.
Finally I made a sequence of modal dialogs which works really great! I first start the first dialog, when its accepted it continues, however when its rejected another dialog comes up which only can get accepted. After you accept the second dialog the first dialog is executed again.
By using a while loop you can easily manage this:
self.notification = firstDialog(self) #custom dialog class
self.notification2 = secondDialog(self) #second custom dialog class
while True:
self.notification.show()
if self.notification.exec_() == QtGui.QDialog.Accepted:
break
else: #in case of rejection (the only other option in this dialog)
self.notification2.show()
if self.notification2.exec_() == QtGui.QDialog.Accepted:
continue
self.startFunction() #start what should happen after people accept the dialog

Qt - Temporarily disable all events or window functionality?

I have a Qt program with many buttons, user-interactable widgets, etc.
At one stage in the program, I would like all the widgets to temporarily 'stop working'; stop behaving to mouse clicks and instead pass the event on to one function.
(This is so the User can select a widget to perform meta operations. Part explanation here: Get variable name of Qt Widget (for use in Stylesheet)? )
The User would pick a widget (to do stuff with) by clicking it, and of course clicking a button must not cause the button's bound function to run.
What is the correct (most abstracted, sensible) method of doing this?
(which doesn't involve too much new code. ie; not subclassing every widget)
Is there anything in Qt designed for this?
So far, I am able to retrieve a list of all the widgets in the program (by calling
QObject.findChildren(QtGui.QWidget)
so the solution can incorporate this.
My current horrible ideas are;
Some how dealing with all the applications events all the time in one
function and not letting through the events when I need the
application to be dormant.
When I need dormancy, make a new transparent widget which recieves
mouse clicks and stretch it over the entire window. Take coordinates
of click and figure out the widget underneath.
Somehow create a new 'shell' instance of the window.
THANKS!
(Sorry for the terrible write-up; in a slight rush)
python 2.7.2
PyQt4
Windows 7
You can intercept events send to specific widgets with QObject::installEventFilter.
graphite answered this one first so give credit where credit is due.
For an actual example in PySide, here's an example you might draw some useful code from:
my_app.py
from KeyPressEater import KeyPressEater
if __name__ == "__main__":
app = QApplication(sys.argv)
eater = KeyPressEater()
app.installEventFilter(eater)
KeyPressEater.py
class KeyPressEater(QObject):
# subclassing for eventFilter
def eventFilter(self, obj, event):
if self.ignore_input:
# swallow events
pass
else:
# bubble events
return QObject.eventFilter(self,obj,event)

Make a window appear on top of another, block access to other windows until button clicked

Python 2.7, PyQt4.8.5
I want to have a main app window and then a second pop up window to display com port settings. This window should always be on top of the parent window until either the ok or the cancel button is clicked; closing the child window. (sort of like a required answer i.e. cant process until you choose the settings from the child window)
Is there a Python Qt command to do this?
Apologies if this has been asked/answered before, my search returned nothing useful.
You want a modal dialog. For example:
dialog = QInputDialog()
dialog.exec_()
You can either implement your own dialog widget (by subclassing QDialog) or use one of the several available.

GtkAboutDialog Close Button Bug

I use GtkAboutDialog and everything works fine except the close button of this widget. All other buttons works fine, I don't know how but all buttons have default callbacks and they create and destroy the windows.
But the "Close" button of GtkAboutDialog widget does not work. I can not even see it's widget. So, can I access it?
[CLARIFICATION] What you're looking at is gtk.AboutDialog — popup window displaying information about an application (new in PyGTK 2.6). This window contains the 'close' button widget which is contained in a GtkHButtonBox widget. The GtkHButtonBox widget is the highest level widget I am able to access for some. Any ideas on how to get to the "close" button and connect a handler for a callback signal?
You don't conenct signals in the same way for a dialog as you do for a window. I made the same mistake when learning PyGTK.
The most basic form of a dialog is you display and run the dialog with:
aboutdialog.run()
Often you will then immediately call:
aboutdialog.destroy()
The .run() line is a loop, which runs until something happens within the dialog.
There is a working example here.
The gtk.AboutDialog is just a gtk.Dialog, and you handle responses from it in the same way. Instead of connecting to the clicked signal of the buttons, the dialog code handles that for you and returns a reponse from your run() call. You can check the value of the response returned to figure out what button was clicked.
If you're trying to override some behaviour instead, you can connect to the response signal of gtk.Dialog.
This is an old question, but since it's one of the first hits from google, I thought I'd throw in the solution that I found. You need an event handler to show the about dialog and one to close it. The first will likely be connected to your help->about menuitem's activate signal. The latter should be connected to the response signal of the about dialog. The two handlers will look something like this:
def on_menuitemHelpAbout_activate(self, *args):
self.builder.get_object('aboutdialog').show()
def on_aboutdialog_response(self, *args):
self.builder.get_object('aboutdialog').hide()
In the example above, I'm using the GtkBuilder to find my about dialog because I've constructed the interface with glade. Note that I'm using .show() over .run() because I don't see the sense in pausing program execution until the dialog is closed. Finally, the response handler can be made to take whatever action depending upon the response, but I'm ignoring it here.

Categories

Resources