I have a class which inherit from QDoubleSpinBox.
class NumericEdit : public QDoubleSpinBox
{
public:
NumericEdit( QWidget *p_parent = nullptr );
protected:
bool event( QEvent *p_event ) override;
void keyPressEvent( QKeyEvent *p_event ) override;
void keyReleaseEvent( QKeyEvent *p_event ) override;
void focusInEvent( QFocusEvent *p_event ) override;
void focusOutEvent( QFocusEvent *p_event ) override;
............
};
NumericEdit::NumericEdit( QWidget *p_parent ) : QDoubleSpinBox( p_parent )
{
initStyleSheet();
setButtonSymbols( QAbstractSpinBox::NoButtons );
setGroupSeparatorShown( true );
..........
}
The result when I double click into the editing field is like this, only the part in between group separators is marked. If I triple click, the whole text is then marked.
How should I change, sothat when I double click into the editing field (no matter in integer part or decimal part), the whole text is marked?
Solution is reimplementing of QLineEdit::mouseDoubleClickEvent method (not QDoubleSpinBox::mouseDoubleClickEvent).
Custom line edit:
class ExtendedLineEdit : public QLineEdit
{
Q_OBJECT
public:
explicit ExtendedLineEdit(QWidget *parent = nullptr);
protected:
void mouseDoubleClickEvent(QMouseEvent *event);
}
void ExtendedLineEdit::mouseDoubleClickEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
{
selectAll();
event->accept();
return;
}
QLineEdit::mouseDoubleClickEvent(event);
}
And then set it to your custom spin box
NumericEdit::NumericEdit(QWidget *p_parent) : QDoubleSpinBox(p_parent)
{
//...
ExtendedLineEdit* lineEdit = new ExtendedLineEdit(this);
setLineEdit(lineEdit);
}
Related
There's a class inherited QQuickPaintedItem and included QwtPlot (in order to use it in QML):
class QmlQwtPlot : public QQuickPaintedItem
{
Q_OBJECT
public:
QmlQwtPlot(QQuickItem* parent = 0);
~QmlQwtPlot();
void paint(QPainter *painter) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent* event) override;
void mouseReleaseEvent(QMouseEvent* event) override;
void wheelEvent(QWheelEvent *event) override;
private:
QwtPlot* qwtPlot;
QwtPlotPanner* panner;
bool isDragging;
QPoint previousPosition;
QwtPlotPicker* picker;
};
For example, panning a plot was implemented by using mouse events handling and the QwtPlotPanner's signal :
void QmlQwtPlot::mouseMoveEvent(QMouseEvent* event) {
if (isDragging) { // if the mouse button has been pressed
QPoint currentPosition = event->pos();
QPoint diff = currentPosition - previousPosition;
emit panner->panned(diff.x(),diff.y());
previousPosition = event->pos();
update();
}
}
QwtPlotPicker is a Qwt library class providing selections on a plot canvas. QwtPlotPicker works well (a cursor with x,y coordinates of point and cross-line moving with cursor are appeared) with QWidget, but it doesn't work with QQuickPaintedItem because of different principles of work.
/* QWidget's child constructor (the same is in QQuickPaintedItem's one) */
PlottingWidget::PlottingWidget(QWidget *parent)
: QWidget(parent)
{
// ...
d_picker = new QwtPlotPicker(
QwtPlot::xBottom, QwtPlot::yLeft,
QwtPlotPicker::CrossRubberBand,
QwtPicker::AlwaysOn,
plot->canvas()
);
d_picker->setRubberBandPen( QColor( Qt::red ) );
d_picker->setTrackerPen( QColor( Qt::black ) );
d_picker->setStateMachine( new QwtPickerTrackerMachine() );
// ...
}
How to force QwtPlotPicker work with QQuickPaintedItem?
I'm trying to use a keyPressEvent, but it is only working when the window has focus and not any of the QWidgets.
Here is my code:
In customdialog.h:
class CustomDialog : public QDialog, public Ui::CustomDialog
{
Q_OBJECT
private:
Ui::CustomDialog *ui;
QString lastKey;
public:
CustomDialog(QWidget * parent = 0);
protected:
void keyPressEvent(QKeyEvent *e);
};
In customdialog.cpp:
void CustomDialog::keyPressEvent(QKeyEvent *e)
{
lastKey = e->text();
qDebug() << lastKey;
}
How can I make all widgets within this class use the same keyPressEvent?
You can solve your problem by installing event filters to every child of CustomDialog:
void CustomDialog::childEvent(QChildEvent *event)
{
if (event->added()) {
event->child()->installEventFilter(this);
}
}
bool CustomDialog::eventFilter(QObject *, QEvent *event)
{
if (event->type() == QEvent::KeyPress)
keyPressEvent(static_cast<QKeyEvent*>(event));
return false;
}
But since every ignored keyPress event is sent to the parent widget, you can get keyPressEvent called multiple times for the same event.
I ended up deciding not to use keyPressEvent in this case for my purposes. I just needed to get the last key pressed in a QTextBrowser. Here is what I ended up doing:
connect(ui->textBrowser, SIGNAL(textChanged()), this, SLOT(handleTextBrowser()));
void CustomDialog::handleTextBrowser()
{
QTextCursor cursor(ui->textBrowser->textCursor());
QString key = ui->textBrowser->toPlainText().mid(cursor.position() - 1, 1);
qDebug() << key;
}
I currently have a QtableView that is attached to a QstandardItemModel. I want to insert a clickable Qlabel in the last column of each row. Initially I wanted to go with a QPushButton but it turns out that it requires extra overhead so now I am planning to go with a clickable Qlabel. Any suggetsions on how I could do that ? Also I would appreciate it if someone could sugget options that are available for simulating click events in a TableView using QStandardItemModel
connect(ui.tableView,SIGNAL(clicked(const QModelIndex& ) ),
this,SLOT( itemClicked(const QModelIndex& ) ) );
slot:
void itemClicked( const QModelIndex& idx) {
int row = idx.row();
int column = idx.column();
}
if you really need just a clickable label you can create class derived from QLabel and add custom signals to handle click event:
class CustomWidget : public QLabel {
Q_OBJECT
public:
explicit CustomWidget(const QString& text, QWidget *parent = 0);
signals:
void released(void);
void clicked(void);
protected:
void mousePressEvent(QMouseEvent* e);
void mouseReleaseEvent(QMouseEvent* e);
private:
bool mousePressed;
};
CustomWidget::CustomWidget(const QString& text, QWidget* parent)
: QLabel(text, parent), mousePressed(false) {
}
void CustomWidget::mousePressEvent(QMouseEvent* e) {
mousePressed = true;
}
void CustomWidget::mouseReleaseEvent(QMouseEvent* e) {
emit released();
if(mousePressed) {
emit clicked();
mousePressed = false;
}
}
full code snippet:
http://www.qtcentre.org/archive/index.php/t-42296.html?s=e9f0fd408147a1cd1048f252967895a0
I have a reimplemented QDoubleSpinBox. I would like to catch mouseDoubleClickEvent to enable the user to change singleStep by way of QInputDialog::getDouble().
My problem is that when I reimplement the mouseDoubleClickEvent I only catch double clicks that occur over the arrow buttons. I actually want to ignore double clicks that occur in the arrows and only catch double clicks that occur in the text field. I have a feeling that I need to reimplement the mouseDoubleClickEvent of a child of the QDoubleSpinBox, but I'm not sure how to reimplement a child event nor how to select the correct child See my attempt at limiting to a child QRect in code: I think I need to specify which child...?
Thanks.
Edit: corrected class declaration/definition name mismatch.
MyQDoubleSpinBox.h
class MyQDoubleSpinBox : public QDoubleSpinBox
{
Q_OBJECT
public:
MyQDoubleSpinBox(QString str, QWidget *parent = 0);
~MyQDoubleSpinBox();
public slots:
void setStepSize(double step);
private:
double stepSize;
QString name;
protected:
void mouseDoubleClickEvent(QMouseEvent *e);
};
MyQDoubleSpinBox.cpp
#include "MyQDoubleSpinBox.h"
MyQDoubleSpinBox::MyQDoubleSpinBox(QString str, QWidget *parent)
: QDoubleSpinBox(parent), stepSize(1.00), name(str)
{
this->setMinimumWidth(150);
this->setSingleStep(stepSize);
this->setMinimum(0.0);
this->setMaximum(100.0);
}
MyQDoubleSpinBox::~MyQDoubleSpinBox()
{
}
void MyQDoubleSpinBox::setStepSize(double step)
{
this->setSingleStep(step);
}
void MyQDoubleSpinBox::mouseDoubleClickEvent(QMouseEvent *e)
{
if( this->childrenRect().contains(e->pos()) )
{
bool ok;
double d = QInputDialog::getDouble(this,
name,
tr("Step Size:"),
this->singleStep(),
0.0,
1000.0,
2,
&ok);
if(ok)
this->setSingleStep(d);
}
}
A bit of the hack getting ref to child, but it works =)
MyQDoubleSpinBox.h:
class MyQDoubleSpinBox : public QDoubleSpinBox
{
Q_OBJECT
public:
MyQDoubleSpinBox(QString str, QWidget *parent = 0);
~MyQDoubleSpinBox();
public slots:
void setStepSize(double step);
private:
double stepSize;
QString name;
protected:
bool eventFilter(QObject *, QEvent *e);
};
MyQDoubleSpinBox.cpp
MyQDoubleSpinBox::MyQDoubleSpinBox(QString str, QWidget *parent)
: QDoubleSpinBox(parent), stepSize(1.00), name(str)
{
this->setMinimumWidth(150);
this->setSingleStep(stepSize);
this->setMinimum(0.0);
this->setMaximum(100.0);
QLineEdit *editor = this->findChild<QLineEdit *>("qt_spinbox_lineedit");
editor->installEventFilter(this);
}
MyQDoubleSpinBox::~MyQDoubleSpinBox()
{
}
void MyQDoubleSpinBox::setStepSize(double step)
{
this->setSingleStep(step);
}
bool MyQDoubleSpinBox::eventFilter(QObject *, QEvent *e)
{
if (e->type() == QMouseEvent::MouseButtonDblClick)
{ bool ok;
double d = QInputDialog::getDouble(this,
name,
tr("Step Size:"),
this->singleStep(),
0.0,
1000.0,
2,
&ok);
if(ok)
this->setSingleStep(d);
}
return false;
}
Instead of overwriting events, i got ref to underlying QLineEdit and assigned event filter to it. In event filter catch only mouse double click.
You have direct access to QLineEdit using this->lineEdit()
MyQDoubleSpinBox::MyQDoubleSpinBox(QString str, QWidget *parent)
: QDoubleSpinBox(parent), stepSize(1.00), name(str)
{
this->setMinimumWidth(150);
this->setSingleStep(stepSize);
this->setMinimum(0.0);
this->setMaximum(100.0);
QLineEdit *editor = this->lineEdit(); // change here
editor->installEventFilter(this);
}
I have a little problem, I need to set my event filter to QComboBox popup.
I need to catch events when left and right keys are pressed.
How can I do this?
Thank you!
You need to set the eventFilter on QComboBox's view() (http://qt-project.org/doc/qt-4.8/qcombobox.html#view).
You may need to add following code somewhere in your code.
void MyComboBox::keyPressEvent (QKeyEvent *event)
{
if (event->button() == Qt::Key_Left)
{
// handle left key press
}
if (event->button() == Qt::Key_Right)
{
// handle right key press
}
}
Hope this helps!
The question is quite old, but I provide my answer since it can help someone else.
After popup all events will be sent to the list view used for the QComboBox popup. You can get the things done using key handler class watching on events for list view.
KeyPressHandler.h:
class KeyPressHandler : public QObject
{
Q_OBJECT
public:
explicit KeyPressHandler(QObject *parent = nullptr);
virtual ~KeyPressHandler() override;
protected:
bool eventFilter(QObject *obj, QEvent *event) override;
};
KeyPressHandler.cpp:
#include <QCoreApplication>
KeyPressHandler::KeyPressHandler(QObject *parent) : QObject(parent)
{
}
KeyPressHandler::~KeyPressHandler()
{
}
bool KeyPressHandler::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::KeyPress)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
switch(keyEvent->key())
{
case Qt::Key_Left:
// Send press event for the Key_Up which understood by list view
QCoreApplication::postEvent(obj, new QKeyEvent(QEvent::KeyPress,
Qt::Key_Up,
Qt::NoModifier));
return true;
case Qt::Key_Right:
QCoreApplication::postEvent(obj, new QKeyEvent(QEvent::KeyPress,
Qt::Key_Down,
Qt::NoModifier));
return true;
default:
break;
}
}
// standard event processing
return QObject::eventFilter(obj, event);
}
In ComboBox you will need to install event filter when popup is shown.
It can be done in different ways, for example by overriding QComboBox::showPopup() function.
MyComboBox.h:
#include <memory>
#include <QComboBox>
class MyComboBox : public QComboBox
{
Q_OBJECT
public:
explicit MyComboBox(QWidget *parent = 0);
protected:
void showPopup() override;
void hidePopup() override;
private:
std::unique_ptr<KeyPressHandler> m_key_press_handler;
};
MyComboBox.cpp:
...
void MyComboBox::showPopup()
{
if(!m_key_press_handler)
{
m_key_press_handler.reset(new KeyPressHandler());
QAbstractItemView *v = view();
v->installEventFilter(m_key_press_handler.get());
}
QComboBox::showPopup();
}
void MyComboBox::hidePopup()
{
m_key_press_handler.reset(nullptr);
QComboBox::hidePopup();
}