2016-07-08 8 views
0

내가 만든 후에 동적으로 채우려는 TableView가 있습니다. 즉, 모델로 설정하려는 C++ 응용 프로그램에서 문자열 목록을 읽습니다. TableView. 나는 그것을 위해 ListModel을 사용하는데, TableView의 Component.onCompleted에서 문제없이 채 웁니다. 그러나로드 된 후에는 기본 옵션으로 목록에서 특정 항목을 선택하려고합니다. 문제는 ListModel에 모든 데이터가 포함되어 있어도 TableView의 rowCount 속성이 업데이트되지 않기 때문에 tableView.selection.select(indexOfTheDefaultItem)을 호출하면 "TableViewSelection : index out of range"라는 경고가 표시된다는 것입니다. ListModel.dataChanged() 신호를 방출하고 거기에서 초기 선택을 처리하려고 시도했지만 도움이되지 않습니다. 또한 다른 모든 신호 (onLayoutChanged, onModelChanged ...)에서 수행하려고 시도했지만 결과가 없습니다. 처음 실패한 시도 후에 데이터를 다시로드하면 첫 번째 시도에서 이미 일부 행이 있으므로 선택 영역이 범위를 벗어나지 않으므로 작동합니다. 그래서 그것은 유일한 문제는 rowCount가 나에게 너무 늦을 때까지 업데이트되지 않는다는 것입니다 (어쩌면 구성 요소가 렌더링 된 후입니까?).QtQuick - 모델이 변경된 후 TableView가 rowCount를 업데이트하도록합니다.

그래서 궁극적으로 질문은 - 내가 응답 할 수있는 rowCount가 업데이트 된 후에 발생하는 신호가 있습니까?? 앱의 C++쪽에 목록을 만들고 beginInsertRows() 및 endInsertRows()를 사용하는 몇 가지 솔루션을 보았습니다.하지만 이들은 ListView의 기능이 아니며 qml에 코드를 유지하는 것이 좋습니다. 여기 내 솔루션은 지금 모습입니다 :

ListModel 
{ 
    id:listModel 
} 
TableView 
{ 
    id: tableView 
    selectionMode:SelectionMode.SingleSelection 
    model: listModel 
    TableViewColumn 
    { 
     role: "myRole" 
     title: "myTitle" 
    } 
    onModelChanged // or Connections{target:listModel onDataChanged .... } or onAnythingThatWillWorkPlease: 
    { 
     if (tableView.rowCount > 0) // this prevents the "index out of range" warning, but does not really solve the problem 
     { 
      var defaultEntityIndex = 5; 
      tableView.currentRow = defaultEntityIndex; // when I don't call this, the code in the onSelectionChanged below has "null pointer" exception, i.e. I presume the currentRow stays at the initial -1 - hence this "hack" 
      tableView.selection.select(defaultEntityIndex); 
     } 
    } 
    Connections 
    { 
     target: tableView.selection 
     onSelectionChanged : 
     { 
      if (tableView.currentRow >= 0) 
       myC++Class.selectedThing = listModel.get(tableView.currentRow).role; 
     } 
    } 
} 
function initList() 
{ 
    var vals = myC++Class.getTheListWithData(); 
    for(var i =0; i<vals.length; i++) 
    { 
     listModel.append({role: vals[i]}); 
    } 
    tableView.model = listModel // I just tried to do this to trigger the modelChanged signal 
    listModel.dataChanged(0, vals.length - 1); 
} 
Component.onCompleted: 
{ 
    initList(); 
} 
Connections // this is to re-fresh the tableView when my data changes 
{ 
    target: myC++class 
    onDataChanged: // my custom signal 
    { 
     initList(); 
    } 
} 

현재의 행동은 :이 코드 창을 열고, 목록보기는 getTheListWithData 방법에서 읽어 내 문자열로 가득하지만, 아무 것도 선택하지 않습니다. 그런 다음 데이터를 다시로드하면 (버튼이 있음) 코드 예제의 끝에있는 연결 덕분에 initList가 다시 호출되고 이번에는 원하는 행을 선택합니다.

+1

'property int defaultEntityIndex'를 추가하고 그것을'onRowCountChanged'에서 사용하는 것은 어떻습니까? – Velkan

+0

그게 바로 내가 원하는 건데 내가 전에 해봤다고 맹세 했어. 작동하지 않았어 ....하지만 코드에 다른 실수가 있었거나 잘못 입력 했음에 틀림 없다. (qml에 대한 코드 자동 완성이 없기 때문에). ... 어쨌든 다시 시도해 보니 작동합니다. 감사합니다. 당신이 그것을 대답으로 만들면 그것을 받아 들일 것입니다 ... 아마도 그것은 쓸모없는 질문 일 뿐이지 만, 여러분이 결정하도록 내버려 둘 것입니다. – tomj

+0

일부 코드로 직접 대답하십시오. StackOverflow에서 qt5의 통계를 향상시킵니다. – Velkan

답변

1

Velkan은 의견에서 지적했듯이 솔루션은 단순히 onRowCountChanged 신호를 사용하는 것이므로 예상대로 작동합니다. 아래는 제 전체 코드입니다.

ListModel 
{ 
    id:listModel 
} 
TableView 
{ 
    id: tableView 
    selectionMode:SelectionMode.SingleSelection 
    model: listModel 
    TableViewColumn 
    { 
     role: "myRole" 
     title: "myTitle" 
    } 
    onRowCountChanged: 
    { 
     if (rowCount > 0) 
     { 
      var defaultEntityIndex = 0; 
      for (var i = 0; i < rowCount; i++) 
      { 
       if (model.get(i).role == qsTr("NameOfTheDefaultItem")) 
        defaultEntityIndex = i; 
      } 
      // select the default item and also set it as current so that it is highlighted 
      currentRow = defaultEntityIndex 
      selection.select(defaultEntityIndex) 
      // move the view to the item so that the user knows that something got selected without his input....though this function actually does not seem to be working 
      positionViewAtRow(defaultEntityIndex, ListView.Beginning) 
      focus = true  
     } 
    } 
    Connections 
    { 
     target: tableView.selection 
     onSelectionChanged : 
     { 
      if (tableView.currentRow >= 0) 
       myC++Class.selectedThing = listModel.get(tableView.currentRow).role; 
     } 
    } 
} 
function initList() 
{ 
    var vals = myC++Class.getTheListWithData(); 
    for(var i =0; i<vals.length; i++) 
    { 
     listModel.append({role: vals[i]}); 
    } 
    // the lines that were here in the original post are (as expected) not needed 
} 
Component.onCompleted: 
{ 
    initList(); 
} 
Connections // this is to re-fresh the tableView when my data changes 
{ 
    target: myC++class 
    onDataChanged: initList(); 
} 

다시 한번 감사드립니다.

유일한 외관상의 문제는 TableView가 자동으로 선택 될 때 기본 요소까지 아래로 스크롤하여 사용자가이 기본 선택이 발생했음을 알 수 있도록하는 것입니다. positionViewAtRow 함수는이를 수행해야하지만 그렇지 않습니다. 나는 같은 문제를 가진 다른 사람들의 몇몇 게시물을 발견했지만, 지금까지 그들의 솔루션 중 어느 것도 나를 위해 일하지 않았다. 하지만 그것은 내 부분에 대한 연구 또는 최악의 경우 다른 문제에 대한 문제입니다 :) 솔루션을 찾으면이 답변을 업데이트 할 것입니다.

관련 문제