Kill only Qt in PyQt - python

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.

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.

"Undecorate" Turtle Window

For a scientific experiment I wrote a turtle.py, which opens a 800x480 window and draws a slowly growing black dot. The turtle.py is started with C:\Users\kaza>python C:\Users\kaza\Desktop\Python_scripts\turtle.py "black" 900 40 1 20 20 10 0 0 30 10 in the cmd. black and the numbers after the command are parameters of the dot, which regulate parameters of the dot like growing speed, maxsize etc.
If I execute the cmd the window opens and the turtle.py starts to draw. the size of the screen is 800x480, so the window covers the full screen. The only thing that bothers me is the menu bar. By clicking on it and choosing "undecorate" I can make it disappear but I was not able to find a way starting the window undecorated. The turtle.py should start simultaneously on 12 raspberrys and it is impossible to run to each raspberry and undecorate the window.
I already tried to modify the rc.xml of openbox but nothing changed. Is there maybe a command for the cmd, which starts the turtle.py automatically in an undecorated window?
The standard module turtle uses Tk (through the Tkinter module in Python) for its windows. When you want to undecorate Tk windows, you could use the overrideredirect method of the Toplevel class. This was suggested in an answer to a similar question. From the documentation of Tkinter:
If called with a True argument, this method sets the override redirect flag, which removes all window manager decorations from the window, so that it cannot be moved, resized, iconified, or closed. If called with a False argument, window manager decorations are restored and the override redirect flag is cleared. If called with no argument, it returns the current state of the override redirect flag.
Be sure to call the .update_idletasks() method (see Section 26, “Universal widget methods”) before setting this flag. If you call it before entering the main loop, your window will be disabled before it ever appears.
This method may not work on some Unix and MacOS platforms.
Note that the window is still resizable, but just not through the platform's window manager.
The quick and dirty way to access this method would be to say
turtle.Screen().get‌​canvas()._root().over‌​rideredirect(True)
after the window has been created (to avoid the need for the aforementioned .update_idletasks() workaround).
Normally, the _ at the beginning of a name indicates that the member should not be touched. However, according to the documentation of Tkinter, this is the way to get to the root window:
To get at the toplevel window that contains a given widget, you can often just refer to the widget’s master. Of course if the widget has been packed inside of a frame, the master won’t represent a toplevel window. To get at the toplevel window that contains an arbitrary widget, you can call the _root() method. This method begins with an underscore to denote the fact that this function is part of the implementation, and not an interface to Tk functionality.

How can I make area outside toplevel unclickable?

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.

Avoid event grab during motion in Tkinter

Is it possible in Tkinter to avoid the event grab which occures when you press a mouse button over a widget and keep it pressed while you move the mouse?
I want to register the mouse button and then track all widgets the user enters while he moves his mouse with the button pressed. When the user releases the mouse button the application executes the same action for all tracked widgets.
The following code should explain what I want to do.
# Set a tracking flag
widget.bind('<Button>', start_tracking)
# Add the entered widget to the tracked widgets, if the tracking flag is set
widget.bind('<Enter>', add_to_tracked_widgets)
# Execute an action for every tracked widget; unset the flag
widget.bind('<ButtonRelease>', end_tracking)
I took a look at the grab_current and grab_status methods, but they always returned None.
Python version is 3.4.1.
This is probably the most complicated way to do this, but okay.
One thing that makes this more complicated is Tkinter itself, because event.widget still refers to the widget that was clicked on initally. A different event we can use is Motion which is activated when the mouse moves inside a widget.
tk.bind("<Motion>", add_tracked)
I think you can implement the list and state variables yourself, so we come to the add_tracked method (I just renamed it, it's your add_to_tracked_widgets):
def add_tracked(event):
if tracking:
# Get coordinated of the event and use the master window method to determine
# wich widget lays inside these.
widget = tk.winfo_containing(event.x_root, event.y_root)
# Since 'Motion' creates many events repeatedly, you have to convert this
# list into a set to remove duplicates.
widgets.append(widget)

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.

Categories