How can I make area outside toplevel unclickable? - python

I want to create a toplevel window in tkinter, and I want the outside area unclickable. So this way, the user cannot click out from the toplevel window, just after it's been destroyed. (And also preventing to be able to create the same window from the root Tk())

Tkinter supports something called a "grab". When you put a grab on a window, all events are funneled through the widget. Even if you click outside the window, the click will register with the window.
There are two types of grabs: local and global. Local means the grab only works for your application -- you can still click on the desktop, for example. A global grab works for the whole computer. These can be very dangerous because you can completely lock up your UI if you don't provide a way to release the grab.
To set a local grab you can call grab_set on any widget, and all events will go to that widget. To set a global graph, call grab_set_global.
A local grab is how tkinter implements modal dialogs -- while the dialog is open it has a local grab so that you must dismiss the dialog before clicking on buttons in the main window.
Danger Will Robinson! if you are working with global grabs, make sure there's a absolutely foolproof way to release the grab. For example, during development you might use after to release the grab after 15 seconds. Or, bind to the escape key. Always, always test with a local grab first. As a rule of thumb, however, you should avoid using a global grab unless absolutely necessary.

Related

Python/PySide: How to make a widget that will stay on top of the main window, but not cover up other widgets?

So I have a script running inside another program (The Foundry's Hiero) and I'm just making a new QWidget object, and calling self.show()
Now, I can set it to self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint), so my window will stay on top of the main window, even if you click on something in the main window.
The problem is, this is a sort of popup window that you configure settings in, and it triggers other QWidget popups. If I set my window to WindowStaysOnTopHint, those subdialogs that my widget triggers end up beneath my widget.
Is there a way in PySide/PyQt to make a window stay on top/keep focus from the main application window in particular, but not everything?
You can use the QApplication.focusChanged signal to raise your widget up when Hiero's main window is selected. Then you would just need to remove the WindowStaysOnTopHint flag.
I'm not familiar with Hiero's API, but I'm guessing you could try something like:
def raiseMyWidget(old, new):
if new == hiero.ui.mainWindow():
myWidget.raise_()
QtWidgets.QApplication.instance().focusChanged.connect(raiseMyWidget)
Hope this helps! You can take advantage of the old parameter or some other means to make sure that your widget isn't raised above the others as well.

The proper way to display multiple windows in tkinter?

I am currently working on a project using Python and tkinter.
The problem is that I don't know what's the proper way to display multiple windows, or screens, I don't know how to call them. Let me explain better.
When the application starts the login screen appears. After that, if I click register, I want to go to the register screen, but I don't want it to be a separate window (I don't want to have 2 windows displayed at the same time), but rather another window with different content ?!
How should I handle properly this situation? Create a second window using Toplevel and hiding the first (can I do that?) or changing the widgets of the first?
Code I've written so far
You can do that- just call window.withdraw() on the Toplevel you need to hide after creating a new Toplevel. Changing the widgets in the first is also an option- if you like, you could always try a Notebook widget and disable manual flipping or just put each "screen" in a frame and grid_ or pack_forget them to remove them from the window.

Kill only Qt in PyQt

In a PyQt application is it possible to kill only the GUI (Qt) part?
Any Python commands running should be unaffected, only the graphics should disappear.
how about QtGui.QWidget.setVisible(visible)
PySide.QtGui.QWidget. setVisible ( visible )
Parameters: visible – PySide.QtCore.bool
This property holds whether the widget is visible.
Calling setVisible(true) or PySide.QtGui.QWidget.show() sets the widget to visible status if all its parent widgets up to the window are visible. If an ancestor is not visible, the widget won’t become visible until all its ancestors are shown. If its size or position has changed, Qt guarantees that a widget gets move and resize events just before it is shown. If the widget has not been resized yet, Qt will adjust the widget’s size to a useful default using PySide.QtGui.QWidget.adjustSize() .
Calling setVisible(false) or PySide.QtGui.QWidget.hide() hides a widget explicitly. An explicitly hidden widget will never become visible, even if all its ancestors become visible, unless you show it.
A widget receives show and hide events when its visibility status changes. Between a hide and a show event, there is no need to waste CPU cycles preparing or displaying information to the user. A video application, for example, might simply stop generating new frames.
A widget that happens to be obscured by other windows on the screen is considered to be visible. The same applies to iconified windows and windows that exist on another virtual desktop (on platforms that support this concept). A widget receives spontaneous show and hide events when its mapping status is changed by the window system, e.g. a spontaneous hide event when the user minimizes the window, and a spontaneous show event when the window is restored again.
You almost never have to reimplement the PySide.QtGui.QWidget.setVisible() function. If you need to change some settings before a widget is shown, use PySide.QtGui.QWidget.showEvent() instead. If you need to do some delayed initialization use the Polish event delivered to the PySide.QtGui.QWidget.event() function.

Make a window top priority

I have a root window with a panel on it. Then there is this function, in which I create a TopLevel (another window) for asking input from user. I'm trying to find some way to make it compulsory for user to either enter input and click OK or cancel to dismiss the window before being able to access the root window. It's like when an error message pops up, you can't just ignore it and do other things in the root window. Does anyone have any suggestion for me?
Have a look at Dialog Windows. You can use widget.wait_window(window) to achieve this.
You can do what is called a grab, which forces all events into the window of your choice. There are several methods for managing grab, including grab_set and grab_release.
For an example, see NiceGrab.
When working with grabs, exercise extreme care. It's possible to lock up your computer if you do a global grab and then have a bug that prevents you from releasing it. During development I will often implement a timer that kills the program after a minute or so, so if I lock everything up it will be automatically released after a short wait.

Change the focus from one Text widget to another

I'm new to Python and I'm trying to create a simple GUI using Tkinter.
So often in many user interfaces, hitting the tab button will change the focus from one Text widget to another. Whenever I'm in a Text widget, tab only indents the text cursor.
Does anyone know if this is configurable?
This is very easy to do with Tkinter.
There are a couple of things that have to happen to make this work. First, you need to make sure that the standard behavior doesn't happen. That is, you don't want tab to both insert a tab and move focus to the next widget. By default events are processed by a specific widget prior to where the standard behavior occurs (typically in class bindings). Tk has a simple built-in mechanism to stop events from further processing.
Second, you need to make sure you send focus to the appropriate widget. There is built-in support for determining what the next widget is.
For example:
def focus_next_window(event):
event.widget.tk_focusNext().focus()
return("break")
text_widget=Text(...)
text_widget.bind("<Tab>", focus_next_window)
Important points about this code:
The method tk_focusNext() returns the next widget in the keyboard traversal hierarchy.
the method focus() sets the focus to that widget
returning "break" is critical in that it prevents the class binding from firing. It is this class binding that inserts the tab character, which you don't want.
If you want this behavior for all text widgets in an application you can use the bind_class() method instead of bind() to make this binding affect all text widgets.
You can also have the binding send focus to a very specific widget but I recommend sticking with the default traversal order, then make sure the traversal order is correct.
It is really simple in PyQt4 simply use this one single line below and you will be able to change focus by pressing tab button:
self.textEdit.setTabChangesFocus(True)
The focus traversal is somewhat customizable, usually letting the X windows manager handle it (with focus follows mouse, or click). According to the manual it should be possible to bind an event to the key press event, for tab presses, and triggering a focusNext event in those cases.

Categories