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
Related
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.
I have a wxpython dialog (wrapped in a function call which returns user selection) that Im using to prompt user for "ok", "cancel" type questions.
I have another thread that is running that allows the user to click a button and perform an emergency stop (also wxpython). when the emergency stop button is clicked, it performs some stuff and then displays its own user dialog.
Now, assume that a popup message has prompted the user with a yes/no question and at the very same time, the user sees something on fire and decides to click the emergency stop.
I need to be able to destroy the current dialog question and eventually display the dialog thats part of the estop thread.
Ive created code that starts the dialog in one thread and another that issues a pub.sendMessage(...) to kill the dialog thread if its displayed on the screen at the time of pressing the estop button.
This works just fine.
Problem is, i cant get the result from the user dialog (yes,no,cancel etc) because the thread never joins back to return what the user picked.
If i add a .join() to my code, i get the user response, but the dialog isnt destroyed if a pub.sendMessage(...) is sent.
heres pseudocode:
1)start up thread to monitor user emergency stop button push
2)start up test which may contain popup window (custom wxdialog) prompting user for answer
3)return user selection from dialog if selected
OR if user has clicked estop button: destroy current dialog and display new dialog related to estop
simple enough, but with the implementation of wrapper functions (this is code for others to call and needs to provide simple function calls), its obviously a little weird. but reimplementing it might not fly right now
heres some code (both are part of larger class so thats why the self references are there)
#the receiver of the pub message first:
def DestroyUI(self):
print 'into destroy'
#self.Hide()
#self.Close()
self.Destroy()
#these 2 fuctions are part of a different class
def closeDialogs(self):
print 'into closeDialogs'
def destroyUI():
if self.okToKill:
print 'closing wx dialogs'
pub.sendMessage("destroyUI")
ts = threading.Thread(target = destroyUI)
ts.start()
ts.join()
def MB(self,blah,blah):
def runMB(*args):
self.okToKill= True
self.response = self.PromptUser(*args)
self.okToKill= False
tr = threading.Thread(target = runMB,args=(blah,blah))
tr.start()
#if i add the join back in, i always return the user values
#but the dialog is never destroyed (if needed) before user
#clicks.
#without the join, the destroy pub send works great, but the
#user values are never returned
#tr.join()
return self.response
I have tried using queues, multiprocess pool, but the problem with those is the q.get() and async_result().get() both block until user clicks and therefore wont allow the destroy to work as needed.
What id love to figure out is how to get the user values IF the user clicked buttons, but also be able to destroy the current dialog and display the new emergency stop dialog instead (with custom buttons).
I wish wxpython just had a closeAll() :)
Also, i have tried closing the windows based on title name, and while that works, it hoses up my wx instance for the next dialog.
Any ideas?
thanks
since i dont really understand what you are asking for, I will instead address "I wish wxpython just had a closeAll() :)"
def wx_closeAll():
for win in wx.GetTopLevelWindows():
win.Destroy()
def closeAllButPrimary():
for win in wx.GetTopLevelWindows():
if win != wx.GetTopLevelWindow():
win.Destroy()
note this will close all frames and dialogs whose parent is None ... if you set a parent for the frame or dialog that dialog will be closed when its parent window is closed
Doing GUI from threads is not a good idea, and nearly always gives unexpected results.
In order to show the message box from a thread, you need to make the thread ask the main thread to show the message box.
You do this using the function wx.CallAfter
I try to create a modal dialog using Python Tkinter. I found no difference between using and not using wait_window().
import tkinter as tk
def button_click():
dlg = tk.Toplevel(master=window)
tk.Button(dlg, text="Dismiss", command=dlg.destroy).pack()
dlg.transient(window) # only one window in the task bar
dlg.grab_set() # modal
#window.wait_window(dlg) # why?
window = tk.Tk()
tk.Button(window, text="Click Me", command=button_click).pack()
window.mainloop()
I've seen some examples in that use wait_window() for creating a modal dialog. So I'm not sure whether the function is required for creating a modal dialog.
I'm using Python 3.5.
Strictly speaking, no, wait_window() is not required to make a modal dialog box. What makes a dialog modal is the grab that you put on the window.
Often, however, once the window is destroyed you may need to run some other code. You can use wait_window() for this purpose, as it will wait for the window to be destroyed before continuing. You can then have code after that, such as a return statement, or some cleanup code. In your case there's nothing to do, so you don't need to call wait_window.
running your code using window.wait_window(dlg) won't change anything as dlg.grab_set() already creates a modal dialog. this does only mean that you cannot close window while dlg is still alive. you cannot close window as the modal dialog grabs all mouse events from window and redirects them to null.
If you want to create a modal dialog without grab_set(), you would need to bind all mouse events to one handler and then decide if they should be allowed or dismissed and use wait_window.
As a modal dialog is defined by "is anything outside the dialog and in my application available to be clicked" == False , you already have a modal dialog only using grab_set().
If your application shall not be able to programatically close window, you would need wait_window() as well.
Hope I made everything clear.
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.
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.