I have created my own widget based on QGraphicsView. I did this in order to re-implement some mouse events as such:
void Workspace::mouseMoveEvent(QMouseEvent *event)
{
qDebug() << (QString("Mouse move (%1,%2)").arg(event->x()).arg(event->y()));
QGraphicsView::mouseMoveEvent(event);
}
as well as install an event filter
bool Workspace::eventFilter(QObject* obj, QEvent* e)
{
if(e->type() == QEvent::Enter)
qDebug() << "Entered Workspace";
}
I did not liked the default 'hand' mouse pointer though and I decided to change it using
this->setCursor(Qt::CrossCursor);
in my constructor.
What happens though is the mouse pointer changing into a cross only while being at the very first pixel of the widget. The moment I move further in it goes back to the default 'hand' cursor that is used to signify drag functionality.
Why is this happening and how can I change the cursor to whatever I like?
It seems that using
QApplication::setOverrideCursor(Qt::CrossCursor);
when entering the widget, and
QApplication::restoreOverrideCursor();
when exiting, does the trick.
I am not sure why setCursor did not work though.
EDIT
Actually using the above is not such a good idea, as it is simpler to just use
QApplication::changeOverrideCursor(*mCurrentCursor);
you will not have to worry about anything else this way, Qt will take care of stack en-queue/de-queue.
Related
I am using QSlider element in my app as a toogle switch. I took this project over from a colleage of mine who left. So far so good, except, that this switch has a black label around it. I can't really change the style and rework everything so, I am stuck with label and slider as switch.
I need to handle events from button clicked and button released. I do it like this-
bool CustomSlider::eventFilter(QObject *obj, QEvent *ev )
{
if (ev->type() == QEvent::MouseButtonRelease)
{
changeSliderValue();
}
if(ev->type() == QEvent::MouseButtonPress){
lastSaved = ui->horizontalSlider->value();
}
return QWidget::eventFilter(obj,ev);
And changeSliderValue()-
void CustomSlider::changeSliderValue()
{
int current = ui->horizontalSlider->value();
if(lastSaved==current){
if(current){
ui->horizontalSlider->setValue(0);
}else{
ui->horizontalSlider->setValue(1);
}
}
}
So, in short, if I click, it saves state of slider and when releasing it checks against saved state. I do it because QSlider has button pressed signal as well. I have put debug messages in my code and funny thing is debug messages fire. So my code works. If I call ui->horizontalSlider->value() I get the correct(changed) value But the slider is not moving. I have tried checking sequences, if it does not change value twice(it does not), I have tried calling repaint() and so far nothing works. Except if don't minimize(via minimize button) or click in different app(like web browser) and then I can see that slider moves to correct postion. I am completely confused. Has anyone encoutered something like this before?
I have undecorated my window as follows:
MainWindow::MainWindow(QWidget *parent) :
QWidget(parent, Qt::FramelessWindowHint | Qt::WindowSystemMenuHint)
{}
How can I make it draggable?
Since you removed the window decoration and thus any access point the windowing system would have for providing movement, you'll have to implement it yourself.
You can either reimplement the window's mouse event handlers, or use an event filter on the window object.
See QWidget::mousePressEvent(), QWidget::mouseMoveEvent(), QWidget::mouseReleaseEvent() and QObject::eventFilter() respectively.
And QWidget::move() for the actual movement of course.
Since you already have a derived class, implementing the event handlers is probably the more straight forward approach.
Since Qt 5.15, there is QWindow::startSystemMode for exactly this use-case.
Here is an example snippet for a widget that triggers the system move handling for its window, when it is left-clicked:
void WindowMoveWidget::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
window()->windowHandle()->startSystemMove();
return;
}
return QWidget::mousePressEvent(event);
}
For more information see the respective blog post.
Note that the function returns whether the operation is supported by the system, so you may want to check its return value and implement a fallback based on QWidget::move.
I have the following widget structure. CDockWidgetInfoBar is just a QDockWidget derived class
When I move over the QDockWidget (CDockWidgetInfoBar), I see this splitter cursor.
Where is it coming from? Can I disable it? Is it part of QDockWidgetLayout? However, QDockWidgetLayout is Qt private and shall not be used.
Any ideas?
It seems to be impossible or extremely painful for system.
I tried to do this as I did this here: How can I prevent transform cursor to SplitHCursor when it's under border between QHeaderView sections
But the main problem, that resize cursor appears before QEvent::Enter event occurs. (if you run next code, you will see resize cursor first, but you will not see "added" word). As I know, there is no any event which can catch cursor when it moves near edge of widget. So it is very difficult to catch this event. There is another way. In mouseMoveEvent every time check is cursor near the dock widget. But I think that it is extremely inefficient.
I wrote this code:
if (obj == ui->dockWidget && event->type() == QEvent::Enter)
{
qApp->setOverrideCursor(QCursor(Qt::ArrowCursor));
qDebug() << "added";
}
if (obj == ui->dockWidget && event->type() == QEvent::Leave)
{
qApp->restoreOverrideCursor();
}
But it really works after user trying to float dock.
I know that it is not full answer, but maybe it helps or prove that it is very difficult. Anyways, if someone will find efficient solution of this problem, it will be extremely great.
I currently am attempting to display a tooltip on focusOutEvent of a widget. This tooltip basically validates the data inside the Widget (QLineEdit). Now the problem is I want to display the errors or issues using a tooltip . Here is what I am doing
void MyLineEdit::focusOutEvent(QFocusEvent *e)
{
QLineEdit::focusOutEvent(e);
QToolTip::showText( this->mapToGlobal( QPoint( 0, 0 ) ), "Something got it" );
emit(focussed(false));
}
Now the problem is the QTooltip is not displayed that is probably because the mouse is moving. My question is how can I make QTooltip be displayed and keep it there until I wish to turn it off ??
A tooltip will only show up if a QHelpEvent was intercepted. While you can send one from focusOutEvent using QCoreApplication::PostEvent and subclass QWidget::event like this
bool MyLineEdit::event (QEvent *event)
{
if (event->type() == QEvent::ToolTip) {
QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event);
QToolTip::showText(helpEvent->globalPos(), "Something got it");
return false;
}
return QWidget::event(event);
}
, this has two undesirable consequences.
1) The event would still be triggered whenever a tooltip would be shown normally (that is, when your mouse pointer stays on the widget for a couple of seconds). You will have to implement some kind of recognition mechanism to distinguish your own help events from the rest.
2) The tooltip is only active while the respective widget is focused. So, displaying a tooltip when the focus is lost will show it only for a couple of seconds, until the next event loop is processed.
There might be a workaround for the latter, but at this point, it is probably better to leave the tooltips for their intended purpose and implement your own pseudo-tooltip which you would control directly.
I am using
void QGraphicsItem::installSceneEventFilter(QGraphicsItem * filterItem);
to set an event filter on a QgraphicsItem (see itemChanged() in QGraphicsItem for a many different items)
Now, for some of these items, I'd like to restrict the movement, i.e. change the x and y position of the item so that the user would be restricted in some area in the object move.
I first tried to modify the event with:
(static cast <QGraphicsSceneMouseEvent*>(event))->setPos(QPoint(150, watched->y()));
The whole handler beiing:
bool generic_graphic_item::sceneEventFilter(QGraphicsItem* watched, QEvent* event)
{
if(event->type() == QEvent::QEvent::GraphicsSceneMouseMove)
{
(static_cast<QGraphicsSceneMouseEvent*>(event))->setPos(QPointF(150, watched->y()));
//emit my_item_changed(watched); // signal that the item was moved
emit(item_pos_changed(watched, watched->x(), watched->y()));
}
return false; // pass the event to the original target item
}
But it did not work. I was not really sure either about the specific event class hiding behind a QEvent::GraphicsSceneMouseEvent.
I then tried to call watched->setX() and watched->setY() within the event handler, but that was not very popular... which I can understand...
Is it possible to restrict the movement within the scene event handler?
I have read that QGraphicsItem::itemChange() can be used to do that, but then I am back into the problem described in 'itemChanged() in QGraphicsItem for a many different items', i.e. how can I have this common to many items without subclassing each of them...
many thanks,
The code you post in this question is responding to the event of the moving of the mouse. For what you're describing that you want to do, I suggest you check for the event of a widget being moved with QEvent::GraphicsSceneMove: -
if(event->type() == QEvent::GraphicsSceneMove)
{
// set the position of the item.
}