Customize PyQt multi-touch pan gestures on QListWidget - python

I'm having a problem with a simple Notepad application I'm writing to teach myself basic Python/PyQt.
Specifically, I want to know how to change the multi-touch pan gesture sensitivity on a QListWidget.
As it is now, when I drag up and down with 2 fingers, it seems like the list is moving up/down one step for each pixel I move with my fingers. This is nothing I've implemented myself, it seems to work out of the box for list widgets
I want the movement to mimic the speed of my fingers i.e one move up/down of the widget items for every x*height_of_item_in_pixels. Is this doable without major hacking into the gesture system?
How would I go about this?
I'm using PyQt 4.8.3 with Python 2.6

Quite a bit late, but maybe I can help others who stumble upon this question:
The solution is to set the scroll mode for the QListWidget to ScrollPerPixel (instead of the default ScrollPerItem):
list_widget.setVerticalScrollMode(list_widget.ScrollPerPixel)
A minimal example:
import sys
from PyQt5 import QtWidgets
# create app
app = QtWidgets.QApplication(sys.argv)
# create list widget
list_widget = QtWidgets.QListWidget()
# populate list widget with dummy items
for index in range(100):
list_widget.addItem(QtWidgets.QListWidgetItem('item {}'.format(index)))
# THIS IS THE IMPORTANT PART: set the scroll mode
list_widget.setVerticalScrollMode(list_widget.ScrollPerPixel)
# OPTIONAL: enable pan by mouse (and one-finger pan)
QtWidgets.QScroller.grabGesture(list_widget.viewport(),
QtWidgets.QScroller.LeftMouseButtonGesture)
# show the list widget
list_widget.show()
# run the event loop
app.exec_()
Note: This example also shows how to implement panning using the mouse, which is useful for testing on devices without touch-screen. Moreover, the mouse pan setting also enables one-finger pan, in addition to the default two-finger pan gesture (at least on Windows, tested on Surface Pro tablet).

More than likely this functionality exists because the multitouch event is being interpreted by your operating system as a scroll of some type and QT is recieving the scroll action, rather than the multitouch action directly.

Related

In a GUI, how to change the mouse to Zoom-to-rectangle

I am creating a GUI that revolves around looking at a plot. The users are assumed to be very dense, as per instruction. That being said, I have been told that the default Zoom-to-rectangle button needs to have another button in the toolbar at the top of the program (which I would also program to a shortcut for ease of use).
The problem I am having is I don't know how to turn the mouse into the Zoom-to-rectangle. I don't want it to actually zoom, just change the mouse to where if it is then dragged across the plot while clicking, it will then zoom.
This is hard to explain, so if you need more information than what is provided please ask.

PyQt4 - detect global mouse click

A part of a small project I am working on involves 'calibrating' the coordinates of the screen of which to take a screen capture of.
By the 'screen', I refer to the entire desktop, not my GUI window.
The coordinates are calibrated when a QDialog window appears (which I've subclassed).
The user is prompted to click several locations on the screen.
I need the program to record the locations of all mouse clicks occuring anywhere on the screen - ones that don't natively trigger a QDialog mouseEvent, since they are outside this window.
Obviously overwriting the mouseEvent method does not work, since the QDialog doesn't recieve the clicks.
How can I capture global mouse clicks, so that an event is triggered and sent to the QDialog when any part of the screen is clicked?
(I'd prefer a Qt based solution, but am open to other libraries if need be).
Thanks!
There are some cross-platform examples of how to do this with http://pypi.python.org/pypi/autopy/0.51
I've assumed this isn't possible and am instead using pyHook,
letting Qt pump the messages.

Python + Qt -> 2D overlay over other full screen app?

Backgroud:
I play Grand Strategy Games a lot. Part of addcition comes out of AARs (After Action Reports). Stories players write about games. Ofc. that require save games cause "quick" game is longer than 10 hours.
Problem:
Game do not support automatic save games other than 3 autosaves that get overridden every time. So I want to write app that will use Qt for tracking file changes. Every time game auto saves, this app will rename and move to choosen location savegame.
But since its full screen game, players may forgot to turn on my app I need way to indicate state of my app.
Question:
How can I make 2D overlay over portion of full screen 3D app, given that I use Python and Qt?
Alternative
I do not think that sound warnings would solve my problem, since it would work if someone forgotten to choose save game to track, but it would not work if someone completely forgot to turn on my app. While lack of icon would be enough to inform about such mistake.
But if you can find any other way to indicate that my app is not turned on or configured, post your ideas in answers.
Very old post, but I will let this reply here for others looking for something similar.
Check PyWinCtl. If you are able to build a frameless, semi-transparent window using Python and Qt, alwaysOnTop(True) and acceptInput(False) methods will make the trick, but only with games based on CGI calls, not if they use DirectDraw Exclusive Mode (for this, I'm also searching for a Python solution, this is why I ended here!)
In the meantime, you can try this on Qt when initializing your window (it's a piece of code, not reproduceble, sorry):
# Make it transparent to input
self.setFocusPolicy(QtCore.Qt.NoFocus)
if "Linux" in platform.platform():
self.setAttribute(QtCore.Qt.WA_X11DoNotAcceptFocus, True)
self.setAttribute(QtCore.Qt.WA_TransparentForMouseEvents, True)
self.setAttribute(QtCore.Qt.WA_InputMethodTransparent, True)
self.setAttribute(QtCore.Qt.WA_ShowWithoutActivating, True)
# Make it semi-transparent
self.setWindowOpacity(128)
# Setting flags: on top, frameless and no focus
self.setWindowFlags(QtCore.Qt.Tool| QtCore.Qt.CustomizeWindowHint | QtCore.Qt.WindowStaysOnTopHint | QtCore.Qt.FramelessWindowHint | QtCore.Qt.WindowDoesNotAcceptFocus)
I think the name of the functions and parameters are self-explicative (let me know if they are not).
The part of making your window transparent to input methods is important, otherwise the window can be eventually clicked and the game will lose focus. This effect on the window is permanent.
The part of making your window semi-transparent will not work as is. You need to implement a custom paintEvent for your window, like this (again, not reproducible, sorry):
def paintEvent(self, event=None):
# This is required to draw a semi-transparent window
# https://stackoverflow.com/questions/33982167/pyqt5-create-semi-transparent-window-with-non-transparent-children
painter = QtGui.QPainter(self)
painter.setOpacity(0.4) # or your desired opacity level
painter.setBrush(QtCore.Qt.black) # or your desired background color
painter.setPen(QtGui.QPenQtCore.Qt.black)) # or your desired background color
painter.drawRect(self.rect())
The part of making it always on top might not be permanent, this is why using pywinctl's alwaysOnTop() is recommended, furthermore, it's better to recall it, for instance every second, to bring your window back to top in case it's obscured by any reason.

Qt - Temporarily disable all events or window functionality?

I have a Qt program with many buttons, user-interactable widgets, etc.
At one stage in the program, I would like all the widgets to temporarily 'stop working'; stop behaving to mouse clicks and instead pass the event on to one function.
(This is so the User can select a widget to perform meta operations. Part explanation here: Get variable name of Qt Widget (for use in Stylesheet)? )
The User would pick a widget (to do stuff with) by clicking it, and of course clicking a button must not cause the button's bound function to run.
What is the correct (most abstracted, sensible) method of doing this?
(which doesn't involve too much new code. ie; not subclassing every widget)
Is there anything in Qt designed for this?
So far, I am able to retrieve a list of all the widgets in the program (by calling
QObject.findChildren(QtGui.QWidget)
so the solution can incorporate this.
My current horrible ideas are;
Some how dealing with all the applications events all the time in one
function and not letting through the events when I need the
application to be dormant.
When I need dormancy, make a new transparent widget which recieves
mouse clicks and stretch it over the entire window. Take coordinates
of click and figure out the widget underneath.
Somehow create a new 'shell' instance of the window.
THANKS!
(Sorry for the terrible write-up; in a slight rush)
python 2.7.2
PyQt4
Windows 7
You can intercept events send to specific widgets with QObject::installEventFilter.
graphite answered this one first so give credit where credit is due.
For an actual example in PySide, here's an example you might draw some useful code from:
my_app.py
from KeyPressEater import KeyPressEater
if __name__ == "__main__":
app = QApplication(sys.argv)
eater = KeyPressEater()
app.installEventFilter(eater)
KeyPressEater.py
class KeyPressEater(QObject):
# subclassing for eventFilter
def eventFilter(self, obj, event):
if self.ignore_input:
# swallow events
pass
else:
# bubble events
return QObject.eventFilter(self,obj,event)

Highlight Select Box in Python

I am trying to rebuild the functionality of the desktop's "highlight to select" feature so that I can use it in my own app. When I say "highlight to select" I mean the selection box that shows up if you click and drag on your desktop (native to all main-stream OS).
I've been working for hours trying to recreate it, and simply can't find a way. I've tried PyGTK, Xlib for python, and a couple other weird hacks. All of which have their own problems that won't allow me to move forward.
I generally don't ask for straight up example code without providing some sort of starting point, but in this project I don't even know where to start. How would you do this?
Here's the requirements:
Must draw on the root window (or a transparent layer that "appears" to be the root)
Must return the coordinates of the selection (x, y, height width)
Update: Forgot some details.
I am using Ubuntu 10.10
I have dual monitors (though, I don't think that should matter)
I don't mind downloading any extra libraries that are necessary
I don't know if this is what you're looking for, but what if you created another window in your module, and have your code show it when you release drag? You could fetch the cursor's current position, and have it draw the window there.
This should help you get the mouse position on the root window.
So, your code may look a little like this (this is untested code!) I'm only showing the relevant portions of what goes inside __ init __.
def __init__(self):
...
#Some of your code here.
...
win = gtk.Window(gtk.WINDOW_TOPLEVEL)
#Note that I am creating a popup window separately.
popwin = gtk.Window(gtk.WINDOW_POPUP)
#I am setting "decorated" to False, so it will have no titlebar or window controls.
#Be sure to compensate for this by having another means of closing it.
popwin.set_decorated(False)
def ShowPopup():
#You may need to put additional arguments in above if this is to be an event.
#For sake of example, I'm leaving this open ended.
#Get the cursor position.
rootwin = widget.get_screen().get_root_window()
curx, cury, mods = rootwin.get_pointer()
#Set the popup window position.
popwin.move(curx, cury)
popwin.show()
def HidePopup():
#This is just an example for how to hide the popup when you're done with it.
popwin.hide()
...
#More of your code here.
...
#Of course, here is the code showing your program's main window automatically.
win.show()
A very simplistic approach, but it should give the appearance of what you're wanting.

Categories

Resources