2016-04-20 3 views
0

Quelle est la bonne façon de dessiner des milliers de rects en QT (environ 100 000 ou plus)?Dessiner des milliers de réclamations rapidement

J'ai essayé:

  • simple avec paintEvent() de QWidget.
  • Dessiner des objets à QImage puis cette image à QWidget.
  • En utilisant QGraphicsScene (peut-être que je ne l'utilise pas correctement, je viens d'ajouter à la scène rects)

Chaque dessin de temps était vraiment lent et je n'ai pas plus d'idées sur la façon de le faire (peut-être avec opengl/directx mais cela ne semble pas être une bonne idée). Je sais qu'il existe des applications qui font cela, donc il devrait y avoir un moyen.

EDIT:

Je me demande comment le travail drawRects()? Y a-t-il une chance que remplir une rangée et le passer à QImage sera mieux?

+0

Règle N1 - dessine uniquement ce qui est visible. Vous ne voulez pas me dire que vous avez des rectangles de 100k sur l'écran en même temps? – dtech

+0

En outre, cela dépend vraiment de ce que vous faites réellement, d'accord, vous dessinez des rectangles de 100k, mais pourquoi, dans quel but, quelle est l'application pratique? – dtech

+0

Parfois il peut y avoir (et j'ai vu des applications qui peuvent le faire mais probablement ils n'étaient pas en qt) Ceci est pour profiler, donc il peut y avoir beaucoup d'objets – Derag

Répondre

0

Solution que j'ai trouvé:

Créer tableau de uint32_t qui peut contenir tous les pixels de widget, remplissez-le à l'aide memcpy(). Créez QImage avec ce tableau et utilisez drawImage() pour le montrer. Il peut avoir une certaine optimisation comme (pour profileur) fusionnant rects qui se poursuit (heure de début seconde est égale à la fin de la première). Ne dessinez pas rects qui sont hors limites temporelles. Peut-être sauter trop petit rects. Pour dessiner des éléments tels que du texte, vous pouvez toujours utiliser les fonctions Qt. Pour le mélange alpha dans le cas le plus simple, vous pouvez simplement prendre des valeurs existantes, les fusionner en boucle et écrire des valeurs combinées ou peut-être utiliser SIMD pour cela.

Bien sûr, pour des formes plus complexes, il sera plus difficile de dessiner mais je pense que ce sera plus rapide que d'utiliser les fonctions Qt.

0

La première astuce consiste à faire le dessin dans un thread séparé sur un QImage, puis passer dans le thread principal. Cela ne le rendra pas plus rapide, mais cela ne le fera pas bloquer le thread graphique.

// https://github.com/KubaO/stackoverflown/tree/master/questions/threaded-paint-36748972 
#include <QtWidgets> 
#include <QtConcurrent> 

class Widget : public QWidget { 
    Q_OBJECT 
    QImage m_image; 
    bool m_pendingRender { false }; 
    Q_SIGNAL void hasNewRender(const QImage &); 
    // Must be thread-safe, we can't access the widget directly! 
    void paint() { 
     QImage image{2048, 2048, QImage::Format_ARGB32_Premultiplied}; 
     image.fill(Qt::white); 
     QPainter p(&image); 
     for (int i = 0; i < 100000; ++i) { 
     QColor c{rand() % 256, rand() % 256, rand() % 256}; 
     p.setBrush(c); 
     p.setPen(c); 
     p.drawRect(rand() % 2048, rand() % 2048, rand() % 100, rand() % 100); 
     } 
     emit hasNewRender(image); 
    } 
    void paintEvent(QPaintEvent *) { 
     QPainter p(this); 
     p.drawImage(0, 0, m_image); 
    } 
public: 
    Widget(QWidget * parent = 0) : QWidget(parent) { 
     this->setAttribute(Qt::WA_OpaquePaintEvent); 
     setMinimumSize(200, 200); 
     connect(this, &Widget::hasNewRender, this, [this](const QImage & img) { 
     m_image = img; 
     m_pendingRender = false; 
     update(); 
     }); 
     refresh(); 
    } 
    Q_SLOT void refresh() { 
     if (!m_pendingRender) { 
     m_pendingRender = true; 
     QtConcurrent::run([this] { paint(); }); 
     } 
    } 
}; 

int main(int argc, char ** argv) { 
    QApplication app{argc, argv}; 
    Widget w; 
    QPushButton button{"Refresh", &w}; 
    button.connect(&button, &QPushButton::clicked, &w, [&w]{ w.refresh(); }); 
    w.show(); 
    return app.exec(); 
} 

#include "main.moc" 

comme une préoccupation à part, vous pouvez diviser le dessin à travers plusieurs travaux parallèles, par clipsage peintre de chaque travail à un sous-domaine de l'image partagée, et notant que le rectangle entièrement clipsé tire sont pas d'habitation, et ceux qui sont partiellement écrêtés ne rempliront que les pixels qu'ils affectent.