I searched for the answers online, but I did not really find one that solved my problem. My question is like: I have a QComboBox, let's say I added three items to this:
ui->comboBox->addItem("First");
ui->comboBox->addItem("Second");
ui->comboBox->addItem("Third");
Then if I press the S on the keyboard, the item will change to Second, if I press T, so item will just change to Third. How can I disable this?
A possible solution is to implement an eventfilter that prevents the letters from being used in the QComboBox:
#include <QApplication>
#include <QComboBox>
#include <QKeyEvent>
class Helper: public QObject{
QComboBox *m_combo;
public:
using QObject::QObject;
void setComboBox(QComboBox *combo){
m_combo = combo;
m_combo->installEventFilter(this);
}
bool eventFilter(QObject *watched, QEvent *event){
if(m_combo){
if(m_combo == watched && event->type() == QEvent::KeyPress){
QKeyEvent *ke = static_cast<QKeyEvent *>(event);
if(!ke->text().isEmpty())
return true;
}
}
return QObject::eventFilter(watched, event);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QComboBox w;
w.addItems({"First", "Second","Third"});
Helper helper;
helper.setComboBox(&w);
w.show();
return a.exec();
}
Related
I am using Qt Creator 4.5.2 (Qt 5.9.5, GCC 7.3.0 64-bit) and running on Ubuntu 18.04.
I just customized the 'QTimeEdit' widget and it worked. Now, I need to intercept the event(s) for the 'Up' and 'Down' arrow (the arrow to change the current time). But, I don't know which event it is.
I already installed the 'evenFilter' and could catch all the events. I printed out all of them. But, I did not see an event trigger when I clicked the 'Up' or 'Down' arrow (The time did get changed). I assumed it was 'keyPressEvent' but apparently it was not since it did not trigger this method when I clicked the 'Up' or 'Down' arrow.
Any idea what events for the 'Up' or 'Down' arrow in the 'QTimeEdit' widget?
void MyTimeEdit::keyPressEvent(QKeyEvent *e)
{
qInfo() << "Key Press";
QTimeEdit::keyPressEvent(e);
}
bool MyTimeEdit::eventFilter(QObject *watched, QEvent *event)
{
if(watched == lineEdit())
qInfo() << "Event Type: " << event->type();
return QTimeEdit::eventFilter(watched, event);
}
If you click with the mouse then the event cannot be caused by a keyboard key.
In this case if you want to detect when you click on the "Up" or "Down" arrow of the QTimeEdit then you must use the mousePressEvent method:
#include <QApplication>
#include <QMouseEvent>
#include <QStyleOptionSpinBox>
#include <QTimeEdit>
#include <QDebug>
class TimeEdit: public QTimeEdit{
public:
using QTimeEdit::QTimeEdit;
protected:
void mousePressEvent(QMouseEvent *event){
QTimeEdit::mousePressEvent(event);
QStyleOptionSpinBox opt;
initStyleOption(&opt);
QStyle::SubControls control = style()->hitTestComplexControl(
QStyle::CC_SpinBox, &opt, event->pos(), this);
if(control == QStyle::SC_SpinBoxUp)
qDebug() << "up";
else if (control == QStyle::SC_SpinBoxDown) {
qDebug() << "down";
}
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
TimeEdit w;
w.show();
return a.exec();
}
But keep in mind that not only the clicks do change the value of what the QTimeEdit shows but also the keyboard, the wheel, etc., so if you want to cover all those cases it is better to track override the stepBy() method
#include <QApplication>
#include <QTimeEdit>
#include <QDebug>
class TimeEdit: public QTimeEdit{
public:
using QTimeEdit::QTimeEdit;
void stepBy(int steps){
qDebug() << steps;
QTimeEdit::stepBy(steps);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
TimeEdit w;
w.show();
return a.exec();
}
Is it possible to prevent right-click from opening the default context menu on QGraphicsTextItem ? The menu with "Undo, Redo, Cut, Copy, Paste..". On Ubuntu 18.04, that is. I don't know how this behaves on Windows.
I have overridden the mouse press handler to eat right-clicks in my view and tried to do that also in the item class itself. This actually did prevent the menu on Qt 5.10.0, but for some reason not anymore on 5.11.1:
void EditorView::mousePressEvent(QMouseEvent * event)
{
if (event->button() == Qt::RightButton)
{
return;
}
...
doOtherHandlingStuff();
...
}
In the item itself it doesn't have any effect if I do this:
void TextEdit::mousePressEvent(QGraphicsSceneMouseEvent * event)
{
event->ignore();
return;
}
You have to override the contextMenuEvent method of QGraphicsTextItem:
#include <QtWidgets>
class GraphicsTextItem: public QGraphicsTextItem
{
public:
using QGraphicsTextItem::QGraphicsTextItem;
protected:
void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override
{
event->ignore();
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QGraphicsScene scene;
QGraphicsView w{&scene};
auto it = new GraphicsTextItem("Hello World");
it->setTextInteractionFlags(Qt::TextEditable);
scene.addItem(it);
w.show();
return a.exec();
}
it's my first question here about Qt (usually internet and doc helps me alot)
I've installed a eventfilter on my app (in main.cpp), and I want this event filter to check the key pressed then redistribute it to lower functions (like moving an item on a QGraphicsScene),
This is working BUT, 5 times..
The qDebug() in filter shows me that the key is pressed 5 times when it was just one.
Event filter is so fast it catches it 5 times.
Can't find a way to debounce that.
Here's the interesting parts of code:
main.cpp
#include "mainwindow.h"
#include "eventfilter.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
xEventFilter *filter = new xEventFilter(&a);
a.installEventFilter(filter);
xMainWindow w;
w.show();
return a.exec();
}
eventfilter.h
#ifndef EVENTFILTER_H
#define EVENTFILTER_H
#include <QObject>
class xEventFilter : public QObject
{
Q_OBJECT
public:
explicit xEventFilter(QObject *parent = nullptr);
protected:
bool eventFilter(QObject *obj, QEvent *event) override;
};
#endif // EVENTFILTER_H
eventfilter.cpp
#include "eventfilter.h"
#include "editor.h"
#include <QKeyEvent>
#include <QDebug>
extern xEditor *editor;
xEventFilter::xEventFilter(QObject *parent) :
QObject(parent)
{ }
bool xEventFilter::eventFilter(QObject *obj, QEvent *event)
{
qDebug() << "Enter filter";
if (event->type() != QEvent::KeyPress)
return QObject::eventFilter(obj, event);
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
qDebug() << keyEvent->text();
switch(keyEvent->key()) {
case Qt::Key_Z: { editor->selection->moveSelection(keyEvent); }
case Qt::Key_S: { editor->selection->moveSelection(keyEvent); }
case Qt::Key_Q: { editor->selection->moveSelection(keyEvent); }
case Qt::Key_D: { editor->selection->moveSelection(keyEvent); }
case Qt::Key_Space: { }
}
return false;
}
Looking up to your answers ;)
The main issue is that even if you handle the event, you return false. According to the documentation, you should return true if you want the event to stop being handled.
In your reimplementation of this function, if you want to filter the
event out, i.e. stop it being handled further, return true; otherwise
return false.
Also, you're missing break in cases of your switch statement.
I want to make a QGraphicsTextItem editable on double click, and make it movable when I click out.
#include <QApplication>
#include <QPainter>
#include <QGraphicsItem>
#include <QGraphicsView>
class TextItem: public QGraphicsTextItem
{
public:
TextItem()
{
setPlainText("hello world");
QFont f;
f.setPointSize(50);
f.setBold(true);
f.setFamily("Helvetica");
setFont(f);
setFlags(QGraphicsItem::ItemIsMovable |
QGraphicsItem::ItemIsFocusable |
QGraphicsItem::ItemIsSelectable);
setTextInteractionFlags(Qt::NoTextInteraction);
}
virtual void paint(QPainter* painter,
const QStyleOptionGraphicsItem* option,
QWidget* widget = NULL)
{
QGraphicsTextItem::paint(painter, option, widget);
}
protected:
virtual void focusOutEvent (QFocusEvent * event)
{
Q_UNUSED(event);
setTextInteractionFlags(Qt::NoTextInteraction);
}
virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent * event)
{
Q_UNUSED(event);
setTextInteractionFlags(Qt::TextEditable); // TextEditorInteraction
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
TextItem* t = new TextItem();
QGraphicsView view(new QGraphicsScene(-200, -150, 400, 300) );
view.scene()->addItem(t);
view.show();
return a.exec();
}
It does what I want - except I have to double-click twice
- first time I double click, I see a cursor but am unable to edit text (with either option, TextEditable or TextEditorInteraction (I probably want the latter). Then I double-click again and I can type to add or delete text.
It is a behavior that a user probably doesn't expect - and nothing I do seems to change it.
Am I doing something wrong, or is there anything I need to add ?
I expected a mouse action on a focusable item to give it focus automatically. I guess not...
In the mouseDoubleClickEvent, I added a call to setFocus()
virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent * event)
{
Q_UNUSED(event);
setTextInteractionFlags(Qt::TextEditorInteraction);
setFocus();
}
Since Qt is using Cocoa under OSX, is it possible to make a modal QDialog to shake if the user enters the wrong password for example? Im not able to find anything about it but it would be really nice to implement on mac.
Thanks!
I'm not aware of a built-in way to do it, but you could implement the shaking yourself, like this:
header.h
#include <QtGui>
class ShakyDialog : public QDialog
{
Q_OBJECT
public slots:
void shake()
{
static int numTimesCalled = 0;
numTimesCalled++;
if (numTimesCalled == 9) {
numTimesCalled = 0;
return;
}
vacillate();
QTimer::singleShot(40, this, SLOT(shake()));
}
private:
void vacillate()
{
QPoint offset(10, 0);
move(((shakeSwitch) ? pos() + offset : pos() - offset));
shakeSwitch = !shakeSwitch;
}
bool shakeSwitch;
};
main.cpp
#include "header.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
ShakyDialog dialog;
QHBoxLayout layout(&dialog);
QPushButton button("Push me.");
layout.addWidget(&button);
QObject::connect(&button, SIGNAL(clicked()), &dialog, SLOT(shake()));
dialog.show();
return app.exec();
}