I'm trying to create an interface for myself on Qt and I need a few rectangles over a DICOM image (a magnetic ressonance image), so they need to be some color other than black but I can't find a way to set a brush for the QGraphicsItemGroup I'm using to keep the rectangles organized.
QGraphicsScene lets me add a QRect associated to a QBrush individually with
QgraphicsScene *scene = new QGraphicsScene();
QRectF rect = QRectF(QPoint(1,2),QPoint(3,4));
scene->addRect(rect, QBrush(Qt::red)); // using red as example
but adding each rectangle individually would make it all too messy and probably way slower. I need a way to set a QBrush for the rectangles but using QGraphicsItemGroup to be added to the QGraphicsScene.
Why can you not reimplement QGraphicsItemGroup and inside have a function called:
void ReimplementedQGraphicsItemGroup::SetRectangleBrush(const QBrush& brush)
and inside that function iterate over every rectangle you have added to the group setting the brush
QgraphicsScene *scene = new QGraphicsScene();
ReimplementedQGraphicsItemGroup ReimplGraphicsGroup = new ReimplementedQGraphicsItemGroup()
// First rect
QGraphicsRectItem rect(1,2,3,4);
rect.setBrush(QColor(Qt::red);
ReimplGraphicsGroup->AddRectangle(rect);
// Second rect
QGraphicsRectItem rect2(5,6,7,8);
rect2.setBrush(QColor(Qt::blue);
ReimplGraphicsGroup->AddRectangle(rect2);
// add reimplemented graphics item group to scene
scene->addItem(ReimplGraphicsGroup);
void ReimplementedQGraphicsItemGroup::SetRectangleBrush(const QBrush& brush)
{
foreach (QGraphicsRectItem rect, m_ListRects)
{
rect.setBrush(brush);
}
}
class ReimplementedQGraphicsItemGroup : public QGraphicsItemGroup {
// a member of ReimplementedQGraphicsItemGroup
QList<QGraphicsRectItem> m_ListRects;
}
void ReimplementedQGraphicsItemGroup::AddRectangle(QGraphicsRectItem rect)
{
addToGroup(rect);
m_ListRects.append(rect);
}
Related
I have a QGraphicsItem with an embedded QWidget, this QWidget have a QPushButton in it.
I'm trying to map the center of the QPushButton to the QGraphicsScene coordinates, so for example, I can add a Circle to the center of the QPushButton.
With the help from another post I was able to find the center of the QPushButton, but it doesn't correspond to its actual position in the QGraphicsScene.
What I tried:
Getting the QRect of the button and then its center, finally mapping to the global coordinates of the view.
Getting the QRect of the button, then its center and mapping it to the QGraphicsItem.
Getting the QRect of the button, then its center, mapping it to the QGraphicsItem and than mapping it to the scene.
In general, I tried mapping it to Scene, to Global and to Item but it always looks incorrect. And the farther I move the QGraphicsItem, the less accurate it gets. Here the circle is supposed to be positioned at the center of the "B" button:
Qwidget:
class NodeFrame : public QFrame
{
public:
NodeFrame();
QRect getButtonRect()
{
return layout->itemAt(0)->geometry();
}
private:
QPushButton* button = nullptr;
QHBoxLayout* layout = nullptr;
};
NodeFrame::NodeFrame()
{
setFixedSize(200,80);
// Creates and add a QPushButton to the frame.
// I need the position of this button on the QGraohicsScene
button = new QPushButton("B");
button->setFixedSize(40,20);
layout = new QHBoxLayout();
layout->addWidget(button);
layout->setAlignment(Qt::AlignCenter);
setLayout(layout);
}
QGraphicsItem:
class Node : public QGraphicsItem
{
public:
Node();
QRectF boundingRect() const override;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
QRect getButtonRect()
{
return frame->getButtonRect();
}
NodeFrame* frame = nullptr;
};
Node::Node()
{
setFlag(ItemIsMovable);
// Create a GraphicsProxyWidget to insert the nodeFrame into the scene
auto proxyWidget = new QGraphicsProxyWidget(this);
frame = new NodeFrame();
proxyWidget->setWidget(frame);
// Center the widget(frame) at the center of the QGraphicsItem
proxyWidget->setPos(boundingRect().center() - proxyWidget->boundingRect().center());
}
QRectF Node::boundingRect() const
{
return QRectF(-10, -10, 280, 150);
}
void Node::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
QPainterPath path;
path.addRoundedRect(boundingRect(), 10, 10);
painter->drawPath(path);
}
main:
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
// Create scene and view
auto scene = new QGraphicsScene();
auto view = new QGraphicsView(scene);
view->setMinimumSize(800, 800);
// Create the QGraphicsItem and add it to the scene
auto item = new Node();
scene->addItem(item);
item->setPos(50, 50);
auto btnRect = item->getButtonRect();
auto center = view->mapToGlobal(btnRect.center());
auto circle = new QGraphicsEllipseItem();
circle->setRect(QRectF(center.x(), center.y(), 25, 25));
scene->addItem(circle);
// Show the the view
view->show();
return app.exec();
}
Appreciate any help.
Solved. This was caused by two things:
1: QRectF getButtonRect() was returning layout->itemAt(0)->geometry(), (index 0 being the first and only widget in the layout) but button->frameGeometry() seems to be a more accurate visual representation of the button's geometry.
2: When adding the widget to the graphic item using QGraphicsProxyWidget, I was adjusting the position of the widget inside the graphic item using:
proxyWidget->setPos(boundingRect().center() - proxyWidget->boundingRect().center());
This was changing the position (obviously) of the widget inside the graphic item, so visually it didn't align with the result given by button->frameGeometry().
How can I append new rectangle shape to QgraphicView In this code which create rectangle when the button click.But when I click the button second time previously created rectangle removed.I need to do create 2 rectangle when I click the button 2 times.create 3 rectangle when I click the button 3 times
void Widget::on_btnCreateRect_clicked()
{
scene = new QGraphicsScene(this);
ui->graphicsView->setScene(scene);
//QBrush redBrush(Qt::red);
QBrush blueBrush(Qt::blue);
QPen blackPen(Qt::black);
blackPen.setWidth(6);
rect = scene->addRect(-10,-10,100,100,blackPen,blueBrush);
rect->setFlag(QGraphicsItem::ItemIsMovable, true);
}
With scene = new QGraphicsScene(this); you create a new scene and add the rectangle to it. The old scene with the previous rectangles exist but is not shown anymore. So instead of creating a new scene use the old one like that: rect = ui->graphicsView->scene()->addRect(-10,-10,100,100,blackPen,blueBrush);. This will also avoid the memory leak you create with new. Here is the corrected code:
void Widget::on_btnCreateRect_clicked()
{
//QBrush redBrush(Qt::red);
QBrush blueBrush(Qt::blue);
QPen blackPen(Qt::black);
blackPen.setWidth(6);
QRect *rect = ui->graphicsView->scene()->addRect(-10,-10,100,100,blackPen,blueBrush);
rect->setFlag(QGraphicsItem::ItemIsMovable, true);
}
How can I change QGraphicView selected item color.In this code which can select items form QGraphicView and delete and also able to disable item moving.How can I change the color of selected Item.
void Widget::on_btnDelete_clicked()
{
foreach (QGraphicsItem *item,ui->graphicsView->scene()->selectedItems()) {
delete item;
}
}
void Widget::on_btnMoveDis_clicked()
{
foreach (QGraphicsItem *item,ui->graphicsView->scene()->selectedItems()) {
item->setFlag(QGraphicsItem::ItemIsMovable,false);
}
}
At first I suggest you to read QGraphicsView examples and docs carefully , I recommend Diagram Scene Example and Elastic Nodes Example as starting point. Because QGraphicsView frame work is smart if you use it smart otherwise you may pay penalties in performance.
And now your question :
whole answer is related to qgraphicsitem_cast, how to use it?
First let me provide some initializations look code below at first I add three rectangles to scene and set their flags.
void MainWindow::on_btnInit_clicked()
{
QColor color = Qt::red;
QBrush brush = Qt::SolidPattern;
brush.setColor(color);
QRect * rectObject = new QRect(QPoint(0,0) , QSize(20,20));
scene.addRect(*rectObject , color, brush);
rectObject = new QRect(QPoint(0,30) , QSize(20,20));
color = Qt::green;
brush.setColor(color);
scene.addRect(*rectObject , color, brush);
rectObject = new QRect(QPoint(0,60) , QSize(20,20));
color = Qt::blue;
brush.setColor(color);
scene.addRect(*rectObject , color, brush);
foreach (QGraphicsItem *item,ui->graphicsView->scene()->items()) {
item->setFlag(QGraphicsItem::ItemIsMovable , true);
item->setFlag(QGraphicsItem::ItemIsSelectable , true);
}
}
I have set ItemIsMovable and ItemIsSelectable flags so for items could be selectable.
and now change color of selected item.
void MainWindow::on_btnSelectItem_clicked()
{
foreach (QGraphicsItem *item, ui->graphicsView->scene()->selectedItems())
{
QGraphicsRectItem *rect = qgraphicsitem_cast<QGraphicsRectItem *>(item);
if (!rect)
continue;
QBrush br(Qt::SolidPattern);
br.setColor(Qt::black);
rect->setBrush(br);
rect->update();
}
}
I use QGraphicsRectItem to cast rectangular objects that i added to scene before. If you want to learn more on use qgraphicsitem read Elastic Nodes Example.
In Qt/c++, I have an overloaded/custom QGraphicsView class.
In this classes' drawBackground event function (same issue happens with paintEvent), I am drawing some lines using the provided Qpainter:
void myGraphicsView::drawBackground(QPainter *painter, const QRectF &rect)
{
QGraphicsView::drawBackground(painter, rect);
QPen pen;
pen.setWidth(2);
painter->setPen(pen);
painter->drawLine(rect.x(),rect.y(),rect.x()+rect.width(),rect.y()+rect.height());
}
Initialization of the GraphicsView custom class:
myGraphicsView::myGraphicsView(GLWidget *myOpenGLWindow,QWidget * parent) : QGraphicsView(parent)
{
setDragMode(QGraphicsView::ScrollHandDrag);
myScene=new actionEditorButtons(this);
myScene->setMainView(this);
setScene(myScene);
setStyleSheet("background: transparent");
setAlignment(Qt::AlignBottom);
}
Initialization of the custom QGraphicsScene, with a button that gets "corrupted" with the line drawn in the custom graphicsview:
actionEditorButtons::actionEditorButtons(BrainClass *theBrain,int receivedActionNb,QObject *parent) : QGraphicsScene(parent)
{
beginButton = new QPushButton();
beginButton->setIcon(QIcon(":/icons/actionBegin.png"));
beginButton->setIconSize(QSize(40,40));
beginButton->setFixedSize(QSize(40,40));
beginButton->setStyleSheet("border: none");
beginProxy=addWidget(beginButton);
beginProxy->setPos(0,80);
connect(beginButton, SIGNAL (released()),this, SLOT (handleBeginButton()));
}
My issue is that this line is not only drawn on this custom QGraphicsView, but it is drawn too on all widgets added this scene. How can I only draw in the main graphicsView and not in the added widgets ?
I want to paint a round rectangle using the paint function in QGraphicsItem, I have a parent item and I want to paint its child in front of it, but I don't know how to do it?
And I have another problem, I want to list this items base on their parent position, but positions are static, how can I position items based on the parent position?
My paint function :
void flipedWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *w)
{
Q_UNUSED(w)
Q_UNUSED(option)
painter->setPen(Qt::NoPen);
QBrush *brush;
if(!m_color.isEmpty())
brush = new QBrush(QColor(m_color)); // set background color
else
brush = new QBrush("#cccccc");
painter->setBrush(*brush);
painter->drawRoundedRect(boundingRect(), 10, 10);
delete brush;
}