Checking user idle in PyQt by examining mouse clicks on the GUI - python

I am trying to implement a feature such that if the user havn't interact with the GUI for some time X, I will stop some functionality of the GUI.
Currently I have a time stamp set up so that if any of the button is not clicked in X seconds, the GUI will terminate some functionality
button1.triggered.connect(keep_alive)
button2.triggered.connect(keep_alive)
....
buttonN.triggered.connect(keep_alive)
As you can see, this is not really elegant, and doesn't scale as the button increases. Therefore I am currently investigating another method such that I monitor the mouse clicks
mouse = app.mouseButtons()
if mouse != Qtcore.Qt.NoButton:
#keep_alive
I think this is a little hacky, but it will work for the functionality I envisioned, however, I do not know how to insert this to the execution loop of the QT.
Any suggestions will be appreciated

You must intercept the mouse events by reimplementing the mousePressEvent.
http://qt-project.org/doc/qt-4.8/qwidget.html#mousePressEvent
To make sure that it won't affect your other functionalities you'll need to propagate it to the parent widget. Read more details: https://www.qt.io/blog/2006/05/27/mouse-event-propagation
I would proceed by implementing it in the main window and make sure all mouse events are propagated to it.

Related

Python 3 - Is there a way to keep the mouse inside the tkinter window

Python 3
Tkinter
Hey, I'm looking for something that don't allow the user to leave a window if a variable is true/false.
basicly, somethings that keeps the mouse inside the tkinter window
Not directly, no. However you could monitor the mouse position with the <Motion> event and correct it every time it goes outside. How to correct it would depend on your OS; look into pyautogui for a crossplatform solution.
You can't force the mouse to stay in the window, though you can "grab" all of the mouse events, preventing the user from clicking anywhere but on your app. This is very dangerous as you can lock up your computer if your code has a bug in it.
See How can I make area outside toplevel unclickable?

Is it possible to see if the file is being dragged over the window in Kivy, Python?

What I want to achieve:
I want to detect the situation when the user is dragging a file over the Kivy app window.
What I already know:
I know how to detect hovering mouse coursor over widgets (with on_mouse_pos), I also know how to detect if a file is dropped onto the window (with on_file_drop).
So, is it possible to see whether the cursor is hovering over the window and "holding" a file? Because then I want to display some prompt (eg. 'Drop HERE'). I hope you get the idea :)
I'm not really sure, because there's this thing with SDL2 (and probably even with old pygame) when the Window just pauses (try some animation or something) when you e.g. drag it with the window decoration (the thing where title and _ O X are). That is the behavior if you do something with the Window directly.
Although, the Window looks like it behaves normally (doesn't pause itself), when you drag file on top of it (I tried with examples/animation/animate.py), to do such thing you'd need to do either the hovering behavior + handling the collisions or bind to mouse_pos.
However, when binding to mouse_pos, it seems like the Window still isn't capable of handling the input from outside and at the same time get mouse properties correctly (I think it's similar to the behavior when you click & drag outside of the Window and Button remains pressed, but this is kind of inversed).
edited animate.py:
class TestApp(App):
def on_mouse_pos(self, win, args):
print args
...
def build(self):
...
from kivy.core.window import Window
Window.bind(mouse_pos=self.on_mouse_pos)
return button
Therefore if you can't get even mouse position when a mouse button is being held, I don't think such an action is possible. You can however make the areas where you want to drop the file already different (e.g. change background) when you'll expect a user to drop the file - a very dirty workaround from UI side for such a problem.
Side note: Kivy should be able to get most (if not all) SDL2 window events via Cython, therefore if you find such event in SDL2 that would make fetching mouse position possible, such action could be performed, feel free to make a feature request in kivy/kivy or make a pull request.

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.

How to specify a full click in Python Tkinter

The following python line will bind the method "click" to the event when the user presses the mouse button while the pointer is on the widget; no matter where the pointer is when she releases the button.
self.bind('<Button-1>',self.click)
If I use "ButtonRelease" instead of "Button" in the code, it seems that the method "click" will be called for the widget on which the mouse was pressed after the button release; no matter where you release it.
1- Isn't there a neat way to make it call the bound method only if the mouse button was released on my widget; no matter where it was pressed?
2- Isn't there neat way to tell it to react only in case of a full click (press and release both on the same widget)?
1- Isn't there a neat way to make it
call the bound method only if the
mouse button was released on my
widget; no matter where it was
pressed?
2- Isn't there neat way to tell it to
react only in case of a full click
(press and release both on the same
widget)?
No "neat" way, because, as Tkinter's docs say:
When you press down a mouse button
over a widget, Tkinter will
automatically "grab" the mouse
pointer, and mouse events will then be
sent to the current widget as long as
the mouse button is held down.
and both of your desires are incompatible with this automatic grabbing of the mouse pointer on press-down (which I don't know how to disable -- I think it may be impossible to disable, but proving a negative is hard;-).
So, you need more work, and a non-"neat" solution: on the button-down event's callback, bind the enter and leave events (to bound methods of a class instance where you can track whether the mouse is currently inside or inside the widget of interest) of that window as well as the button-release; this way, when the release event comes, you know whether to perform the "actual application callback" (if inside) or do nothing (if outside) -- that gives you your desire number 2, but describing this as neat would be a stretch.
Desire number 1 is even harder, because you have to track enter and leave events on EVERY widget of interest -- it's not enough to know one bit, whether the mouse is inside or outside, but rather you must keep track of which widget (if any) it's currently in, to direct the "actual application callback" properly (if at all) at button release time.
While the internals aren't going to be neat, each functionality can be bound into one neat-to-call function... with slightly "indaginous" internals (a term that's used more often to refer to root canal work or the like, rather than programming, but may be appropriate when you're wanting to go against the grain of functionality hard-coded in a framework... that's the downside of frameworks -- you're in clover as long as you want to behave in ways they support, but when you want to defeat their usual behaviors to do something completely different, that can hardly ever be "neat"!-).
The tkinter documentation does provide you info on that:
http://www.pythonware.com/library/tkinter/introduction/events-and-bindings.htm
You can do a binding on
<ButtonRelease-1>
Binding on ButtonRelease-1 isn't enough. The callback won't fire until the button is released, but it doesn't matter where the mouse is when it's released. What governs is where the mouse was when it was clicked, as Alex Martelli's said. An easy way to get the desired behavior is to put everything on a canvas, and bind the callback to ButtonRelease-1. Now you have something like
def callback(event):
x1, y1, x2, y2 = canvas.bbox(widget)
if x1 <= event.x <= x2 and y1 <= event.y <= y2:
<whatever>
I've used this approach in my own code to get arbitrary widgets to behave like buttons in this respect.

Can you auto hide frames/dialogs using wxPython?

I would like to create an application that has 3-4 frames (or windows) where each frame is attached/positioned to a side of the screen (like a task bar). When a frame is inactive I would like it to auto hide (just like the Windows task bar does; or the dock in OSX). When I move my mouse pointer to the position on the edge of the screen where the frame is hidden, I would like it to come back into focus.
The application is written in Python (using wxPython for the basic GUI aspects). Does anyone know how to do this in Python? I'm guessing it's probably OS dependent? If so, I'd like to focus on Windows first.
I don't do GUI programming very often so my apologies if this makes no sense at all.
As far as I know, there's nothing built in for this.
When the window is hidden, do you want it completely invisible or can a border of a few pixels be showing? That would be an easy way to get a mouse hover event. Otherwise you might have to use something like pyHook to get system-wide mouse events to know when to expand your window.
The events EVT_ENTER_WINDOW and EVT_LEAVE_WINDOW might also be useful here to know when the user has entered/left the window so you can expand/collapse it.
Expanding/collapsing can just be done by showing/hiding windows or resizing them. Standard window functions, nothing fancy.
By the way, you might want to use wx.ClientDisplayRect to figure out where to position your window. That will give you a rectangle of the desktop that does NOT include the task bar or any other toolbars the user has, assuming you want to avoid overlapping with those things.
Personally, I would combine the EVT_ENTER_WINDOW and EVT_LEAVE_WINDOW that FogleBird mentioned with a wx.Timer. Then whenever it the frame or dialog is inactive for x seconds, you would just call its Hide() method.
I think you could easily just make a window that is the same size as the desktop then do some while looping for an inactivity variable based on mouse position, then thread off a timer for loop for the 4 inactivity variables. I'd personally design it so that when they reach 0 from 15, they change size and position to become tabular and create a button on them to reactivate. lots of technical work on this one, but easily done if you figure it out

Categories