Trolltech Home | Qt-jambi-interest Home | Recent Threads | All Threads | Author | Date
All threads index page 1

Qt-jambi-interest Archive, November 2006
QGraphicsItem parent/child with clipping


Message 1 in thread

Hello,

I'm pretty new to Qt and Qt-Jambi and I'm currently playing around with
QGraphicsItem.
What I want to do is to add an item as the child of another item with the
parent item
defining the clipping bounds of the child item(s).

Right now my paint method looks like this:

		public void paint(QPainter painter, QStyleOptionGraphicsItem
arg1, QWidget arg2) {
			if (parentItem() != null) {
	
painter.setClipRect(parentItem().boundingRect());
				painter.setClipping(true);
			}
	
painter.setRenderHint(QPainter.RenderHint.Antialiasing);
			painter.setPen(new QPen(QColor.black));
			painter.setBrush(new QBrush(QColor.yellow));

			painter.drawRect(rectangle);
		}		

Problem is: I can still move my child item outside the bounds of th parent
item and
it's not clipped at all.

I'm pretty sure I'm missing something really basic here - I'm just not sure
what ;)
Any pointers would really be appreciated.

Best regards,
Lennart Steinke


Message 2 in thread

Hi, Lennart.

Lennart Steinke wrote:

>What I want to do is to add an item as the child of another item with the
>parent item
>defining the clipping bounds of the child item(s).
>
>Right now my paint method looks like this:
>
>		public void paint(QPainter painter, QStyleOptionGraphicsItem
>arg1, QWidget arg2) {
>			if (parentItem() != null) {
>	
>painter.setClipRect(parentItem().boundingRect());
>  
>

The bounding rect of the parent is in the parent's coordinate system and 
the painter is in the current item's coordinate system.

This should help:

    QPainterPath path = new QPainterPath();
    path.addPolygon(mapFromParent(parentItem().boundingRect());
    painter.setClipPath(path);

Another way of achieving this for all your items is to override the 
drawItems() method in QGraphicsScene. I've attached a quick example of 
this, but please note that the we are currently working on fine tuning 
the API where the class QNativePointer occurs (as this is an 
inconvenient class to use.) Thus, this example will look different in 
the next release of Qt Jambi, but it should illustrate the point, at least.

-- Eskil


import java.util.List;
import java.util.List;

import com.trolltech.qt.QNativePointer;
import com.trolltech.qt.core.QPointF;
import com.trolltech.qt.core.QRectF;
import com.trolltech.qt.core.QSizeF;
import com.trolltech.qt.core.Qt;
import com.trolltech.qt.gui.QApplication;
import com.trolltech.qt.gui.QBrush;
import com.trolltech.qt.gui.QColor;
import com.trolltech.qt.gui.QGradient;
import com.trolltech.qt.gui.QGraphicsItem;
import com.trolltech.qt.gui.QGraphicsItemInterface;
import com.trolltech.qt.gui.QGraphicsScene;
import com.trolltech.qt.gui.QGraphicsSceneMouseEvent;
import com.trolltech.qt.gui.QGraphicsView;
import com.trolltech.qt.gui.QLinearGradient;
import com.trolltech.qt.gui.QPainter;
import com.trolltech.qt.gui.QPainterPath;
import com.trolltech.qt.gui.QStyleOptionGraphicsItem;
import com.trolltech.qt.gui.QWidget;


public class GraphicsSceneClipping extends QGraphicsScene {
    
    private static class Basket extends QGraphicsItem {
        private QRectF boundingRect;
        private QPainterPath shape;
        private QGradient gradient;

        public Basket(QSizeF size) {
            boundingRect = new QRectF(-size.width() / 2, -size.height() / 2, size.width(), size.height());
            shape = new QPainterPath();
            shape.addEllipse(boundingRect);
            
            gradient = new QLinearGradient(boundingRect.topLeft(), boundingRect.bottomLeft());
            gradient.setColorAt(0.0, QColor.fromRgb(128, 128, 128, 200));
            gradient.setColorAt(1.0, QColor.fromRgb(200, 200, 200, 200));                        
        }

        @Override
        public QRectF boundingRect() {
            return boundingRect;
        }
        
        @Override
        public QPainterPath shape() {
            return shape;
        }
        
        @Override
        public void paint(QPainter painter, QStyleOptionGraphicsItem option, QWidget widget) {
            painter.setBrush(new QBrush(gradient));
            painter.drawPath(shape());
        }               
    }
    
    private static class Egg extends QGraphicsItem {
        private QRectF boundingRect;
        private QPainterPath shape;
        private QGradient gradient;
        
        public Egg(QSizeF size) {
            boundingRect = new QRectF(0.0, 0.0, size.width(), size.height());
            shape = new QPainterPath();
            shape.addEllipse(boundingRect);
            
            gradient = new QLinearGradient(boundingRect.topLeft(), boundingRect.bottomRight());
            gradient.setColorAt(0.0, QColor.fromRgb(230, 230, 230, 200));
            gradient.setColorAt(1.0, QColor.fromRgb(250, 250, 250, 200));
        }
        
        @Override 
        public QPainterPath shape() {
            return shape;
        }

        @Override
        public QRectF boundingRect() {
            return boundingRect;
        }

        @Override
        public void paint(QPainter painter, QStyleOptionGraphicsItem option, QWidget widget) {
            painter.setBrush(new QBrush(gradient));
            painter.drawPath(shape());
        }
        
    }
    
    public static void main(String[] args) {
        QApplication.initialize(args);
        GraphicsSceneClipping scene = new GraphicsSceneClipping();
        QGraphicsView view = new QGraphicsView();
        view.setScene(scene);
        view.setRenderHint(QPainter.RenderHint.Antialiasing);
        
        view.show();
       
        QApplication.exec();
    }
        
    private Basket baskets[] = new Basket[4];
    private Egg eggs[] = new Egg[100];
    public GraphicsSceneClipping() {
        // Make baskets
        for (int i=0; i<4; ++i) {
            baskets[i] = new Basket(new QSizeF(200.0 - i * 30.0, 200.0 - i * 30.0));
            
            addItem(baskets[i]);
            baskets[i].setPos((i % 2) * 200.0, (i / 2) * 200.0);
            baskets[i].setZValue(2.0);
        }
        
        // Make eggs
        for (int i=0; i<100; ++i) {
            eggs[i] = new Egg(new QSizeF(20.0, 50.0));
            
            addItem(eggs[i]);
            eggs[i].setPos(400.0 + Math.random() * 200.0, Math.random() * 400.0);
            eggs[i].setZValue(5.0);
        }
    }
    
    @Override
    protected void drawItems(QPainter painter, int numItems, QNativePointer _items, QStyleOptionGraphicsItem options, QWidget widget) {
        List<QGraphicsItemInterface> items = items(itemsBoundingRect());
                        
        for (int i = items.size()-1; i>=0; --i) {
            QGraphicsItemInterface item = items.get(i);
            
            painter.save();
            painter.setMatrix(item.sceneMatrix(), true);
            
            QPainterPath path = new QPainterPath();
            if (item.parentItem() != null) { 
                path.addPath(item.mapFromParent(item.parentItem().shape()));
                painter.setClipPath(path, Qt.ClipOperation.ReplaceClip);
            }
            painter.setClipRect(item.boundingRect().adjusted(-1.0, -1.0, 1.0, 1.0), Qt.ClipOperation.IntersectClip);
            item.paint(painter, null, widget);
                        
            painter.restore();
        }                
    }

        
    private QGraphicsItemInterface draggedItem = null;
    
    @Override
    protected void mouseMoveEvent(QGraphicsSceneMouseEvent event) {
        if (draggedItem != null) {                        
            QPointF pos = event.scenePos();
            if (draggedItem.parentItem() != null) 
                pos = draggedItem.parentItem().mapFromScene(pos);
            
            draggedItem.setPos(pos);            
        }
    }

    @Override
    protected void mousePressEvent(QGraphicsSceneMouseEvent event) {
        draggedItem = itemAt(event.scenePos());
    }

    @Override
    protected void mouseReleaseEvent(QGraphicsSceneMouseEvent event) {
        if (draggedItem != null) {
            List<QGraphicsItemInterface> items = items(event.scenePos());
            
            if (draggedItem instanceof Egg) {
                for (QGraphicsItemInterface basket : items) {   
                    if (basket instanceof Basket) {
                        draggedItem.setParentItem(basket);
                        draggedItem.setPos(basket.mapFromScene(event.scenePos()));
                        break;
                    }
                }
            }
            draggedItem = null;
        }
    }

}