I'm using a QTableView where I show a list of Icons, the user can select some icons with mouse and control key button, and I'm able to handle these selections. But I want to disable the use of shift+left mouse key over the QTableView.
Is there any way to totally disable the shift key button during the process when GUI is being run? I am able to detect the shift key pressing using the eventFilter that is installed on the viewport of QTableView, but I cannot find any way to totally make the shift key inactive when the user presses shift key and the left mouse button together.
My event filter is as below:
bool MainWindow::eventFilter(QObject* obj, QEvent *ev)
{
if(obj == ui->listOfImages->viewport())
{
if(ev->type() == QEvent::MouseButtonPress)
{
QMouseEvent * mouseEv = static_cast<QMouseEvent*>(ev);
if((mouseEv->buttons() & Qt::LeftButton) && (QApplication::keyboardModifiers().testFlag(Qt::ControlModifier) == true) && (QApplication::keyboardModifiers().testFlag(Qt::ShiftModifier) == false))
{
controlButtonCounter++;
fetch = true;
//I use these variables for some purposes.
return QObject::eventFilter(obj,ev);
}
else if((mouseEv->buttons() & Qt::LeftButton) && (QApplication::keyboardModifiers().testFlag(Qt::ControlModifier) == false) && (QApplication::keyboardModifiers().testFlag(Qt::ShiftModifier) == false))
{
if(selectedImages.size()>0)
{
ui->listOfImages->clearSelection();
selectedImages.clear();
selectedList.clear();
ui->selectedFiles->clear();
ui->selectedFiles->show();
}
fetch = false;
controlButtonCounter = 0;
//I use these variables for some purposes.
}
else if((mouseEv->buttons() & Qt::LeftButton) && (QApplication::keyboardModifiers().testFlag(Qt::ControlModifier) == false) && (QApplication::keyboardModifiers().testFlag(Qt::ShiftModifier) == true) )
{
qDebug()<<"Shift button pressed!";
// Don't how to prevent shift button from selecting multiple icon.
}
}
}
return QObject::eventFilter(obj,ev);
}
Regarding your code, I believe you want to change the way you select things in the QTableView and disabling the shift-button would be just a work around.
You can disable multi-selections with:
QAbstractItemView::selectionMode(QAbstractItemView::SingleSelection);
See: http://qt-project.org/doc/qt-4.8/qabstractitemview.html#SelectionMode-enum: for more info
I will handle mouse clicks and button state in the following way:
bool MyWidget::eventFilter(QObject *obj, QEvent *event)
{
[..]
if (event->type() == QEvent::MouseButtonPress ||
event->type() == QEvent::MouseButtonRelease) {
Qt::KeyboardModifiers modifiers = QApplication::keyboardModifiers();
if (modifiers & Qt::ShiftModifier) {
// Filter the event, when mouse pressed/released
// with the shift key pressed.
return true;
}
}
[..]
return false;
}
Related
This is my question. When I edit a cell in a QTableView, I would like that if I press TAB key, the current cell is updated, but the next cell isn't in edit mode.
I have try to create a eventFilter in a table, but it doesn't work. Neither if I create the eventFilter in the editor widget of the delegate.
This is my try of a eventFilter in the QTableView. My idea is that if the current cell is in the last column and row and the current row is not empty, I insert another row (this works fine) and if I am editing any cell, when I press TAB I can place on the next cell but without Edit Mode
This is a snippet of the code:
bool MiTabla::eventFilter(QObject *watched, QEvent *e)
{
if (e->type() == QEvent::KeyPress)
{
QModelIndex indice = this->currentIndex();
QKeyEvent *ke =static_cast<QKeyEvent*>(e);
switch (ke->key())
{
case (Qt::Key_Delete):
{
if (this->selectionModel()->isRowSelected(indice.row(),QModelIndex()))
{
//borrarLineas();
}
else
{
this->model()->setData(this->currentIndex(),"",Qt::EditRole);
}
break;
}
case (Qt::Key_Tab):
{
if (indice.row() == this->model()->rowCount(QModelIndex())-1
&& indice.column() == this->model()->columnCount(QModelIndex())-1
&& !NombreVacio())
{
this->model()->insertRow(this->model()->rowCount(QModelIndex()));
QModelIndex ind = this->model()->index(indice.row()+1,0);
this->setCurrentIndex(ind);
}
else //this doesn't work
{
QModelIndex ind = this->model()->index(indice.row(),indice.column()+1);
this->setCurrentIndex(ind);
}
break;
Thank you. I have solved it as you said.
I have reimplement the eventFilter() function in the delegate class (subclassed from QStyledItemDelegate) as below:
bool DelegadoNombre::eventFilter(QObject *obj, QEvent* event)
{
if (event->type()==QEvent::KeyPress)
{
QKeyEvent* key = static_cast<QKeyEvent*>(event);
if (key->key()==Qt::Key_Tab || key->key()==Qt::Key_Enter || key->key()==Qt::Key_Return)
{
QLineEdit *editor=qobject_cast<QLineEdit*>(obj);
emit commitData(editor);
emit closeEditor(editor, QStyledItemDelegate::NoHint);
}
else
{
return QObject::eventFilter(obj, event);
}
return false;
}
else
{
return QObject::eventFilter(obj, event);
}
return false;
}
This function says to editor of the delegate that if Tab Key is pressed it must commit the data and close the editor but no open the next editor in Edit Mode QStyledItemDelegate::NoHint.
Also, return false for allow to the table use this event
I want to get rid of the my application's title and border, but to do that I need to be able to move the window by dragging on the menuBar. The two method's I've found to do this is:
void TopMenuBar::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
dragPosition = event->globalPos() - frameGeometry().topLeft();
event->accept();
}
}
void TopMenuBar::mouseMoveEvent(QMouseEvent *event)
{
if (event->buttons() & Qt::LeftButton) {
move(event->globalPos() - dragPosition);
event->accept();
}
}
However if I put this in the MainWindow, it will move around no matter what you click on, and if I put it in a custom QMenuBar, it only moves the menubar within the window. I've also attempted to do some signals and slots trickery between the objects (Like keeping mousePressEvent in menuBar and mouseMoveEvent in MainWindow), but the tendency is that the window will "jump" to where the mouse pointer is instead of moving it smoothly.
Anyone else have a solution for this?
Environment is Windows
This will work for certain - just checked it. Call ui->menuBar->installEventFilter(this); in the MainWindow constructor.
bool MainWindow::eventFilter(QObject *watched, QEvent *event)
{
if (watched == ui->menuBar)
{
if (event->type() == QEvent::MouseButtonPress)
{
QMouseEvent* mouse_event = dynamic_cast<QMouseEvent*>(event);
if (mouse_event->button() == Qt::LeftButton)
{
dragPosition = mouse_event->globalPos() - frameGeometry().topLeft();
return false;
}
}
else if (event->type() == QEvent::MouseMove)
{
QMouseEvent* mouse_event = dynamic_cast<QMouseEvent*>(event);
if (mouse_event->buttons() & Qt::LeftButton)
{
move(mouse_event->globalPos() - dragPosition);
return false;
}
}
}
return false;
}
I Have a Form with several LineEdits and other Elements and want to jump from one to the next by pressing the return key.
I find Return key instead of/additional to the tab key more user friendly.
I can probably do it if i use returnPressed() and setFocus() but i hope there is a better more elegant solution for this.
Is there a way to modify the built in tab order to also work with
return?
If not, what are the best ways to accomplish the above?
You're probably looking for the event handler. ( QEvent )
Example from the doc
bool MyWidget::event(QEvent *event)
{
if (event->type() == QEvent::KeyPress) {
QKeyEvent *ke = static_cast<QKeyEvent *>(event);
if (ke->key() == Qt::Key_Tab) {
// special tab handling here
return true;
}
} else if (event->type() == MyCustomEventType) {
MyCustomEvent *myEvent = static_cast<MyCustomEvent *>(event);
// custom event handling here
return true;
}
return QWidget::event(event);
}
It's easily adjustable to any key.
For example if return is pressed simulate a tab key press event.
As mentioned, it is more efficient to override QWidget::keyPressEvent
Some code:
protected:
void keyPressEvent(QKeyEvent *event) override;
void MyWidget::keyPressEvent(QKeyEvent *event){
if(event->key()==Qt::Key_Return){
this->focusNextChild();
}
}
I am using Qt 5.3.2 with Qt Creator 3.2.1 with MinGW 4.8.2 on Windows 7. I have a QSpinBox and can change its value with the mouse wheel only if the mouse is over the QSpinBox. If the mouse is not over the QSpinBox, scrolling the mouse wheel has no effect, even though the QSpinBox still has focus. What do I need to do to be able to change values in the QSpinBox that has focus with the mouse wheel even if the mouse is not hovering over it? Setting mouseTracking to true does not have that effect.
Use eventFilter to do this. Install it on your mainWindow:
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if (obj == this && event->type() == QEvent::Wheel)
{
QWheelEvent *wheelEvent = static_cast<QWheelEvent *>(event);
if(wheelEvent->delta() > 0)
ui->spinBox->setValue(ui->spinBox->value() + 1);
else
ui->spinBox->setValue(ui->spinBox->value() - 1);
}
}
It is just example, so you can improve it as you want.
Or use this:
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if (obj == this && event->type() == QEvent::Wheel)
{
QApplication::sendEvent(ui->spinBox,event);
}
}
In this example, when you detect wheel event, you send it to your spinbox.
But don't forget
protected:
bool eventFilter(QObject *obj, QEvent *event);//in header
and
qApp->installEventFilter(this);//in constructor
As DmitrySazonov recommended. We will detect wheelEvents when our spinBox in focus, when spinBox losed focus, we don't react on wheel(other widgets react normal). We do this in one eventFilter. To do this provide new bool variable. For example:
private:
bool spin;//in header
Initialize it in constructor:
spin = false;
And your eventFilter should be.
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if(obj == ui->spinBox && event->type() == QEvent::FocusIn)
spin = true;
if(spin)
{
if (obj == this && event->type() == QEvent::Wheel)
{
QApplication::sendEvent(ui->spinBox,event);
}
}
if(obj == ui->spinBox && event->type() == QEvent::FocusOut)
spin = false;
}
Or do just this, without additional variable:
if (obj == this && event->type() == QEvent::Wheel)
{
if(ui->spinBox->hasFocus())
QApplication::sendEvent(ui->spinBox,event);
}
I did not mention it in the question but I have more that one QSpinBox and testing them all seems sub-optimal, so I need a generic message forwarder. Based on the Chernobyl's code I made my own version of the message filter:
bool MainWindow::eventFilter(QObject *obj, QEvent *event){
if (obj == this && event->type() == QEvent::Wheel)
{
auto focusWidget = QApplication::focusWidget();
if (focusWidget){
qApp->removeEventFilter(this);
QApplication::sendEvent(focusWidget, event);
qApp->installEventFilter(this);
return true;
}
}
return false;
}
This forwards all QWheelEvents to the QWidget with the focus. One could also add other events that need to be forwarded.
The qApp->removeEventFilter and qApp->installEventFilter inside the event filter is the only way I found that prevents the event filter calling itself when scrolling on the main window causing a stack overflow (condition focusWidget != this does not help). There isprobably a way to prevent the infinite recursion without reinstalling the event filter on every QWheelEvent.
I want to prevent control+A shortcut from selecting all the files in QTableView, I want to make it as such that it can only select with mouse but not with a keyboard shortcut. Right now my eventFilter code is as below. Could you please suggest me a way to do that?
bool MainWindow::eventFilter(QObject* obj, QEvent *ev)
{
if(ev->type() == QEvent::MouseButtonPress)
{
if(obj == ui->listOfImages->viewport())
{
QMouseEvent * mouseEv = static_cast<QMouseEvent*>(ev);
if((mouseEv->buttons() & Qt::LeftButton) && (QApplication::keyboardModifiers().testFlag(Qt::ControlModifier) == true))
{
controlButtonCounter++;
fetch = true;
return QObject::eventFilter(obj,ev);
}
else if((mouseEv->buttons() & Qt::LeftButton) && (QApplication::keyboardModifiers().testFlag(Qt::ControlModifier) == false))
{
if(selectedImages.size()>0)
{
ui->listOfImages->clearSelection();
selectedImages.clear();
selectedList.clear();
ui->selectedFiles->clear();
ui->selectedFiles->show();
}
fetch = false;
controlButtonCounter = 0;
}
}
}
return QObject::eventFilter(obj,ev);
}
I would try to extend your event filter's code with the following block:
[..]
if (event->type() == QEvent::KeyPress && obj == ui->listOfImages->viewport()) {
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
int key = keyEvent->key();
Qt::KeyboardModifiers modifiers = keyEvent->modifiers();
if(modifiers & Qt::ShiftModifier)
key += Qt::SHIFT;
if(modifiers & Qt::ControlModifier)
key += Qt::CTRL;
if(modifiers & Qt::AltModifier)
key += Qt::ALT;
if(modifiers & Qt::MetaModifier)
key += Qt::META;
if (QKeySequence(key) == QKeySequence(QKeySequence::SelectAll)) {
// Filter the event.
return true;
}
}
[..]
This code is supposed to return true (filter the event) if standard "select all" key combination pressed. It is usually Ctrl+A keys.