I am writing an application for arm board. I have a mainwindow and I need to get the touch co-ordinates for single touch. Due to lack of Qt knowledge I am facing a problem of getting the touch event.
As per the QTouchEvent Class document, I have declared a slot as below.
#include <QTouchEvent>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(int x, int y, QWidget *parent = 0);
public slots:
void touchEvent(QTouchEvent *ev);
};
and in mainwindow.cpp I redefine it as below. The FFLabel[1] is already declared by me and I am writing it to confirm if the event is received.
void MainWindow::touchEvent(QTouchEvent *ev)
{
ui->FFLabel[1]->setText(QString("Event"));
switch (ev->type())
{
case QEvent::TouchBegin:
case QEvent::TouchEnd:
case QEvent::TouchUpdate:
{
}
}
}
I am not able to get the touchEvent. Can someone please help me.
I have verified the /dev/input/event2 and am receiving the event there.
QWidget has a number of protected virtual members, e.g., QWidget::mousePressEvent. They are called when the event occurs.
Usually one overrides such a function to run some code when a certain event happens.
The problem is, that, unlike for mouse press, there is no such virtual function QWidget::touchEvent (as of Qt 5.12). That is, you can't override it and it cannot be called when a touch event happens as QWidget is not aware of such a method.
C++11 introduced the override-keyword. If you had used it, you would have noticed that issue.
In order to receive touch events, you must override the more general QWidget::event method. Then filter for the events you're actually interested in:
bool MainWindow::event(QEvent* event)
{
switch (event->type()) {
case QEvent::TouchBegin:
qDebug() << "touch!";
return true;
default:
// call base implementation
return QMainWindow::event(event);
}
}
Note that you must state setAttribute(Qt::WA_AcceptTouchEvents); in order to receive any touch events (put it in the MainWindow-constructor).
You can read more details in the docs.
Events aren't slots. Declare it as a protected function.
protected:
void touchEvent(QTouchEvent *ev);
Edit: And you didn't put anything in your switch statement to show if you get the event.
void MainWindow::touchEvent(QTouchEvent *ev)
{
switch (ev->type())
{
case QEvent::TouchBegin:
ui->FFLabel[1]->setText("Event began.");
break;
case QEvent::TouchEnd:
ui->FFLabel[1]->setText("Event ended.");
break;
case QEvent::TouchUpdate:
{
ui->FFLabel[1]->setText("Event updated.");
break;
}
}
}
Edit: If it's still not working, it means your mainwindow isn't accepting touch events. You need to do this in your mainwindow's constructor:
setAttribute(Qt::WA_AcceptTouchEvents, true);
Disclaimer:
I had a similar issue and this is not a solution but may be a workaround depending on what you want to do.
In my case, the touch events were interpreted as mouse events so, MainWindow::touchEvent was never called but, the mouse events handler were.
I used MainWindow::mousePressEvent to get the touch point and MainWindow::mouseMoveEvent to get the drag.
This does not handle the multi-touch (it works for the separate contact points but you will have only one move event for all your points)
From Qt5.4, one may try (I didn't test as I'm stuck with Qt4), in the mouse events handler, to check the MouseEventSource If it's MouseEventSynthesizedBySystem it means from the documentation that:
the mouse event was synthesized from a touch event by the platform.
One can find more details checking this solution provided by Chirag Sachdeva in this post
And of course, with regards to the OP code, as user4516901 said, events aren't slots.
Related
I have a mainwindow which in there is a Qtableview by clicking on insert record I go to other modal windows to add record when I add record and close the second windows I come back to main windows but the qtableview doesn't show the new record that is added. The record is in database.
I already make this somehow work with :
void MainWindow::showEvent( QShowEvent* event ) {
QWidget::showEvent( event );
updTbl();
}
But it only works when windows get minimized.
QMainWindow has also two event handler from QWidget
void QWidget::focusInEvent(QFocusEvent *event)
void QWidget::focusOutEvent(QFocusEvent *event)
If you use QtCreator, go to your mainwindow.h and search the line "class MainWindow : public QMainWindow". Right click on QMainWindow -> Refactoring -> Insert virtual function. That's an easy way to find which virtual functions exist and that can be overloaded, you can select focusInEvent and focusOutEvent from there.
Handling activate/deactivate events as follows will give you the desired behaviour
// overloading event(QEvent*) method of QMainWindow
bool MainWindow::event(QEvent* e)
{
switch (e->type())
{
case QEvent::WindowActivate:
// gained focus
//Update Table
break;
case QEvent::WindowDeactivate:
// lost focus
break;
};
return QMainWindow::event(e);
}
Ref: https://gist.github.com/01walid/2276009
Is there a way to connect signal and slot without using connect function?
If a way exists, please give some examples.
Nope, there is no other way, not in the public API at least. In Qt4 there is only the connect() function with the SIGNAL() and SLOT macro().
In Qt5 you have another, type-safe connection syntax, but it still uses the connect() function. And in QML you can use "attached handlers" - onSignal: doStuff() - but that's just for QML.
There is a way to use the meta-call interface to avoid using the connect() function. Depending on what you precisely need to do though this may not be the solution you are looking for, or it may be.
You essentially define a callback slot function in your QOBJECT class with a certain syntax and let the MOC sort the 'connection' out.
So say you wanted to use:
connect(ui->actionButton, SIGNAL(triggered()), this, SLOT(someCallbackSlot()));
but without having to use the callback function...
You can do it implicitly with a particular syntax of a member function in the QOBJECT who receives the signal:
class MyQtObj : public QWidget
{
QObject
private slots:
void on_actionButton_triggered();
}
Where on_actionButton_triggered is the functional equivalent of someCallbackSlot(), actionButton is the name of the button/action/signal emitter and triggered() is the signal emitted.
So any of these functions are valid providing the signal emitter is correct:
void on_minimizedButton_clicked();
void on_closeButton_released();
etc
When you run the Qt Meta-Object-Compiler and generate your moc_.cpp file of this class there will be a function called qt_static_metacall; this contains a switch statement that looks like :
void MyQtObj::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
MyQtObj*_t = static_cast<MyQtObj*>(_o);
Q_UNUSED(_t)
switch (_id) {
case 0: _t->on_actionButton_triggered(); break;
default: ;
}
}
}
If you put a break point in this and trigger your action/button/signal you should see your function get executed.
I'm not too sure of the details of how this works though and I noticed it when I used this frame-less Qt window code and have now adopted it in my own Qt C++ projects.
I wanted to do some action when a dialog shows when it opens or when it maximizes from a minimal status or it moves from out of a screen.
Does QT have such a signal?
I am also not sure where to find if QT has a list of signals defined.
Does each QT widget have a 'show' signal?
If you look at Qt source code then you will find QWidget::show to be a slot:
public Q_SLOTS:
// Widget management functions
virtual void setVisible(bool visible);
void setHidden(bool hidden);
void show();
The slot is mainly for us, programmers to make us able to connect with signals for specific purposes like clicking the button we created does something to certain widget. As for Windows or Mac OS, we have the app serving all the events coming from the system via event loop. And QWidget reacts on all the 'signals' in the form of system events coming and yes, may, execute show() or showMaximized() or showMinimized slots then.
But I can assume you want to overload
virtual void showEvent(QShowEvent *);
virtual void hideEvent(QHideEvent *);
Like:
void MyWidget::showEvent(QShowEvent *e)
{
if (isMaximized())
{
if (e->spontaneous())
{
// the author would like to know
// if the event is issued by the system
}
; // the action for maximized
}
else
{
; // the action for normal show
}
}
void MyWidget::hideEvent(QHideEvent *)
{
if (isMinimized())
{
; // the action for minimized
}
else
{
; // the action for hide
}
}
For recognizing cases when the system operates the widget we can use QEvent::spontaneous().
Please also refer to show and hide event doc pages:
http://doc.qt.io/qt-5/qshowevent-members.html
http://doc.qt.io/qt-5/qhideevent.html
I'm implementing a class that inherits the QTreeWidget,
I'm trying to do something only when the user left-clicks on an item.
Since itemDoubleClicked only gives you the item and not the mouse event,
and mouseDoubleClickEvent only gives you the mouse event with no item,
so I thought I would add a member in the class and record whether left or right button was pressed in mouseDoubleClickEvent,
then check that info when entering the slot connected to signal itemDoubleClicked.
That is, if the signal is emitted after the event handler. I was planning on experimenting if this was true, but then I ran into this issue.
Ok, back to the class, it looks something like this:
class myTreeWidget : public QTreeWidget{
Q_OBJECT
private:
Qt::MouseButton m_button;
public:
myTreeWidget(QWidget* parent):QTreeWidget(parent){
m_button = Qt::NoButton;
connect(this, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)),
this, SLOT(slot_doubleClick(QTreeWidgetItem*,int)));
}
void mouseDoubleClickEvent(QMouseEvent* event){
m_button = event->button();
}
public slots:
void slot_doubleClick(QTreeWidgetItem* item, int column);
signals:
void itemDoubleClicked(QTreeWidgetItem* item, int column);
}
Yep, something like this.
Then I used gdb to check which was called first,
mouseDoubleClickEvent or slot_doubleClick,
and it turns out that slot_doubleClick was not called at all.
I commented out mouseDoubleClickEvent and tried again,
and slot_doubleClick was called.
So um... what I'm asking here is...
is this a limitation in Qt?
Can I only choose one between signals&slots and event handlers?
Or am I just doing it wrong?
Moreover, if this is a limitation,
can you recommend another solution to what I'm trying to do?
(only respond to left double-clicks)
Sorry for the long post and thanks!
If you override some event handler and want also default behavior, you should call base handler implementation. For example try this:
void mouseDoubleClickEvent(QMouseEvent* event){
m_button = event->button();
QTreeWidget::mouseDoubleClickEvent(event);
}
I use MarbleWidget with OpenStreetMap on Qt.
Wheel zoom shows blurry images on the map. Therefore, I want to synchronize the mouse wheel with ZoomIn() and ZoomOut() inorder user to get sharp images on the map.
I want to do something like this:
QObject::connect( MarbleWidget, SIGNAL(??????), this, SLOT(wheelEvent(wheelEvent)) );
void MainWindow::wheelEvent(QWheelEvent *event){
//....
}
Is there any signal or event that I can use from MarbleWidget for ??????? above line?
And, how can I disable the mouse zoom on the MarbleWidget?
You can make your own input handler and tell MarbleWidget to use it. This will allow you to intercept mouse wheel events in the way you are asking.
Create a custom input handler
MarbleWidget uses a default input handler. Inside of MarbleInputHandler.cpp there is a function eventFilter(QObject*, QEvent*) that handles (among other things) the QEvent::Wheel event. Derive from this class and override eventFilter:
class MyMarbleInputHandler : public MarbleWidgetDefaultInputHandler
{
Q_OBJECT
public:
explicit MyMarbleInputHandler(MarbleWidget* mw) :
MarbleWidgetDefaultInputHandler(mw) {}
virtual bool eventFilter(QObject *o, QEvent *e);
signals:
void wheelEvent(QWheelEvent *event);
};
Basically, you want to intercept QEvent::Wheel and emit your own signal. Anything you don't handle yourself should be passed along to the base class.
bool MyMarbleInputHandler::eventFilter(QObject *o, QEvent *e)
{
if (e->type() == QEvent::Wheel)
{
emit wheelEvent(static_cast<QWheelEvent*>(e));
return true;
}
return MarbleWidgetDefaultInputHandler::eventFilter(o, e);
}
Create a custom MarbleWidget
The constructor below shows how you can set the input handler defined above. You'll also have to wire the signal/slot.
class MyMarbleWidget : public MarbleWidget
{
Q_OBJECT
public:
explicit MyMarbleWidget()
{
MyMarbleInputHandler *myMarbleInputHandler = new MyMarbleInputHandler(this);
setInputHandler(myMarbleInputHandler);
connect(myMarbleInputHandler, SIGNAL(wheelEvent(QWheelEvent*)),
this, SLOT(handleWheelEvent(QWheelEvent*)));
}
public slots:
void handleWheelEvent(QWheelEvent *event)
{
if (event->delta() > 0) zoomIn();
else zoomOut();
}
};
handleWheelEvent() provides the code to zoom in/out. Not all scroll wheels work the same, so you'll have to figure out how much movement of the mouse wheel it will take to zoom in/out by one step. In this example, it zooms in/out one step based on each event, paying attention only to the sign of delta() and ignoring its magnitude.
You might also check out MarbleDefaultInputHandler::handleWheel() to see what's going on with the default behavior. They use interpolated/stretched bitmap images between vector layers to provide a smoother animation when zooming. Note that the plus+ and minus- keys on the keyboard will allow you to zoom to non-interpolated map levels, whereas the mouse wheel zooms using animated ("blurry") interpolated layers. This behavior is documented in a bug report.