I am using several instances of QQuickPaintedItem class that listen to hoverEnterEvent and hoverLeaveEvent, as well as mousePressEvent and mouseReleaseEvent. I have a need to select or deselect items when the cursor passes over them with the mouse button held down. However, the "hover" events are no longer handled when the button is held down. How can I fix it?
In this case, the sequence of actions is as follows:
mouse button is clicked over first element.
the cursor is dragged over the second element
when the cursor leaves the second element, it is highlighted
the same with the next element, until the mouse button is released.
'Item::Item( QQuickItem* parent )
: QQuickPaintedItem( parent )
{
setAcceptedMouseButtons( Qt::LeftButton );
setAcceptHoverEvents( true );
}
void Item::mousePressEvent( QMouseEvent* e )
{
myStateHandler->mousePressed = true;
}
void Item::mouseReleaseEvent( QMouseEvent* e )
{
myStateHandler->mousePressed = false;
}
void Item::hoverLeaveEvent( QHoverEvent* e )
{
QQuickItem::hoverEnterEvent( e );
if( myStateHandler->mousePressed )
{
isSelected = !isSelected;
update();
}
}
void Item::paint( QPainter* p )
{
if(isSelected )
{
p->setPen( Qt::NoPen );
p->setBrush( QColor( 205, 205, 0 ) );
p->drawRect( boundingRect() );
}
}'
Thank you in advance.
Related
I build a widget which accepts drag&drop as follows:
MyWidget::MyWidget( QWidget *p_parent ) : QFrame( p_parent )
{
setAcceptDrops( true );
m_layout = new QLayout( this ); //this is layout of my custom widget
layout->setSpacing( 0 );
m_indicator = new QWidget( this );
m_indicator->setObjectName( "indicator" );
m_indicator->setFixedWidth( 5 );
layout->addWidget( m_indicator );
....
....
}
void MyWidget::dragMoveEvent( QDragMoveEvent *p_event )
{
p_event->acceptProposedAction();
}
My main job is to insert the dragged object into the layout, therefore, I should identify which item is under the mouse, and do my job after that. In function dragMoveEvent above, I can do p_event->pos() to get the position of the mouse. But QLayout does not have method itemAt(int x, int y). What should I do now?
Layouts can't do that, but fortunately the parent widget can. Example code (untested):
void MyWidget::dragMoveEvent( QDragMoveEvent *p_event )
{
auto *widget = childAt(p_event->pos());
if(widget) {
....
}
I am trying to get my TitledPane to NOT open when it is in the process of expanding. I created a boolean variable isExpanding to set to true when it's expanding, and false after it's done expanding.
My issue is that, while using the SceneBuilder GUI, I have a TitledPane that when clicked it expands by default and I don't think I can change that. What I need is for when my var isExpanding == true then clicking on the TitledPane event is consumed, and it does nothing.
Here is my MouseEvent for when you click on the TitledPane. After the animation is completed in a different function the isExpanding is set to false.
#FXML
private void handleTitledPaneMouseClickDNSAction(MouseEvent event) {
if( dnsTitledPane.expandedProperty() == null || dnsTitledPane.isExpanded() == false ) {
animateCollapse( dnsPane, dnsTitledPane );
isExpanding = false;
} else {
expanTimeline = new Timeline(new KeyFrame(
Duration.millis( 15 ),
ae -> animateExpanstion( dnsPane, dnsTitledPane )));
expanTimeline.setCycleCount( Timeline.INDEFINITE );
expanTimeline.play();
isExpanding = true;
}
}
Its just a workaround. You can explicitly set titledPane Expansion as false in its mouse click handler.
Here's the code:
titlePane.setOnMouseClicked((evt) -> {
if(isExpanding)
titlePane.setExpanded(false);
else
titlePane.setExpanded(true);
});
I have implemented the panning view on the QGraphicsView, using the mouse move event using
void View::mouseMoveEvent(QMouseEvent* event) {
pan();
QGraphicsView::mouseMoveEvent(event);
}
and in the scene of this view I have added few items where some of the items are resizable, so I implemented
void Item::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
if(m_resizeMode)
{
resize();
e->accept();
}
}
I tried to filter the mouse move not to propagate to any further using e->accept()
but my View mouseMove event has been called first , so when ever I tried to resize the item, the view started to pan all the way.
How can I avoid this event propagation from view to scene.
You can call the base class implementation of the QGraphicsView and check if the event is accepted. However I would do this in the mousePressEvent instead of the mouseMoveEvent. After all this is where you determine if you should resize an item or do some panning. This is how I do something similar in my project:
void View::mousePressEvent(QMouseEvent *event)
{
...
QGraphicsView::mousePressEvent(event);
if(event->isAccepted())
move = false;
else
move = true;
}
void View::mouseMoveEvent(QMouseEvent *event)
{
if(!move)
{
QGraphicsView::mouseMoveEvent(event);
return;
}
... // you would do the panning here
QGraphicsView::mouseMoveEvent(event);
}
void View::mouseReleaseEvent(QMouseEvent *event)
{
if(!move)
{
QGraphicsView::mouseReleaseEvent(event);
return;
}
else
{
...
move = false;
}
QGraphicsView::mouseReleaseEvent(event);
}
The view will always receive the mouse event first.
So, in the view, check to see if the mouse is over an item before allowing it to pan by getting the mouse pos in scene coordinates and retrieving the items at that position with QGraphicsScene::items( )
I want to ask a question about can I resize QGraphicsItem without creating a class that inherits QGraphicsItem. For example, something like this:
void MyScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
point = event->scenePos();
if( ArrowCursor )
{
curItem = this->itemAt( point, view->transform() );
if( curItem && !curItem->isSelected() )
{
curItem->update( 10,10, 100, 100 );
}
}
}
curItem->setTransform(QTransform::fromScale(2.0,2.0), true);
Offtopic: This is strange that you are doing this by subclassing QGraphicsScene.
So I have a ON-OFF button that draws a circle. The trouble I am encountering is that the ON OFF states are random depending on how long I press the button. I guess this is due to the draw() function which also loops my button function in time with framerate. What I want is for the button to turn on when pressed once and turn off when pressed again irrespective of how long the button is pressed. Here is the code.
else if (circle4.pressed()) {
println("button 4 is pressed");
if(drawCirclesPrimary){
drawCirclesPrimary = false;
}
else{
drawCirclesPrimary = true;
}
println("drawCirclesPrimary"+drawCirclesPrimary);
}
I would suggest looking at the Buttons tutorial on processing.org. The following code is a subset of what is contained in the tutorial (you will need to review all the code in the tutorial, however). Comments are mine.
void setup() {
// Create instances of your button(s)
}
void draw() {
// Draw buttons, update cursor position, check if buttons have been clicked.
}
// Provides the overRect() method (among others).
class Button
{
// If the cursor is placed within the footprint of the button, return true.
boolean overRect(int x, int y, int width, int height)
{
if (mouseX >= x && mouseX <= x+width && mouseY >= y && mouseY <= y+height) {
return true;
}
else {
return false;
}
}
}
class RectButton extends Button
{
// Create a rectangle button with these size/color attributes.
RectButton(int ix, int iy, int isize, color icolor, color ihighlight)
{
x = ix;
y = iy;
size = isize;
basecolor = icolor;
highlightcolor = ihighlight;
currentcolor = basecolor;
}
// Determines whether the cursor is over the button.
boolean over()
{
if( overRect(x, y, size, size) ) {
over = true;
return true;
}
else {
over = false;
return false;
}
}
// Draws the rectangle button into your sketch.
void display()
{
stroke(255);
fill(currentcolor);
rect(x, y, size, size);
}
}
This thread has some example code for drawing an object only while a key is pressed. That's pretty similar to what you want.
Instead of keyPressed and keyReleased, you can use mouseClicked. which is called once after a mouse button has been pressed and then released. Use a boolean variable to store the on/off state. Inside of mouseClicked, toggle the value of that boolean variable.