QML ListView的indexAt()函数始终返回-1的技术问题咨询
Hey there, let's dig into why your ListView's indexAt() keeps returning -1. I've run into this exact issue a few times with Qt QML, so here are the most common fixes and explanations:
1. You're using the wrong coordinate system
The indexAt(x, y) method expects coordinates relative to the ListView itself, not global screen coordinates. If you're passing screen-wide x/y values, that's almost certainly why you're getting -1.
For example, to target the top-left corner of the ListView's visible area (where the first item should be), use local coordinates like (1, 1) (avoiding the exact edge which might not register):
var firstVisibleIndex = id_conversation_list.indexAt(1, 1);
If you do need to use global screen coordinates, convert them to the ListView's local space first with mapFromGlobal():
// Let's say you have global screen coordinates (e.g., from a mouse event) var globalX = mouseX; var globalY = mouseY; var localPos = id_conversation_list.mapFromGlobal(globalX, globalY); var index = id_conversation_list.indexAt(localPos.x, localPos.y);
2. The ListView hasn't finished laying out items yet
If you're calling indexAt() too early (like in Component.onCompleted right after assigning the model), the ListView might not have rendered its items or finished calculating layouts yet.
Fix this by delaying the call until the ListView is ready. Use Qt.callLater() to let the event loop finish processing layout updates:
ListView { id: id_conversation_list anchors.fill: parent model: Conversations Component.onCompleted: { Qt.callLater(() => { var firstVisibleIndex = indexAt(1, 1); console.log("First visible index:", firstVisibleIndex); }); } }
Alternatively, you can listen to signals like onContentHeightChanged or onModelChanged to trigger your logic once items are loaded.
3. There are no visible items in the view
Double-check two things here:
- Does your
Conversationsmodel actually have data? Printid_conversation_list.countto confirm. - Is the
contentY(orcontentXfor horizontal lists) offset so far that no items are in the visible area? You can reset it to0temporarily to test.
4. Your delegate items have no size or are hidden
If your ListView's delegate has a height of 0, or its visible property is set to false, indexAt() won't detect it. Verify your delegate has explicit width/height values, or uses implicit sizing correctly.
5. Use visibleItems for a more reliable approach
If you just need the first visible item's index, skip indexAt() entirely and use the ListView's visibleItems property. This returns an array of all currently visible delegate items, so you can grab the first one directly:
var visibleItems = id_conversation_list.visibleItems; if (visibleItems.length > 0) { var firstVisibleIndex = visibleItems[0].index; console.log("First visible index:", firstVisibleIndex); }
This avoids coordinate-related issues entirely and is often more straightforward for this use case.
内容的提问来源于stack exchange,提问作者Swapnil

