How to hide Gtk widget on clicking outside it? - python

I have a custom GTK widget (basically an overlay of HBox over a Cairo surface). I wish to hide it when I click outside the widget in the window. Similar to how menus behave.
I tried using grab_focus and wait for the focus-out-event but the widget doesn't grab focus, I think it's not a focusable widget.[1]
[1] https://developer.gnome.org/pygtk/2.24/class-gtkwidget.html#method-gtkwidget--grab-focus

You might have to set the CAN_FOCUS flag, if you want to use the focus_out event.
But if you want to click outside to hide the widget, as is necessary with menus, then you have to connect to events of the area below the widget. You could connect to the button_press event of the window, taking care not to stop event propagation.

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.

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.

Adding a tooltip to an image

I'm trying to add a tooltip to an image. Following a PyGTK tutorial it seems that this should work:
image = gtk.Image()
image.set_from_file(image_path)
box.pack_start(image, expand=False)
tooltip = gtk.Tooltips()
tooltip.set_tip(image, "Hello!")
Except it doesn't. Nothing happens when I mouse over the image. However, I know that works with buttons (I ran the sample code from the tutorial).
With GTK 2.12 and above, I could probably just use image.set_tooltip_text("Hello!") but I'm stuck at 2.10.4 and have to use gtk.Tooltips.
Edit
According to the documentation for gtk.Tooltips:
Tooltips can only be set on widgets which have their own X window. To check if a widget has its own window use widget.flags()&gtk.NO_WINDOW. To add a tooltip to a widget that doesn't have its own window, place the widget inside a gtk.EventBox and add a tooltip to the eventbox instead.
So that solves my problem but leaves me a bit confused. I checked the flags for a button and it has the same gtk.NO_WINDOW flag that images have. So why don't buttons need an EventBox but images do?
To satisfy its interface, GktButton creates an event box (well, something like an event box) for itself, internally. I.e. it captures events in a non-visible gdk window. GtkImage doesn't have a similar interface to satisfy so it doesn't need to capture events.
Perhaps it's an accident of the button's internal implementation that using the tooltip interface works without embedding a button in an EventBox or perhaps the tooltip interface actually depends upon a gdk window whether it's visible or not and the Widget interface lacks that sort of flag.

How to get clicks on disabled buttons with wxpython?

I have a disabled button, and it does not receive clicks when I use EVT_BUTTON on it. Is there a way to receive clicks even when it has been Disabled()?
The whole point of disabling a button is so that the EVT_BUTTON event is not fired. I'm sure you could create create an ugly hack using EVT_LEFT_DOWN and detecting where the mouse is in your app as a workaround, but why bother? This is intended behavior.
Perhaps wxpython has a mechanism similar to pygtk.
In pygtk you create a input-only (that is transparent) window over the widget you want to get clicks for and get your clicks there.

'hover over' popup with Tkinter

I have implemented an informational popup in a python app using a Tkinter Menu widget. I have a Text widget on a canvas in the root window. I created a Menu widget that has root as its parent. When I detect a mouse hover over the text widget I post the popup menu with menuWidget.post(). When I get a leave event from the text widget my intention was to have the popup disappear by calling menuWidget.unpost(), only the popup menu does not disappear until I click elsewhere outside the text widget.
First, is this a sane method for implementing an informational popup? And can anyone tell me why the popup menu won't disappear?
This is not the right way to do an informational popup. On the Mac and on windows machines menus are native controls. Because of this the unpost command doesn't work because tk cedes control to the system event loop in order to get platform-specific behavior.
What you want is to use instead is a toplevel window with the overrideredirect flag set. This lets you display a borderless window anywhere you want. The upside to this is that you aren't limited to simple text -- you can put anything you want in that toplevel -- another text widget, a canvas, buttons, etc.

Categories