Russian Qt Forum

Qt => Qt Quick => Тема начата: tyorn от Август 11, 2015, 16:17



Название: Выпадающие списки
Отправлено: tyorn от Август 11, 2015, 16:17
Добрый день. Пытаюсь реализовать выпадающие списки, элементы которого в свою очередь могут иметь подсписки (произвольное количество вложенности). Для этого написал простой класс, который позволяет хранить это дерево и в данный момент пытаюсь сделать qml часть, которая это дело отображала бы, однако столкнулся с проблемой рекурсии. Как ее решить? Вот собственно код.

menu.h
Код:
#include <QObject>
#include <QList>
#include <QString>
#include <QVariant>

class Menu : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
    //Q_PROPERTY(QList<Menu* > subMenuItems READ subMenuItems NOTIFY subMenuItemsChanged)
public:
    explicit Menu(QString text, QObject *parent = 0);

    QString text() const;
    void setText(const QString& text);


    void addItem(Menu* item);


    int count() const;


signals:
    void textChanged();
    void subMenuItemsChanged();
public slots:
    bool hasSubMenu() const;
    QList<Menu* > subMenuItems() const;
    QList<QVariant> subMenuItemsAsQVar() const;

private:
    QString m_text;
    QList<Menu *> m_subMenuItems;
};
Q_DECLARE_METATYPE(Menu*)
Q_DECLARE_METATYPE(QList<Menu*>)

#endif // MENU_H

menu.cpp
Код:
#include "menu.h"
#include <QDebug>

Menu::Menu(QString text, QObject *parent)
    : QObject(parent),
    m_text(text)
{

}

QString Menu::text() const
{
    return m_text;
}

void Menu::setText(const QString &text)
{
    if (m_text != text)
    {
        m_text = text;
        emit textChanged();
    }
}

QList<Menu* > Menu::subMenuItems() const
{
    return m_subMenuItems;
}

int Menu::count() const
{
    return m_subMenuItems.count();
}

bool Menu::hasSubMenu() const
{
    return (!(m_subMenuItems.isEmpty()));
}

void Menu::addItem(Menu *item)
{
    m_subMenuItems<<item;
}

QList<QVariant> Menu::subMenuItemsAsQVar() const
{
    QList<QVariant> tl;
    for (int i = 0; i < count(); ++i)
    {
        tl<<QVariant::fromValue(m_subMenuItems[i]);
        //qDebug()<<tl[i];
    }
    return tl;
}

ClickableCMItem.qml
Код:
import QtQuick 2.0
Item{
    property alias label: labelText.text
    id: root
    Text {
        id: labelText
        text: modelData.text

        MouseArea
        {
            anchors.fill: parent

            onClicked: {
                popupSubMenuWrap.visible ^= true
                popupSubMenuWrap.x = parent.x
                popupSubMenuWrap.y = parent.y + parent.height
            }
        }
    }

    

    Rectangle {
        id: popupSubMenuWrap
        width: 150
        height: 400
        visible: false
        PopupContent {
            model: modelData.subMenuItemsAsQVar()
            //model: menu.subMenuItems()
        }
    }

main.qml
Код:
import QtQuick 2.0

Rectangle {
    id: root
    width: 300
    height: 600


    ListView {
        id: rootList
        model: menu
        delegate: Component {
            id: rootListViewDelegate
            Item {
                width: root.width
                height: 25

                Column {
                    ClickableCMItem {
                        label: menu.text
                    }
                }
            }
        }

    }

PopupContent.qml
Код:
import QtQuick 2.0

ListView {
    anchors.fill: parent

    delegate: Component {
        id: viewDelegat
        Item {
            width: root.width
            height: 25
            
            
            Column {
                ClickableCMItem {
                    label: modelData.text
                }
                //Text {
                //    text: modelData.text
                //}

                
            }
        }
    }
}

Вот собственно и все.


Название: Re: Выпадающие списки
Отправлено: ksk- от Август 11, 2015, 18:44
Что-то как-то мудрёно слишком, по-моему. В QML есть готовый компонент "Menu". Почему бы не воспользоваться им?


Название: Re: Выпадающие списки
Отправлено: Отражение луны от Август 12, 2015, 20:44
Что-то мудрено как-то (2) зачем хранить данные в каком-то там классе, если их можно хранить в яваскрипт массиве?
И что за проблема с рекурсией? Нужны подробности на тему чего смотреть.


Название: Re: Выпадающие списки
Отправлено: tyorn от Август 13, 2015, 09:55
мудрёно потому что мне нужен кастомный стиль отображения, но использовать приходится qt 5.2.1 в котором нет MenuStyle QML Type, у Menu все еще есть свойство style, но явное задние стиля вроде
Код:
style: someMyStyleComponent {} 
не отрабатывает на Mac'е, хотя вполне себе работает на Win. В итоге решил написать свой компонент.
проблема рекурсии в том, что нельзя сделать компонент вида (примерно):
@Popup.qml
Код:
ListView {
    ...
    delegate: {
        Item {
            ...
            Text {...}
            Popup {...}
            ...
        }
   }
}
т.е. запрещено recursiv instantiate, что в общем-то логично и правильно. вопрос был в том как эту штуку обойти, на данный момент я это обхожу с помощью динамического создания компонента внутри Item. примерно так:
Код:
Component.onCompleted: {
                        var component = Qt.createComponent("qrc:/ClickableCMItem.qml")
                        var clickable = component.createObject(out, {
                                                                   "model": "modelData.subMenuItemsAsQVar()",
                                                                   "label": modelData.text
                                                               })
где ClickableCMItem.qml хранит все, что мне необходимо от подэлемента меню, включая и компонент popup для уже своих подэлементов (если такие есть). не знаю, есть ли другой способ, но этот вполне работает


Название: Re: Выпадающие списки
Отправлено: Отражение луны от Август 13, 2015, 12:55
Вы нашли самый верный способ, поздравляю )