Sortierten Index in Original-Index umwandeln



  • Hallo,

    Ich schreibe einen Music Player und habe ein QTableWidget mit allen Tracks.

    Nun wollte ich die Kolonnen sortierbar machen, wobei sich der Index dabei ändert, wenn ich z.B. einen Track anklicke, damit der abgespielt wird.

    Intern habe ich dann eine QMediaPlaylist wobei ich bei jedem neuen Zeileneintrag den Track hinzufüge.

    Um den Track zu ändern habe ich hierfür bloß eine QMediaPlaylist::setCurrentIndex() zur Verfügung, wobei der Index falsch ist, wenn die Kolonnen sortiert sind.

    Wie mappe ich jetzt am effizientesten den sortierten zum originalen Index damit der richtige Track abgespielt wird?



  • Speichere dir doch den Originalindex in deinem TableWidgetItem als UserData und greife über die zu. Aktuell scheinst du es ja über die Zeilennummer zu tun was keine gute Idee ist. Zeig mal wie du die Items in deinem TableWidget erstellst.
    Ich denke der Beitrag gehört eher ins Qt Forum.



  • @Braunstein, vielen Dank das hat funktioniert 🙂



  • Es gibt da auch QSortFilterProxyModel (https://doc.qt.io/qt-5/qsortfilterproxymodel.html)
    Der für solche Sachen geschaffen ist (Im UI items zu sortieren/filtern)



  • @firefly
    Das ist schon richtig, löst aber sein Problem nicht. Zum simplen Sortieren nach Einträgen braucht man es meist auch nicht es sei denn man will das Standard-Sortierverhalten ändern.



  • @Braunstein sagte in [erledigt] Sortierten Index in Original-Index umwandeln:

    @firefly
    Das ist schon richtig, löst aber sein Problem nicht. Zum simplen Sortieren nach Einträgen braucht man es meist auch nicht es sei denn man will das Standard-Sortierverhalten ändern.

    Doch würde es schon, da das ursprungsmodel dabei nicht in der reihenfolge modifiziert wird. Und über das Proxy Model kann man den index des echten model auch abfragen. (via mapToSource https://doc.qt.io/qt-5/qsortfilterproxymodel.html#mapToSource)

    Wobei die Ablage der Information in den UserData da flexibler ist um eine "Referenz" auf die eigentlichen Daten zu bekommen.

    Das "Standard-Sortierverhalten" wird von diesem Proxy Model implementiert 🙂
    Und eines der ersten Beispiele in der Doku verwendet auch das Model direkt ohne eigene Implementierung.
    Nur wenn man was eigenes will, kann man durch Ableitung das verhalten ändern.



  • Sicher, kann man alles so machen. Ich bastle mir eigentlich nur ProxyModelle wenn ich filtern will oder ein anderes Sortierverhalten brauche. Deswegen hatte ich UserData empfohlen.



  • Mir ist jetzt aufgefallen, dass ich doch lieber mit nem Proxy-Modell arbeiten soll.

    Wenn ich Tracks aus der Playlist wieder lösche sind die Daten in den User Pointern futsch.



  • Ich brauch nochmal Hilfe in Bezug auf QModelIndex.

    Ich habe jetzt ein QTableView mit QStandardItemModel als Source-Modell und ein QSortFilterProxyModel als Modell für die View.

    Tracks per Doppelklick abspielen funktioniert wunderbar mit QModelIndex::mapToSource() aber ich habe Probleme mittels QModelIndex über die Zeilen zu iterieren.

    Ich zeig mal etwas Code. Hier ist mein QTableView:

    class columns_list : public QTableView{
    public:
        QStandardItemModel* model{new QStandardItemModel{this}};
        QSortFilterProxyModel* sorted_model{new QSortFilterProxyModel{this}};
    
        columns_list(const QStringList& labels, QWidget* parent = nullptr) : QTableView{parent}{
            setup_columns_list(0, labels);
        }
    ...
        void setup_columns_list(int rows, const QStringList& labels){
            sorted_model->setSourceModel(model);
            setModel(sorted_model);
    
            model->setRowCount(rows);
            model->setColumnCount(labels.size());
    ...
        }
    };
    

    Wenn ein Track nun zu Ende abgespielt wurde soll der nächste Track in der Liste abgespielt werden. Aktuell mach ich das so, was jedoch immer wieder auf den ersten Track in der Liste zugreift, statt auf den Nächsten:

    void main_window::select_next_row(int value){
        if(value == QMediaPlayer::EndOfMedia){
            for(int n{}; n < tabs->count(); ++n){
                auto* list = (files_list*)tabs->widget(n);
    
                if(list->playlist == player->player->playlist()){
                    auto index = list->selectionModel()->currentIndex();
                    index = list->model->index(index.row() + 1, 0);
    
                    while(list->isRowHidden(index.row()))
                        index = list->model->index(index.row() + 1, 0);
    
                    list->clearSelection();
                    list->selectionModel()->select(index, QItemSelectionModel::Select | QItemSelectionModel::Rows);
    
                    // probiert: list->playlist->setCurrentIndex(list->sorted_model->mapFromSource(index).row());
                    // probiert: list->playlist->setCurrentIndex(list->sorted_model->mapToSource(index).row());
                    // probiert: list->playlist->setCurrentIndex(index.row());
                    player->play();
                }
            }
        }
    }
    

    Wenn der Media-Status QMediaPlayer::EndOfMedia erreicht wurde, soll bitte die aktuelle Playlist ausgesucht werden und solange die Position um Eins inkrementieren, bis die nächste sichtbare Zeile erreicht wurde. Aber irgendwie funktioniert das alles nicht?



  • Habs rausgefunden.

    Das gute Stück heißt QModelIndex::mapSelectionToSource()



  • Wenn es funktioniert ist das ja gut.
    Ich finde deine Herangehensweise etwas merkwürdig. Ich hätte jetzt nicht ein neues TableView abgeleitet sondern mir eher ein neues Model gebastelt welches auch gleich die Datenhaltung übernimmt. Das kann man einem normalen QTableView überhelfen. Ich sehe hier in deinem abgeleiteten TableView keine Funktion die nicht auch außerhalb sein könnte.


Log in to reply