跳到內容
  • 版面
  • 最新
  • 標籤
  • 熱門
  • 使用者
  • 群組
  • 搜尋
  • Get Qt Extensions
  • Unsolved
Collapse
品牌標誌
  1. 首頁
  2. Qt Development
  3. QML and Qt Quick
  4. Feasability study: Displaying a graph with QML ?
Forum Updated to NodeBB v4.3 + New Features

Feasability study: Displaying a graph with QML ?

已排程 已置頂 已鎖定 已移動 QML and Qt Quick
29 貼文 7 Posters 18.3k 瀏覽 1 Watching
  • 從舊到新
  • 從新到舊
  • 最多點贊
回覆
  • 在新貼文中回覆
登入後回覆
此主題已被刪除。只有擁有主題管理權限的使用者可以查看。
  • Z 離線
    Z 離線
    Zaxy
    寫於 最後由 編輯
    #1

    Hello guys,

    I am starting working with QML and want to know if the following is feasable:

    I want to display a graph with QML in the following way:

    • nodes are represented by an icon (image file)
    • you can right click on an node and do some simple stuff like rename the node's name
    • nodes are connected with lines and the graph is drawn in a suitable easy to visualize way

    I saw that there is GridView in QML, but not sure that you can draw lines between the elements or arrange them on the screen in a suitable way.

    Can you please give me an oppinion if this is feaseable with QML and which elements should I use ?

    Many thanks in advance !

    1 條回覆 最後回覆
    0
    • Z 離線
      Z 離線
      Zaxy
      寫於 最後由 編輯
      #2

      P.S. I want to create the graph with C++ and display (visualize) it with QML.

      1 條回覆 最後回覆
      0
      • sierdzioS 離線
        sierdzioS 離線
        sierdzio
        Moderators
        寫於 最後由 編輯
        #3

        GridView is not suitable. In QML2, there is QML Canvas element and Paths can also be used. For your use case, though, I think some very custom implementation is more suitable, or even transfer to QGraphicsView.

        (Z(:^

        1 條回覆 最後回覆
        0
        • Z 離線
          Z 離線
          Zaxy
          寫於 最後由 編輯
          #4

          So which elements should I use - QGraphicsView or Canvas + Paths ?

          Is it better to do it entierly with Qt instead ? Maybe will be simplier ?

          Thanks

          1 條回覆 最後回覆
          0
          • sierdzioS 離線
            sierdzioS 離線
            sierdzio
            Moderators
            寫於 最後由 編輯
            #5

            QML is integral part of Qt. Better to differentiate between QtWidgets and QtQuick/QML.

            The answer is: I don't know. Try making test projects using both technologies and then decide. There is no built-in mechanism that will allow you to create this in a couple lines of code. I would personally recommend QML, as it's easy and fast but you have to judge yourself.

            You can also take a look at Qwt, maybe Uwe has some classes there that would help you. I think it's a charting library, but have never tried - it's quite probable there is some graphing stuff there, too.

            (Z(:^

            1 條回覆 最後回覆
            0
            • Z 離線
              Z 離線
              Zaxy
              寫於 最後由 編輯
              #6

              Why do you recommend QML ? Is it easier to be done with QML ? For QML, which elements you could advise me to use or even if you have a simular tutorial on that ?

              Thanks again

              1 條回覆 最後回覆
              0
              • sierdzioS 離線
                sierdzioS 離線
                sierdzio
                Moderators
                寫於 最後由 編輯
                #7

                "QML, as it's easy and fast" :) It's a pure pleasure to code in. Lame reason, I know, but a valid one for me. There are components like Image, Transform and various Paths that can make it quite straightforward to code, although there are caveats, too. That is why I'm not sure what to recommend to you.

                No I don't have any tutorials at hand. Search the documentation.

                (Z(:^

                1 條回覆 最後回覆
                0
                • Z 離線
                  Z 離線
                  Zaxy
                  寫於 最後由 編輯
                  #8

                  Thanks a lot, sierdzio !

                  Anyone else has an idea ?

                  1 條回覆 最後回覆
                  0
                  • N 離線
                    N 離線
                    nizeguy
                    寫於 最後由 編輯
                    #9

                    Try porting some small js library that already does that to html canvas and tell us about it.

                    If it can't be done easily in javascript qml for some reason, it can surely be done in QtQuick in C++ .

                    ps: just found this one in reddit/programming : http://tenxer.github.com/xcharts/examples/

                    1 條回覆 最後回覆
                    0
                    • Z 離線
                      Z 離線
                      Zaxy
                      寫於 最後由 編輯
                      #10

                      Hello,

                      I have the following example - a QList of Nodes in ConfigurationModel .
                      I want to bind the properties "QString nodeID" and "QString iconFilePath" beween the QML component Node and the C++ class Node.

                      Unfortunetly the binding is not working - when you create the Node instances from C++, the properties of the correspondingly generated QML objects don't have the given values. They are empty. I cannot find where the issue comes from ... Could you please advise me, what I do wrong ?

                      main.qml
                      @import QtQuick 1.0

                      Rectangle {
                      width: 500
                      height: 500

                      Repeater {
                          anchors.fill: parent
                          model: configModel
                          delegate: Node {}
                      }
                      

                      }
                      @

                      Node.qml
                      @import QtQuick 1.0
                      import NodeLib 1.0

                      Node {
                      id: nodeDelegate

                      Image{
                          id : nodeIcon
                          source: nodeDelegate.iconFilePath
                      }
                      
                      Text {
                         anchors.top: nodeIcon.bottom
                         text: nodeDelegate.nodeID
                      }
                      
                      MouseArea {
                         anchors.fill: parent
                      }
                      

                      }
                      @

                      main.cpp
                      @#include <QApplication>
                      #include "qmlapplicationviewer.h"
                      #include <QDeclarativeContext>
                      #include <QtDeclarative>

                      #include "ConfigurationModel.h"

                      Q_DECL_EXPORT int main(int argc, char *argv[])
                      {
                      QScopedPointer<QApplication> app(createApplication(argc, argv));

                      QDeclarativeView    declarativeView;
                      qmlRegisterType<Node>("NodeLib", 1, 0, "Node");
                      
                      ConfigurationModel* p_configModel = ConfigurationModel::GetConfigModelInstance();
                      p_configModel->addNodeInConfigurationModel(new Node("PanelXXXX", PLUG_IN, EVALUATION_BLOCK, "./ui-images/cutetube.png"));
                      p_configModel->addNodeInConfigurationModel(new Node("PanelYYYY", PLUG_IN, EVALUATION_BLOCK, "./ui-images/cutetube.png"));
                      Node *p_nodeZ = new Node("PanelZZZZ", PLUG_IN, EVALUATION_BLOCK, "./ui-images/cutetube.png");
                      p_nodeZ->setNodeID("NODE ZZZZ");
                      p_configModel->addNodeInConfigurationModel(p_nodeZ);
                      
                      // if the configuration has been changed, you need to call setContextProperty() again to update the QML view
                      
                      declarativeView.rootContext()->setContextProperty("configModel", ConfigurationModel::GetConfigModelInstance());
                      
                      declarativeView.setSource(QUrl::fromLocalFile&#40;"qml/ConfigurationView/main.qml"&#41;);
                      declarativeView.show();
                      
                      return app->exec&#40;&#41;;
                      

                      }
                      @

                      1 條回覆 最後回覆
                      0
                      • Z 離線
                        Z 離線
                        Zaxy
                        寫於 最後由 編輯
                        #11

                        Node.h
                        @#ifndef NODE_H
                        #define NODE_H

                        #include <QString>
                        #include <QList>
                        #include <QDeclarativeItem>

                        #include "GlobalDeclarations.h"

                        // Inherit from QDeclarativeItem in order to override paint() method and to display links to parent nodes
                        class Node : public QDeclarativeItem
                        {
                        Q_OBJECT
                        Q_PROPERTY(QString iconFilePath READ getIconFilePath WRITE setIconFilePath NOTIFY iconFilePathChanged)
                        Q_PROPERTY(QString nodeID READ getNodeID WRITE setNodeID NOTIFY nodeIDchanged)

                        public:
                        // Constructors
                        Node();
                        Node(QString nodeID, NodeType nodeType, PlugInType plugInType, QString iconFilePath);

                         QHash<int, QByteArray> roleNames() const;
                        // Destructor
                        ~Node();
                        
                        QString getNodeID() const;
                        Q_INVOKABLE bool setNodeID(const QString &nodeID);
                        
                        QString  getIconFilePath() const;
                        Q_INVOKABLE bool setIconFilePath(const QString &iconFilePath);
                        
                        void hide();
                        void show();
                        
                        void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
                        

                        signals:
                        void nodeIDchanged(QString data);
                        void iconFilePathChanged(QString data);
                        void dataChanged();

                        private:
                        QString _nodeID;
                        NodeType _nodeType;
                        PlugInType _plugInType;
                        QString _iconFilePath;

                        QList<Node*>    _parents;
                        QList<Node*>    _children;
                        

                        };

                        #endif // NODE_H
                        @

                        1 條回覆 最後回覆
                        0
                        • Z 離線
                          Z 離線
                          Zaxy
                          寫於 最後由 編輯
                          #12

                          ConfigurationModel.h
                          @#ifndef CONFIGURATIONVIEW_H
                          #define CONFIGURATIONVIEW_H

                          #include <QList>
                          #include <QDeclarativeItem>
                          #include <QAbstractListModel>

                          #include "Node.h"

                          // This class is implemented as Singleton
                          class ConfigurationModel : public QAbstractListModel
                          {

                          Q_OBJECT
                          

                          public:

                          // Destructor
                          ~ConfigurationModel();
                          
                          static ConfigurationModel* GetConfigModelInstance ();
                          
                          void addNodeInConfigurationModel(Node *p_node);
                          QList< Node* >&  accessAllNodes();
                          const QList< Node* >&  getAllNodes() const;
                          void removeNodeFromConfigurationModel(Node *p_node);
                          
                          QModelIndex indexFromItem(const Node *item) const;
                          
                          // Functions from QAbstractListModel that should be implemented
                          int rowCount(const QModelIndex &parent) const;
                          QVariant data(const QModelIndex &index, int role) const;
                          

                          signals:
                          void dataChanged();

                          private slots:
                          void handleItemChange();

                          private:
                          // Constructor
                          explicit ConfigurationModel(QObject* parent = 0);

                          // Copy constructor
                          ConfigurationModel(const ConfigurationModel& sourceConfView) {}
                          
                          // Assignment operator
                          ConfigurationModel& operator=(const ConfigurationModel& sourceConfView) {}
                          
                          static ConfigurationModel*       _pConfigModelInstance;
                          
                          QList< Node* >                  _rootNodes;
                          QList< Node* >                  _standAloneNodes;
                          QList< Node* >                  _allNodes;
                          

                          };

                          #endif // CONFIGURATIONVIEW_H
                          @

                          1 條回覆 最後回覆
                          0
                          • Z 離線
                            Z 離線
                            Zaxy
                            寫於 最後由 編輯
                            #13

                            Node.cpp
                            @#include <Node.h>

                            // Constructors
                            Node::Node() : _nodeID(""), _nodeType(NOT_DEFINED), _plugInType(NOT_DEFINEDD), _iconFilePath("")
                            {
                            setFlag(ItemHasNoContents, false);
                            }

                            Node::Node(QString nodeID, NodeType nodeType, PlugInType plugInType, QString iconFilePath) :
                            QDeclarativeItem (), _nodeID(nodeID), _nodeType(nodeType), _plugInType(plugInType), _iconFilePath(iconFilePath)
                            {
                            emit nodeIDchanged(_nodeID);
                            emit iconFilePathChanged(_iconFilePath);
                            emit dataChanged();

                            setFlag(ItemHasNoContents, false);
                            

                            }

                            // Destructor
                            Node::~Node()
                            {
                            }

                            QHash<int, QByteArray> Node::roleNames() const
                            {
                            QHash<int, QByteArray> names;
                            names[Qt::UserRole + 1] = "name";
                            return names;
                            }

                            QString Node::getNodeID() const
                            {
                            return _nodeID;
                            }

                            bool Node::setNodeID(const QString &nodeID)
                            {
                            _nodeID = nodeID;
                            emit nodeIDchanged(_nodeID);
                            emit dataChanged();

                            return true;
                            

                            }

                            QString Node::getIconFilePath() const
                            {
                            return _iconFilePath;
                            }

                            bool Node::setIconFilePath(const QString &iconFilePath)
                            {
                            _iconFilePath = iconFilePath;
                            emit iconFilePathChanged(_iconFilePath);
                            emit dataChanged();

                            return true;
                            

                            }
                            @

                            1 條回覆 最後回覆
                            0
                            • Z 離線
                              Z 離線
                              Zaxy
                              寫於 最後由 編輯
                              #14

                              ConfigurationModel.cpp
                              @#include "ConfigurationModel.h"

                              // The global static instance of the Singleton
                              ConfigurationModel* ConfigurationModel::_pConfigModelInstance = NULL;

                              // Constructor
                              ConfigurationModel::ConfigurationModel(QObject *parent) :
                              QAbstractListModel(parent)
                              {
                              }

                              // Destructor
                              ConfigurationModel::~ConfigurationModel()
                              {

                              // free memory allocated for all nodes of the given configuration
                              for (QList<Node*>::iterator itAllNodesList = _pConfigModelInstance->_allNodes.begin();
                                   itAllNodesList != _pConfigModelInstance->_allNodes.end();
                                   itAllNodesList++)
                              {
                                  delete  *itAllNodesList;
                                  *itAllNodesList = NULL;
                              }
                              
                              // free memory of the ConfigurationView instance itself
                              delete _pConfigModelInstance;
                              _pConfigModelInstance = NULL;
                              

                              }

                              // The class ConfigurationView is implemented as Singleton.
                              // GetConfigModelInstance() is a static method.
                              ConfigurationModel* ConfigurationModel::GetConfigModelInstance ()
                              {
                              if (_pConfigModelInstance == NULL)
                              {

                                  _pConfigModelInstance = new ConfigurationModel();
                              }
                              
                              return _pConfigModelInstance;
                              

                              }

                              void ConfigurationModel::addNodeInConfigurationModel(Node *p_node)
                              {
                              beginInsertRows(QModelIndex(), rowCount(QModelIndex()), rowCount(QModelIndex())); // QModelIndex() is a dummy parameter, not used actually
                              connect(p_node, SIGNAL(dataChanged()),this, SLOT(handleItemChange()));

                              _allNodes.append(p_node);
                              
                              endInsertRows();
                              
                              // ...
                              refreshView();
                              

                              }

                              QList<Node*>& ConfigurationModel::accessAllNodes()
                              {
                              return _allNodes;
                              }

                              const QList<Node*>& ConfigurationModel::getAllNodes() const
                              {
                              return _allNodes;
                              }

                              void ConfigurationModel::removeNodeFromConfigurationModel(Node *p_node)
                              {
                              // ...
                              refreshView();
                              }

                              QModelIndex ConfigurationModel::indexFromItem(const Node *item) const
                              {
                              Q_ASSERT(item);
                              for(int row = 0; row < _allNodes.size(); row++) {
                              if(_allNodes.at(row) == item) return index(row);
                              }
                              return QModelIndex();
                              }

                              void ConfigurationModel::handleItemChange()
                              {
                              Node* node = static_cast<Node*>(sender());
                              QModelIndex index = indexFromItem(node);
                              if(index.isValid())
                              emit dataChanged();
                              }

                              // Functions from QAbstractListView that should be implemented
                              int ConfigurationModel::rowCount(const QModelIndex &parent) const
                              {
                              Q_UNUSED(parent);
                              return _allNodes.size();
                              }

                              QVariant ConfigurationModel::data(const QModelIndex &index, int role) const
                              {
                              if(index.row() < 0 || index.row() >= _allNodes.size())
                              return QVariant();

                              if(role == (Qt::UserRole + 1))
                                  return _allNodes.at(index.row())->getNodeID();
                              return QVariant();
                              

                              }
                              @

                              1 條回覆 最後回覆
                              0
                              • sierdzioS 離線
                                sierdzioS 離線
                                sierdzio
                                Moderators
                                寫於 最後由 編輯
                                #15

                                I'm sorry, but are you insane? Do you really expect me to read all this?

                                @
                                Node {
                                id: nodeDelegate

                                Image{
                                    id : nodeIcon
                                    source: nodeDelegate.iconFilePath // no need for referencing nodeDelegate
                                }
                                
                                Text {
                                   anchors.top: nodeIcon.bottom
                                   text: nodeDelegate.nodeID // no need for referencing nodeDelegate
                                }
                                

                                }
                                @

                                I suspect you must feed the delegate with entries from the model. Debug, or better - create a small, dumb example to get the hang of Repeater.

                                Also, I would suggest making node connections separately, not by overriding ::paint().

                                (Z(:^

                                1 條回覆 最後回覆
                                0
                                • Z 離線
                                  Z 離線
                                  Zaxy
                                  寫於 最後由 編輯
                                  #16

                                  Exactly, I want to feed the delegate with entries from the model by using the Q_Property binding in Node.h

                                  The example is not complicated, but the binding is not working, and I cannot find why.

                                  If I have Q_PROPERTIes like this:

                                  @class Node : public QDeclarativeItem
                                  {
                                  Q_OBJECT
                                  Q_PROPERTY(QString iconFilePath READ getIconFilePath WRITE setIconFilePath NOTIFY iconFilePathChanged)
                                  Q_PROPERTY(QString nodeID READ getNodeID WRITE setNodeID NOTIFY nodeIDchanged)
                                  @

                                  How should I refer to them in the QML component Node ?
                                  Is the following correct:

                                  @import QtQuick 1.0
                                  import NodeLib 1.0

                                  Node {
                                  id: nodeDelegate

                                  Image{
                                      id : nodeIcon
                                      source: nodeDelegate.iconFilePath
                                  }
                                  
                                  Text {
                                     anchors.top: nodeIcon.bottom
                                     text: nodeDelegate.nodeID
                                  }
                                  
                                  MouseArea {
                                     anchors.fill: parent
                                  }
                                  

                                  }
                                  @

                                  1 條回覆 最後回覆
                                  0
                                  • sierdzioS 離線
                                    sierdzioS 離線
                                    sierdzio
                                    Moderators
                                    寫於 最後由 編輯
                                    #17

                                    You inherit from Node.h, so the properties are visible in QML without refering to the id. Instead of "source: nodeDelegate.iconFilePath" you can just write "iconFilePath". But that has nothing to do with the model - that just assigns the value set in c++.

                                    To access the model, you need to use variables declared in the model. See "this page":http://doc-snapshot.qt-project.org/4.8/qdeclarativemodels.html for reference.

                                    (Z(:^

                                    1 條回覆 最後回覆
                                    0
                                    • Z 離線
                                      Z 離線
                                      Zaxy
                                      寫於 最後由 編輯
                                      #18

                                      Hi Sierdzio,

                                      Thanks for the article. I implemented a model with nodeID and iconFilePath roles and now I can display the Node objects in a GridView for example or in a Repeater.

                                      But I need a way to draw the graph on the screen:
                                      - order the Node objects in a suitable way on the screen - how could I place the objects in a custom way ? Is there something like currentNode.left = previousNode.right etc. ?
                                      - draw connection lines between some nodes - for that could I use the paint function ?

                                      Thanks again for the help !

                                      1 條回覆 最後回覆
                                      0
                                      • sierdzioS 離線
                                        sierdzioS 離線
                                        sierdzio
                                        Moderators
                                        寫於 最後由 編輯
                                        #19

                                        I would use QML Rectangle for that. If you want to detect things like previousnode.right, you need to implement it yourself. You could base this on meta object's parent and children properties if you wish.

                                        Or, of course, you can use your own paint function.

                                        (Z(:^

                                        1 條回覆 最後回覆
                                        0
                                        • Z 離線
                                          Z 離線
                                          Zaxy
                                          寫於 最後由 編輯
                                          #20

                                          So , to use the paint function to draw a line between two nodes.

                                          And about displaying the QList<Node*> in a customized way - for example in a tree view, what could I do ? I think, whan a new node is added to the list, it is automatically displayed, but I want somehow to re-order the graphical representation. I have also additional llist, containing the root Node(s), so I could visit all tree nodes, but don't know how to display them node by node and place them on the screen.

                                          Thanks

                                          1 條回覆 最後回覆
                                          0

                                          • 登入

                                          • Login or register to search.
                                          • 第一個貼文
                                            最後的貼文
                                          0
                                          • 版面
                                          • 最新
                                          • 標籤
                                          • 熱門
                                          • 使用者
                                          • 群組
                                          • 搜尋
                                          • Get Qt Extensions
                                          • Unsolved