LINUX.ORG.RU

Кто как управляется с маштабируемыми (Scale) элементами в QML?

 , , , , элемент


0

1

У меня в приложении много экранных элементов, которые должны масштабироваться относительно ширины/высоты экрана или ширины/высоты поля, которое выделено под какой-нибудь функционал.

Проблема в том, что при применении свойства scale, или при применении трансформации Scale, меняется только «видимое отображение» элемента. А его width и height остаются прежними.

И поэтому невозможно привязывать смасштабированные элементы друг к другу или к краям родителя через anchors и задавать им margins. Так же невозможно из распихивать в различные Row, Grid и д. т. Ну, то есть, возможно, но все будет размещено относительно полных размеров элементов.

Поэтому приходится размещать смасштабированные элементы по-старинке, через координаты x/y, которые вычисляются по всяким заковыристым формулам.

Это уже надоело, и я хотел бы узнать, как народ решает эту проблему. Как позиционировать смасштабированные элементы с помощью стандартных средств в QML?

★★★★★

Последнее исправление: Xintrea (всего исправлений: 1)

Что значит «относительно» ширины/высоты? Если равняться ему, то простой биндинг. Если в процентном соотншении, то умножить высоту/ширину. Если суммарно с другими элементами, то есть набор Layout-классов. Нужен пример.

Dendy ★★★★★
()
Ответ на: комментарий от Dendy

Ну вот смотри. Есть такой элемент MetallFrameButton:

// Кнопка с металлической рамкой
Item {
    id: root

    signal click()

    // Масштаб
    property double currentScale: 1.0

    // Размер (начальный?)
    width: buttonFrame.implicitWidth
    height: buttonFrame.implicitHeight

    // Масштабирование элемента
    transform: Scale {
        xScale: root.currentScale
        yScale: root.currentScale
    }

    ... много элементов ...

    // Металлическая рамка
    // Относительно нее считаются размеры всех остальных элементов
    Image {
        id: buttonFrame
        source: "qrc:/resource/pic/button/metallFrameButton/metallFrame.png"

        anchors.top: parent.top
        anchors.left: parent.left
    }

    // Область нажатия кнопки
    MouseArea {
        id: mouseArea
        anchors.fill: parent
        onClicked: { root.click(); }
    }
}

Попробуем разместить два таких элемента рядом друг с другом, на неком прямоугольнике. Масштаб кнопки будет вычисляться так, чтобы по ширине она была в четверть ширины прямоугольника:
Rectangle {
    id: root

    property double elementScale: width / 4.0 / followToTransportButton.width

    MetallFrameButton {
        id: followToTransportButton
        
        iconSource: "qrc:/resource/pic/mapTools/buttons/followToTransport.png"
        
        currentScale: root.elementScale
        
        x: 0
        y: 0
    }
    
    MetallFrameButton {
        id: trackingTransportPathButton
        
        iconSource: "qrc:/resource/pic/mapTools/buttons/trackingTransportPath.png"
        
        currentScale: root.elementScale
        
        anchors.top: followToTransportButton.top
        anchors.left: followToTransportButton.right
    }
}

В результате вторая кнопка не прижмется к первой кнопке, а будет от нее на расстоянии таком, каком занимает несмасштабированная кнопка:

http://i.piccy.info/i9/850e1f3d91d339f2da49d30befcad725/1533919558/92855/1262...

Если же попробовать задавать размер Item-а в MetallFrameButton с учетом масштаба, вот так:
    // Размер (начальный?)
    width: buttonFrame.implicitWidth*root.currentScale
    height: buttonFrame.implicitHeight*root.currentScale

То будет ошибка:


qrc:/qmlCode/pageInteractiveMap/InteractiveMap.qml:96:9: QML MapToolsPanel: Binding loop detected for property «elementScale»


И даже понятно почему она возникает. Потому что elementScale вычисляется через followToTransportButton.width:

property double elementScale: width / 4.0 / followToTransportButton.width

Тогда я пробую разорвать эту связь. В MetallFrameButton пишу:
    // Размер (начальный?)
    implicitWidth: buttonFrame.implicitWidth
    implicitHeight: buttonFrame.implicitHeight
    width: buttonFrame.implicitWidth*root.currentScale
    height: buttonFrame.implicitHeight*root.currentScale

И формулу расчета масштаба меняю на:
property double elementScale: width / 4.0 / followToTransportButton.implicitWidth

Ошибка пропадает, других не появляется. Кнопки как тояли на большом расстоянии, так и стоят. В MetallFrameButton добавляю:
    Component.onCompleted: {
        console.log("scale: "+root.currentScale+" implicitWidth: "+root.implicitWidth+" width: "+root.width);
    }

И мне в ответ:


qml: scale: 0.5983739837398373 implicitWidth: 123 width: 123


Как так то? У width есть умножение на currentScale, а оно в результате такое же.

Дальше я уже не могу понять что происходит.

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea

Если кнопки располагаются в ряд, почему бы не использовать RowLauout? Вообще любой элемент завёрнутый в класс не должен пытаться неявно менять свои размеры, они должны задаваться извне, в том числе трансформации.

Dendy ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.