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

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.

Related

How do I restore a destroyed widget in tkinter?

def change_section_to_main():
SUB_SECTION.destroy()
APP_MAIN_FRAME.pack()
I want to restore the widget "APP_MAIN_FRAME". I thought I could do it with pack() turns out I was wrong. I keep getting this Error >>
_tkinter.TclError: bad window path name ".!frame
You can't "undestroy" a widget. Once it has been destroyed it can no longer be used.
Usually, the solution to this specific problem is to hide the widget rather than destroy it. You can hide it by using one of pack_forget, grid_forget, grid_remove or place_forget depending on exactly what you want to have happen and on which tool (pack, grid, or place) that you used to add it to the window.
If you expect to hide and show a widget often, grid is the best choice since grid_remove will remember how the item was placed. A subsequent call to grid() with no arguments will restore all of the settings. pack and place do not remember the configuration of a widget when it is forgotten.

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.

wxpython call a function when focus of TextCtrl changes

Morning, I would like to call a function in my GUI in the event that the content of a TextCtrl is changed. Only after the user leaves the TextCtrl object though, not during editing.
Please can you help me find the right event handler to use, I'm very new to wxpython and I can't even find a list of allowable events.
Many thanks
You can bind the TextCtrl to wx.EVT_TEXT to capture changes to the value and wx.EVT_KILL_FOCUS to trigger an even when the focus changes. Alternatively you could bind it to wx.EVT_SET_FOCUS and save the current TextCtrl value and also bind to it wx.EVT_KILL_FOCUS to and compare the new value to see if it's changed.
------- EDIT -------
WxFormBuilder is fantastic tool for quickly creating basic UIs. It will also show you every event that you can bind to a widget by clicking on the 'events'` tab.

Automatic focus on showing deletes the placeholder text of a QLineEdit

I use PyQt4 and Python 2.7.9.
My program contains a few QLineEdit objects. The problem is that when the program is launched, one of the QLineEdits is being focused automatically, which causes my placeholder text to disappear.
Is there any way to prevent it, or at least don't let it hide the placeholder text?
Another way is
self.this_widget.clearFocus()
after window has been shown. Only in Qt5 placeholder texts are displayed even with focus. So maybe switch to PyQt5.
You can use setFocus to put the focus on a different widget (although, depending on which widget you pick, you might also need to set the focus-policy first):
self.some_other_widget.setFocusPolicy(QtCore.Qt.TabFocus)
self.some_other_widget.setFocus()
Alternatively, if you use Qt Designer to create the GUI, you could edit the tab-order so that the line-edit is not the first in the chain. This can also be done programmatically using QWidget.setTabOrder.

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