I use folowing code. In it lineEdit->selectAll() works called by pushButton and only at first launch called by eventFilter. Although label->setText works all time propperly. Why?
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
ui->lineEdit->installEventFilter(this);
}
void Widget::on_pushButton_clicked()
{
ui->lineEdit->selectAll();
}
bool Widget::eventFilter(QObject *object, QEvent *event)
{
if (object == ui->lineEdit && event->type() == QEvent::FocusIn )
{
ui->lineEdit->selectAll();
ui->label->setText("Focused!");
return false;
}
if (object == ui->lineEdit && event->type() == QEvent::FocusOut )
{
ui->label->setText("unFucused!");
return false;
}
return false;
}
UPD: Did what Ilya recomended. Still have same problem.
void myLine::focusInEvent(QFocusEvent* event)
{
setText("Focused!");
selectAll();
}
void myLine::focusOutEvent(QFocusEvent* event)
{
setText("UnFocused!");
}
Found answer here Select text of QLineEdit on focus
Instead ui->lineEdit->selectAll()
should use QTimer::singleShot(0,ui->lineEdit,SLOT(selectAll())),
because mousePressEvent trigers right after focusInEvent so text selected in focusInEvent unselects by mousePressEvent.
Not really answering the question, but there's a more "standard" way of customizing these events.
Create a QLineEdit subclass and define your own focusInEvent / focusOutEvent handlers.
If you're using the UI Designer, promote your lineEdit to your subclass (right-click > "Promote to").
Because you use eventFilter in a wrong way:
bool Widget::eventFilter(QObject *object, QEvent *event)
{
if (object == ui->lineEdit && event->type() == QEvent::FocusIn )
{
ui->lineEdit->selectAll();
ui->label->setText("Focused!");
}
if (object == ui->lineEdit && event->type() == QEvent::FocusOut )
{
ui->label->setText("unFucused!");
}
return QWidget::eventFilter(object, event);
}
Related
When I type tab in QLineEdit, I go to the next widget. How to disable this behavior and type the TAB character in the QLineEdit box?
You need to check the keys via handle:
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if (obj == m_lineEdit)
{
if (event->type() == QEvent::KeyPress)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
if (keyEvent->key() == Qt::Key_Tab)
{
//do here
return true;
}
}
//return event to the parent class
return QMainWindow::eventFilter(obj, event);
}
Or you can create your own class inherited from QLineEdit and overload the method:
void LineEdit::keyPressEvent(QKeyEvent* event)
{
if (keyEvent->key() == Qt::Key_Tab)
{
emit tabPressed();
return;
}
QLineEdit::keyPressEvent(event);
}
I'm trying to design an image viewer application where I use a QGraphicsView to display my images. I want to enable the user to use the arrow keys to open the next/previous image, but my QGraphicsView is always consuming my keyPressEvent. I would like these events to be handled by my QMainWindow class instead. I realize this is a common issue, and apparently I can solve it by installing an event filter and/or ensuring that my QMainWindow can have focus. I have done both, but so far the only thing I have done is to not let the QGraphicsView get the event, but it still does not propagate to the QMainWindow. So far I've implemented the eventFilter method in my QMainWindow class and installed it on my QGraphicsView object.
QMainWindow class
IVMainWindow::IVMainWindow(QWidget *parent)
: QMainWindow(parent)
{
setWindowTitle("ImageViewer++");
setFocusPolicy(Qt::StrongFocus); // Enabled the QMainWindow to get focus
m_image_widget = new IVImageWidget();
m_image_widget->installEventFilter(this); // Install event filter on QGraphicsView
setCentralWidget(m_image_widget);
resize(QGuiApplication::primaryScreen()->availableSize() * 3 / 5);
// For DEBUG purpose
loadImage("res/image.png");
createMenuBar();
createToolBar();
}
/**
* Filters out arrow key presses.
*/
bool IVMainWindow::eventFilter(QObject *obj, QEvent *event) {
if (event->type() == QEvent::KeyPress) {
auto *keyEvent = static_cast<QKeyEvent *>(event);
int key = keyEvent->key();
// Return true to reject the key-presses
return (key == Qt::Key_Left || key == Qt::Key_Right || key == Qt::Key_Up || key == Qt::Key_Down);
} else {
// standard event processing
return QMainWindow::eventFilter(obj, event);
}
}
//Never gets to this point, unless I explicitly give it focus by clicking on some other widget than the QGraphicsView...
void IVMainWindow::keyPressEvent(QKeyEvent *event) {
if (event->key() == Qt::RightArrow) {
m_logger.Debug("Right arrow pressed.");
} else if (event->key() == Qt::LeftArrow) {
m_logger.Debug("Left arrow pressed.");
}
}
You need to process the event in the event filter, it is ok to call QMainWindow::eventFilter for sanity but it do not
process the event as an incoming event, so the event handlers will not be called.
bool IVMainWindow::eventFilter(QObject *obj, QEvent *event) {
if (event->type() == QEvent::KeyPress) {
auto *keyEvent = static_cast<QKeyEvent *>(event);
int key = keyEvent->key();
// Return true to reject the key-presses
if (key == Qt::Key_Left || key == Qt::Key_Right || key == Qt::Key_Up || key == Qt::Key_Down)
{
//process event here somehow, or instruct your class to do it later
return true; //filter the event
}
} else {
// standard event processing
return QMainWindow::eventFilter(obj, event);
}
}
//This will only be called for the 'real' events, the ones that eventually are received by the main window
void IVMainWindow::keyPressEvent(QKeyEvent *event) {
if (event->key() == Qt::RightArrow) {
m_logger.Debug("Right arrow pressed.");
} else if (event->key() == Qt::LeftArrow) {
m_logger.Debug("Left arrow pressed.");
}
}
I'm trying to implement Drag and Drop behavior, across my whole application, I would like to execute some action when a drop occurs, no mater where in the MainWindow. The Problem that I'm facing is that in my MainWindow, I have a Widget which contains a QGraphicsView, which again contains a QGraphicsScene, I can detect the drop anywhere in the application via EventFilter, except in the in the View and Scene. Is it possible to achieve some kind of global drag and drop behavior which I can detect from the MainWindow? I'm trying to avoid spreading the Logic across all my visible Widgets.
This is the drag and drop logic in my MainWindow, works, as said, for all drag and drops that happen not over the View/Scene:
void MainWindow::dropEvent(QDropEvent *event)
{
auto pixmap = QPixmap(event->mimeData()->urls().first().toString().remove("file://"));
if(!pixmap.isNull()) {
load(pixmap);
}
event->acceptProposedAction();
}
void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{
if (event->mimeData()->hasUrls()) {
event->acceptProposedAction();
}
}
For the drag and drops over the View/Scene I've tried to install following event filter:
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if(event->type() == QEvent::DragEnter) {
qDebug("Enter");
} else if(event->type() == QEvent::Drop) {
qDebug("Drop");
} else if(event->type() == QEvent::GraphicsSceneDrop) {
qDebug("Scene drop");
} else if (event->type() >= 159 && event->type() <= 168) {
qDebug("Any Scene Event");
}
return QObject::eventFilter(obj, event);
}
And apply it in the MainWindow ctor, the only thing that I detect is an enter when it enters the view.
...
setAcceptDrops(true);
mChildWidget->installEventFilter(this);
mChildWidget->setAcceptDrops(true);
...
It looks like I was facing two issues here. The first one is explained in this question here Accepting drops on a QGraphicsScene. The QGraphicsScene ignores DragAndDrops that are not happening over items. Basically you can enable drag and drop but only for evey item individually, which still leaves the arae that is not covered by an item. The solution to this issue seems to be to overwrite dragMoveEvent
void MyQGprahicsScene::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
{
Q_UNUSED(event)
// Overriding default dragMoveEvent in order to accept drops without items under them
}
The second issue was that i was facing is that I was trying to apply the eventFilter to Child widget, but it looks like I had to apply it to qApp, after which everything seemed to work, probably because qApp is the top QObject where all events will land when not handled.
#include "DragAndDropHandler.h"
bool DragAndDropHandler::eventFilter(QObject *obj, QEvent *event)
{
if(event->type() == QEvent::DragEnter) {
handleDragEnter(dynamic_cast<QDragEnterEvent *>(event));
} else if(event->type() == QEvent::Drop) {
handleDrop(dynamic_cast<QDropEvent *>(event));
} else if(event->type() == QEvent::GraphicsSceneDrop) {
handleDrop(dynamic_cast<QGraphicsSceneDragDropEvent *>(event));
} else if (event->type() == QEvent::GraphicsSceneDragEnter) {
handleDragEnter(dynamic_cast<QGraphicsSceneDragDropEvent *>(event));
}
return QObject::eventFilter(obj, event);
}
void DragAndDropHandler::handleDragEnter(QDragEnterEvent *event)
{
if (event->mimeData()->hasUrls()) {
event->acceptProposedAction();
}
}
void DragAndDropHandler::handleDragEnter(QGraphicsSceneDragDropEvent *event)
{
if (event->mimeData()->hasUrls()) {
event->acceptProposedAction();
}
}
void DragAndDropHandler::handleDrop(QDropEvent *event)
{
auto path = getUrlFromMimeData(event->mimeData());
event->acceptProposedAction();
emit imageDropped(path);
}
void DragAndDropHandler::handleDrop(QGraphicsSceneDragDropEvent *event)
{
auto path = getUrlFromMimeData(event->mimeData());
event->acceptProposedAction();
emit imageDropped(path);
}
QString DragAndDropHandler::getUrlFromMimeData(const QMimeData *mimeData) const
{
return mimeData->urls().first().toString().remove("file://");
}
And, in the constructor of my MainWindow:
setAcceptDrops(true);
qApp->installEventFilter(mDragAndDropHandler);
connect(mDragAndDropHandler, &DragAndDropHandler::imageDropped, this, &MainWindow::loadImageFromFile);
I have a QLineedit with mask and qvalidator (subclassed)
How can i prevent to move away the focus if the input isn't match the mask or validator ?
Because neither mask nor qvalidator don't prevent to move away focus from QLineEdit.
And editingfinished isn't work because :
void QLineEdit::editingFinished()
This signal is emitted when the Return or Enter key is pressed or the line edit loses focus. Note that if there is a validator() or inputMask() set on the line edit and enter/return is pressed, the editingFinished() signal will only be emitted if the input follows the inputMask() and the validator() returns QValidator::Acceptable."
void MainWindow:n_lineEdit_editingFinished()
{
if (ui->lineEdit->text() != "1111") ui->lineEdit->setFocus();
}
So mask (an validator) doesn't work together with editingFinsihed signal.
plus i have tried this
bool MainWindow::eventFilter(QObject *filterObj, QEvent *event)
{
if (filterObj == ui->lineEdit ) {
if(event->type() == QEvent::FocusOut) {
if (ui->lineEdit->text() != "1111") { ui->lineEdit-`>setFocus();};
return true;
};
};
return false;
}
thank you Attila
From the Qt's doc:
Note that if there is a validator set on the line edit, the
returnPressed()/editingFinished() signals will only be emitted if the
validator returns QValidator::Acceptable.
But you can set a focus on every event, not only for FocusOut:
bool MainWindow::eventFilter(QObject *filterObj, QEvent *event)
{
if (filterObj == ui->lineEdit )
ui->lineEdit->setFocus();
if(event->type() == QEvent::KeyRelease)
{
QKeyEvent* e = (QKeyEvent*)event;
if(e->key() == Qt::Key_Return
|| e->key() == Qt::Key_Enter)
{
/* do what you want here */
}
}
return QObject::eventFilter(filterObj, event); // usual process other events
}
I have a console input in my Qt based application, it's a QLineEdit, all Ui is designed via QtDesigner. Is it any easy way way to handle up and down arrows in order to implement input history? The 'go to slot' only show returnProcessed signal, no way i can see to handle up and down arrows :(
you can install event filter and watch your line edit event in your window class. Below is an example:
declare event handler method on your window class:
class MainWindow : public QMainWindow {
Q_OBJECT
...
protected:
void changeEvent(QEvent *e);
...
};
window constructor
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
...
ui->lineEdit->installEventFilter(this);
}
event handler implementation:
bool MainWindow::eventFilter(QObject* obj, QEvent *event)
{
if (obj == ui->lineEdit)
{
if (event->type() == QEvent::KeyPress)
{
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
if (keyEvent->key() == Qt::Key_Up)
{
qDebug() << "lineEdit -> Qt::Key_Up";
return true;
}
else if(keyEvent->key() == Qt::Key_Down)
{
qDebug() << "lineEdit -> Qt::Key_Down";
return true;
}
}
return false;
}
return QMainWindow::eventFilter(obj, event);
}
hope this helps, regards
You can subclass QLineEdit and re-implement the virtual keyPressEvent method to handle your special keys.
void MyLineEdit::keyPressEvent(QKeyEvent *event)
{
if(event->key() == Qt::Key_Up){
// move back in history
}
else if(event->key() == Qt::Key_Down){
// move forward in history
}
else{
// default handler for event
QLineEdit::keyPressEvent(event);
}
}
I had the same problem, but I find out in other forums that you need to setFocus, e.g.:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
...
ui->lineEdit->installEventFilter(this);
this->setFocus();
}
It works for me.
Reference:
http://www.qtforum.org/article/28240/how-to-get-arrow-keys.html
For me in PyQt this was not working,
class MainWidget(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.setupUi()
self->installEventFilter(self)
But this worked,
class MainWidget(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.setupUi()
QtGui.QApplication.instance().installEventFilter(self)