2011-09-24 77 views
3

所以我试图为吉他效果程序制作一个gui。其中一个目标是让其他人设计svg“皮肤”来定制外观。我制作了继承每个小部件(即qdial)的小部件,并在初始化程序中将由皮肤指定的svg文件加载到qGraphicsSvgItem中。这是放入一个场景和一个视图,我适当地重载了调整大小和重新绘制。这工作。自定义外观svg QT中的GUI部件,性能非常差

当我将这些自定义svg窗口小部件(5个拨号,一个按钮和一个led)加载到父窗口小部件中时,cpu导轨和我的程序冻结。我是否完全用错误的方式来解决这个问题?我应该甚至使用QT吗?这似乎比试图用样式表做所有事情更容易(特别是我无法弄清楚如何改变拨号外观)。它会改进的东西离开小部件作为qGraphicsSvgItems并把他们都放到父窗口小部件的场景和视图?

这是一个实时信号处理程序,所以我不想在GUI中烧掉很多CPU。我试图做一些研究,但无法找到很多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 

父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(); 
} 

希望这可以帮助。正如你所看到的,我有一个QGraphicsViews层,每个层都有一个小部件。我怀疑现在这可能是最糟糕的做法,所以我不知道是否有人有更多的经验,然后我才朝坏的方向前进。在玩了更多它之后,当我有2个qSVGDial实例时,问题似乎就会发生。如果我加载其他组件的组合,它的工作正常。再次感谢大家!

+0

没有看到你的代码,我们可以”告诉你是否做错了事。与位图类型格式相比,SVG的渲染成本更高,因此无论您使用哪种工具包,都需要付出代价。你确定你需要SVG吗? (我发现你看到这样的放缓令人惊讶。)至于“Qt最好”,请不要问这种主观问题 – Mat

+0

对不起,我不是故意问这样的问题。我只是想知道是否有一些我不知道为此设计的库。我想我不需要,但我喜欢工作和可扩展性。 – user962342

+0

'QDial :: paintEvent'没有被覆盖内部调用,是否正确? – Troubadour

回答

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

这看起来对我很可疑。做任何可能导致paintEvent方法重绘的事情都是危险的,可能会导致无限的更新循环。

您应该将拨号的sliderMoved信号连接到班级中的某个插槽,并旋转该插槽中的针,并完全删除paintEvent处理程序。如果这不会触发更新,请在该插槽中拨打update(),但我认为这不是必需的。

(要检查,如果这是摆在首位的问题,尝试打印一些东西到paintEvent处理程序内的控制台。如果打印像疯了似的,那是你的问题。)

+0

谢谢。你的建议非常有效。这确实是一个无限循环。我在那里留下了paintEvent函数,但里面没有代码,所以表盘并没有被绘制在我的svg对象后面。但信号和插槽的想法是票。现在它要轻得多。再次感谢! – user962342

+0

err ..即使没有代码,它似乎循环,所以我只是拿出paintEvent重新定义。 – user962342

+0

那么可能还有其他问题。仔细检查resizeEvent处理程序,做出可能会触发调整大小的事情也会产生不良影响。我有点担心'view.setFixedSize'并专门移动调用。他们真的有必要吗? (但是我从来没有用过这些观点,所以我无法帮助更多。) – Mat