PDA

View Full Version : Working with mouse events: How to do that with QTableWidget?



robgeek
10th September 2015, 16:58
Hello!

I'm trying to make a QTableWidget shows me different things when i click(one click) on a cell with the right button and when i click with left button. I'm using QtCreator-3.4.2 and when i click on QTableWidget and "Go To Slot" i can use only "cellClicked(int, int)". It works when i click with left button, but i don't know how to do the same thing with the right button. I know there is QMouseEvent, but i don't know how to use now because i'm already using "cellClicked".

How can i do that?
Thanks!

prasad_N
10th September 2015, 17:22
You can implement mousePressEvent for table widget & have a flag there to get to know whether it is left click or right click event.


void tablewidget::mousePressEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton)
m_isLeftClick = true; // bool m_isLeftClick; is class member
else if (event->button() == Qt::RightButton)
m_isLeftClick = false;
}

then in your slot check whether it is left click or right click

d_stranz
10th September 2015, 18:35
How can i do that?

prasad_N's solution requires you to derive your own class from QTableWidget and override mousePressEvent. The alternative is to use the out-of-the-box QTableWidget and install an event filter on it that you monitor from some other class (like your main window that owns the table widget).

You probably don't want to use only mousePressEvent() for this anyway. I would use the mousePressEvent / mouseReleaseEvent as a pair, for the following reason: If the user presses the mouse in your table widget, it automatically triggers your action. This means there is no way for the user to say, oops, I didn't mean to do that - I clicked accidently. In most other mouse click scenarios, the action isn't triggered unless the mouse press and mouse release both occur in the same window. Mouse press sets a flag, mouse release does the action if and only if the flag is set. This avoids things like clicking in the window and then moving out of it to release (a common way to "escape" out of doing something you didn't intend) or clicking outside the window and moving into it to release. If you only watched for one or the other event, your app would almost certainly have unintended consequences where something is performed that the user didn't want.

Be careful using right mouse press events if you also use context menus.

robgeek
10th September 2015, 23:17
Thanks for your help! I tried to make a test program with a qtablewidget, but did not work! I created an UI with a QWidget a
I created a derived class from QTableWidget and override mousePressedEvent. When i click on the table nothing happens. I believe this is happening because i didn't call mousePressedEvent anywhere, but i don't know where to call it.

Take a look at the code, please. What is wrong?


#ifndef TESTEVT_H
#define TESTEVT_H

#include <iostream>
#include <QMouseEvent>
#include <QTableWidget>

using namespace std;

class TestEvt : public QTableWidget {

public:
TestEvt( );
virtual void mousePressEvent(QMouseEvent *event);
};

#endif // TESTEVT_H

#include "testevt.h"

TestEvt::TestEvt( ) {
cout << "Object created." << endl;
}

void TestEvt::mousePressEvent(QMouseEvent *event) {
if(event->button( ) == Qt::LeftButton)
cout << "Left Button Clicked." << endl;
}

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow {
Q_OBJECT

public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow( );

private:
Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

#include "mainwindow.h"
#include "testevt.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) : QMainWindow( parent ), ui(new Ui::MainWindow) {
ui->setupUi( this );
TestEvt evt;
}

MainWindow::~MainWindow( ) {
delete ui;
}

anda_skoa
11th September 2015, 06:48
You need to pass the even on to the implementation that QTableWidget was using before you overwrote it, i.e. calling the base class implementation either before or after you do you custom handling.

Cheers,
_

prasad_N
11th September 2015, 07:39
When i click on the table nothing happens. I believe this is happening because i didn't call mousePressedEvent anywhere
first of all you can n't see table, because you are creating table on stack. create it on heap (TestEvt* eve = new TestEvt (this)) or have it as class member.


but i don't know where to call it.
You don't need to cal this explicitly, when you click on table mousePressEvent will be called automatically.

changes I can suggest you is:


class TestEvt : public QTableWidget {

public:
TestEvt(QWidget* parent ):QTableWidget(parent) {}
virtual void mousePressEvent(QMouseEvent *event) {
if(event->button( ) == Qt::LeftButton)
qDebug() << "Left Button Clicked.";
QTableWidget::mousePressEvent(event); // call base class implementation
}
};



MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);

TestEvt* eve = new TestEvt(this); //create instance on heap

}


Note: you may not see table widget fully here, please use layout in order to fit table widget in you main window.

Added after 41 minutes:


I would use the mousePressEvent / mouseReleaseEvent as a pair, for the following reason: If the user presses the mouse in your table widget, it automatically triggers your action. This means there is no way for the user to say, oops, I didn't mean to do that - I clicked accidently. In most other mouse click scenarios, the action isn't triggered unless the mouse press and mouse release both occur in the same window. Mouse press sets a flag, mouse release does the action if and only if the flag is set. This avoids things like clicking in the window and then moving out of it to release (a common way to "escape" out of doing something you didn't intend) or clicking outside the window and moving into it to release. If you only watched for one or the other event, your app would almost certainly have unintended consequences where something is performed that the user didn't want.

Be careful using right mouse press events if you also use context menus.

informative, Thanks a lot.

robgeek
11th September 2015, 17:09
I did what you said and worked fine. The only problem was the table was created above the one i created using "Design". The new one i don't know how to configure the size and position using Design, i believe i have to do that in TestEvt class since she is derived from QTableWidget.

Yesterday i tried one thing i saw in a video from youtube. I tried to do the same thing, but instead creating TestEvt on heap i created on stack "TestEvt evt;" and promoted the table i created with Desing to "TestEvt". Yesterday worked fine, but today i tried it again, and i'm getting the following error message:

/usr/include/qt/QtCore/qobject.h:135: error: 'void QObject::setObjectName(const QString&)' is inaccessible
void setObjectName(const QString &name);
^

/home/rob/Programming/C-C++/Linux/Qt/build-Test-Desktop-Debug/ui_mainwindow.h:37: error: within this context
histTable->setObjectName(QStringLiteral("histTable"));
^

/home/rob/Programming/C-C++/Linux/Qt/build-Test-Desktop-Debug/ui_mainwindow.h:37: error: 'QObject' is not an accessible base of 'TestEvt'

/usr/include/qt/QtWidgets/qwidget.h:481: error: 'void QWidget::setGeometry(const QRect&)' is inaccessible
void setGeometry(const QRect &);
^

/home/rob/Programming/C-C++/Linux/Qt/build-Test-Desktop-Debug/ui_mainwindow.h:38: error: within this context
histTable->setGeometry(QRect(10, 10, 381, 281));
^

/home/rob/Programming/C-C++/Linux/Qt/build-Test-Desktop-Debug/ui_mainwindow.h:38: error: 'QWidget' is not an accessible base of 'TestEvt'

anda_skoa
11th September 2015, 17:15
I tried to do the same thing, but instead creating TestEvt on heap i created on stack "TestEvt evt;" and promoted the table i created with Desing to "TestEvt".

When you promote a widget in designer you don't have to create an instance yourself at all.
The code generated from designer's ui file will contain an instantiation of the promoted class.



Yesterday worked fine, but today i tried it again, and i'm getting the following error message:
That sounds like you are no longer publically inheriting from QTableView.

Cheers,
_

robgeek
11th September 2015, 17:38
That sounds like you are no longer publically inheriting from QTableView.
Thanks! I put "public" before QTableWidget and now everything is working fine!

class TestEvt : public QTableWidget {...

Which one do you thing is more correct? Promote my table or do like prasad_N did.

robgeek
11th September 2015, 23:00
Now i'm getting another weird problem! Sorry bother you, guys! Is another problem, but with my QTableWidget, that's why i did'nt create another topic.

I'm trying to get the row and column number when i click in a certain cell, but to see the correct output, i have to click in the same line ten times, maybe more, then the output changes to the correct row number. Why this is happening? Whith the following code, i'm trying to get e correct line and column of a certain cell when click on it.


void Table::mousePressEvent(QMouseEvent *event) {
if(event->button() == Qt::LeftButton) {
cout << "(" << this->currentRow( ) << ", " << this->currentColumn( ) << ")" << endl;
}
}

Considering i promoted my QTableWidget to "TestEvt" which is derived from QTableWidget. I did that to reimplement "mousePressEvent()" in "TestEvt" class.

anda_skoa
12th September 2015, 10:01
Which one do you thing is more correct? Promote my table or do like prasad_N did.

Both are equally correct, the promotion option is just more convenient.



void Table::mousePressEvent(QMouseEvent *event) {
if(event->button() == Qt::LeftButton) {
cout << "(" << this->currentRow( ) << ", " << this->currentColumn( ) << ")" << endl;
}
}


If that is your actual code then you are forgetting to call the base class implementation of mousePressEvent().

Cheers,
_

robgeek
12th September 2015, 14:56
If that is your actual code then you are forgetting to call the base class implementation of mousePressEvent().

Sorry, i didn't understand! All code examples i saw look alike my code. How can i do that?

Here, my "guide". (http://www.codeprogress.com/cpp/libraries/qt/qtClasses.php?item=QMouseEvent)

d_stranz
12th September 2015, 16:44
Here, my "guide".

If you are relying on that as your "guide", no wonder you are lost in the wilderness. In just one example I looked at, I saw at least three errors.

This should be your guide instead. (http://doc.qt.io/qt-5/eventsandfilters.html) Pay close attention to what it says about overriding vs. extending event behavior as well as what it says about return values for the basic QObject::event() method.

robgeek
13th September 2015, 02:06
I really don't know anymore if is an event problem or what, because my code works "fine", i just have to click many times on a cell to get the correct value of (line, column).
I tried to change my code of post #11, i don't know if is what anda_skoa said, but i got the same problem. Nothing changed.


void Table::mousePressEvent(QMouseEvent *event) {
if(event->button( ) == Qt::LeftButton) {
cout << "(" << this->currentRow( ) << ", " << this->currentColumn( ) << ")" << endl;
}
else {
QWidget::mousePressEvent( event );
}
}

d_stranz
13th September 2015, 17:21
The problem is likely that you never let the table widget do anything with the mouse press event when it is a left press. The events don't magically get passed up the line unless you call QTableWidget:: mousePressEvent() in addition to whatever you do with it.

You are also calling QWidget's mousePressEvent() handler instead of the superclass of your own Table class (presumably QTableWidget) which bypasses the QTableWidget's handling of any other mousePressEvent. So it is no wonder your table widget isn't working properly - you've completely prevented it from seeing any mouse press events at all.

So in the code you posted last, there's no correct current row or current column, because you haven't let the table widget see the mouse press event before your code swallows it and eats it.

Try this instead:



void Table::mousePressEvent(QMouseEvent *event)
{
QTableWidget::mousePressEvent( event );
if(event->button( ) == Qt::LeftButton)
{
cout << "(" << this->currentRow( ) << ", " << this->currentColumn( ) << ")" << endl;
}
}

robgeek
13th September 2015, 20:07
Now is working fine. Thanks a lot!