Evgenii Legotckoi
Қар. 26, 2019, 2:35 Т.Ж.

QML сабағы 038. Элемент немесе тіктөртбұрыш ішіндегі еншілес нысандарды қиып алу үшін clip сипатын пайдалану

Довольно часто на форуме возникает один и тот же вопрос, касающийся проблемы отображения контента, встроенного в какие-либо QML-объекты.

Наиболее частым проявлением этой проблемы является прокрутка содержимого ListView за пределы его области. В любом случае, это один из тех частых случаев, когда с этой проблемой сталкиваются новички, приступая к изучению QML. Ну или еще вариант, когда столкнулся с такой проблемой при использовании объектов Rectangle.

На следующем изображении ниже вы можете увидеть два окна приложения, которые иллюстрируют эту проблему.

  • В левом окне показано, как изначально выглядит макет
  • Правое окно показывает, что если вы начнете прокручивать содержимое ListView, оно уйдет под текст заголовка, хотя должно было быть обрезано.


Пример исходного кода

Вот так выглядит исходный код программы.

import QtQuick 2.12
import QtQuick.Window 2.12

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    Text {
        id: topText
        text: qsTr("Title")

        anchors.horizontalCenter: parent.horizontalCenter
        anchors.top: parent.top
    }

    ListView {
        width: 180; height: 200

        model: contactModel
        delegate: Text {
            text: name + ": " + number
        }

        anchors.horizontalCenter: parent.horizontalCenter
        anchors.top: topText.bottom
    }

    ListModel {
        id: contactModel
        ListElement {
            name: "Bill Smith"
            number: "555 3264"
        }
        ListElement {
            name: "John Brown"
            number: "555 8426"
        }
        ListElement {
            name: "Sam Wise"
            number: "555 0473"
        }
    }
}

Чтобы решить эту проблему, просто установите свойство clip: true в ListView .

ListView {
    clip: true

    /* код */
}

И теперь содержимое ListView не будет выходить за пределы ListView

Использование прямоугольных объектов

Точно так же clip работает для объектов Rectangle. Вот код программы, а также пример до и после включения клипа.

import QtQuick 2.12
import QtQuick.Window 2.12

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    Rectangle {
        x: 27
        y: 31
        width: 100
        height: 100
        color: "blue"
        clip: true

        Rectangle {
            x: -20
            y: -20
            width: 100
            height: 100

            color: "green"
        }
    }
}

Округление

Но что не работает при использовании клипа, так это скругление, даже если вы настраиваете радиус скругления у родительского объекта Rectangle.

Например вот у нас такой код не даст ожидаемого результата

import QtQuick 2.12
import QtQuick.Window 2.12

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    Rectangle {
        x: 27
        y: 31
        width: 100
        height: 100
        color: "blue"
        radius: 30 // set rounding
        clip: true // enable cropping

        Rectangle {
            x: -20
            y: -20
            width: 100
            height: 100

            color: "green"
        }
    }
}

The result

Такое поведение клипа является стандартным и было сделано из соображений производительности, поскольку почти все графические элементы QML наследуются от типа Item. Это означает, что дополнительная обработка масок во всем приложении избыточна.

Но ожидаемого результата можно добиться следующим программным кодом с использованием эффекта прививки OpacityMask

import QtQuick 2.12
import QtQuick.Window 2.12
import QtGraphicalEffects 1.13

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    Rectangle {
        id: rect
        x: 27
        y: 31
        width: 100
        height: 100
        color: "blue"

        layer.enabled: true
        layer.effect: OpacityMask {
            maskSource: Item {
                width: rect.width
                height: rect.height
                Rectangle {
                    anchors.centerIn: parent
                    width: rect.adapt ? rect.width : Math.min(rect.width, rect.height)
                    height: rect.adapt ? rect.height : width
                    radius: 30
                }
            }
        }

        Rectangle {
            x: -20
            y: -20
            width: 100
            height: 100

            color: "green"
        }
    }
}

И результат будет следующим

Вывод

В заключение скажу, что clip — очень полезное свойство, которое из соображений производительности по умолчанию установлено в false. При этом это свойство выполняет только простую обрезку в виде прямоугольника, а что-то более сложное нужно обрезать по маске.

Ол саған ұнайды ма? Әлеуметтік желілерде бөлісіңіз!

f
  • Қаз. 21, 2021, 3:24 Т.Қ.

Зачем внутри OpacityMask Item, почему сразу Rectangle не вставить?
И что за rect.adapt?

Мое предложение:

        layer.enabled: true
        layer.effect: OpacityMask {
            maskSource: Rectangle {
                width: rect.width
                height: rect.height
                radius: 30
            }
        }

Пікірлер

Тек рұқсаты бар пайдаланушылар ғана пікір қалдыра алады.
Кіріңіз немесе Тіркеліңіз