What does the documentation say
QPushButton has a clicked() signal so one can do something like this
connect(ui->Btn,SIGNAL(clicked()),this,SLOT(DoSmth()));
QLineEdit has a textEdited() signal that allows to track the edit action.
What I am trying to achieve
I'm trying to run a function when a QLineEdit was just clicked on, not edited. Is that possible?
You can subclass QLineEdit and reimplement QWidget::focusInEvent, where you can check if the reason of the focus was mouse click. Then use this subclass instead of QLineEdit. You may create a custom signal and emit it from this event handler too to be able to use it through signal/slots.
#include <QLineEdit>
#include <QFocusEvent>
class FocusHandlerLineEdit : public QLineEdit
{
Q_OBJECT
protected:
void focusInEvent(QFocusEvent * event) {
QLineEdit::focusInEvent(event);
if(event->reason() == Qt::MouseFocusReason)
emit gotFocus();
}
signals:
void gotFocus();
};
Related
I am a beginner in Qt and I would like to know, how can I create an event which checks when a button in the windows gets clicked? The window has a single push button.
I could not find a simple and correct example for my question, that's why I am asking here. I did google first.
Thank you
class MyClass : public QWidget
{
public:
MyClass ()
{
QPushButton *pButton = new QPushButton(this);
QObject::connect(pButton, &QPushButton::clicked, this, &MyClass::onButtonClicked);
}
public slots:
void onButtonClicked () {qDebug () << "Button clicked";};
};
onButtonClicked will be called if the button pressed.
Please see signals & slots and QPushButton signals for more information.
Qt employs the signals and slots paradigm. You don't check if a button is clicked. When a button is clicked, it emits a signal. You can connect your own functions to that signal. So whenever that button is clicked, the signal is emitted, and triggers all the functions it is connected to.
Be sure to check out signals and slots, which is a core concept of Qt, along with properties and meta data.
Note that as a QWidget derived, a button comes with the following methods, which are triggered by mouse events and you can override them if you wish, although in the case of something as a button that is hardly necessary:
virtual void mouseDoubleClickEvent(QMouseEvent * event)
virtual void mouseMoveEvent(QMouseEvent * event)
virtual void mousePressEvent(QMouseEvent * event)
virtual void mouseReleaseEvent(QMouseEvent * event)
EDIT and Some Self Critisicm
I tried both given solutions, which both solved my problem, and thus I thank you both! I marked the transparent solution as accepted because I thought it is was the easiest implementation when I only had one child widget, but I wish to share some insight for other beginners:
I first used QLabel, which apperently has enabled Qt::WA_TransparentForMouseEvents by default and thus obviously worked, but I also wanted the text to be selectable, by using QPlainTextEdit instead. Laughably, this is not possible in any way, because if you try to select the text (by clicking) you will close the window! I ended up keeping the transparancy, and neglecting the select-text-feature.
I'm guessing my following question has been answered somewhere before, but after an hour of searching I now post the question myself. I'm grateful if someone can point me to an already answered question that solves my problem.
Anyhow, I'm creating a popup window, using C++ and Qt. I've created the following PopupDialog class which works well and fine for all its purposes. However, I've removed its frame (including the bar containing the close button and window title) to make it look minimalistic, and now I want it to close if the user presses/releases the mouse button anywhere inside the popup window (dialog).
The below code works, however in such a way that I have to click and release the mouse exactly at the QDialog-window itself. It will not close when i click if the mouse hovers over the child widget(s) inside the QDialog, e.g. a QPlainTextEdit, which is displaying text.
Hence, I'm in need of a solution for QDialog to recognize QMouseEvents inside its child widgets. Please, don't hesitate to ask if something is unclear. I have not included my mainwindow.h/.cpp files, or popupdialog.ui file since I believe it would be a little too much to post here, but the .ui extremely simple: Just the QDialog window holding a QBoxLayout, containing a single widget, a QPlainTextEdit. I may posts these on request if it helps.
// popupdialog.h
#ifndef POPUPDIALOG_H
#define POPUPDIALOG_H
#include <QDialog>
#include <QString>
namespace Ui {class PopupDialog;}
class PopupDialog : public QDialog
{
Q_OBJECT
public:
explicit PopupDialog(QWidget *parent = 0, QString msgTxt="");
~PopupDialog();
private:
Ui::PopupDialog *ui;
QString messageText;
void mouseReleaseEvent(QMouseEvent*);
};
#endif //POPUPDIALOG_H
...
// popupdialog.cpp
#include "popupdialog.h"
#include "ui_popupdialog.h"
PopupDialog::PopupDialog(QWidget *parent, QString msgTxt) :
QDialog(parent),
ui(new Ui::PopupDialog),
messageText(msgTxt)
{
ui->setupUi(this);
setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
setModal(true);
ui->message_text_display->setText(messageText);
// The message_text_display is an instance of the class,
// "PlainTextEdit". Using "QLabel" partly solves my
// problem, but does not allow text selection.
}
PopupDialog::~PopupDialog()
{
delete ui;
}
void PopupDialog::mouseReleaseEvent(QMouseEvent *e)
{
this->close();
}
As you already noticed mouse events are handled from child widgets and propagated to parents if not accepted. You can read more about it here
To close your popup window when the click is done inside a child widget you can do two things. You could try looking into installEventFilter and set it up on each child widget to call close().
Another option would require you to have a kind of centralWidget (like the MainWindow usually has) - just to group all your child widgets. This way you could call setAttribute() on it to set Qt::WA_TransparentForMouseEvents property to simply skip handling mouse events on the widget and all of its children.
groupWidget->setAttribute(Qt::WA_TransparentForMouseEvents);
According to Qt docs:
When enabled, this attribute disables the delivery of mouse events to
the widget and its children. Mouse events are delivered to other
widgets as if the widget and its children were not present in the
widget hierarchy; mouse clicks and other events effectively "pass
through" them. This attribute is disabled by default.
Which basically means the event would be passed up the chain to the first widget which can handle the event. In your case it would be the PopupDialog and the already overriden mouseReleaseEvent slot.
in header file
class PopupDialog : public QDialog
{
Q_OBJECT
public:
explicit PopupDialog(QWidget *parent = 0, QString msgTxt="");
~PopupDialog();
//////////////////////////////////
protected:
bool eventFilter(QObject *obj, QEvent *event);
//////////////////////////////////////
private:
Ui::PopupDialog *ui;
QString messageText;
void mouseReleaseEvent(QMouseEvent*);
};
in cpp
PopupDialog::PopupDialog(QWidget *parent, QString msgTxt) :
QDialog(parent),
ui(new Ui::PopupDialog),
messageText(msgTxt)
{
ui->setupUi(this);
setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
setModal(true);
ui->message_text_display->setText(messageText);
// The message_text_display is an instance of the class,
// "PlainTextEdit". Using "QLabel" partly solves my
// problem, but does not allow text selection.
///////////////////////////////////////
foreach (QObject *child, children())
{
child->installEventFilter(this);
}
///////////////////////////////////////
}
///////////////////////////////////////
bool PopupDialog::eventFilter(QObject *obj, QEvent *event)
{
if(event->type() == QEvent::MouseButtonRelease)
{
this->close();
}
}
I am using Qt 5.7 (the latest version). I can't get the mouse events to work in QGraphicsScene, but they work in window outside of my scene. I have followed this question.
So I have overwritten QWidget::mouseMoveEvent() in my main widget's subclass like this:
// header:
class MyWidget {
...
void mouseMoveEvent( QMouseEvent * event );
};
// source:
MyWidget::MyWidget() {
setMouseTracking();
}
void MyWidget::mouseMoveEvent( QMouseEvent * event ) {
}
It doesn't work for: mouseMoveEvent, mouseGrabber, mousePressEvent, mouseReleaseEvent, or mouseDoubleClickEvent. But somehow it only works for mousePressEvent.
Could this be a bug in Qt?
SOURCE CODE:
In objectloader.cpp
ObjectLoader::ObjectLoader(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::ObjectLoader)
{
ui->setupUi(this);
scene=new QGraphicsScene(this);
ui->graphicsView->setScene(scene);
ui->graphicsView->setMouseTracking(true);
setMouseTracking(true);
}
Thats were i set mouse tracking twice
In objectloader.h
Then i define that method in objectloader.h
class ObjectLoader : public QMainWindow
{
Q_OBJECT
public:
explicit ObjectLoader(QWidget *parent = 0);
~ObjectLoader();
private slots:
void mouseMoveEvent(QMouseEvent *event);
protected:
private:
};
#endif // OBJECTLOADER_H
And implementation of that method in objectloader.cpp
void ObjectLoader::mouseMoveEvent(QMouseEvent *event){
qDebug()<<"Mouse moved";
}
When a mouse event is generated by Qt it is generally passed initially to the QWidget that was under the mouse pointer when the event was generated. If that QWidget accepts the event then no further processing will take place. If the event isn't accepted then Qt may propogate the event to that QWidget's parent and so on.
In your particular case the mouse move events you are interested in are being sent to the QGraphicsView/QGraphicsScene conponents where they are being accepted and, hence, no further processing takes place. In a case like that you generally need to install an event filter to intercept and process the events of interest.
Mouse move events will occur only when a mouse button is pressed down, unless mouse tracking has been enabled with QWidget::setMouseTracking().
So, I think you should check whether mouseTracking is really enabled or not, by using `bool hasMouseTracking() const'.
I have two different class in two files:
class Game: public QGraphicsView()
class Window: public QMainWindow()
{
public: Window();
Game *game;
public slots: void test() {game = new Game();};
}
in Window.cpp I start a new Game using test() function:
Window::Window() {test();}
now in Game.cpp I create a QMessageBox with two QPushButton
QMessageBox *box= new QMessageBox();
QPushButton *btYES = box->addButton(tr("YES"),QMessageBox::ActionRole);
QPushButton *btNO = box->addButton(tr("NO"),QMessageBox::ActionRole);
box->exec();
if (box->clickedButton() == btYES) {Window::test();}
if (box->clickedButton() == btNO) {close();}
As you can see I want to connect the function test() to btYES inside the Game.cpp but that function is inside Window.cpp and its function is to start a new game.
It is possible to do so?
QPushButton emits events when it its pressed/released
So you could connect the, lets say, released signal to a slot:
connect(button, SIGNAL(released()), windowClass, SLOT(handleButton()));
In your case you need to send it across classes, so you may need to do it in two steps.
In game:
// connect the button to a local slot
connect(btYES, SIGNAL(released()), this, SLOT(handleYesButton()));
// in the slot emit a signal - declare the signal in the header
game::handleYesButton()
{
emit userChoiceYes();
}
In window
// connect the signal in game to a your slot:
connect(game, SIGNAL(userChoiceYes()), this, SLOT(test()));
Then when btnYes is pressed/released the signal released is emitted - you pick that up in handleYesButton() and emit your own signal which your window class is connected to and handles it in test()
Based on #code_fodder answer, but you don't even need another slot, plus the basic signal for a QPushButton is clicked(). Here's the documentation :
A push button emits the signal clicked() when it is activated by the
mouse, the Spacebar or by a keyboard shortcut. Connect to this signal
to perform the button's action. Push buttons also provide less
commonly used signals, for example pressed() and released().
To start, instead of adding another slot in your class Game, just connect the button's signal clicked() to another signal :
connect(btYES, SIGNAL(clicked()), this, SIGNAL(btYesClicked()));
The signal from the class Game is now emitted when you press the button btYes. Now, you just have to connect this signal to a slot test() in your class Window :
connect(game, SIGNAL(btYesClicked()), this, SLOT(test()));
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);
}