Need Help with QList !



  • Hello everyone ! I need help ! I store the objects for painting in QList .
    What is better to store painters or the objects ?
    And how erase the QList ? ( depend on objects of QList is pointers or objects )

    QList <Object> Menu::objects()
    {
        QList <Object> objects;
        Object object(QRect(100,100,600,189),":/images/logo.png");
        objects.push_back(object);
    
        return objects;
    }
    
    void GameWidget::paintEvent(QPaintEvent *event)
    {
        QPainter painter(this);
     foreach(const Object& obj,Game::Instance().current->objects())
        {
            painter.drawPixmap(obj.size,QPixmap(obj.pixmap));
        }
    
        timer->start(10);
    
    }
    
    void Menu::clearList()
    {
        // What to write ?
    }
    


  • Hi and Welcome to devnet,

    if Object is a subclass of QObject you cannot store objects inside a list but you must use pointers; this because QObject is not copyable.


  • Moderators

    Looking at your code I assume Object is not a QObject derived. In that case it depends on the size of the object and the cost of copy.
    As for clearing the list - currently you're passing it by value so if the list contains objects (not pointers) then the objects will be destroyed automatically upon list destruction. If you'll be keeping pointers then you can delete all objects at once using qDeleteAll and then clear() to empty the list of invalidated pointers.

    Some performance tips:

    • If you store the objects somewhere already and creating that list to point to only some of them then a list of pointers is a natural choice (to avoid copies).
    • In other case it will be more cache friendly to keep objects instead of pointers so unless the Object class is big and the list will hold thousands of them I would vote for keeping objects.
    • Consider switching to QVector and calling reserve before filling it. You will avoid many reallocations and get a much better cache locality when iterating over it.
    • If you're on a c++11 compiler and decide to store objects instead of pointers consider switching to std::vector and using emplace_back instead of push_back. This will save you from unnecessary copy when placing the objects in a container (the reserve tip also applies here).
    • Don't do this: painter.drawPixmap(obj.size,QPixmap(obj.pixmap));. This creates a temporary copy of the pixmap which you already have. Instead do this: painter.drawPixmap(obj.size, obj.pixmap);

    Bonus remark: paintEvent is a weird place to start a timer. Also, if the timer has anything to do with painting, then interval of 10ms is way too small for most consumer grade displays (which usually ticks at 60Hz --> 16.66...ms per frame).



  • @Chris-Kawa Ohhh! Thanks a lot !!!! You give a most nedeed information !
    I use timer to update GameWidget ( inherited from QWidget) to paint objects.

    GameWidget::GameWidget(QWidget *parent)
        : QWidget(parent)
    {
        resize(800,600);
        timer = new QTimer(this);
        timer->stop();
        connect(timer,SIGNAL(timeout()),this,SLOT(update()));
    }
    

    And as for Object:

    class Object
    {
    public:
        QRect size;
        QPixmap pixmap;
    
        Object(QRect rect, QString load)
        {
            size = rect;
            pixmap.load(load);
        }
    
        ~Object(){};
    };
    

    For such object is better store in vector of objects ?
    And i have a leak of memeory.I think it's caused by updating every milisecond the paintEvent wich call the QList <Object*> objects() method that creates the objects,and don't delete them.Am I right ?


  • Moderators

    Well yeah. If you allocate memory dynamically and don't delete it it's gonna leak.

    As for objects or pointers - do you store them somewhere or do you recreate them every frame?

    As for the timer - by calling start in the paint event you are restarting it every time. That's a weird thing to do. If I may suggest a different approach: Don't create you own timer. Start the built-in timer of the GameWidget. Set it to desired interval (e.g. 30FPS = 1000ms/30= 33.333ms, 60FPS = 1000ms/60=16.666ms). Then override the timerEvent and call update and repaint there.



  • @Chris-Kawa said:

    As for objects or pointers - do you store them somewhere or do you recreate them every frame?

    I recreate them every time. Are there better way ?
    And how i can connect the slot of differents objects to built-in timer of QWidget ?


  • Moderators

    @Afterwork said:

    I recreate them every time. Are there better way ?

    If they change then there's no way around it but if they're the same every frame then it's a waste of time. Generate the list once, store it as a class member and just expose them by reference e.g.

    //split that to .h and .cpp of course
    class GameWidget : public QWidget {
       Q_OBJECT
    public:
       GameWidget(QWidget* parent = nullptr) : QWidget(parent) {
          generateMyListOfObjects();
       }
       const QVector<Object>& objects() const { return objects_; }
    private:
        void generateMyListOfObjects() {
             //fill the objects vector here
        }
       QVector<Object> objects_;
     };
    

    And how i can connect the slot of differents objects to built-in timer of QWidget ?

    You don't. As I said - reimplement the timerEvent method. It will be called every time the timer times out. You can call some methods directly in it or emit a custom signal if you'd like.


Log in to reply
 

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