How to get multitouch to work in QGraphicsView, Qt 5.0.2 in Windows 8 - windows

I am struggling with getting multi-touch to work on a couple of QWidgets that I have added to a QGraphicsView. I have created a subclass of QWidget in which I set up a QGraphicsScene and QGraphicsView. This is my (test) subclass of QWidget:
#include "qttest1.h"
#include <QtWidgets>
#include <QTouchEvent>
qttest1::qttest1(QWidget *parent)
: QWidget(parent)
{
setEnabled(true);
if(!QCoreApplication::testAttribute(Qt::AA_DontCreateNativeWidgetSiblings))
setAttribute(Qt::WA_NativeWindow);
setAttribute(Qt::WA_AcceptTouchEvents);
scene = new QGraphicsScene(this);
scene->setSceneRect(0, 0, 1920, 1080);
graphicsView = new QGraphicsView(scene, this);
graphicsView->setRenderHints(QPainter::Antialiasing);
graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
graphicsView->setAttribute(Qt::WA_AcceptTouchEvents);
graphicsView->viewport()->setAttribute(Qt::WA_AcceptTouchEvents);
QBoxLayout *layout = new QVBoxLayout;
layout->addWidget(graphicsView);
setLayout(layout);
}
qttest1::~qttest1() {}
void qttest1::showGraphics()
{
for(int i = 0; i < 10; i++)
{
Dial *dial = new QDial();
dial->move(i * 120 + 50, 200);
dial->resize(120, 120);
dial->setAttribute(Qt::WA_AcceptTouchEvents);
QGraphicsProxyWidget *proxy = scene->addWidget(dial);
proxy->setAcceptTouchEvents(true);
}
}
This is my main:
int main(int argc, char **argv)
{
QApplication app(argc, argv);
app.setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
QRect rect = app.desktop()->screenGeometry();
qttest1 test;
test.resize(rect.width(), rect.height());
test.showFullScreen();
test.showGraphics();
return app.exec();
}
I know the code isn't pretty and probably leaking a bit, but the point is to try to get multi-touch to work.
I can see and use every kind of widget I add to the scene, but as soon as I touch a dial it swallows every touch that comes after the first. Which makes the dial jump between several positions. What I want is that every dial (or any type of widget) can be used individually and at the same time. I am using QT 5.0.2, Windows 8 with a monitor that supports up to 10 touches.

The Qt docs state : -
Reimplement QWidget::event() or QAbstractScrollArea::viewportEvent()
for widgets and QGraphicsItem::sceneEvent() for items in a graphics
view to receive touch events.
With that, I believe that you need to handle the QEvent::TouchBegin, QEvent::TouchUpdate and QEvent::TouchEnd events, which I don't see in the code you've posted.
Qt may handle the first touch for you, but it's not going to know what you want to do with the second, third, fourth etc. simultaneous touches. For example, you may want your app to do any of the following with the second touch moving: -
1) Rotate the object that the first item is over
2) Scale the object that the first item is over
3) Select the second item
4) Translate the view
5) etc.
So, you need to handle the consecutive touches to do what you want it to do. Also, you may want to look at Gestures in Qt.

Related

Using Qt to create the OS X Yosemite Translucency effect

We're trying to make a QMainWindow with the Mac OSX Yosemite translucency effect. We're using PyQt, but the problem is a Qt issue. With what we've tried so far, it's always either fully transparent or fully opaque (like a normal window). If we turn on Qt.WA_TranslucentBackground, the window background becomes 100% completely transparent.
Additionally, the QGraphicsView we're displaying on it then leaves trails behind when you scroll. The mouse input also "passes through" the transparent parts - clicking on a transparent portion of the graphics view will register as a click on the window behind it. Setting a stylesheet with any custom background color then has no effect. If we turn it off, the window remains opaque. Then we can change the background color using a style sheet, but it's still opaque. Turing WA_FramelessWindowHint on and off doesn't seem to fix anything, either. Nor does setAutoFillBackground(). Do you know how to make a window with the Yosemite translucency effect?
Here's a sample Python program to test this: -
# Attempt at Mac OSX Translucency (example code)
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
Qt = QtCore.Qt
class ExampleMainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.testWidget = QtWidgets.QLabel('Test label, which should be transparent')
# Make sure the testWidget is transparent
self.testWidget.setStyleSheet('background: transparent')
self.testWidget.setAttribute(Qt.WA_TranslucentBackground, True)
self.testWidget.setAutoFillBackground(True)
self.setStyleSheet('background: rgba(255, 255, 255, 0.8)')
self.setAttribute(Qt.WA_TranslucentBackground, True)
self.setAutoFillBackground(True)
#self.setWindowFlags(Qt.FramelessWindowHint) # Doesn't seem to help
self.setCentralWidget(self.testWidget)
def main():
global app, exWindow
app = QtWidgets.QApplication(sys.argv)
exWindow = ExampleMainWindow()
exWindow.show()
exitcodesys = app.exec_()
app.deleteLater()
sys.exit(exitcodesys)
if __name__ == '__main__': main()
Your stylesheet isn't valid. Qt's rgba expects an integer in range 0-255 or a percentage for the values only. So use 80% instead of 0.8. Along with WA_TranslucentBackground that should get you going.
And please post your code in the question, as your pastes expire in a few days and this question will then be unusable.
Here is code that is working for me; I see my other applications' windows underneath. It's C++. I'm using Qt4 rather than 5; perhaps this matters.
#include <QMainWindow>
#include <QApplication>
#include <QLabel>
class MyMain : public QMainWindow
{
Q_OBJECT
public:
MyMain(QWidget* parent = 0);
};
MyMain::MyMain(QWidget* parent)
: QMainWindow(parent)
{
setAttribute(Qt::WA_TranslucentBackground, true);
setStyleSheet("background: rgba(0,0,0,80%);");
QLabel* foo = new QLabel();
foo->setText("hello");
foo->setStyleSheet("color: white;");
setCentralWidget(foo);
}
#include "main.moc"
int main(int argc, char** argv)
{
QApplication app(argc, argv);
MyMain m;
m.show();
return app.exec();
}

AS3: FPS drops down significantly because of innocent mouse moves

I have ~10000 objects in my game and exactly 60 (maximum) FPS when mouse isn't moved. But just when you start moving mouse in circles FPS tries to reach 30 averaging at 45. When you stop mouse it's INSTANTLY 60 (as so program lost it's heartbeat). SWF is run standalone - without any browsers.
I removed any MouseEvent.MOUSE_MOVE listeners and made mouseEnabled=false and mouseChildren=false for the main class.
I increased my FPS one-by-one from 12 to 60 - I gave name to each frame I born and it's really painful watching how 15 of them die just because of nothing...
Sample code:
public class Main extends Sprite
{
private var _periods : int = 0;
/** Idling FPS is 23. Move mouse to drop FPS to 21.*/
public function Main() : void
{
//true if need to drop FPS to 18 instead of 21 moving mouse:
const readyToKill2MoreFrames : Boolean = true;
if ( readyToKill2MoreFrames )
{
var ellipse : Sprite = new Sprite;
ellipse.graphics.beginFill( 0x00FF00 );
ellipse.graphics.drawEllipse( 300, 300, 400, 200 );
ellipse.graphics.endFill();
addChild( ellipse );
//uncomment to fall only to 21 instead of 18:
/*ellipse.mouseChildren = false;
ellipse.mouseEnabled = false;*/
}
var fps : TextField = new TextField;
//uncommenting doesn't change FPS:
//fps.mouseEnabled = false;
addChild( fps );
fps.text = "???";
fps.scaleX = fps.scaleY = 3;
var timer : Timer = new Timer( 1000 );
timer.addEventListener( TimerEvent.TIMER, function( ... args ) : void
{
fps.text = _periods.toString();
_periods = 0;
} );
timer.start();
addEventListener( Event.ENTER_FRAME, function( ... args ) : void
{
//seems like PC is too fast to demonstrate mouse movement
// drawbacks when he has nothing else to do, so let's make
// his attention flow:
for ( var i : int = 0; i < 500000; ++i )
{
var j : int = 2 + 2;
}
++_periods;
} );
}
}
You've probably moved on to more modern problems, but I've recently struggled with this issue myself, so here's an answer for future unfortunates stuck with the problems created by Adobe's decade-old sins.
It turns out legacy support for old-style buttons is the culprit. Quote from Adobe's tutorial on the excellent Scout profiling tool:
"Flash Player has some special code to handle old-style button objects (the kind that you create in Flash Professional).
Independently of looking for ActionScript event handlers for mouse
events, it searches the display list for any of these buttons whenever
the mouse moves. This can be expensive if you have a large number of
objects on the display list. Unfortunately, this operation happens
even if you don't use old-style button objects, but Adobe is working
on a fix for this."
Turns out Adobe never really got around to fixing this, so any large number of DisplayObjects will wreak havoc on your FPS while the mouse is moved. Only fix is to merge them somehow, e.g. by batch drawing them using Graphics. In my early tests, it seems setting mouseEnabled = false has no real effect, either.

Cannot get XCreateSimpleWindow to open window at the right position

The following code opens a window of the right size, w,h, but not at the correct position, x,y.
#include <iostream>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xresource.h>
using namespace std;
int main(int argc, char* argv[]){
Display *display; // A connection to X server
int screen_number;
Window canvas_window;
unsigned long white_pixel;
unsigned long black_pixel;
display = XOpenDisplay(NULL); // Connect X server by opening a display
if(!display){
cerr<<"Unable to connect X server\n";
return 1;
}
screen_number = DefaultScreen(display);
white_pixel = WhitePixel(display, screen_number);
black_pixel = BlackPixel(display, screen_number);
int x=0, y=100, w=300, h=400;
canvas_window = XCreateSimpleWindow(display,
RootWindow(display, screen_number),
x,y, // top left corner
w,h, // width and height
2, // border width
black_pixel,
white_pixel);
XMapWindow(display, canvas_window); // Map canvas window to display
XSync(display, False);
cin >> x; // just so that the program does not end
}
I compiled this with g++ xwindowtest.cpp -lX11 where g++ is version 4.6.2 and ran under Debian GNU/Linux.
The above solution is sort of correct, but not complete.
Creating a new top-level window on the desktop, and creating a new (child) window within the top-level window of your application use the same XCreateSimpleWindow() call, but the actual behaviour can be different.
When creating a new child window within your application you are in charge, and the origin coordinates (relative to its parent window's origin) and size you give for the new window will be honoured. In other words the window will go where you want it to.
However when creating a new top-level window on the desktop you have to deal with the pesky window manager, for example Motif, KDE, Gnome, etc. This intervenes when you create a top-level window to add borders ("decoration"), title, possibly icons, etc. More to the point it will, by default, ignore your requested origin coordinates in most cases and put the new window where it wants rather than where you asked it to put it. It is only when it has been mapped (somewhere) that you can then move it with XMoveWindow().
To avoid this you can ask, or in X11-speak "Hint to", the Window manager that "no, I want you to put the window where I ask, not where you want to put it". You do this with the following sequence:
(1) Define a XSizeHints structure.
(2) Set the flags bit in this structure with a mask of what you want to specify
(3) Populate the relevant arguments
(4) Call XSetNormalHints() on the newly created window (before you map it).
So in C code you would do:
XSizeHints my_hints = {0};
my_hints.flags = PPosition | PSize; /* I want to specify position and size */
my_hints.x = wanted_x_origin; /* The origin and size coords I want */
my_hints.y = wanted_y_origin;
my_hints.width = wanted_width;
my_hints.height = wanted_height;
XSetNormalHints(disp, new_window, &my_hints); /* Where new_window is the new window */
Then map it and - hopefully - it will be where you want it.
I usually declare a XSizeHints first and assign x,y coordinates etc to hints.
When creating x window you could do
XCreateSimpleWindow(display,
DefaultRootWindow(display),
hints.x, hints.y,
hints.width,hints.height,
borderWidth,
blackPixel, whitePixel)
That always works for me with 100% correct windows location.
I had the same problem. I am just starting with X11. Maybe others with more experience can clarify why this works (and simply specifying the x, y for XCreateSimpleWindow does not).
Here's my fix:
disp is your display, win0 is your canvas_window:
XMoveWindow(disp, win0, 200, 200);
XSync (disp, FALSE);
..... do something .....
XMoveWindow(disp, win0, 0, 0);
XSync (disp, FALSE);
... do something
When I run this code snippet, the window moves. You need to follow the XMoveWindow by XSync so that requests (such as a move) are handled appropriately.

Example code for a minimal paint program (MS Paint style)

I want to write a paint program in the style of MS Paint.
On a most basic level, I have to draw a dot on the screen whenever the user drags the mouse.
def onMouseMove():
if mouse.button.down:
draw circle at (mouse.position.x, mouse.position.y)
Unfortunately, I'm having trouble with my GUI framework (see previous question), I'm not getting mouse move messages frequently enough. I'm using the GUI framework wxWidgets and the programming language Haskell.
Question: Could you give me some example code that implements such a minimal paint procedure? Preferably, your code should be use wxWidgets, but I also accept GTK+ or Cocoa. I don't mind any programming language, as long as I can install it easily on MacOS X. Please include the whole project, makefiles and all, since I probably don't have much experience with compiling your language.
Basically, I would like to have a small example that shows me how to do it right in wxWidgets or another GUI framework, so I can figure out why my combination of Haskell and wxWidgets doesn't give a decent frequency of mouse move events.
For Cocoa, Apple provides an example named CIMicroPaint, though it's a bit complicated in that it uses Core Image instead of Quartz 2D. Here a screenshot:
I know this is an old question but nevertheless - in order to get smooth drawing, it is not simply enough to put an instance of your brush at the location of the mouse, as input events are not polled nowhere nearly as fast as they need to for smooth drawing.
Drawing lines is a very limited solution as lines ... are lines, and for a drawing app you need to be able to use custom bitmap brushes.
The solution is simple, you have to interpolate between the previous and current position of the cursor, find the line between the two points and interpolate it by adding the brush for every pixel between the two points.
For my solution I used Qt, so here is the method that interpolates a line between the last and current position in order to fill it out smoothly. Basically it finds the distance between the two points, calculates the increment and interpolates using a regular for loop.
void Widget::drawLine()
{
QPointF point, drawPoint;
point = newPos - lastPos;
int length = point.manhattanLength();
double xInc, yInc;
xInc = point.x() / length;
yInc = point.y() / length;
drawPoint = lastPos;
for (int x=0; x < length; ++x) {
drawPoint.setX(drawPoint.x()+xInc);
drawPoint.setY(drawPoint.y()+yInc);
drawToCanvas(drawPoint);
}
}
This should give you smooth results, and performance is very good, I have even tested it on my Android tablet which is a pretty slow and laggy device and it works very well.
To answer my own question, here is a minimal paint example in C++ using wxWidgets. I have mainly assembled snippets from the book Cross-Platform GUI Programming with wxWidgets which is available online for free.
The drawing is as smooth as it can get, there are no problems with mouse event frequency, as can be seen from the screenshot. Note that the drawing will be lost when the window is resized, though.
Here is the C++ source code, assumed to be in a file minimal.cpp.
// Name: minimal.cpp
// Purpose: Minimal wxWidgets sample
// Author: Julian Smart, extended by Heinrich Apfelmus
#include <wx/wx.h>
// **************************** Class declarations ****************************
class MyApp : public wxApp {
virtual bool OnInit();
};
class MyFrame : public wxFrame {
public:
MyFrame(const wxString& title); // constructor
void OnQuit(wxCommandEvent& event);
void OnAbout(wxCommandEvent& event);
void OnMotion(wxMouseEvent& event);
private:
DECLARE_EVENT_TABLE() // this class handles events
};
// **************************** Implementation ****************************
// **************************** MyApp
DECLARE_APP(MyApp) // Implements MyApp& GetApp()
IMPLEMENT_APP(MyApp) // Give wxWidgets the means to create a MyApp object
// Initialize the application
bool MyApp::OnInit() {
// Create main application window
MyFrame *frame = new MyFrame(wxT("Minimal wxWidgets App"));
//Show it
frame->Show(true);
//Start event loop
return true;
}
// **************************** MyFrame
// Event table for MyFrame
BEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_MENU(wxID_ABOUT, MyFrame::OnAbout)
EVT_MENU(wxID_EXIT , MyFrame::OnQuit)
END_EVENT_TABLE()
void MyFrame::OnAbout(wxCommandEvent& event) {
wxString msg;
msg.Printf(wxT("Hello and welcome to %s"), wxVERSION_STRING);
wxMessageBox(msg, wxT("About Minimal"), wxOK | wxICON_INFORMATION, this);
}
void MyFrame::OnQuit(wxCommandEvent& event) {
Close();
}
// Draw a dot on every mouse move event
void MyFrame::OnMotion(wxMouseEvent& event) {
if (event.Dragging())
{
wxClientDC dc(this);
wxPen pen(*wxBLACK, 3); // black pen of width 3
dc.SetPen(pen);
dc.DrawPoint(event.GetPosition());
dc.SetPen(wxNullPen);
}
}
// Create the main frame
MyFrame::MyFrame(const wxString& title)
: wxFrame(NULL, wxID_ANY, title)
{
// Create menu bar
wxMenu *fileMenu = new wxMenu;
wxMenu *helpMenu = new wxMenu;
helpMenu->Append(wxID_ABOUT, wxT("&About...\tF1"), wxT("Show about dialog"));
fileMenu->Append(wxID_EXIT, wxT("E&xit\tAlt-X"), wxT("Quit this program"));
// Now append the freshly created menu to the menu bar...
wxMenuBar *menuBar = new wxMenuBar();
menuBar->Append(fileMenu, wxT("&File"));
menuBar->Append(helpMenu, wxT("&Help"));
// ... and attach this menu bar to the frame
SetMenuBar(menuBar);
// Create a status bar just for fun
CreateStatusBar(2);
SetStatusText(wxT("Warning: Resize erases drawing."));
// Create a panel to draw on
// Note that the panel will be erased when the window is resized.
wxPanel* panel = new wxPanel(this, wxID_ANY);
// Listen to mouse move events on that panel
panel->Connect( wxID_ANY, wxEVT_MOTION, wxMouseEventHandler(MyFrame::OnMotion));
}
To build, I use the following Makefile, but this will not work for you, since you probably don't have the macosx-app utility. Please consult the wiki guide to Building a MacOSX application bundle.
CC = g++ -m32
minimal: minimal.o
$(CC) -o minimal minimal.o `wx-config --libs`
macosx-app $#
minimal.o: minimal.cpp
$(CC) `wx-config --cxxflags` -c minimal.cpp -o minimal.o
clean:
rm -f *.o minimal
like your eyes, a cursor moves in jumps, so you will want to draw lines between each point the cursor was recorded.

Which API can be used to _capture_ the mouse when moving OS X "Carbon" windows?

On request I have implemented support for moving an OS X window by dragging it using an area within the content part of the window, i.e replicating the drag and move functionality of the title bar but in another area.
The problem I have yet to resolve is the fact that if the user drags the mouse quickly it can leave the window area and then no more mouse move events are received.
On windows this type of problem can simply be fixed by calling the win32 method SetCapture(), what's the corresponding OSX method?
This application is a cross platform C++ application using Carbon for the OS X specific parts. (And yes, I know all about the Cocoa benefits but this is an older code base and there no time nor money for a Cocoa port at this point in time.)
I have found Carbon API methods like for example TrackMouseLocation() but can't really see how I could use them for this application. In listing 2-7 here http://developer.apple.com/legacy/mac/library/documentation/Carbon/Conceptual/Carbon_Event_Manager/Tasks/CarbonEventsTasks.html
the mouse is captured but the problem is that TrackMouseLocation() blocks waiting for input. Blocking is something this application can not do since it also host a flash player that must be called many times per second.
The protototype I have assembled when trying to figure this out basically looks like this:
switch(GetEventKind(inEvent))
{
case kEventMouseDown:
// A silly test to make parts of the window border "draggable"
dragging = local_loc.v < 25 || local_loc.h < 25;
last_screen_loc = screen_loc;
break;
case kEventMouseUp:
dragging = false;
break;
case kEventMouseMoved:
break;
case kEventMouseDragged:
if (dragging) {
Rect rect;
GetWindowBounds (windowRef, kWindowContentRgn, &rect);
int dx = screen_loc.h - last_screen_loc.h;
int dy = screen_loc.v - last_screen_loc.v;
rect.left += dx;
rect.right += dx;
rect.top += dy;
rect.bottom += dy;
SetWindowBounds (windowRef, kWindowContentRgn, &rect);
}
last_screen_loc = screen_loc;
break;
Any ideas appreciated?
I feel you should track mouse in Window as well as out of window. Following code should solve your problem,
EventHandlerRef m_ApplicationMouseDragEventHandlerRef;
EventHandlerRef m_MonitorMouseDragEventHandlerRef;
{
OSStatus ErrStatus;
static const EventTypeSpec kMouseDragEvents[] =
{
{ kEventClassMouse, kEventMouseDragged }
};
ErrStatus = InstallEventHandler(GetEventMonitorTarget(), NewEventHandlerUPP(MouseHasDragged), GetEventTypeCount(kMouseDragEvents), kMouseDragEvents, this, &m_MonitorMouseDragEventHandlerRef);
ErrStatus = InstallApplicationEventHandler(NewEventHandlerUPP(MouseHasDragged), GetEventTypeCount(kMouseDragEvents), kMouseDragEvents, this, &m_ApplicationMouseDragEventHandlerRef);
return true;
}
//implement these functions
OSStatus MouseHasDragged(EventHandlerCallRef inCaller, EventRef inEvent, void *pUserData){}
Hope it helps!!
I Hope It Help´s you too:
// Get Mouse Position --> WAY 1
printf("Get Mouse Position Way 1\n");
HICoordinateSpace space = 2;
HIGetMousePosition(space, NULL, &point);
printf("Mouse Position: %.2f %.2f \n", point.x, point.y);
// Get Mouse Position --> WAY 2
printf("Get Mouse Position Way 2\n");
CGEventRef ourEvent = CGEventCreate(NULL);
point = CGEventGetLocation(ourEvent);
printf("Mouse Position: %.2f, y = %.2f \n", (float)point.x, (float)point.y);
I´m looking for the way to get a WindowPart Reference at a certain location (over all windows of all aplications)
Certain methods in Carbon doesn´t work, always return 0 as a windowRef... Any ideas?
You could also try just calling DragWindow in response to a click in your window's content area. I don't think you need to implement the dragging yourself.

Resources