Qt rightclick QPushButton - qt

I'm using Qt Creator to create a gui for a mineseeper game.
How can I know a QpushButton clicked with rightclick? for flag in the game.
In other word, which signal used for rightclick?

Create your own button with filter at mousePressEvent slot.
qrightclickbutton.h
#ifndef QRIGHTCLICKBUTTON_H
#define QRIGHTCLICKBUTTON_H
#include <QPushButton>
#include <QMouseEvent>
class QRightClickButton : public QPushButton
{
Q_OBJECT
public:
explicit QRightClickButton(QWidget *parent = 0);
private slots:
void mousePressEvent(QMouseEvent *e);
signals:
void rightClicked();
public slots:
};
#endif // QRIGHTCLICKBUTTON_H
qrightclickbutton.cpp
#include "qrightclickbutton.h"
QRightClickButton::QRightClickButton(QWidget *parent) :
QPushButton(parent)
{
}
void QRightClickButton::mousePressEvent(QMouseEvent *e)
{
if(e->button()==Qt::RightButton)
emit rightClicked();
}
Now connect like this
QRightClickButton *button = new QRightClickButton(this);
ui->gridLayout->addWidget(button);
connect(button, SIGNAL(rightClicked()), this, SLOT(onRightClicked()));
Create a slot in MainWindow.cpp.
void MainWindow::onRightClicked()
{
qDebug() << "User right clicked me";
}
It works for me!

I think QPushButton is internally implemented to listen to left mouse clicks only. But you can easily extend QPushButton and re-implement let's say the mouse release event and do your thing if the right mouse button was pressed, e.g. emit a custom rightClicked() signal for example:
signals:
void rightClicked();
protected:
void mouseReleaseEvent(QMouseEvent *e) {
if (e->button() == Qt::RightButton) emit rightClicked();
else if (e->button() == Qt::LeftButton) emit clicked();
}
... or you can create an overload of the clicked signal that forwards the mouseEvent pointer so you can do the same check outside of the button.
signals:
void clicked(QMouseEvent *);
protected:
void mouseReleaseEvent(QMouseEvent *e) {
emit clicked(e);
}
Then you do the check in the slot you connect the button's clicked(QMouseEvent *) signal to and proceed accordingly.

I just wrote this little helper adapter to make any existing button right-clickable with no need to subclass it:
class CRightClickEnabler : public QObject
{
public:
CRightClickEnabler(QAbstractButton * button): QObject(button), _button(button) {
button->installEventFilter(this);
};
protected:
inline bool eventFilter(QObject *watched, QEvent *event) override {
if (event->type() == QEvent::MouseButtonPress)
{
auto mouseEvent = (QMouseEvent*)event;
if (mouseEvent->button() == Qt::RightButton)
_button->click();
}
return false;
}
private:
QAbstractButton* _button;
};
Usage:
connect(ui->pushButton, &QPushButton::clicked, [](){qDebug() << "Button clicked";});
new CRightClickEnabler(ui->pushButton);
From now on, the clicked signal will be triggered by the right click as well as left click. There's no need to delete this object - it uses ui->pushButton as parent and will be auto-deleted by Qt when the parent is destroyed.
Obviously, you can write 2 lines of code (literally) to declare a new signal here and emit that signal upon right click instead of clicked, if desired.

I'd like to suggest this option as well, without need for event filter/other stuffs...
self.button.released.connect(self.doStuff)
self.button.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
self.button.customContextMenuRequested.connect(partial(self.doStuff, False))
def doStuff(self,state=True,p=QPoint()):
print("True for left, False for right!",state)

Related

How to connect to mousePressEvent slot Qt

In Class Buttons, I have a btnRightClicked signal and a mousePressEvent slot:
void Buttons::mousePressEvent(QMouseEvent *e)
{
if(e->button() == Qt::RightButton) {
emit btnRightClicked();
}
}
And in mainwindow.cpp, I connect the btnRightClicked signal to onRightClicked slot like this:
connect(&mButtons, SIGNAL(btnRightClicked()), this, SLOT(onRightClicked()));
The onRightClicked slot is like this:
void MainWindow::onRightClicked()
{
qDebug() << "right clicked";
}
But I ran this program, nothing happened. I guess the reason is because I did not connect to the mousePressEvent slot. I am kind of new to Qt, I do not know if I am right or not.
I set up some buttons on the central widget, I want them to have the right clicked event when right click each of them. So how can I make this work?Thanks
Edit:
in button.h:
class Buttons : public QObject
{
Q_OBJECT
public:
Buttons();
QVector<QPushButton*> buttons;
void setButtons(int totalBtns) {
for(int i = 0; i < totalBtns; i++) {
buttons[i]->setObjectName(QString::number(i));
buttons[i]->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
}
}
public slots:
void mousePressEvent(QMouseEvent *e) {
if(e->button() == Qt::RightButton) {
emit btnRightClicked();
}
}
signals:
void btnRightClicked();
};
To get the mouse right click on your widget, you need to implement your own button widget.
class MyButton : public QPushButton
{
Q_OBJECT
public:
MyButton(QWidget *parent = Q_NULLPTR);
private slots:
void mousePressEvent(QMouseEvent *e);
signals:
void btnRightClicked();
};
cpp
MyButton:MyButton(QWidget * parent) :
QPushButton(parent)
{
}
void MyButton::mousePressEvent(QMouseEvent *e)
{
if(e->button()==Qt::RightButton)
emit btnRightClicked();
//this forwards the event to the QPushButton
QPushButton::mousePressEvent(e);
}
In your buttons class change the button vector to
QVector<MyButton*> buttons;
Then register the right click event of your MyButton to your signal in Buttons class then forwared the signal to your mainWindow
connect(&mButtons, &Buttons::btnRightClicked,
this, &MainWindow::onRightClicked);

QLabel click event using Qt?

I'm new in Qt and have a question.
I have QLabel and QLineEdit objects, and when QLabel text is clicked on, I want to set this text in QLineEdit.
Also I have read that QLabel has not clicked signal.
Can you explain how can I do this and write code for me ?!
Either style another type of QWidget such as a specific QPushButton to look like a QLabel and use its clicked() signal or inherit QLabel yourself and emit your own clicked() signal.
See this example:
https://wiki.qt.io/Clickable_QLabel
If you choose the latter option you can pass the text in the signal. Then connect the necessary signals/slots up between the QLabel and the QLineEdit like so:
QObject::connect(&label, SIGNAL(clicked(const QString& text)),
&lineEdit, SLOT(setText(const QString& text)));
A simple way to accomplish that, without a need for any subclassing, is a signal source that monitors the events on some object and emits relevant signals:
// main.cpp - this is a single-file example
#include <QtWidgets>
class MouseButtonSignaler : public QObject {
Q_OBJECT
bool eventFilter(QObject * obj, QEvent * ev) Q_DECL_OVERRIDE {
if ((ev->type() == QEvent::MouseButtonPress
|| ev->type() == QEvent::MouseButtonRelease
|| ev->type() == QEvent::MouseButtonDblClick)
&& obj->isWidgetType())
emit mouseButtonEvent(static_cast<QWidget*>(obj),
static_cast<QMouseEvent*>(ev));
return false;
}
public:
Q_SIGNAL void mouseButtonEvent(QWidget *, QMouseEvent *);
MouseButtonSignaler(QObject * parent = 0) : QObject(parent) {}
void installOn(QWidget * widget) {
widget->installEventFilter(this);
}
};
The emit keyword is an empty macro, Qt defines it as follows:
#define emit
It is for use by humans as a documentation aid prefix only, the compiler and moc ignore it. As a documentation aid, it means: the following method call is a signal emission. The signals are simply methods whose implementation is generated for you by moc - that's why we have to #include "main.moc" below to include all the implementations that moc has generated for the object class(es) in this file. There's otherwise nothing special or magical to a signal. In this example, you could look in the build folder for a file called main.moc and see the implementation (definition) of void MouseButtonSignaler::mouseButtonEvent( .. ).
You can then install such a signaler on any number of widgets, such as a QLabel:
int main(int argc, char ** argv) {
QApplication app(argc, argv);
MouseButtonSignaler signaler;
QWidget w;
QVBoxLayout layout(&w);
QLabel label("text");
QLineEdit edit;
layout.addWidget(&label);
layout.addWidget(&edit);
signaler.installOn(&label);
QObject::connect(&signaler, &MouseButtonSignaler::mouseButtonEvent,
[&label, &edit](QWidget*, QMouseEvent * event) {
if (event->type() == QEvent::MouseButtonPress)
edit.setText(label.text());
});
w.show();
return app.exec();
}
#include "main.moc"
You need to create one Custom Label class, which will inherit QLabel. Then you can use MouseButtonRelease event to check clicking of Label and emit your custom signal and catch in one SLOT.
Your .h file will be as below:
class YourLabelClass : public QLabel{
signals:
void myLabelClicked(); // Signal to emit
public slots:
void slotLabelClicked(); // Slot which will consume signal
protected:
bool event(QEvent *myEvent); // This method will give all kind of events on Label Widget
};
In your .cpp file, your constructor will connect signal & slot as below :
YourLabelClass :: YourLabelClass(QWidget* parent) : QLabel(parent) {
connect(this, SIGNAL(myLabelClicked()), this, SLOT(slotLabelClicked()));
}
Remaining event method and SLOT method will be implemented as below:
bool YourLabelClass :: event(QEvent *myEvent)
{
switch(myEvent->type())
{
case(QEvent :: MouseButtonRelease): // Identify Mouse press Event
{
qDebug() << "Got Mouse Event";
emit myLabelClicked();
break;
}
}
return QWidget::event(myEvent);
}
void YourLabelClass :: slotLabelClicked() // Implementation of Slot which will consume signal
{
qDebug() << "Clicked Label";
}
For Changing a Text on QLineEdit, you need to create a Custom Class and share object pointer with custom QLabel Class. Please check test code at this link
In the above example the header needs Q_OBJECT:
class YourLabelClass : public QLabel{
Q_OBJECT
signals:

Cannot implement Drag and Drop for TextItem

this is my first try trying to use Drag&Drop feature of Qt. I'm a beginner, I made my first subclassing this week although I have made other 2 Qt programs in the past.
I need a movable by Drag&Drop QGraphicsTextItem to show on a QGraphicsView that is connected to the corresponding QGraphicScene. So I can retrieve the new position of the item.
I have looked at the animated robot example and this link: http://www.qtcentre.org/threads/50028-Drag-and-Drop-QGraphicsTextItem
The code of the link above, looked well for my. So I reimplemented it but when building, the compiler shows all kind of errors I´m not sure how to overcome. I don't know where to start, and don't know what piece of code is incorrect...
examples of errors appearing:
error: no matching function for call to 'GraphicsTextItem::setCursor(Qt::CursorShape)'
setCursor(Qt::OpenHandCursor);
^
error: invalid use of incomplete type 'class QGraphicsSceneDragDropEvent'
if(event->mimeData()->hasText())
^
error: forward declaration of 'class QGraphicsSceneDragDropEvent'
class QGraphicsSceneDragDropEvent;
^
I'll leave the code:
Header:
#ifndef GRAPHICSTEXTITEM_H
#define GRAPHICSTEXTITEM_H
#include <QGraphicsTextItem>
class GraphicsTextItem : public QGraphicsTextItem
{
Q_OBJECT
public:
GraphicsTextItem(QGraphicsItem *parent = 0);
protected:
void dragEnterEvent(QGraphicsSceneDragDropEvent *event);
void dragLeaveEvent(QGraphicsSceneDragDropEvent *event);
void dropEvent(QGraphicsSceneDragDropEvent *event);
void mousePressEvent(QGraphicsSceneMouseEvent *);
void mouseReleaseEvent(QGraphicsSceneMouseEvent *);
void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
private:
bool dragOver;
};
//! [0]
#endif // GRAPHICSTEXTITEM_H
and the Implementation:
#include <graphicstextitem.h>
#include <QDrag>
//#include <QGraphicsScene>
GraphicsTextItem::GraphicsTextItem(QGraphicsItem *parent)
:QGraphicsTextItem(parent)
{
//setFlag(QGraphicsItem::ItemIsSelectable);
setFlag(QGraphicsItem::ItemIsMovable);
setTextInteractionFlags(Qt::TextEditorInteraction);
setAcceptedMouseButtons(Qt::LeftButton);
setAcceptDrops(true);
setCursor(Qt::OpenHandCursor);
}
void GraphicsTextItem::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
{
if(event->mimeData()->hasText())
{
event->setAccepted(true);
update();
dragOver = true;
}
else
event->setAccepted(false);
}
void GraphicsTextItem::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
{
Q_UNUSED(event);
dragOver = false;
update();
}
void GraphicsTextItem::dropEvent(QGraphicsSceneDragDropEvent *event)
{
event->setAccepted(true);
//qDebug() << "I dropped it";
dragOver = false;
update();
}
void GraphicsTextItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
Q_UNUSED(event);
setCursor(Qt::ClosedHandCursor);
}
void GraphicsTextItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
if (QLineF(event->screenPos(), event->buttonDownScreenPos(Qt::LeftButton)).length()
< QApplication::startDragDistance())
return;
QDrag *drag = new QDrag(event->widget());
QMimeData *mime = new QMimeData;
mime->setText(this->toPlainText());
drag->setMimeData(mime);
drag->exec();
setCursor(Qt::OpenHandCursor);
}
void GraphicsTextItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
Q_UNUSED(event);
setCursor(Qt::OpenHandCursor);
}
The error message is telling you that there is a forward declaration somewhere in your code, although that is not true based on the code you have shown so far.
Either way, for accessingt members of your heap object, you need more than just forward declaration. You are missing this include:
#include <QGraphicsSceneDragDropEvent>

QLineEdit mouseEnter() and mouseExit() events

I want to subclass QLineEdit to add it some signals like mouseEnter() and mouseExit() to become informed when the mouse courser is over the widget and when leaves it.
I could write mouseEnter() like below.
class MyLineEdit:public QLineEdit{
//
// ..
//
protected:
void mouseMoveEvent(QMouseEvent *e);
signals:
void mouseEnter();
}
void MyLineEdit::mouseMoveEvent(QMouseEvent *e)
{
emit mouseEnter();
QLineEdit::mouseMoveEvent(e);
}
It works correctly.
How can I write mouseExit()?
leaveEvent is not a very good name!
#include <QtGui>
#include <QEvent>
class Editor : public QLineEdit
{
Q_OBJECT
public:
void leaveEvent(QEvent *);
signals:
void mouseLeave();
};
void Editor::leaveEvent(QEvent *e);
{
qDebug() << "Mouse has left the building..";
emit mouseLeave();
}

MousePressEvent in view and items in Qt

I have a custom QGraphicsView and a custom QGraphicsItem. I want the Item to handle my click if I click in the item, else I want the click to be handled by the View.
But when I click on the item, the item handles the click. This is ok. But if I click somewhere else the click isn't handled at all. All the code in my classes that have anything to do with mouseEvents is below.
class CustomView : public QGraphicsView
{
Q_OBJECT
public:
void mousePressEvent(QGraphicsSceneMouseEvent *event);
};
void CustomView::mousePressEvent(QGraphicsSceneMouseEvent *event){
cout << "pressing in view";
}
class CustomItem : public QGraphicsItem
{
public:
CustomItem(CustomView* widget)
void mousePressEvent(QGraphicsSceneMouseEvent *event);
};
CustomItem::CustomItem(CustomView* widget){
setFlag(ItemIsSelectable);
setFlag(ItemIsMovable);
}
void CustomItem::mousePressEvent(QGraphicsSceneMouseEvent *event){
cout << "pressing in item";
}
It seems that when I remove the mousePressEvent function from the CustomItem class and change in the CustomView the mousePressEvent function to:
void CustomView::mousePressEvent(QMouseEvent *event){
cout << "pressing in view";
}
the CustomView handles all the mouseEvents.
How can I let the CustomItem handles the clicks in the items and the CustomView handle all the other clicks?
Thank you.
EDIT
So now I have changed it to:
class CustomView : public QGraphicsView
{
Q_OBJECT
public:
};
class CustomScene : public QGraphicsScene
{
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event);
};
void CustomScene::mousePressEvent(QGraphicsSceneMouseEvent *event){
cout << "pressing in scene";
}
class CustomItem : public QGraphicsItem
{
public:
CustomItem(CustomView* widget)
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event);
};
CustomItem::CustomItem(CustomView* widget){
setFlag(ItemIsSelectable);
setFlag(ItemIsMovable);
}
void CustomItem::mousePressEvent(QGraphicsSceneMouseEvent *event){
cout << "pressing in item";
}
A Click in the scene but not in an item get handled by the scene. But clicks in the items
dont get handled by the items itself, instead it get handled by the scene. Unless if you click 2 times really fast on the items it gets handled by the scene and the item.
Any ideas?
QGraphicsView isn't really a good place to handle scene-specific events. Instead, you'll need to override QGraphicsScene::mousePressEvent. I would recommend something like this:
void CustomScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
if (itemAt(event) == NULL)
{
// do stuff if not clicked on an item
}
else
{
QGraphicsScene::mousePressEvent(event); // this forwards the event to the item
}
}
Note that QGraphicsScene::itemAt might give you difficulties if you have items with the ItemIgnoresTransformations flag set to true. Look to the docs for QGraphicsScene::itemAt for how to resolve this.

Resources