So should I make big QGraphicsRectItem and then inside that item smaller QGraphicsRectItem?
Not exactly. A QGraphicsRectItem will draw a complete 4-sided rectangle. You need to be able to draw rectangles with one or more edges missing. You could use a QGraphicsRectItem for the outside box and make it the parent of all of the smaller boxes. That way, when it changes size, all of the boxes inside it will automatically be resized, too. If you set Qt::NoPen as the pen for this outer box, then the outline will not be drawn (which is what you want, because you need to leave openings for the entrance and exit of the maze.
For the inside boxes, you can derive a new class from QGraphicsRectItem, and override the paint() method. You could also add data members and methods to set which sides of the box are open. Then, in your paint method, you will draw lines only for the edges that are closed.
An easy way to keep a data structure for the sides is to use QFlags:
// A MazeRectItem is a 10 x 10 square (logical coordinates) with 0 - 4 closed sides
{
public:
enum Side {
None = 0,
Left = 1,
Right = 2,
Top = 4,
Bottom = 8,
AllSides = Left | Right | Top | Bottom
};
Q_DECLARE_FLAGS( Side, Sides );
Sides closedSides() const { return mClosedSides; }
void setClosedSides( const Sides & sides ) { mClosedSides = sides; }
void setClosedSide( const Side & side ) { mClosedSides |= side; }
bool isSideClosed( const Side & side ) const { return mClosedSides.testFlag( side ); }
private:
Sides mClosedSides = None;
};
Q_DECLARE_OPERATORS_FOR_FLAGS( MazeRectItem::Sides );
// A MazeRectItem is a 10 x 10 square (logical coordinates) with 0 - 4 closed sides
class MazeRectItem : public QGraphicsRectItem
{
public:
enum Side {
None = 0,
Left = 1,
Right = 2,
Top = 4,
Bottom = 8,
AllSides = Left | Right | Top | Bottom
};
Q_DECLARE_FLAGS( Side, Sides );
MazeRectItem( QGraphicsItem * parent ) : QGraphicsRectItem( parent ), mClosedSides( None ) { setRect( QRectF( -5.0, -5.0, 5.0, 5.0 ); }
Sides closedSides() const { return mClosedSides; }
void setClosedSides( const Sides & sides ) { mClosedSides = sides; }
void setClosedSide( const Side & side ) { mClosedSides |= side; }
bool isSideClosed( const Side & side ) const { return mClosedSides.testFlag( side ); }
void paint( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = nullptr ) override;
private:
Sides mClosedSides = None;
};
Q_DECLARE_OPERATORS_FOR_FLAGS( MazeRectItem::Sides );
To copy to clipboard, switch view to plain text mode
and the way you use this is:
{
// Save the current pen, set the pen to NoPen, then let the base class draw itself. NoPen means there will be
// no outline drawn
setPen( Qt::NoPen );
setPen( savePen );
if ( isSideClosed( Left ) )
{
// draw the left side
}
if ( isSideClosed( Right ) )
{
// draw the right side
}
// etc.
}
void MazeRectItem::paint( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget )
{
// Save the current pen, set the pen to NoPen, then let the base class draw itself. NoPen means there will be
// no outline drawn
QPen savePen = pen();
setPen( Qt::NoPen );
QGraphicsRectItem::paint( painter, option, widget );
setPen( savePen );
if ( isSideClosed( Left ) )
{
// draw the left side
}
if ( isSideClosed( Right ) )
{
// draw the right side
}
// etc.
}
To copy to clipboard, switch view to plain text mode
And remember for QGraphicsRectItem, the origin (0, 0 ) is the center of the rect and position (pos()) is relative to the parent of the item. So when you draw a maze rect, all you have to calculate is the position of the lines in the rect's own coordinates. If the rect has a width and height of 10, then the top line goes from (-5, -5) to (5, -5). When you put the maze rect inside another rect, all of the drawing coordinates will automatically be adjusted by the painter. You do not have to care. You just draw your 4 lines in your -5 - +5 coordinate space.
Bookmarks