delegates - QML-自定义PageIndicator以为其指示的每个页面显示图像

标签 delegates qml customization

更新:添加了SwipeView的代码

我正在尝试自定义PageIndicator以执行我目前拥有的三个按钮,即


通过单击PageIndicator内的相应项来更改页面(当前我有3页,每页一个按钮,其中onClicked设置为将SwipeView更改为预定义索引-无需PageIndicator
显示每个页面指示符项的自定义图像(当前我有3页,每页带有一个自定义图像的按钮-没有PageIndicator


我的SwipeView具有以下结构:

SwipeView {
    id: detailsView
    Layout.fillWidth: true
    Layout.preferredHeight: layoutTopLevel.height * .9
    Page {
        id: captureViewPage
        header: Text {
            text: "Capture view"
            horizontalAlignment: Text.AlignHCenter
            font.pixelSize: 20
        }
    }
    Page {
        id: helpViewPage
        header: Text {
            text: "Help view"
            horizontalAlignment: Text.AlignHCenter
            font.pixelSize: 20
        }

        footer: TabBar {
            id: helpViewSubCategories
            currentIndex: 0
            TabButton {
                text: qsTr("Gestures")
            }
            TabButton {
                text: qsTr("General")
            }
        }
    }
    Page {
        id: settingsViewPage
        header: Text {
            text: "Settings view"
            horizontalAlignment: Text.AlignHCenter
            font.pixelSize: 20
        }

        footer: TabBar {
            id: settingsViewSubCategories
            currentIndex: 0
            TabButton {
                text: qsTr("Language")
            }
            TabButton {
                text: qsTr("Device")
            }
        }
    }
}


SwipeViewPageIndicator(请参见下文)都是ColumnLayout的一部分,并且是子类:

ColumnLayout {
        id: layoutDetailsAndMenu
        spacing: 0
        SwipeView { ... }
        PageIndicator { ... }
}


首先,我研究了delegatePageIndicator属性如何工作。例如以下QML代码

    PageIndicator {
            id: detailsViewIndicator
            count: detailsView.count
            currentIndex: detailsView.currentIndex
            interactive: true
            anchors.bottom: detailsView.bottom
            anchors.bottomMargin: -40
            anchors.horizontalCenter: parent.horizontalCenter


            delegate: Rectangle {
                    implicitWidth: 15
                    implicitHeight: 15

                    radius: width
                    color: "#21be2b"

                    opacity: index === detailsView.currentIndex ? 0.95 : pressed ? 0.7 : 0.45

                    Behavior on opacity {
                        OpacityAnimator {
                            duration: 100
                        }
                    }
                }
        }


产生以下绿色结果:

enter image description here



通过单击PageIndicator内的相应项目可以更改页面

由于某些原因,inactive根本不起作用。我将引用文档说明此属性的作用:


互动式:布尔

此属性保存控件是否为交互式。互动式
页面指​​示器对压力做出反应并自动更改当前
适当索引。默认值为false。


我不知道这是一个错误还是丢失了某些东西,但是即使没有通过delegate进行自定义,也无法单击页面指示器项来更改当前页面(这些项的数量等于页面数,因此单击没有分配页面的索引是毫无疑问的)。

因此,为了实现我的第一个愿望,我添加了MouseArea

    PageIndicator {
            // ...
            delegate: Rectangle {
                MouseArea {
                    anchors.fill: parent
                    onClicked: {
                        if(index !== detailsView.currentIndex) {
                            detailsView.setCurrentIndex(index);
                        }
                    }
                }
            }
    }


如您所见,我正在使用onClicked事件处理程序(或任何此类调用),并检查PageIndicator的当前索引是否等于SwipeView中的页面。如果不是这种情况,我可以使用setCurrentIndex(index)SwipeView设置为所选索引。

写完这篇文章后,我很满意它能按我的设想工作(尽管interactive仍然困扰着我)。接下来是添加图像...



显示每个页面指示器项目的自定义图像

首先,让我向您展示我希望外观如何(这实际上是最终结果,但更多内容-稍后讲):

注意:我使用了我不拥有的Qt徽标。这是为了示范

enter image description here

从左至右,QRC URL为:


qrc:/icons/qtlogo.png

enter image description here
qrc:/icons/qtlogo1.png

enter image description here
qrc:/icons/qtlogo2.png

enter image description here


来源如下:

            delegate: Image {
                source: detailsViewIndicator.indicatorIcons[detailsView.currentIndex]
                height: 30
                width: 30
                opacity: index === detailsView.currentIndex ? 0.95 : pressed ? 0.7 : 0.45
                MouseArea {
                    anchors.fill: parent
                    onClicked: {
                        if(index !== detailsView.currentIndex) {
                            detailsView.setCurrentIndex(index);
                            source = detailsViewIndicator.indicatorIcons[detailsView.currentIndex];
                        }
                    }
                }
            }


其中indicatorIcons是我的variantPageIndicator属性:

    property variant indicatorIcons: [
                "qrc:/icons/qtlogo.png",
                "qrc:/icons/qtlogo1.png",
                "qrc:/icons/qtlogo2.png"
            ]


我已经为string URL使用了QRC对象数组,因为似乎无法做到

delegate: detailsViewIndicator.indicatorImages[detailsView.currentIndex]


indicatorImages

property list<Image> indicatorImages: [
  Image { source: "..." },
  Image { source: "..." },
  Image { source: "..." }
]


我遇到的问题与图像的实际加载有关,并且我感觉到它与上述的list问题有关。用代码

            delegate: Image {
                source: detailsViewIndicator.indicatorIcons[detailsView.currentIndex]
                // ...
            }


第一次运行应用程序时,我得到:

enter image description here

这是由于以下事实:最初选择的索引是0,所以生成了带有Imagesource: "qrc:/icons/qtlogo.png",并且所有页面指示符项均已填充。如果我选择其他两个页面之一作为最初选择的页面,则分别得到qrc:/icons/qtlogo1.pngqrc:/icons/qtlogo2.png

SwipeView中滑动(不单击PageIndicator)会导致

enter image description here



enter image description here

仅在一个方向上(从左到右为索引方向)。如果我向后走,我得到的结果却是相反的。

单击使事情变得更有趣。在下面的屏幕快照中,我在初始化后单击了第二个页面指示符项(以qrc:/icons/qtlogo1.png作为Image的源):

enter image description here

接下来,我单击了第三页指示符项:

enter image description here

再点击几下,我得到:

enter image description here

显然,这不是应该工作的方式。我希望从头到尾始终保持最终结果,无论哪一页被刷掉或单击页面指示符项。

有人做过这样的事情吗?这有可能吗?

最佳答案

由于某种原因,非活动状态根本不起作用


我假设这是一个错字,因为使用interactive属性对我有效(Qt 5.7):

import QtQuick 2.7
import QtQuick.Controls 2.0

ApplicationWindow {
    visible: true

    PageIndicator {
        count: 3
        interactive: true
        onCurrentIndexChanged: print(currentIndex)
    }
}


第一个示例的简化版本也是如此:

import QtQuick 2.7
import QtQuick.Controls 2.0

ApplicationWindow {
    visible: true

    PageIndicator {
        id: detailsViewIndicator
        count: 3
        currentIndex: 0
        interactive: true

        delegate: Rectangle {
            implicitWidth: 15
            implicitHeight: 15

            radius: width
            color: "#21be2b"

            opacity: index === detailsViewIndicator.currentIndex ? 0.95 : pressed ? 0.7 : 0.45

            Behavior on opacity {
                OpacityAnimator {
                    duration: 100
                }
            }
        }
    }
}


因此,如果SwipeView没有更改页面,则可能是问题所在,我们需要查看该代码。


我希望从头到尾始终保持最终结果,无论哪一页被刷掉或单击页面指示符项。


我认为问题出在您用于图标数组的索引上:

source: detailsViewIndicator.indicatorIcons[detailsView.currentIndex]


那是使用当前选择的索引,而您似乎想使用该委托的索引:

source: detailsViewIndicator.indicatorIcons[index]


顺便说一句,指定图标源的一种更简单的方法是使用字符串串联(并为文件提供适当的命名以进行匹配):

source: "qrc:/icons/qtlogo" + index + ".png"




在您添加的代码中,SwipeView并未将其currentIndex设置为currentIndexPageIndicator。您可以这样做:

currentIndex: detailsViewIndicator.currentIndex


完整的例子:

import QtQuick 2.5
import QtQuick.Layouts 1.1
import QtQuick.Controls 2.0

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

    ColumnLayout {
        anchors.fill: parent

        SwipeView {
            id: detailsView
            currentIndex: detailsViewIndicator.currentIndex
            Layout.fillWidth: true
            Layout.fillHeight: true

            Page {
                id: captureViewPage
                header: Text {
                    text: "Capture view"
                    horizontalAlignment: Text.AlignHCenter
                    font.pixelSize: 20
                }
            }
            Page {
                id: helpViewPage
                header: Text {
                    text: "Help view"
                    horizontalAlignment: Text.AlignHCenter
                    font.pixelSize: 20
                }

                footer: TabBar {
                    id: helpViewSubCategories
                    currentIndex: 0
                    TabButton {
                        text: qsTr("Gestures")
                    }
                    TabButton {
                        text: qsTr("General")
                    }
                }
            }
            Page {
                id: settingsViewPage
                header: Text {
                    text: "Settings view"
                    horizontalAlignment: Text.AlignHCenter
                    font.pixelSize: 20
                }

                footer: TabBar {
                    id: settingsViewSubCategories
                    currentIndex: 0
                    TabButton {
                        text: qsTr("Language")
                    }
                    TabButton {
                        text: qsTr("Device")
                    }
                }
            }
        }

        PageIndicator {
            id: detailsViewIndicator
            count: detailsView.count
            currentIndex: detailsView.currentIndex
            interactive: true
            anchors.horizontalCenter: parent.horizontalCenter
        }
    }
}


另一个注意事项:在anchors.bottom中使用垂直锚点(anchors.topColumnLayout)将不起作用。在垂直布局的直接子级中只能使用水平锚,反之亦然。

关于delegates - QML-自定义PageIndicator以为其指示的每个页面显示图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38520083/

相关文章:

python - 如何将 PyQt 中的动态菜单条目添加到 QML 抽屉中

javascript - CRM 2016 表单上的随机脚本错误

ios - 是否可以共享委托(delegate),或将协议(protocol)的方法重新委托(delegate)给另一个委托(delegate)?

qt - 如何使用 QML 在父 MouseArea 中包含子鼠标悬停事件?

qt - QML:WorkerScript 的线程模型

php - Wordpress 文件小部件 - 自定义 html 输出

iphone - 自定义UITableView中的删除按钮

ios - 以编程方式滚动 UIScrollView 但不仅仅在委托(delegate)方法中处理此操作?

objective-c - Swift:在 didSet 中通知委托(delegate)?

objective-c - Objective-C 的 Swift 回调