How to invoke QBrush.setTexture() with QPixmap on QGraphicsRectItem?



  • I am trying to use QBrush.setTexture() to update QGraphicsRectItem with a .png background. But I cannot set the exact size to fit the QGraphicsRectItem with the QPixMap.

    brush->setTexture((QPixmap(":/images/h_shutdown.png"))
    .scaled(70,30,Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
    

    But the .png always piled to extend from center crossed.
    As the png in the link:
    Example Image

    Do you have any suggestions?

    BRs
    Kevin



  • Hi,
    you can try to use a QGraphicsProxyWidget containing a QLabel instead. The latter can show the pixmap directly.
    -Michael.



  • Thank you very much for your quick answer!
    Do you have code example for reference?

    On more thing, I am not sure if the HoverEvent and contextMenu still work after using QGraphicsProxyWidget?

    BRs
    Kevin



  • Hi,
    You create a QLabel and set the pixmap with the setPixmap function. You create a QGraphicsProxyWidget and set the label with the setWidget function. Everything else you do as with the rect item you had before.

    Hover- and context menu events should work as with any QGraphicsItem.
    -Michael.



  • QGraphicsProxyWidget is not a good choice, because it's terribly slow and unnecessarily complex.

    How about QGraphicsPixmapItem?



  • Thanks for your suggestion.

    Maybe I don't make myself clear.

    What I want to implement a QGraphicsRectItem with a png as background.

    Is it possible to use QGraphicsPixmapItem as the background for QGraphicsRectItem?

    BRs
    kevin



  • You could add a QGraphicsPixmapItem as a child to the QGraphicsRectItem. To get the clipping and z-Order right, you would need to set QGraphicsItem::ItemClipsChildrenToShape (to the QGraphicsRectItem)
    and QGraphicsItem::ItemStacksBehindParent (to the QGraphicsPixmapItem)

    An alternative is to write a class derived from QGraphicsRectItem, overload paint(), paint the background pixmap, then call the base class paint().

    Edit: On re-reading your initial post, this might not be quite what you need. In this case, it might be easier to implement your own QGraphicsItem and write the paint () method exactly as you want it.



  • Be honest, I am not very familiar with Qt.

    Could you please show me some example code?

    Many thanks.

    BRs
    Kevin


  • Qt Champions 2016

    @Kevin-Zhong
    Hi
    The solution mentioned is to create your own class
    http://www.bogotobogo.com/Qt/Qt5_QGraphicsView_QGraphicsScene_QGraphicsItems.php

    Something like. ( pseudo code-ish)

    class MyItem :public QGraphicsRectItem  ( OR QGraphicsItem )
    {
    public:
    ...
        // overriding paint()
    void paint(QPainter * painter,   const QStyleOptionGraphicsItem * option,   QWidget * widget) 
    {
      // draw pixmap
      QPixmap pix(":/images/h_shutdown.png")
      painter->drawPixmap(pix);
      // draw normally
      QGraphicsRectItem::paint(painter, option, widget); ( or QGraphicsItem::paint)
     }
    };
    


  • Thanks for all of you kindly support.

    It really works.

    One more questions, How can I update the png after the item status changed?
    I mean if the item changed status from shutdown to startup, the png should changed into ":/images/h_startup.png".


  • Qt Champions 2016

    @Kevin-Zhong

    • One more questions, How can I update the png after the item status changed?

    You make the class know which image to draw via variable

    
    **NEW** 
    const int StartImage=1; ( or use enum)
    const int StopImage=2;
    
    class MyItem :public QGraphicsRectItem  ( OR QGraphicsItem ) {
    int Status=StartImage; // some flag to tell if start or stop  **NEW**
    public:
    void SetStatus(int newStatus) {  Status=newStatus;  update(); /* this makes it redraw ( i hope) */ } **NEW**
    ...
        // overriding paint()
    void paint(QPainter * painter,   const QStyleOptionGraphicsItem * option,   QWidget * widget) 
    {
      // draw pixmap
      QPixmap pixStart(":/images/h_startdown.png"); // could be loaded in constructor so we dont do each draw
      QPixmap pixStop(":/images/h_shutdown.png");
    // draw one or the other   
    if (Status == StartImage )
      painter->drawPixmap(pixStart);
      else
      painter->drawPixmap(pixStop);
    
      // draw normally
      QGraphicsRectItem::paint(painter, option, widget); ( or QGraphicsItem::paint)
     }
    };
    
    

    Then from outside, you can do

    myitem->SetStatus(StartImage);
    or
    myitem->SetStatus(StopImage);



  • Thank you very MUCH!!!
    It's very helpful.

    You are so nice!

    BRs
    Kevin



  • @mrjj

    I try to update the png for the item when some status changed.

    But every time I need to trigger the ui to repaint, it seems that it never repaint the ui unless there are some change in the UI, such as move cursor or focus on the UI.

    Is there any way to update the UI automatically?

    BRs
    Kevin



  • Calling update() on the item should do the trick.


  • Qt Champions 2016

    @Kevin-Zhong
    Hi
    Did you call the
    void SetStatus(int newStatus) {
    Status=newStatus;
    update(); /* this makes it redraw ( i hope) */ << this should make it draw the other bitmap?
    }



  • @mrjj

    The behavior is the same as I mentioned before whatever I use update or repaint. Actually, I prefer to use repaint because I need to refresh the item secondly.

    BRs
    Kevin


  • Qt Champions 2016

    @Kevin-Zhong
    Ok, im not sure why.
    maybe update() dont trigger painter.
    Would need to debug to know.
    Normally it just works.



  • @mrjj

    I try to overload the paintEvent in my own code.
    But after I call item.repaint() the paintEvent was not invoked.

    But this is the interface description for Qt 5.6.

    [slot] void QWidget::repaint()
    Repaints the widget directly by calling paintEvent() immediately, unless updates are disabled or the widget is hidden.
    We suggest only using repaint() if you need an immediate repaint, for example during animation. In almost all circumstances update() is better, as it permits Qt to optimize for speed and minimize flicker.
    Warning: If you call repaint() in a function which may itself be called from paintEvent(), you may get infinite recursion. The update() function never causes recursion.
    See also update(), paintEvent(), and setUpdatesEnabled().


  • Qt Champions 2016

    Hi
    are we still talking about the QGraphicsItem ?
    As far as I know they do not have paintEvent only
    void paint(QPainter * painter,xx)

    So item.update() should trigger it ?

    Maybe show full code of what you are doing ?



  • @mrjj

    My code is a little bit complex.
    Let's recap my original purpose.
    At the beginning, I just want to use a png as background at the GraphicsRectItem.
    I tried to use code below:

    QImage mage = (QImage(":/images/h_" + filename + ".png"));                        
    brush.setTextureImage(image.scaled(70,30,Qt::KeepAspectRatio, Qt::FastTransformation));
    

    The result is not what I want.
    So, I try to follow your guys' suggestion.

    map = QPixmap(":/images/h_" + statusStr + ".png");
    painter->drawPixmap((int)x, (int)y, 40, 50, map);
    

    It's really works, the png can be shown correctly, not collage.
    But the png cannot be redraw immediately only I move the cursor or focus the window.
    So, is it possible to show the png in the GraphicsRectItem? Because I need to show lots of triangle, rectangle and cricle on the QGraphsicsView with hoverEvent and click Event.

    BRs
    Kevin


  • Qt Champions 2016

    • But the png cannot be redraw immediately only I move the cursor or focus the window.

    That is the part i dont understand.
    It should trigger paint()!?!

    • So, is it possible to show the png in the GraphicsRectItem?
      Yes , same as with QGraphicsItem , but i be surprised if that alters anything.

    When calling update() it should draw the png. Else there is a bug in the code. or something im not aware of.
    You should looking to this. Using break points. etc.

    item->update() should trigger paint() , else i have no idea what is going on.



  • Do not confuse paintEvent with paint.
    paintEvent is for Widgets
    paint is for GraphicsItems



  • Hi all,

    Finally, I solved this problems.
    @mrjj, as you mentioned that use

    item->update()
    

    WORKs.

    My code is a little bit complex, all the item were originated from a template:

    template <typename T, typename Event>
    class DeviceEventHandler : public Event, public QObject
    

    At the beginning, I try to update the from the template, it doesn't work.
    Then I move the

    update()
    

    method in the all the subclass, then the pixmap can be updated automatically.

    So, really thanks for your patience and kindly support.

    Have a nice weekend.

    PS: Be honest, I am newbie in Qt area and I got so kindly support. I really appreciate your kindness. :)

    BRs
    Kevin


  • Qt Champions 2016

    @Kevin-Zhong

    Hi
    You are most welcome. we do like Qt newbies here :)

    It was a bit odd with update() but good you found the solution.
    Still not sure why it didn't trigger inside SetStatus :)
    Good weekend to you too


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.