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);
}
Related
I have two classes that are interacting with each other, let's call them for the sake of simplicity ClassA and ClassB. In ClassA, I would like to emit a signal when a specific QGroupBox is shown that triggers a slot in ClassB to set the given channel's checkbox.
I have a code that consists of several thousand lines, so I included only the most relevant parts.
ClassA header
private:
QGroupbox* m_Channel1GroupBox;
void setup();
signals:
void setCheckBox(int, bool);
ClassA source
void ClassA::setup()
{
m_Channel1GroupBox = new QGroupBox("Channel 1", this);
connect(m_Channel1GroupBox, &QGroupBox::show, [this]()
{
emit setCheckBox(1, true);
});
}
ClassB header
private:
QCheckBox* m_Channel1CheckBox;
public slots:
void setCheckBox(int, bool);
ClassB source
void ClassB::setCheckBox(int channel, bool check)
{
if (channel == 1)
{
m_Channel1CheckBox->setChecked(check);
}
}
Main.cpp
connect(m_ClassA, &ClassA::setCheckBox, m_ClassB, &ClassB::setCheckBox);
The lambda expression compiles, but unfortunately it doesn't do what it is expected to do, which is whenever m_Channel1GroupBox->show() is called, then tick the checkbox of Channel1. Actually this block of code never executes, which would emit setCheckBox.
Please note that the setCheckBox function works perfectly when called in another function of ClassA and it checks or unchecks the desired channel in ClassB. This is possible using another connect in the Main.cpp file where the object instances are created.
You will need to subclass QGroupBox to achieve the functionality you require.
Override QWidget::showEvent(QShowEvent*) in your QGroupBox subclass and do the work there.
Please see the documentation for QWidget.
run the code and you will see that the
QGroupBox has no signal to emit called show...
show is actually a slot
QObject::connect: signal not found in QGroupBox
But...
if you are calling show per hand, then emit the signal right after that...
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)
I catch the mouseMoveEvent of my QWebView for restarting a timer of a screensaver. The problem is that now the mouseMoveEvent isnt distribued to the HTML elements so its impossible for example to move a sliding bar on the page.
I use connect to bind mouseMoveEvent to the restart slot :
QObject::connect(_view, SIGNAL(mouseMoveEvent(QMouseEvent*)), _mediaPlayer, SLOT(stop()));
WebView class :
class WebView : public QWebView
{
Q_OBJECT
public:
WebView(QString menu) : _menuDesc(menu) {};
WebView(){};
void setMenuDesc(QString menu) {_menuDesc = menu;};
QString getMenuDesc() {return _menuDesc;};
void setCurrPage(QString page) {_currPage = page;};
QString getCurrPage() {return _currPage;};
void setCurrCategory(QString page) {_currPage = page;};
QString getCurrCategory() {return _currPage;};
void mouseMoveEvent(QMouseEvent *)
{
emit mouseMoved();
};
signals :
void mouseMoved();
private:
QString _menuDesc = 0;
QString _currPage;
QString _currCategory = 0;
};
Is there a solution to still catch the signal and pass it to the HTML page?
mouseMoveEvent is not a signal but an event handler. You can reimplement this event handler and let it emit a signal you can connect to if you need that.
Like this:
MyWebView::mouseMoveEvent(QMouseEvent * e) {
emit mouseMoved(); // this would be signal you could connect to.
}
Seems you misunderstand event handler and signal usages.
mouseMoveEvent is a member method of QWidget, is not a signal so you cannot connect to it. You can override it in you subclass and emit your own signal.
And if a QWidget's mouse tracking is switched off, mouse move events only occur if a mouse button is pressed while the mouse is being moved. Maybe you need to call setMouseTracking too.
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();
};
I have subclassed QDialog to implement functionality similar to QMessageBox ( I needed this to allow for customization). It has a text message and OK, Cancel buttons. I am showing the dialog using exec() to make it blocking. Now, how do I return values of true/false when the user clicks on OK/Cancel?
I tried connecting the buttons to setResult() and then, return the result value when clicked, but
Clicking the buttons does not close the dialog box
the return value is incorrect.
Following is the code I have written. I think I am wrong in the exec/result part - but I am not sure how to fix it.
class MyMessageBox : public QDialog {
Q_OBJECT
private slots:
void onOKButtonClicked() { this->setResult(QDialog::Accepted); }
void onCancelButtonClicked() { this->setResult(QDialog::Rejected); }
public:
MyMessageBox(QMessageBox::Icon icon, const QString& title,
const QString& text, bool showCancelButton = true,
QWidget* parent = 0);
virtual void resizeEvent(QResizeEvent* e);
QDialog::DialogCode showYourself()
{
this->setWindowModality(Qt::ApplicationModal);
this->exec();
return static_cast<QDialog::DialogCode>(this->result());
}
};
The user will instantiate the class and call showYourself() which is expected to return the value and also close(and delete) the dialog.
I have posted partial code. Let me know if you need more and I will post the complete version.
Some points :
Rather than using setResult() yourself, use QDialog::accept() and QDialog::reject().
It seems you are not taking full advantage of the signals and slots. You need the object which create the dialog (or another one) to listen to the signals of the dialog.
In your code you are not connecting signals to slots either.
With my fix onOKButtonClicked and onCancelButtonClicked are unnecessary.
With my fix you don't need showYourself(). Just call exec and with the events
information will flow.
You need to add this code before showing the dialog (this assume it is in a dialog method):
QObject::connect(acceptButton, SIGNAL(clicked()), this, SLOT(accept()));
QObject::connect(rejectButton, SIGNAL(clicked()), this, SLOT(reject()));
In the caller object you have
void someInitFunctionOrConstructor(){
QObject::connect(mydialog, SIGNAL(finished (int)), this, SLOT(dialogIsFinished(int)));
}
void dialogIsFinished(int){ //this is a slot
if(result == QDialog::Accepted){
//do something
return
}
//do another thing
}
Another solution:
// set signal and slot for "Buttons"
connect(YesButton, SIGNAL(clicked()), dlg, SLOT(accept()));
connect(NoButton, SIGNAL(clicked()), dlg, SLOT(reject()));
// show modal window event loop and wait for button clicks
int dialogCode = dlg->exec();
// act on dialog return code
if(dialogCode == QDialog::Accepted) { // YesButton clicked }
if(dialogCode == QDialog::Rejected) { // NoButton clicked }
Case 1 Clicking the buttons does not close the dialog box.
For this you have to close the dialog on respective SLOTS, so Use
void onOKButtonClicked(){ this->setResult(QDialog::Accepted); this->close();}
void onCancelButtonClicked(){ this->setResult(QDialog::Rejected);this->close();}
Note: Only after you have clicked the Ok button or Cancel button in a standard QMessageBox, setResult() function is triggered and the status is changed. It's not the same effect when done vice versa.
Case 2 The return value is incorrect.
I think only after your dialog gets closed, you will have the result available in result() function. So I guess it will be solved, after you have made the changes specified in Case 1.
If it still persists, use your own private member function to resolve it.