Пользовательский вид SVG GUI виджетов в QT, очень плохая производительность - PullRequest
3 голосов
/ 24 сентября 2011

Так что я пытаюсь сделать графический интерфейс для программы эффектов гитары. Одна из целей - позволить другим разрабатывать svg "скины" для настройки внешнего вида. Я создал виджеты, которые унаследовали каждый виджет (т.е. qdial), и в инициализаторе загрузил файл svg, указанный скином, в qGraphicsSvgItem. Это помещено в сцену и вид, и я перегрузил размеры и перекрасил соответственно. Это работает.

Когда я загружаю несколько из этих пользовательских виджетов svg (5 циферблатов, кнопку и светодиод) в родительский виджет, рельсы процессора и моя программа зависают. Я иду по этому пути совершенно неправильно? Должен ли я даже использовать QT? Это казалось проще, чем пытаться делать все с помощью таблицы стилей (особенно я не мог понять, как изменить внешний вид циферблата). Будет ли это лучше, если оставить виджеты как qGraphicsSvgItems и поместить их все в сцену и вид родительского виджета?

Это программа обработки сигналов в реальном времени, поэтому я не хочу перегружать процессор в графическом интерфейсе. Я пытался сделать некоторые исследования, но не смог найти много для SVG. Я также не вижу никакой проверки производительности в qtCreator, или я бы попытался увидеть, что является узким местом. В любом случае, я очень ценю любой совет, который вы могли бы дать, прежде чем уделять больше времени попыткам сделать что-то неправильно.

Большое спасибо! _ssj71

p.s. Вот часть кода (надеюсь, достаточно) виджет SVG:

#ifndef QSVGDIAL_H
#define QSVGDIAL_H

#include <QWidget>
#include <QDial>
#include <QtSvg/QSvgRenderer>
#include <QtSvg/QGraphicsSvgItem>
#include <QGraphicsView>
#include <QGraphicsScene>

class qSVGDial : public QDial
{
    Q_OBJECT

public:
    explicit qSVGDial(QWidget *parent = 0);
    explicit qSVGDial(QString knobFile = "defaultKnob.svg", QString needleFile = "defaultNeedle.svg", QWidget *parent = 0);
    ~qSVGDial();

private:
    void paintEvent(QPaintEvent *pe);
    void resizeEvent(QResizeEvent *re);
    float degPerPos;
    float middle;
    float mysize;
    QGraphicsView view;
    QGraphicsScene scene;
    QGraphicsSvgItem *knob;
    QGraphicsSvgItem *needle;
    QSize k,n;

};

#endif // QSVGDIAL_H

cpp:

#include "qsvgdial.h"
#include "math.h"

qSVGDial::qSVGDial(QWidget *parent) :
    QDial(parent)
{
    knob = new QGraphicsSvgItem("defaultKnob.svg");
    needle = new QGraphicsSvgItem("defaultNeedle.svg");
    view.setStyleSheet("background: transparent; border: none");

    k = knob->renderer()->defaultSize();
    n = needle->renderer()->defaultSize();
    needle->setTransformOriginPoint(n.width()/2,n.height()/2);
    knob->setTransformOriginPoint(k.width()/2,k.height()/2);
    degPerPos = 340/(this->maximum() - this->minimum());
    middle = (this->maximum() - this->minimum())/2;
    mysize = k.width();
    if (mysize<n.width())  mysize = n.width();
    if (mysize<k.height()) mysize = k.height();
    if (mysize<n.height()) mysize = n.height();
    mysize = sqrt(2)*mysize;
    view.setDisabled(true);
    view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    scene.addItem(knob);
    scene.addItem(needle);
    view.setScene(&scene);
    view.setParent(this,Qt::FramelessWindowHint);
}

qSVGDial::qSVGDial(QString knobFile, QString needleFile, QWidget *parent) :
    QDial(parent)
{
    knob = new QGraphicsSvgItem(knobFile);
    needle = new QGraphicsSvgItem(needleFile);
    view.setStyleSheet("background: transparent; border: none");
    k = knob->renderer()->defaultSize();
    n = needle->renderer()->defaultSize();
    needle->setTransformOriginPoint(n.width()/2,n.height()/2);
    knob->setTransformOriginPoint(k.width()/2,k.height()/2);
    if (k!=n)
        needle->setPos((k.width()-n.width())/2,(k.height()-n.height())/2);

    degPerPos = 340/(this->maximum() - this->minimum());
    middle = (this->maximum() - this->minimum())/2;
    mysize = k.width();
    if (mysize<n.width())  mysize = n.width();
    if (mysize<k.height()) mysize = k.height();
    if (mysize<n.height()) mysize = n.height();
    mysize = sqrt(2)*mysize;
    view.setDisabled(true);
    view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);

    scene.addItem(knob);
    scene.addItem(needle);
    view.setScene(&scene);
    view.setParent(this,Qt::FramelessWindowHint);
}

qSVGDial::~qSVGDial()
{
    //delete ui;

}

void qSVGDial::paintEvent(QPaintEvent *pe)
{
   needle->setRotation((this->sliderPosition() - middle)*degPerPos);
}

void qSVGDial::resizeEvent(QResizeEvent *re)
{
    if (this->width()>this->height())
    {
        view.setFixedSize(this->height(),this->height());
        view.move((this->width()-this->height())/2,0);
        knob->setScale(this->height()/mysize);
        needle->setScale(this->height()/mysize);
        view.centerOn(knob);
    }
    else
    {
        view.setFixedSize(this->width(),this->width());
        view.move(0,(this->height()-this->width())/2);
        knob->setScale(this->width()/mysize);
        needle->setScale(this->width()/mysize);
        view.centerOn(knob);
    }
    QDial::resizeEvent(re);
}

родительский заголовок:

#ifndef PEDAL_H
#define PEDAL_H

#include <QtGui/QWidget>
#include <QString>
#include <QtSvg/QSvgRenderer>
#include <QtSvg/QGraphicsSvgItem>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <skin.h>
#include <qsvgdial.h>
#include <qsvgbutton.h>
#include <qsvgled.h>
#include <qsvgslider.h>

class Pedal : public QWidget
{
    Q_OBJECT

public:
    explicit Pedal(QWidget *parent = 0);
    explicit Pedal(QString boxFile, QWidget *parent = 0);
    ~Pedal();
    int LoadSkin(skin skinfiles);
    QWidget* AddControl(QString type, QString param, int x, int y, int w, int h, QString file1, QString file2, QString file3, QString file4);

private:
    void resizeEvent(QResizeEvent *re);
    QRect PedalPosition();
    float myheight;
    float mywidth;
    float scale;
    int effectNumber;
    QGraphicsView view;
    QGraphicsScene scene;
    QGraphicsSvgItem *box;
    QSize p;
    QWidget* controls[20];
    QRect ctrlPos[20];
    int numControls;
};

#endif // PEDAL_H

parent cpp

#include "pedal.h"
#include "math.h"

Pedal::Pedal(QWidget *parent)
    : QWidget(parent)
{
    numControls = 0;
    box = new QGraphicsSvgItem("stompbox.svg");
    view.setStyleSheet("background: transparent; border: none");
    p = box->renderer()->defaultSize();
    box->setTransformOriginPoint(p.width()/2,p.height()/2);

    myheight = p.height();
    mywidth = p.width();
    view.setDisabled(true);
    view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);

    scene.addItem(box);
    view.setScene(&scene);
    view.setParent(this,Qt::FramelessWindowHint);
}

Pedal::Pedal(QString boxFile, QWidget *parent) :
    QWidget(parent)
{
    numControls = 0;
    box = new QGraphicsSvgItem(boxFile);
    view.setStyleSheet("background: transparent; border: none");
    p = box->renderer()->defaultSize();
    box->setTransformOriginPoint(p.width()/2,p.height()/2);

    myheight = p.height();
    mywidth = p.width();
    view.setDisabled(true);
    view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);

    scene.addItem(box);
    view.setScene(&scene);
    view.setParent(this,Qt::FramelessWindowHint);
}


Pedal::~Pedal()
{

}

void Pedal::resizeEvent(QResizeEvent *re)
{
    view.setFixedSize(this->width(),this->height());
    //view.move((this->width()-this->height())/2,(this->width()-this->height())/2);
    if (this->width()/mywidth>this->height()/myheight)
    {
        scale = this->height()/myheight;
    }
    else
    {
        scale = this->width()/mywidth;
    }
    box->setScale(scale);
    view.centerOn(box);
    //QWidget::resizeEvent(re);
    QRect v = PedalPosition();
    QRect cpos;
    for(int i = 0; i<numControls; i++)
    {
        cpos = ctrlPos[i];
        controls[i]->setGeometry(v.x()+cpos.x()*scale,v.y()+cpos.y()*scale,cpos.width()*scale,cpos.height()*scale);
    }
}

QWidget* Pedal::AddControl(QString type, QString param, int x, int y, int w, int h, QString file1, QString file2, QString file3, QString file4)
{
    QWidget* control;
    if (type.toLower() == "dial")
    {
        if (!file2.isEmpty())
            control = new qSVGDial(file1,file2,this);
        else
            control = new qSVGDial(this);
    }
    else if (type.toLower() == "button")
    {
        if (!file2.isEmpty())
            control = new qSVGButton(file1,file2,this);
        else if (!file1.isEmpty())
            control = new qSVGButton(file1,this);
        else
            control = new qSVGButton(this);
    }
    else if (type.toLower() == "slider")
    {
        if (!file2.isEmpty())
            control = new qSVGSlider(file1,file2,this);
        else if (!file1.isEmpty())
            control = new qSVGSlider(file1,this);
        else
            control = new qSVGSlider(this);
    }
    else if (type.toLower() == "led")
    {
        if (!file2.isEmpty())
            control = new qSVGLED(file1,file2,this);
        else
            control = new qSVGLED(this);
    }
    control->setToolTip(param);
    ctrlPos[numControls] = QRect(x,360-y-h,w,h);
    controls[numControls] = control;
    numControls++;
    return control;
}

QRect Pedal::PedalPosition()
{
    QRect mypos;
    mypos.setWidth(mywidth*scale);
    mypos.setHeight(myheight*scale);
    mypos.setX((this->width()-mypos.width())/2);
    mypos.setY((this->height()-mypos.height())/2);
    return mypos;
}

наконец-то основной тест

#include <QtGui/QApplication>
#include "pedal.h"

#include <string.h>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Pedal w("skins/default/stompbox.svg",0);
    w.AddControl("Dial" , "Level", 133, 295, 47, 47, "skins/default/blackKnob.svg", "skins/default/whiteNeedle.svg","","");
    w.AddControl("Button", "On", 20, 21, 182, 111, "skins/default/blackButton.svg","","","");
    w.AddControl("LED", "On", 106, 328, 11, 11, "skins/default/redLEDOff.svg", "skins/default/redLEDOn.svg","","");
    w.AddControl("Dial", "Gain", 44, 295, 47, 47, "skins/default/blackKnob.svg", "skins/default/whiteNeedle.svg","","");
    w.AddControl("Dial", "Low", 36, 244, 31, 31, "skins/default/blackKnob.svg", "skins/default/whiteNeedle.svg","","");
    w.AddControl("Dial", "Mid", 98, 244, 31, 31, "skins/default/blackKnob.svg", "skins/default/whiteNeedle.svg","","");
    w.AddControl("Dial", "High", 160, 244, 31, 31, "skins/default/blackKnob.svg", "skins/default/whiteNeedle.svg","","");
    w.show();

    return a.exec();
}

надеюсь, это поможет. Как вы можете видеть, у меня есть слои QGraphicsView, каждый из которых имеет один виджет. Я подозреваю, что сейчас это может быть худший способ сделать это, поэтому мне интересно, есть ли у кого-то больше опыта, прежде чем я буду двигаться в плохом направлении. Кроме того, после того, как я поигрался с ним еще раз, проблема возникает, когда у меня есть 2 экземпляра qSVGDial. Если я загружаю другие комбинации виджетов, все работает нормально. Еще раз спасибо всем!

1 Ответ

6 голосов
/ 24 сентября 2011
void qSVGDial::paintEvent(QPaintEvent *pe)
{
   needle->setRotation((this->sliderPosition() - middle)*degPerPos);
}

Это выглядит очень подозрительно для меня. Выполнение всего, что может привести к перерисовке из метода paintEvent, опасно, может привести к бесконечным циклам обновления.

Вы должны подключить сигнал sliderMoved диска к слоту в вашем классе, повернуть стрелку в этом слоте и полностью удалить обработчик paintEvent. Если это не вызывает обновления, позвоните update() и в этот слот, но я не думаю, что это необходимо.

(Чтобы проверить, является ли это проблемой в первую очередь, попробуйте распечатать что-нибудь на консоли внутри обработчика paintEvent. Если он печатается как сумасшедший, это ваша проблема.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...