Qt disable touch screen detection - c++

Is there a way to configure a Qt application to not detect the touch screen to keep the behavior of a normal screen?

It depends. If your operating system differentiates between touch events and mouse presses, you could create a touchEvent filter to ignore the events like so:
#include <QObject>
#include <QTouchEvent> // to get rid of "error: invalid use of incomplete type 'class QEvent'"
class QTouchEventFilter: public QObject
{
Q_OBJECT
public:
QTouchEventFilter(QObject *parent = 0) : QObject(parent)
{
}
protected:
bool eventFilter(QObject * p_obj, QEvent * p_event)
{
if (p_event->type() == QEvent::TouchBegin ||
p_event->type() == QEvent::TouchUpdate ||
p_event->type() == QEvent::TouchEnd ||
p_event->type() == QEvent::TouchCancel)
{
p_event->ignore();
return true;
}
return false;
}
};
Then install it on the widget you want to ignore the touch events:
myWidget->installEventFilter(new QTouchEventFilter);
However, my instinct is that on most OS's the 'touches' you're talking about are going to come in as mouse press events, and you won't be able to filter them out unless you are willing to give up all mouse input for that widget. If you are willing, use the same concept but replace the QEvent's with the once associated with the mouse.

Related

Mouse right click option using eventFilter in Qt

I have QGraphicsView, which has many QGraphicsItem. I am trying to create a right click menu on these QGraphicsItem. Right click menu has multiple options. But only 1st option works. It means, if I click on 2nd option, it does not work. If I change the sequence ( means 1st one will go to 2nd position, and 2nd one will come to 1st position ) then still 2nd one will not work.
bool myClass::eventFilter(QObject *watched, QEvent *event)
{
switch(event->type())
{
case QEvent::ContextMenu:
{
foreach(QGraphicsItem* pItem, _scene->items())
{
if(pItem->isUnderMouse())
{
QMouseEvent *mouseEvent = static_cast<QMouseEvent*> (event);
menu = new QMenu(this);
myMenu = menu->addMenu("Copy");
myMenu ->addAction(Name);
myMenu ->addAction(Address);
if(Name == menu->exec(mouseEvent->globalPos()))
{
// logic
}
if(Address == menu->exec(mouseEvent->globalPos()))
{
// logic
}
}
}
}
}
Always works only 1st mouse right click option. Why is so ?
The usual way to do something like this is to override the QGraphicsItem::mouseReleaseEvent() or QGraphicsItem::mousePressEvent() function of your item class.
This way, you won't have to do anything (no looping, etc...), it is already handled by the event loop.
Here you can find a simple example:
void MyItem::mouseReleaseEvent(QGraphicsSceneMouseEvent * event)
{
if(event->button() == Qt::RightButton)
{
QMenu my_menu;
// Build your QMenu the way you want
my_menu.addAction(my_first_action);
my_menu.addAction(my_second_action);
//...
my_menu.exec(event->globalPos());
}
}
From the Qt documentation:
Note that all signals are emitted as usual. If you connect a QAction to a slot and call the menu's exec(), you get the result both via the signal-slot connection and in the return value of exec().
You just need to QObject::connect() the QActions you added to the context menu to the proper slots (here goes the "logic") and the job is done.
If you prefer to check the returned value by yourself, you just have to get the returned QAction* once and for all (only one call to QMenu::exec()) and branch on it.
For example:
void MyItem::mouseReleaseEvent(QGraphicsSceneMouseEvent * event)
{
if(event->button() == Qt::RightButton)
{
QMenu my_menu;
// Build your QMenu the way you want
my_menu.addAction(my_first_action);
my_menu.addAction(my_second_action);
//...
QAction * triggered = my_menu.exec(event->globalPos());
if(triggered == my_first_action)
{
// Do something
}
else if(triggered == my_second_action)
{
// Do some other thing
}
//...
}
}
I would personnally prefer to stick with the signal-slot connections instead that manually handling the returned value, especially since each QAction is most likely to be already connected to its corresponding slot.

uniquely identify a QQuickItem instance across app restart

Context:
We are developing an IDE for VR/AR effects editing. Users would like to have MACRO recording. Something similar to Selenim/AutoIT in spirit, but specific for this app with deep dataModel integration. Users are trained JS developers. Software GUI is Qt/QML (mostly qml)
Current Blocker
I need a way to uniquely identify a specific QQuickItem by its objectName:
across multiple restart of the app.
across platform (OS/Cpu/...)
name should be human readable enough for use in JS Macro
Should serialise enough information from QQuickItem/QEvent to post a valid event
It is acceptable to use CI static analysis to ensure all item have a valid unique name and detect name changes.
The problem here is some button, for instance the number buttons have exactly the same fqn/path/name unless I use and ugly hack, renaming it by the text of its sub-component:
Component.onCompleted: {
objectName = "button." + button.text
}
property bool keepObjectName: true
Here a fully qualified name based on metaObject()->className() is not enough, as it wont be unique. qml ids are not usable as per documentation.
Question: Is there a way in Qt to obtain such unique identifier?
Related Question:
Qt GUI event recording and playback
Abandoned Road:
print trace of signals/slots called
Reason: Most events in IDE do not use connect() the standard Qt way. Too Low level.
Draft Technical Solution / POC (mostly for reference)
https://doc.qt.io/qt-5/qtdoc-demos-calqlatr-example.html
Using the Qt QML calculator example here. Added this to main.cpp:
#include "Filter.h"
#include <unordered_map>
std::unordered_map<QString,QQuickItem*> map;
void install(QQuickItem* root, KeyPressEater* keyPressEater, const QString& fqn){
if(!root->property("keepObjectName").isValid() || !root->property("keepObjectName").value<bool>()){
qDebug("setObjectName: %s", root->metaObject()->className());
qDebug("Object original name:%s", root->objectName().toStdString().c_str());
root->setObjectName(root->metaObject()->className());
}
else{
qDebug("unchanged Object Name: %s", root->objectName().toStdString().c_str());
}
auto fqnRoot = fqn.isEmpty() ? root->objectName() : fqn + "." + root->objectName();
qDebug("Object fqn: %s", fqnRoot.toStdString().c_str());
root->installEventFilter(keyPressEater);
keyPressEater->insert(root,fqnRoot);
for(auto* child: root->childItems()){
QString fqn = fqnRoot + "." + child->metaObject()->className();
install(child, keyPressEater,fqnRoot);
}
qDebug("\n\n\n");
}
Filter.h looks like this:
#ifndef FILTER_H
#define FILTER_H
#include <QQuickItem>
#include <QtCore>
#include <unordered_map>
#include <QQuickItem>
class KeyPressEater : public QObject
{
Q_OBJECT
public:
void insert(QQuickItem* item,const QString& str){
if(map2.find(str) != map2.end())
{
qDebug("Duplicate object name:%s", str.toStdString().c_str());
}
else{
qDebug("Object name:%s", str.toStdString().c_str());
map.insert({item,str});
map2.insert({str,item});
}
}
void play(){
playing = true;
for(auto p: records){
//p.second->event(p.first);
QCoreApplication::postEvent(p.second, p.first);
QCoreApplication::sendPostedEvents();
}
playing = false;
}
protected:
bool eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::MouseButtonPress) {
//QMouseEvent *keyEvent = static_cast<QMouseEvent *>(event);
qDebug("click");
QQuickItem *item = static_cast<QQuickItem *>(obj);
qDebug("%s",map[item].toStdString().c_str());
qDebug("%s",item->metaObject()->className());
if(!playing){
records.push_back({event->clone(),item});
}
return false;
} else {
// standard event processing
if(event->type() == QEvent::KeyPress){
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if(keyEvent->key() == 32){
play();
}
}
return QObject::eventFilter(obj, event);
}
}
std::unordered_map<QQuickItem*,QString> map;
std::unordered_map<QString,QQuickItem*> map2;
std::atomic<bool> playing = false;
std::vector<std::pair<QEvent*,QObject*>> records;
};
#endif // FILTER_H
How to use:
Copy the above the main.cpp and new filter.h file in the calculator app example. Call install in main function:
install(view.rootObject(), &keyPressEater,"");

QFileDialog: How to select multiple files with touch-screen input?

In our application that uses Qt 4 and supports touch input, we use the QFileDialog with the options QFileDialog::DontUseNativeDialog and QFileDialog::ExistingFiles.
The first is needed because we set our own stylesheet and that does not work with the native dialog. The second is for needed for selecting multiple files, which is what we want to do.
The problem ist that one can not select multiple files with touch input in the QFileDialog, because we have no "shift" or "ctrl"-key available. In Windows the problem is solved by adding checkboxes to the items. QFileDialog has no checkboxes.
I tried to manipulate the QFileDialog to make it displays check boxes for the items, but I failed.
I tried to exchanged the QFileSystemModel that is used by the underlying QTreeView and QListView, but this breaks the signal-slot connections between the model and the dialog. I could not find a way to restore them because they are burried deep in the private intestants of the dialog.
At this moment the only solution I can imagine is writing a whole new dialog, but I would like to avoid the effort.
So is there a way to add checkboxes to the QFileDialog model views ?
Do you have another idea how selecting multiple files could be made possible?
Is the problem fixed in Qt 5? We want to update anyway.
Thank you for your Help.
As I failed to add checkboxes to the item views, I implemented a "hacky" work-around. It adds an extra checkable button to the dialog that acts as a "ctrl"-key. When the button is checked, multiple files can be selected. The solution is a little bit ugly, because it relies on knowing the internals of the dialog, but it does the job.
So here is the code for the header ...
// file touchfiledialog.h
/*
Event filter that is used to add a shift modifier to left mouse button events.
This is used as a helper class for the TouchFileDialog
*/
class EventFilterCtrlModifier : public QObject
{
Q_OBJECT;
bool addCtrlModifier;
public:
EventFilterCtrlModifier( QObject* parent);
void setAddCtrlModifier(bool b);
protected:
virtual bool eventFilter( QObject* watched, QEvent* e);
};
/*
TouchDialog adds the possibility to select multiple files with touch input to the QFileDialog.
This is done by adding an extra button which can be used as control key replacement.
*/
class QTOOLS_API TouchFileDialog : public QFileDialog
{
Q_OBJECT
EventFilterCtrlModifier* listViewEventFilter;
EventFilterCtrlModifier* treeViewEventFilter;
bool initialized;
public:
TouchFileDialog( QWidget* parent);
protected:
virtual void showEvent( QShowEvent* e);
private slots:
void activateCtrlModifier(bool b);
private:
void initObjectsForMultipleFileSelection();
};
with the implementation ...
// file touchfiledialog.cpp
#include "touchfiledialog.h"
EventFilterCtrlModifier::EventFilterCtrlModifier(QObject* parent)
: QObject(parent)
, addCtrlModifier(false)
{
}
void EventFilterCtrlModifier::setAddCtrlModifier(bool b)
{
addCtrlModifier = b;
}
bool EventFilterCtrlModifier::eventFilter(QObject* watched, QEvent* e)
{
QEvent::Type type = e->type();
if( type == QEvent::MouseButtonPress || type == QEvent::MouseButtonRelease)
{
if( addCtrlModifier)
{
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(e);
// Create and post a new event with ctrl modifier if the event does not already have one.
if( !mouseEvent->modifiers().testFlag(Qt::ControlModifier))
{
QMouseEvent* newEventWithModifier = new QMouseEvent(
type,
mouseEvent->pos(),
mouseEvent->globalPos(),
mouseEvent->button(),
mouseEvent->buttons(),
mouseEvent->modifiers() | Qt::ControlModifier
);
QCoreApplication::postEvent(watched, newEventWithModifier);
return true; // absorb the original event
}
}
}
return false;
}
//#######################################################################################
TouchFileDialog::TouchFileDialog(QWidget* parent)
: QFileDialog(parent)
, listViewEventFilter(NULL)
, treeViewEventFilter(NULL)
, initialized(false)
{
}
void TouchFileDialog::showEvent(QShowEvent* e)
{
// install objects that are needed for multiple file selection if needed
if( !initialized)
{
if( fileMode() == QFileDialog::ExistingFiles)
{
initObjectsForMultipleFileSelection();
}
initialized = true;
}
QFileDialog::showEvent(e);
}
void TouchFileDialog::initObjectsForMultipleFileSelection()
{
// install event filter to item views that are used to add ctrl modifiers to mouse events
listViewEventFilter = new EventFilterCtrlModifier(this);
QListView* listView = findChild<QListView*>();
listView->viewport()->installEventFilter(listViewEventFilter);
treeViewEventFilter = new EventFilterCtrlModifier(this);
QTreeView* treeView = findChild<QTreeView*>();
treeView->viewport()->installEventFilter(treeViewEventFilter);
QGridLayout* dialogLayout = static_cast<QGridLayout*>(layout()); // Ugly because it makes assumptions about the internals of the QFileDialog
QPushButton* pushButtonSelectMultiple = new QPushButton(this);
pushButtonSelectMultiple->setText(tr("Select multiple"));
pushButtonSelectMultiple->setCheckable(true);
connect( pushButtonSelectMultiple, SIGNAL(toggled(bool)), this, SLOT(activateCtrlModifier(bool)));
dialogLayout->addWidget(pushButtonSelectMultiple, 2, 0);
}
void ZFFileDialog::activateCtrlModifier(bool b)
{
listViewEventFilter->setAddCtrlModifier(b);
treeViewEventFilter->setAddCtrlModifier(b);
}
The TouchFileDialog installs an event filter to the item views that will add a ControlModifier to the mouse events of the views when the corresponging button in the dialog is checked.
Feel free to post other solutions, because this is somewhat improvised.

QGestures on ios

i am trying to use gestures on ios with qt like this:
#ifndef SWIPESTACKWIDGET_H
#define SWIPESTACKWIDGET_H
#include <QStackedWidget>
#include <QSwipeGesture>
class SwipeStackWidget : public QStackedWidget
{
Q_OBJECT
public:
explicit SwipeStackWidget(QWidget *parent = 0);
bool event(QEvent *event);
bool gestureEvent(QGestureEvent *event);
void swipeTriggered(QSwipeGesture *gesture);
signals:
public slots:
};
#endif // SWIPESTACKWIDGET_H
and
#include "swipestackwidget.h"
#include <QDebug>
SwipeStackWidget::SwipeStackWidget(QWidget *parent) :
QStackedWidget(parent)
{
setAttribute(Qt::WA_AcceptTouchEvents);
grabGesture(Qt::TapGesture);
grabGesture(Qt::TapAndHoldGesture);
grabGesture(Qt::PanGesture);
grabGesture(Qt::PinchGesture);
grabGesture(Qt::SwipeGesture);
}
bool SwipeStackWidget::event(QEvent *event)
{
if (event->type() == QEvent::Gesture)
return gestureEvent(static_cast<QGestureEvent*>(event));
return QWidget::event(event);
}
bool SwipeStackWidget::gestureEvent(QGestureEvent *event)
{
qDebug() << "gestureEvent():" << event->gestures().size();
if (QGesture *swipe = event->gesture(Qt::SwipeGesture))
swipeTriggered(static_cast<QSwipeGesture *>(swipe));
if (QGesture *pan = event->gesture(Qt::PanGesture))
qDebug() << "Pan";
if (QGesture *pinch = event->gesture(Qt::PinchGesture))
qDebug() << "Pinch";
if (QGesture *pinch = event->gesture(Qt::TapGesture))
qDebug() << "Tap";
if (QGesture *pinch = event->gesture(Qt::TapAndHoldGesture))
qDebug() << "Tapandhold";
return true;
}
void SwipeStackWidget::swipeTriggered(QSwipeGesture *gesture)
{
qDebug() << "swipeTriggered()";
if (gesture->state() == Qt::GestureFinished) {
if (gesture->horizontalDirection() == QSwipeGesture::Left) {
qDebug() << "swipeTriggered(): swipe to previous";
setCurrentIndex( std::max( 0, currentIndex()-1) );
} else if (gesture->horizontalDirection() == QSwipeGesture::Right) {
qDebug() << "swipeTriggered(): swipe to next";
setCurrentIndex( std::min( count()-1, currentIndex()+1) );
}
update();
}
}
I can compile the code and execute it on the iphone. I do recieve tab gestures and tabAndHold reliably. Pan and Pimch do occur sometimes. Swipe is a big problem:
It only appears with 3 fingers
It appears only when swiping to bottom or to the right
It appears only sometimes
Swiping to the bottom is sometime recognized as next, sometimes as left
Does anyone have experience with QGestures on ios an can help me?
My test class is directly used in the main window and i use the grabGestures command in the main window as well but i do not handle the gestures there.
I can confirm that it requires three fingers. I tested with PyQt, Qt5.3.1, on an iPad. (Also, pan requires two fingers.)
I suspect that Qt designed it that way, so it is the same across platforms (choosing the finger count that is common on Ubuntu, since Canonical may have contributed much of the code?)
In the iOS SDK, some of the base gesture classes are configurable for number of fingers and directions. Read more. Thats only relevant since it means Qt could easily have configured the native gestures Qt subscribes to, if they are subscribing to native gestures. You could look at Qt's code (for the iOS platform abstraction QPA and in their other gesture related code) to verify that they designed 3 fingers for a swipe (that it is not a bug.)
But the 3-finger swipe physical gesture in the upward direction on the iOS platforms should mean "hide the app and show the system tray"? (That's my experience, I can't quote the iOS HIG, and don't know what the App Store requires.) If so, then an app should subscribe to Qt's swipe gesture and follow the guidelines.
But you could also implement a recognizer in Qt for a one-finger swipe?

Irrlicht event for mouse wheel

I want to get the status for the mouse wheel or get triggered, when the user uses the mouse wheel.
I already have an event receiver like in the example(which is extending from IEventReceiver) but I cannot see / find a way for the mouse wheel.
Is there another receiver / event handler / solution?
class MyEventReceiver : public IEventReceiver {
public:
virtual bool OnEvent(const SEvent& event) {
if(event.EventType == irr::EET_MOUSE_INPUT_EVENT && event.MouseInput.Event == EMIE_MOUSE_WHEEL)
printf("%f\n", event.MouseInput.Wheel);
return false;
}
...
Check the Wheel public attribute of the SMouseInput event type
http://irrlicht.sourceforge.net/docu/structirr_1_1_s_event_1_1_s_mouse_input.html