c++ QML,在放大ListView时保持位置不变

u0sqgete  于 2023-07-01  发布在  其他
关注(0)|答案(3)|浏览(150)

我被一个关于放大ListView的问题卡住了好几天。我希望这里有人能有一个解决方案或想法。
我有一个ListView(ID为pageView),它有一个图像模型。ListView有一个属性defaultPageHeight,它表示每个图像的默认高度。它还有一个zoomFactor属性,默认初始化为1。每个委托的height设置为:

height: Math.round(pageView.defaultPageHeight * pageView.zoomFactor)

我已经覆盖了我的ListViewonWheel事件,以便我可以手动处理它。当我按下CTRL+Scroll时,调用zoom(factor)函数,其中有一个factor参数,用于指示缩放的程度。
zooms函数看起来像这样:

function zoom(factor)
{
    let newZoomFactor = pageView.zoomFactor * factor;
    let newPageHeight = Math.round(pageView.defaultPageHeight * newZoomFactor);
    
    // Make sure to store the position the listview was looking at before zooming
    let currentPageHeight = Math.round(pageView.defaultPageHeight * pageView.zoomFactor);
    let currentPageNumber = /*Gets the current page*/;
    let currentPos = pageView.contentY - pageView.originY;
    
    // Get the offset, meaning how far is the position away from the current page's top
    let pageOffset = currentPos - (currentPageHeight * currentPageNumber);
    
    // Apply the new zoom
    pageView.zoomFactor = newZoomFactor;

    // Set the new contentY
    pageView.contentY = newPageHeight * currentPageNumber + Math.round(pageOffset * newZoomFactor) + pageView.originY;
}

缩放本身工作正常,但我无法恢复缩放前ListView的位置。因此,当我缩放时,由于某种原因,我也在列表视图中向上或向下移动。
你可以在下面看到一个例子:https://imgur.com/a/cO4cAxq正如您所看到的,ListView正在成功地缩放,但它正在改变其位置。我希望它能放大到屏幕中间,而不是在缩放时在文档周围移动。
我已经建立了一个简单的,最小的副本,以便您可以在本地测试它。它看起来是这样的:https://imgur.com/a/acUmjjx您再次看到它成功地缩放了,但是在ListView中移动,而不是缩放到一个点。下面是最小副本的代码:https://gist.github.com/DavidLazarescu/337d8b28e941cdbe6db3d4873ae45fd3
提前感谢你的任何帮助

ngynwnxp

ngynwnxp1#

[重写]
我重新尝试了一下,发现ListView和GridView做了类似的事情,但是,我觉得GridView可能更好,因为它预先警告了所有的子单元格。
我发现的另一件事是需要contentY和originY来确定滚动位置。如果你单独使用contentY,会出现一种无法解释的漂移,最终会让你缩小什么。为了简单地理解它,等式近似为:

currentIndex = (currentY - originY) / cellHeight

currentY = currentIndex * cellHeight + originY

如果没有它,你可能会尝试假设originY === 0,并在缩放问题中得到一些爬行。
下面是我的GridView实现:

import QtQuick
import QtQuick.Controls
Page {
    GridView {
        id: pageView
        property int defaultCellHeight: 400
        cellHeight: defaultCellHeight
        cellWidth: Math.round(cellHeight * 0.7)
        height: parent.height
        width: cellWidth
        anchors.centerIn: parent
        clip: true
        model: 500
        delegate: Rectangle
        {
            height: pageView.cellHeight
            width: pageView.cellWidth
            color: modelData % 2 == 0 ? "gray" : "green"
            border.color: GridView.isCurrentItem ? "black" : "transparent"
            border.width: 5
            Label
            {
                anchors.centerIn: parent
                font.bold: true
                font.pointSize: 20 * (pageView.cellHeight / 400)
                text: modelData
            }
        }
        WheelHandler {
            acceptedModifiers: Qt.ShiftModifier
            onWheel: event => {
                let currentIndex = (pageView.contentY - pageView.originY + pageView.height / 2) / pageView.cellHeight - 1/2;
                let newCellHeight = Math.round(pageView.cellHeight * Math.pow(1.001, event.pixelDelta.y));
                pageView.cellHeight = newCellHeight;
                pageView.contentY = (currentIndex + 1 / 2) * newCellHeight - pageView.height / 2 + pageView.originY;
                event.accepted = true;
            }
        }
    }
}

你可以Try it Online!

zdwk9cvp

zdwk9cvp2#

您可以尝试对onWheel事件(positionViewatIndex)进行此修改

onWheel: {event => {
            let currentIndex = (pageView.contentY - pageView.originY + pageView.height / 2) / pageView.cellHeight - 1/2;
pageView.positionViewatIndex(currentIndex,ListView.Beginning)}
ejk8hzay

ejk8hzay3#

这似乎是一个问题的起源。在记录了一些缩放数据后,我注意到设置pageView.zoomFactor = newZoomFactor;不会导致originY刷新,所以我设置:

pageView.contentY = newPageHeight * currentPageNumber + Math.round(pageOffset * newZoomFactor) + pageView.originY;

originY是旧的originY,所以我移动到一个位置,这是originY远离它应该在的地方。为了在计算新位置之前刷新originY,我需要调用pageView.forceLayout();,以便使用更新后的originY来计算实际位置。
编辑:我已经更新了要点,以包含修复。

相关问题