继QML2.0TabView之后,打算简单说下PathView这个QML视图,最近找到先前研究的项目,但是对于PathView这个在qml2.0里面继续出现的旧东西,感觉好熟悉,看看qml2.0是否新增了一些特性或者修复了哪些bug,遂研究了下。
Properties cacheItemCount : int count : int currentIndex : int currentItem : Item delegate : Component dragMargin : real dragging : bool flickDeceleration : real flicking : bool highlight : Component highlightItem : Item highlightMoveDuration : int highlightRangeMode : enumeration interactive : bool maximumFlickVelocity : real model : model moving : bool offset : real path : Path pathItemCount : int preferredHighlightBegin : real preferredHighlightEnd : real snapMode : enumeration Attached Properties isCurrentItem : bool onPath : bool view : PathView Signals dragEnded() dragStarted() flickEnded() flickStarted() movementEnded() movementStarted() Methods decrementCurrentIndex() incrementCurrentIndex() int indexAt(int x, int y) Item itemAt(int x, int y) positionViewAtIndex(int index, PositionMode mode)
个人比较喜欢C++与QML混合编程,应该纯QML可能对于数据处理部分很是吃力,所以部分数据处理放置C++,这样是比较好,UI都是QML来实现
看下C++部分代码:
widget.h部分
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include <QtDeclarative/QtDeclarative> #include <QGraphicsObject> #include <QParallelAnimationGroup> class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = 0); ~Widget(); QDeclarativeView* lolView; QGraphicsObject* lolObj; QParallelAnimationGroup* qrGroup; QString lolJson; void showQMLView(); QString pingzhuangJson(QList<QStringList>); void showAnimation(); QList<QStringList> getFileName(QString str); public slots: void slotClose(QVariant,int); void slotQrFinishedAnimation(); }; #endif // WIDGET_H
#include "widget.h" #include <QApplication> #include <QDesktopWidget> Widget::Widget(QWidget *parent) : QWidget(parent),lolView(NULL) { QList<QStringList> lst=getFileName("./qml/CoverFlowQuickApp/lol/"); lolJson = pingzhuangJson(lst); } Widget::~Widget() { } void Widget::showQMLView() { if(NULL==lolView){ qDebug() << "hello in Show Log view1"; lolView = new QDeclarativeView(0); lolView->setMinimumSize(QSize(1320,800)); lolView->setSource(QUrl("qrc:qml/CoverFlowQuickApp/main.qml")); lolView->setWindowFlags(Qt::FramelessWindowHint); lolView->setAttribute(Qt::WA_TranslucentBackground); lolView->setStyleSheet("background:transparent;"); lolView->setWindowTitle(QString::fromUtf8("LOL客户端")); lolObj = lolView->rootObject(); connect(lolObj,SIGNAL(signalsendClose(QVariant,int)),this,SLOT(slotClose(QVariant,int))); } QMetaObject::invokeMethod(lolView->rootObject(),"getJsonfromWidget", Q_ARG(QVariant,QVariant::fromValue(lolJson))); lolView->move(((QApplication::desktop()->width()/2)-(lolView->width()/2)),((QApplication::desktop()->height()/2)-(lolView->height()/2))); lolView->show(); } QString Widget::pingzhuangJson(QList<QStringList> lst) { QString strJson ="{\"response\":100,\"message\":\"xxxxxx\",\"data\":{\"lolinfo\":{\"lol_info\":["; for(int i=0;i<lst.count();i++){ strJson += "{"; strJson.append("\"userid\":"); strJson.append("\""+QString::number(i)+"\""); strJson.append(",\"icon\":"); strJson.append("\"lol/"+lst.at(i).at(0)+"\""); strJson.append(",\"name\":"); QString tmp = lst.at(i).at(1); tmp.chop(4); strJson.append("\""+tmp+"\""); strJson.append("},"); } strJson.chop(1); strJson.append("]}}}"); //qDebug()<<"strJsonstrJsonstrJson "<<strJson; return strJson; } QList<QStringList> Widget::getFileName(QString str){ //"./qml/CoverFlowQuickApp/lol/ QString root = str; QDir rootDir(root); QStringList strings; strings << "*.png" ; QStringList fileList; QString fileListName; QList<QStringList> listVetor; QFile file("./lol.txt"); QFileInfoList list = rootDir.entryInfoList(strings); for(int i=0;i<list.count();i++) { QFileInfo tmpInfo= list.at(i); if(tmpInfo.isFile() && !(tmpInfo.baseName().contains("close"))) { QString fileName = tmpInfo.fileName(); fileListName.append(tmpInfo.baseName()); fileListName.append("\n"); fileList.append(fileName); if(fileList.count() == 5){ listVetor.append(fileList); fileList.clear(); } } } qDebug()<<"listVetor "<<listVetor<<listVetor.count(); return listVetor; } void Widget::showAnimation() { qrGroup = new QParallelAnimationGroup; connect(qrGroup,SIGNAL(finished()),this,SLOT(slotQrFinishedAnimation())); QPropertyAnimation *animation2 = new QPropertyAnimation(lolView, "size"); animation2->setDuration(1000); animation2->setStartValue(QSize(this->width(),this->height())); animation2->setEndValue(QSize(0,0)); QPropertyAnimation *animation4 = new QPropertyAnimation(lolView, "windowOpacity"); animation4->setDuration(800); animation4->setStartValue(1.0); animation4->setEndValue(0.0); animation2->setEasingCurve(QEasingCurve::OutCubic); animation4->setEasingCurve(QEasingCurve::OutCubic); qrGroup->addAnimation(animation2); qrGroup->addAnimation(animation4); qrGroup->start(); } void Widget::slotQrFinishedAnimation() { qApp->quit(); } void Widget::slotClose(QVariant var,int iType) { int localx; int localy; qDebug()<<""<<iType<<" "<<var; if(iType == 0){ QStringList lst=var.toStringList(); if(lst.count()==2){ localx = lolView->x(); localy = lolView->y(); lolView->move(localx + lst.at(0).toInt(), localy+lst.at(1).toInt()); } }else{ showAnimation(); // qApp->quit(); } }
再来看下QML部分
import QtQuick 1.1 Item { width: 120*11; height: 800 signal signalsendClose(variant strclose,int iType) ListModel { id: appModel // ListElement { name: "弗力贝尔"; icon: "lol/Volibear_Square_0.png" } // ListElement { name: "沃里克"; icon: "lol/Warwick_Square_0.png" } // ListElement { name: "齐勒斯"; icon: "lol/Xerath_Square_0.png" } // ListElement { name: "XinZhao_Square_0"; icon: "lol/XinZhao_Square_0.png" } // ListElement { name: "Yorick_Square_0"; icon: "lol/Yorick_Square_0.png" } // ListElement { name: "Ziggs_Square_0"; icon: "lol/Ziggs_Square_0.png" } // ListElement { name: "Zilean_Square_0"; icon: "lol/Zilean_Square_0.png" } // ListElement { name: "Zyra_Square_0"; icon: "lol/Zyra_Square_0.png" } // ListElement { name: "Nidalee_Square_0"; icon: "lol/Nidalee_Square_0.png" } // ListElement { name: "Nocturne_Square_0"; icon: "lol/Nocturne_Square_0.png" } // ListElement { name: "Nunu_Square_0"; icon: "lol/Nunu_Square_0.png" } // ListElement { name: "Olaf_Square_0"; icon: "lol/Olaf_Square_0.png" } // ListElement { name: "Fiddlesticks_Square_0"; icon: "lol/Fiddlesticks_Square_0.png" } // ListElement { name: "Fiora_Square_0"; icon: "lol/Fiora_Square_0.png" } // ListElement { name: "Fizz_square_0"; icon: "lol/Fizz_square_0.png" } // ListElement { name: "Galio_Square_0"; icon: "lol/Galio_Square_0.png" } } // property XmlListModel tmpModel; // XmlListModel { // id: xmlModel // source:"qrc:/qml/CoverFlowQuickApp/pics/lol.xml" // query: "/lol/lolel/File" // XmlRole { name: "fileName"; query: "fileName/string()" } // XmlRole { name: "filePng"; query: "filePng/string()" } // Component.onCompleted: { // console.log("kasjkashjkashkahksj "+query.toString()) // tmpModel = xmlModel; // } // } Item{ id: myText anchors.bottom: parent.bottom anchors.horizontalCenter: parent.horizontalCenter width: parent.width height: 30 Text { id: myText1 text: "当前为 -1" anchors.centerIn: parent font.bold: true font.pixelSize: 20 font.family: "微软雅黑" } } CoverFlow { listModel: appModel width: parent.width anchors.top: parent.top anchors.horizontalCenter: parent.horizontalCenter anchors.bottom: myText.top onIndexChanged: { myText1.text = "当前为: " + index } itemWidth: 120 itemHeight: 120 color: "black" } Image { source: "lol/close.png" anchors.right: parent.right anchors.top: parent.top anchors.margins: 10 MouseArea { anchors.fill: parent onClicked: signalsendClose([""],1); } } MouseArea { id: backmove height: 200 anchors{ left: parent.left right: parent.right rightMargin: 100 top:parent.top } acceptedButtons: Qt.LeftButton property int ix:0 property int iy:0 onPressed: { backmove.ix = mouseX; backmove.iy = mouseY; } onPositionChanged: { var dyx = mouseX - backmove.ix; var dyy = mouseY - backmove.iy; var paralist = [dyx,dyy] //paralist si windows move offset signalsendClose(paralist,0) } } function getJsonfromWidget(str){ console.log("str "+str); var jsonObject = eval('(' + str + ')'); var resultDataObj = jsonObject.data.lolinfo.lol_info; var response = jsonObject.response; console.log("refresh data : "+response+" "+resultDataObj[0].icon) for(var i =0;i<16;i++) { if(typeof resultDataObj[i] == "object") console.log("refresh: "+resultDataObj[i].name) appModel.append(resultDataObj[i]); } } }
import QtQuick 1.0 Rectangle { id: coverFlow property int itemWidth: 120*listModel.count property int itemHeight: 120*listModel.count property ListModel listModel property int angleValue: 60 signal indexChanged(string index) gradient: Gradient { GradientStop { position: 0.0; color: "black" } GradientStop { position: 0.5; color: "gray" } GradientStop { position: 1.0; color: "black" } } Component { id: appDelegate Flipable { id: myFlipable property bool flipped: false property real rotationAngle: PathView.angle width: itemWidth; height: itemHeight z: PathView.z scale: PathView.iconScale function itemClicked() { if(PathView.isCurrentItem) { //myFlipable.flipped = !myFlipable.flipped myPathView.interactive = !myFlipable.flipped } else if(myPathView.interactive) { myPathView.currentIndex = index; console.log("sljaslfajlfjal") } } Keys.onReturnPressed: itemClicked() MouseArea { anchors.fill: parent onClicked: itemClicked() } transform: Rotation { id: rotation origin.x: myFlipable.width/2 origin.y: myFlipable.height/2 axis.x: 0; axis.y: 1; axis.z: 0 angle: rotationAngle } states: State { name: "back" PropertyChanges { target: rotation; angle: 180 } PropertyChanges {target: myFlipable; width: myPathView.width; height: myPathView.height } when: myFlipable.flipped } transitions: Transition { ParallelAnimation { NumberAnimation { target: rotation; property: "angle"; duration: 250 } NumberAnimation {target: myFlipable; properties: "height,width"; duration: 250} } } front: CoverItem{ id:items width: itemWidth height: itemHeight*2 onSignalClickeItem: { console.log("skajfkajffafaf "+iIndex+ " icon "+iconString); backs.curImg = iconString; animationx.stop(); animationx.start(); } } // back: } } CoverBackItem{ id:backs // width: itemWidth*2 // height: itemHeight*2 opacity: 0.0 z:100 anchors.centerIn: parent } SequentialAnimation { id:animationx NumberAnimation { target: backs; property: "opacity"; to: 1; duration: 500;easing.type: Easing.InQuad } PauseAnimation { duration: 500 } NumberAnimation { target: backs; property: "opacity"; to: 0; duration: 500;easing.type: Easing.InQuad } } PathView { id: myPathView Keys.onRightPressed: if (!moving && interactive) incrementCurrentIndex() Keys.onLeftPressed: if (!moving && interactive) decrementCurrentIndex() anchors.fill: parent preferredHighlightBegin: 0.5 preferredHighlightEnd: 0.5 focus: true interactive: true model: listModel delegate: appDelegate path: Path { startX: 0 startY: coverFlow.height / 2 PathAttribute { name: "z"; value: 100 } PathAttribute { name: "angle"; value: angleValue } PathAttribute { name: "iconScale"; value: 1.0 } PathLine { x: coverFlow.width / 2; y: coverFlow.height / 2; } PathAttribute { name: "z"; value: 0 } PathAttribute { name: "angle"; value: 0 } PathAttribute { name: "iconScale"; value: 0.7 } PathLine { x: coverFlow.width; y: coverFlow.height / 2; } PathAttribute { name: "z"; value: 100 } PathAttribute { name: "angle"; value: -angleValue } PathAttribute { name: "iconScale"; value: 1.0 } } } Item{ id: myText3 anchors.top: parent.top anchors.topMargin: 10 anchors.horizontalCenter: parent.horizontalCenter width: parent.width height: 30 Text { id: myText4 text: "英雄联盟-英雄抉择" anchors.centerIn: parent font.bold: true font.pixelSize: 18 font.family: "微软雅黑" color: "red" } } Component.onCompleted: { myPathView.currentIndexChanged.connect(function(){ //indexChanged(myPathView.currentIndex); indexChanged(listModel.get(myPathView.currentIndex).name); }) } }
SourceCode