PyQt4, Generating multiple Instances of the same widget? - python

I am creating a PyQt4 gui that allows the user in a qmainwindow to input some initial parameters and then click a start button to begin a program. When they click the start button, a new window that displays the parameters appears, and the program begins. I would like the user to be able to initiate multiple instances of the program. However, when the parameters are changed in the qmainwindow and the start button is clicked a second time, the first program window disappears.
Is there a way to have the start button call a second window that runs concurrently with the first window? I imagine this would be something like threading, but from what I have read, PyQt4 doesn't seem to have a method for threading within an application.
Any help would be much appreciated.

I am guessing that you are saving the reference to newly created window in the same variable. If you want to create multiple windows, try to save the reference to that window in a separate variable, i.e each window should have it's own reference variable.
def showWindow(self):
self.child = Window(self)
self.child.show()
If this is your situation, the first window will loose it's reference as soon as the second time showWindow() executes. Because the self.child will contain the reference to second window, resulting in closing the first window, because the first window has no reference reference. As soon as the widget looses reference in Qt, the widget will be destroyed. To overcome this problem maintain a list of variables:
# declare a list in __init__ as self.widgetList = []
def showWindow(self):
win = Window(self):
win.show()
self.widgetList.append(win)

Related

Restart button for a tkinter tic-tac-toe [duplicate]

I just want the equivalent of closing and reopening my main program. I want to invoke it when a "new"-like option from a drop-down menu is clicked on. Something like calling root.destroy() and then re-initiating the mainloop.
How can I get this done?
There are at least three ways you can solve this.
Method one: the head fake. When you create your app, don't put all the widgets in the root window. Instead, hide the root window and create a new toplevel that represents your application. When you restart it's just a matter of destroying that new toplevel and re-running all your start-up logic.
Method two: nuke and pave. Similar in concept but slightly different in execution. In this model, when you want to restart you simply delete all the widgets in the main window, reset the geometry to null (so the window will once again resize itself based on its contents) and then run the logic that draws all the other widgets.
Method three: if it worked the first time... As suggested by Martin v. Löwis, simply have your program exec a new instance of the program, then exit.
The first two methods are potentially faster and have the (dis?)advantage of preserving the current environment. For example you could save the copy of the clipboard, column widths, etc. The third method absolutely guarantees a blank slate.
If you are on Unix, restart the entire application with os.execv. Make sure you pass all command line arguments etc.
You could take all your GUI building logic and initial state code out of the mainloop and put it into functions. Call these functions from the mainloop (something like: buildgui() & initstate()) and then, when the user clicks your menu icon, just call initstate() to set it back like it was when the application first started.

How should I make a class that can be used as my main app window, but also can be used as a secondary window

I know that I can subclass a tk.Frame (or ttk.Frame) and add that to a TopLevel to make secondary windows, but I'm not sure how I should use that as the main window. I know that creating an instance of a Frame class and calling .mainloop() on it seems to work for using it as the main window, but I feel like that's bad practice...
What do other people do when they are making GUI layouts that they want to have available to main windows and secondary windows?
Create a subclass of a Frame, and then put it either in the root window or a toplevel. In either case, you still call mainloop only once on the root window.
The only care you have to take is that you have to be careful about letting the user close the root window, because it will cause all of the other windows to be destroyed.
If you're creating a program that can have multiple windows, you might want to consider hiding the root window and always putting your window in a Toplevel. Of course, when you do that you need to make sure you destroy the root window whenever the last toplevel window is destroyed, or your program will continue to run but the user will have no way to access it.
Do you mean having a home screen that you can flip back to? If so, you can try looking here: Using buttons in Tkinter to navigate to different pages of the application?

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)

How do I prevent Qt buttons from appearing in a separate frame?

I'm working on a PyQt application. Currently, there's a status panel (defined as a QWidget) which contains a QHBoxLayout. This layout is frequently updated with QPushButtons created by another portion of the application.
Whenever the buttons which appear need to change (which is rather frequently) an update effect gets called. The existing buttons are deleted from the layout (by calling layout.removeWidget(button) and then button.setParent(None)) and the new buttons are added to the layout.
Generally, this works. But occasionally, when I call button.setParent(None) on the button to delete, it causes it to pop out of the application and start floating in its own stand-alone frame.
How can I remove a button from the layout and ensure it doesn't start floating?
You should call the button's close() method. If you want it to be deleted when you close it, you can set the Qt.WA_DeleteOnClose attribute:
button.setAttribute(Qt.WA_DeleteOnClose)
Try calling QWidget::hide() on the button before removing from the layout if you don't want to delete your button.

Resetting the main GUI window

I just want the equivalent of closing and reopening my main program. I want to invoke it when a "new"-like option from a drop-down menu is clicked on. Something like calling root.destroy() and then re-initiating the mainloop.
How can I get this done?
There are at least three ways you can solve this.
Method one: the head fake. When you create your app, don't put all the widgets in the root window. Instead, hide the root window and create a new toplevel that represents your application. When you restart it's just a matter of destroying that new toplevel and re-running all your start-up logic.
Method two: nuke and pave. Similar in concept but slightly different in execution. In this model, when you want to restart you simply delete all the widgets in the main window, reset the geometry to null (so the window will once again resize itself based on its contents) and then run the logic that draws all the other widgets.
Method three: if it worked the first time... As suggested by Martin v. Löwis, simply have your program exec a new instance of the program, then exit.
The first two methods are potentially faster and have the (dis?)advantage of preserving the current environment. For example you could save the copy of the clipboard, column widths, etc. The third method absolutely guarantees a blank slate.
If you are on Unix, restart the entire application with os.execv. Make sure you pass all command line arguments etc.
You could take all your GUI building logic and initial state code out of the mainloop and put it into functions. Call these functions from the mainloop (something like: buildgui() & initstate()) and then, when the user clicks your menu icon, just call initstate() to set it back like it was when the application first started.

Categories

Resources