How to set background for QGraphicsSimpleTextItem (Qt C++)? - c++

I have added to my QGraphicsScene a QGraphicsSimpleTextItem, but just a simple text is unreadable of current background. Therefore I'd like to set background color of the QGraphicsSimpleTextItem, but... there is no such method. What's the simplest solution?

It seems that the simplest solution is to use QGraphicsTextItem instead of QGraphicsSimpleTextIem and to call setHtml() in the constructor, for example:
this->setHtml(QString("<div style='background-color: #ffff00;'>") + text + "</div>");

To change the background of your whole scene:
myScene->setBackgroundBrush( Qt::red );
Or if you want to change the background of just your text item, you'll probably have to subclass QGraphicsSimpleTextItem and override the paint() method.
class MyTextItem : public QGraphicsSimpleTextIem {
public:
void paint( QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget=0 )
{
painter->setBrush( Qt::red );
painter->drawRect( boundingRect() );
QGraphicsSimpleTextItem::paint( painter, option, widget );
}

Here is how you can access the background color.
QPalette currentPalette = myGraphicScene.palette();
// Set a new color for the background, use QPalette::Window
// as QPalette::Background is obsolete.
currentPalette.setColor( QPalette::Window, Qt::red );
// Set the palette.
myGraphicScene.setPalette( currentPalette );

Related

Will paint(), redraw everything from scene or will redraw only updated items in Qt?

I have QGraphicsView which contains many QGraphicsItem such as Rectangle, polylines. I have overriden paint() method. I am drawing QGraphicsItem using boost-graph. While drawing items, I am storing boost-graph pointer on every QGraphicsItem.
Now I am right clicking on some rectangle from scene and trying to hide it. While hiding it, I am trying to hide lines connected to it also. For that, I am taking boost-graph pointer stored at every item and iterating through it.
In boost graph, there is a flag isVisible, through setting-resetting it, I am hidding-unhidding that item.
myView.cpp
while(true)
{
// iterating thorugh boost-graph and finding co-ordinates
myRect* _rect = new myRect(rect co-ordinates);
_rect->setBrush(Qt::yellow);
_rect->setPtr(boost-graph pointer);
_scene->addItem(static_cast<QGraphicsRectItem*>(_rect));
}
void myView::HideSelectedRectangle() // after choosing hide from right mouse click, control comes here
{
foreach(QGraphicsItem* currentItem, _scene->selectedItems())
{
myRect* rItem = qgraphicsitem_cast<myRect*>(currentItem);
if(rItem)
{
VertexDescriptor vPtr = rItem->getBoostPtr(); // getting boost-graph ptr
// logic for making it hide
// Question is how paint() will know about this QGraphicsItem that it is hidden?
};
}
}
myRect.h
class myRect: public QGraphicsRectItem
{
public:
explicit myRect();
explicit myRect(QRectF &rectPoints,QGraphicsItem *parent = nullptr)
: QGraphicsRectItem(rectPoints,parent){}
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
void setPtr(VertexDescriptor);
VertexDescriptor getPtr();
VertexDescriptor boostPtr;
}
myRect.cpp
void myRect::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
auto copied_option = *option;
copied_option.state &= ~QStyle::State_Selected;
auto selected = option->state & QStyle::State_Selected;
QGraphicsRectItem::paint(painter, &copied_option, widget);
if(selected)
{
painter->save();
painter->setBrush(Qt::NoBrush);
painter->setPen(QPen(option->palette.windowText(), 0, Qt::SolidLine));
painter->drawPath(shape());
painter->restore();
}
}
void myRect::setPtr(VertexDescriptor vIter)
{
this->boostPtr = vIter;
}
VertexDescriptor myRect::getPtr()
{
return boostPtr;
}
Now assume I have made _isVisible = false (which is in boost-graph) for rectangle and some connected lines.
And now I want to redraw view using paint(). And expecting, paint() should not draw those
rectangle and lines which are marked as not visible.
While doing this :
Is paint() redraw every QGraphicsItem from view or it will redraw only
those were updated ?
How paint() will know, which shape should it draw and its co-ordinates
?
Is it possible in my paint(), by checking QGraphicsItem's flag (isVisible) I can guide paint() which items to redraw and which not to
redraw ?

Why is the selection border of a QGraphicsWidget not visible in QGraphicsScene?

I have added a widget to a graphic scene (QGraphicScene) through a QGraphicsProxyWidget. The problem is that when I select the item it's selected, but the selection border is not visible.
Here is the code:
QDial *dial= new QDial(); // Widget
dial->setGeometry(3,3,100,100);// setting offset for graphicswidget and widget
QGraphicsWidget *ParentWidget = new QGraphicsWidget();// created to move and select on scene
ParentWidget->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
Scene->addItem(ParentWidget); // adding to scene
QGraphicsProxyWidget *proxy = new QGraphicsProxyWidget();// adding normal widget through this one
proxy->setWidget( DialBox );
proxy->setParentItem(ParentWidget);
Here is the output:
How could I fix this?
Cause
QGraphicsWidget does not paint anything (including a selection rectangle), as seen from the source code:
void QGraphicsWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(painter);
Q_UNUSED(option);
Q_UNUSED(widget);
}
QGraphicsRectItem, however, does (see the source code):
void QGraphicsRectItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QWidget *widget)
{
...
if (option->state & QStyle::State_Selected)
qt_graphicsItem_highlightSelected(this, painter, option);
}
Solution
My solution would be to use QGraphicsRectItem instead of QGraphicsWidget as a handle to select/move the dial like this:
auto *dial= new QDial(); // The widget
auto *handle = new QGraphicsRectItem(QRect(0, 0, 120, 120)); // Created to move and select on scene
auto *proxy = new QGraphicsProxyWidget(handle); // Adding the widget through the proxy
dial->setGeometry(0, 0, 100, 100);
dial->move(10, 10);
proxy->setWidget(dial);
handle->setPen(QPen(Qt::transparent));
handle->setBrush(Qt::gray);
handle->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
Scene->addItem(handle); // adding to scene
This code produces the following result:
Click the dark gray area around the dial widget to select/move it or the widget itself in order to interact with it.
I know this question is old but here is a python code for anyone looking for the same. It will draw a border whenever the widget is clicked.
class rectangle(QtWidgets.QGraphicsProxyWidget):
def __init__(self):
super().__init__()
self.container = Container() # a class inheriting Qwidget class
self.setWidget(self.container)
self.setFlag(QGraphicsItem.ItemIsSelectable, True)
def paint(self, qp, opt, widget):
qp.save()
pen = QtGui.QPen()
pen.setColor(Qt.transparent)
pen.setWidth(3)
if self.isSelected():
pen.setColor(Qt.yellow) # selection color of your choice
qp.setBrush(Qt.transparent)
qp.setPen(pen)
qp.drawRect(0, 0, self.container.width(), self.container.height()) # draws rectangle around the widget
super().paint(qp, opt, widget)
qp.restore()
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.setSelected(True)
super().mousePressEvent(event)

paint qgraphicsitem in front of its parent

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;
}

QPainter::drawImage() clips QImage when X, Y are not 0 on a QDeclarativeItem

I'm developing a new QML element in C++ based on this sample code. My class inherits from QDeclarativeItem and it's paint() method is responsible to draw a QImage to the screen:
void NewQMLitem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
// image is QImage* that was loaded at the constructor of the class
painter->drawImage(0, 0, *image);
}
The widget size is 800x480 and the image is 400x240. The code below works perfectly as long as the drawing starts at (0, 0), as you can see below:
The problem I'm facing is that drawing at an arbitrary coordinate such as(200, 0), seems to clip the drawing. It looks like QPainter only updates the screen starting from (0, 0):
void NewQMLitem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
painter->drawImage(200, 0, *image);
}
And the following is the result:
My current workaround involves calling widget->update() at the end of the paint(). Of course, this is terrible because it makes the widget be painted twice.
What is the proper way to handle this? I'm currently using Qt 5.2 on Windows.
I found out that in these situations you need to call prepareGeometryChange() to let the parent know that the size/position of your widget has changed, and that it needs to query the new geometry to be able to paint it correctly to the screen.
This will make the parent invoke boundingRect() on your widget, so it's your responsibility to implement it:
void NewQMLitem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
prepareGeometryChange()
painter->drawImage(200, 0, *image);
}
QRectF NewQMLitem::boundingRect() const
{
return QRectF(m_x, m_y, m_width, m_height);
}

How to create a resizable Qt thumbnail preview?

I'm working on a basic image viewer/tagger that will need a thumbnail view to select an image. So far, I've used a QDockWidget enclosing a QScrollArea with a QHBoxLayout to contain a series of QLabels, each of which has its QPixMap set.
This seems very inelegant, and it only gets uglier to consider how I might implement auto-scaling of the thumbnails when the QDockWidget is resized. It's further complicated by the additional need to resize the thumbnails when the scroll bar appears and disappears.
There must be a better way to do this?
I've ran into a similar problem when trying to animate resizing a qlabel with a qpixmap. The method I found that worked best was to use a QWidget instead and re-implement the paintEvent function. Then your QWidget image will automatically be scaled if it's resized. Here is an example:
In my case I had the private variables in a private object called private_:
bool image_set_;
QImage image_;
QBrush paintbrush_;
void MyClass::paintEvent( QPaintEvent* event )
{
// if the QWidget has an image set, then we use our custom painting.
if( this->private_->image_set_ )
{
//I've made it so that my QWidget has a 1px white border
this->private_->paintbrush_.setTextureImage( this->private_->image_.scaled(QSize( this->width() - 2, this->height() - 2 ) ) );
QPainter painter( this );
QRect temp_rect = QRect( 1, 1, this->width()-2, this->height() - 2 );
painter.fillRect( this->rect(), Qt::white );
painter.fillRect( temp_rect, this->private_->paintbrush_ );
}
else
{
QWidget::paintEvent( event );
}
}