IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Discussion :

Adaptation de la classe KLed et bogue d'affichage

  1. #1
    Membre émérite
    Avatar de VivienD
    Homme Profil pro
    Développeur logiciel
    Inscrit en
    Octobre 2009
    Messages
    523
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Allemagne

    Informations professionnelles :
    Activité : Développeur logiciel
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Octobre 2009
    Messages : 523
    Points : 2 278
    Points
    2 278
    Par défaut Adaptation de la classe KLed et bogue d'affichage
    Bonjour,

    Je cherchais à coder un indicateur «lumineux» et dans mes recherches préliminaires je suis tombé sur la classe KLed de la bibliothèque KDE (datant vraisemblablement de Qt 3).
    J'ai alors essayé une première adaptation, restreinte aux diodes rondes et enfoncées, de cette classe et en résulte la classe Led dont voici le code:
    Code led.h : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    #ifndef LED_H
    #define LED_H
     
    //Superclass
    #include <QtWidgets/QWidget>
     
    //Needed classes
    #include <QtCore/QRectF>
    #include <QtCore/QPointF>
    #include <QtCore/QSize>
    #include <QtGui/QBrush>
    #include <QtGui/QConicalGradient>
    #include <QtGui/QColor>
    #include <QtGui/QImage>
    #include <QtGui/QPainter>
    #include <QtGui/QPalette>
    #include <QtGui/QPixmap>
    #include <QtGui/QRadialGradient>
     
    class Led : public QWidget
    {
        Q_OBJECT
     
        public:
            explicit Led(QWidget* parent = 0);
            explicit Led(const QColor& colour, QWidget* parent = 0);
            virtual ~Led();
            inline QColor colour() const { return m_colour; }
            void setColour(const QColor& newColour);
     
        public slots:
            void toggle();
            void turnOff();
            void turnOn();
     
        private:
            QColor m_colour;
            QPixmap m_ledOff;
            QPixmap m_ledOn;
            bool m_lit;
     
        protected:
            bool paintCachedPixmap();
            virtual void paintEvent(QPaintEvent* e);
            virtual void resizeEvent(QResizeEvent* e);
    };
     
    #endif // LED_H
    Code led.cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    #include "led.h"
     
    Led::Led(QWidget* parent) :
        QWidget     (parent)            ,
        m_colour    (QColor(0, 255, 0)) ,
        m_ledOff    ()                  ,
        m_ledOn     ()                  ,
        m_lit       (false)
    {
        setMinimumSize(3, 3);
    }
     
    Led::Led(const QColor& colour, QWidget* parent) :
        QWidget     (parent)    ,
        m_colour    (colour)    ,
        m_ledOff    ()          ,
        m_ledOn     ()          ,
        m_lit       (false)
    {
        setMinimumSize(3, 3);
    }
     
    Led::~Led()
    {
     
    }
     
    void Led::setColour(const QColor& newColour)
    {
        if(m_colour != newColour)
        {
            m_colour = newColour;
            update();
        }
    }
     
    void Led::toggle()
    {
        m_lit = !m_lit;
        update();
    }
     
    void Led::turnOff()
    {
        if(m_lit)
        {
            m_lit = !m_lit;
            update();
        }
    }
     
    void Led::turnOn()
    {
        if(!m_lit)
        {
            m_lit = !m_lit;
            update();
        }
    }
     
    bool Led::paintCachedPixmap()
    {
        if (m_lit && m_ledOn.isNull())
            return false;
        if (!m_lit && m_ledOff.isNull())
            return false;
     
        QPainter painter;
        painter.begin(this);
        if(m_lit)
            painter.drawPixmap(1, 1, m_ledOn);
        else
            painter.drawPixmap(1, 1, m_ledOff);
        painter.end();
        return true;
    }
     
    void Led::paintEvent(QPaintEvent* e)
    {
        QWidget::paintEvent(e);
        if (paintCachedPixmap())
            return;
     
        QColor borderColour;
        QConicalGradient borderGradient;
        QPointF center;
        QColor fillColour;
        QRadialGradient fillGradient;
        QImage image;
        QSize ledSize;
        QPainter painter;
        QBrush penBrush;
        qreal penWidth;
        QRectF r;
     
        if(width() < height())
            ledSize = QSize(width() - 2, width() - 2);
        else
            ledSize = QSize(height() - 2, height() - 2);
        center = QPointF(ledSize.width() / 2.0, ledSize.height() / 2.0);
        penWidth = ledSize.width() / 8.0;
        r = QRectF(penWidth / 2.0, penWidth / 2.0, ledSize.width() - penWidth, ledSize.height() - penWidth);
     
        image = QImage(ledSize, QImage::Format_ARGB32_Premultiplied);
     
        if(m_lit)
            fillColour = m_colour;
        else
            fillColour = m_colour.dark(300);
        fillGradient = QRadialGradient(center, ledSize.width() / 2.0, QPointF(center.x(), ledSize.height() / 3.0));
        fillGradient.setColorAt(0.0, fillColour.light(250));
        fillGradient.setColorAt(0.5, fillColour.light(130));
        fillGradient.setColorAt(1.0, fillColour);
     
        borderColour = palette().color(QPalette::Dark);
        borderGradient = QConicalGradient(center, 90);
        borderGradient.setColorAt(0.2, borderColour);
        borderGradient.setColorAt(0.5, palette().color(QPalette::Light));
        borderGradient.setColorAt(0.8, borderColour);
        penBrush = QBrush(borderGradient);
     
        painter.begin(&image);
        painter.setRenderHint(QPainter::Antialiasing);
        painter.setBrush(QBrush(fillGradient));
        painter.setPen(QPen(penBrush, penWidth));
        painter.drawEllipse(r);
        painter.end();
     
        if(m_lit)
            m_ledOn = QPixmap::fromImage(image);
        else
            m_ledOff = QPixmap::fromImage(image);
     
        painter.begin(this);
        if(m_lit)
            painter.drawPixmap(1, 1, m_ledOn);
        else
            painter.drawPixmap(1, 1, m_ledOff);
        painter.end();
    }
     
    void Led::resizeEvent(QResizeEvent* e)
    {
        QWidget::resizeEvent(e);
        m_ledOff = QPixmap();
        m_ledOn = QPixmap();
        update();
    }
    Pour tester ma classe j'utilise le code suivant.
    Code main.cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    #include <QtWidgets/QApplication>
     
    #include <QtCore/QTimer>
    #include "led.h"
     
    int main(int argc, char* argv[])
    {
        QApplication app(argc, argv);
        Led led;
        QTimer timer;
        int rVal;
     
        timer.setInterval(500);
        timer.setSingleShot(false);
        timer.setTimerType(Qt::PreciseTimer);
     
        led.setGeometry(100,100,200,200);
     
        app.connect(&timer, SIGNAL(timeout()), &led, SLOT(toggle()));
        led.show();
        timer.start();
     
        rVal = app.exec();
     
        timer.stop();
     
        return rVal;
    }
    Lorsque je compile le projet et que je le lance, alors là! c'est le festival du bogue d'affichage; je vous mets en pièce jointe une petite capture d'écran bien représentative du problème. Par ailleurs, le redimensionnement de la fenêtre semble avoir deux comportements distincts. Quand la taille de la fenêtre est en deçà d'un certain seuil, le bogue ne s'arrange pas du tout; quand la taille de la fenêtre excède ce seuil, alors il n'y a plus le moindre bogue.
    J'ai tenté remédier à ce problème mais je n'ai même pas réussi à trouver l'origine du bogue. C'est pourquoi je sollicite votre aide.

    Merci d'avance.

    Bis dann!

    PS: J'ai trouvé le code source de la classe KLed sur ce site (www.purinchu.net)
    Images attachées Images attachées  
    De retour, plus sportif mais toujours aussi moche.
    _____________
    Pro: Programmation en C/C++ (embarqué ou non)
    Loisir: Programmation en C++11/14/17 avec la STL ou Qt 5

  2. #2
    Membre émérite
    Avatar de VivienD
    Homme Profil pro
    Développeur logiciel
    Inscrit en
    Octobre 2009
    Messages
    523
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Allemagne

    Informations professionnelles :
    Activité : Développeur logiciel
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Octobre 2009
    Messages : 523
    Points : 2 278
    Points
    2 278
    Par défaut
    J'ai tenté une nouvelle approche qui se départit des classes QImage et QPixmap.
    Toutefois, je la considère plutôt brutale et guère économique au niveau de l'utilisation du processeur, car la «grosse» fonction de dessin est appelée à chaque changement de taille ou d'état. Je vais essayer de voir si c'est possible d'utiliser un objet QPainter directement sur un objet QPixmap et si ça ne cause pas de bogue d'affichage.

    PS: Désolé du double-post...
    De retour, plus sportif mais toujours aussi moche.
    _____________
    Pro: Programmation en C/C++ (embarqué ou non)
    Loisir: Programmation en C++11/14/17 avec la STL ou Qt 5

  3. #3
    Responsable Qt & Livres


    Avatar de dourouc05
    Homme Profil pro
    Ingénieur de recherche
    Inscrit en
    Août 2008
    Messages
    26 618
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur de recherche
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2008
    Messages : 26 618
    Points : 188 593
    Points
    188 593
    Par défaut
    Citation Envoyé par VivienD Voir le message
    Toutefois, je la considère plutôt brutale et guère économique au niveau de l'utilisation du processeur, car la «grosse» fonction de dessin est appelée à chaque changement de taille ou d'état.
    Ça me rappelle un article, ça, pour mettre en cache (une fois un état calculé, il est mis dans le cache et ne sera plus calculé, sauf besoin spécifique) : http://qt-quarterly.developpez.com/qq-12/qpixmapcache/.
    Vous souhaitez participer aux rubriques Qt (tutoriels, FAQ, traductions) ou HPC ? Contactez-moi par MP.

    Créer des applications graphiques en Python avec PyQt5
    Créer des applications avec Qt 5.

    Pas de question d'ordre technique par MP !

  4. #4
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Points : 15 620
    Points
    15 620
    Par défaut
    Un article de blog d'ICS hier avec un LED : http://www.ics.com/blog/integrating-...r#.Ueh5_Ky2y0E
    Ca sera peut être plus simple ?

  5. #5
    Membre émérite
    Avatar de VivienD
    Homme Profil pro
    Développeur logiciel
    Inscrit en
    Octobre 2009
    Messages
    523
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Allemagne

    Informations professionnelles :
    Activité : Développeur logiciel
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Octobre 2009
    Messages : 523
    Points : 2 278
    Points
    2 278
    Par défaut
    Je suis arrivé à mes fins. Pour ce faire, j'ai déclaré deux objets de la classe QPixmap qui permettront à sauvegarder les deux affichages possibles de l'indicateur lumineux. Ils sont réinitialisés dès que le widget est redimensionné et redessinés s'ils sont vides (c'est-à-dire égaux à QPixmap()) et si on a besoin de les afficher.
    Toutefois il y a un détail bien fourbe et vicieux que j'ai dû considérer et qui semble être l'origine des bogues d'affichage dont je me suis plaint: lors de l'initialisation du dessin du pixmap, après le dimensionnement du pixmap concerné et avant l'initialisation de l'objet QPainter, il faut penser à remplir le pixmap avec la couleur au code RVBA #00000000. Le code correspondant à ce bout d'algorithme donne à peu près ce qui suit.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    //Initialisation du dessin
    //[...]
    myPixmap = QPixmap(size());
    myPixmap.fill(QColor(0, 0, 0, 0)); // <-- la fourberie en question
     
    //Dessin
    painter.begin(&myPixmap);
    //[...]
    Je ne sais pas pourquoi mais, dès lors que j'ai l'audace! ... le culot! que dis-je, le culot? l'effronterie! de mettre cette ligne honnie en commentaire, l'infâme et horripilant bogue graphique revient de plus belle afin de défigurer le widget que je m'échine à coder. Par ailleurs, je me rends compte que la lecture d'une célèbre pièce de théâtre a de drôles effets sur mon verbe.

    Citation Envoyé par dourouc05 Voir le message
    Ça me rappelle un article, ça, pour mettre en cache (une fois un état calculé, il est mis dans le cache et ne sera plus calculé, sauf besoin spécifique) : http://qt-quarterly.developpez.com/qq-12/qpixmapcache/.
    Citation Envoyé par gbdivers Voir le message
    Un article de blog d'ICS hier avec un LED : http://www.ics.com/blog/integrating-...r#.Ueh5_Ky2y0E
    Ca sera peut être plus simple ?
    Moi, qui comptait améliorer le code de ma classe, je crois que j'ai de quoi faire.
    De retour, plus sportif mais toujours aussi moche.
    _____________
    Pro: Programmation en C/C++ (embarqué ou non)
    Loisir: Programmation en C++11/14/17 avec la STL ou Qt 5

Discussions similaires

  1. une class de connection et d'affichage
    Par salyiohh dans le forum Langage
    Réponses: 2
    Dernier message: 04/12/2012, 21h16
  2. Petit bogues d'affichage
    Par Piscium dans le forum Interfaces Graphiques en Java
    Réponses: 4
    Dernier message: 25/10/2012, 09h13
  3. Bogue d'affichage avec Qt 4.8 ?
    Par EdLeH dans le forum PyQt
    Réponses: 5
    Dernier message: 11/05/2012, 12h45
  4. Problème d'adaptation avec la classe Bitmap
    Par anto2b dans le forum Android
    Réponses: 7
    Dernier message: 01/05/2012, 01h46
  5. [MySQL] Class pagination avec problème d'affichage
    Par eltyty dans le forum PHP & Base de données
    Réponses: 11
    Dernier message: 09/07/2011, 11h48

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo