2011-09-24 19 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