Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

[QTableView + QSqlite] Jak przy wybraniu wiersza zawsze otrzymywać dane z pierwszej komórki



  • Dzień Dobry
    Proszę o poradę.
    Poniższy kod wypisuje mi w konsoli dane z komórki (klikniętej) w wybranym wierszu, jednak mi zależy aby dane wyświetlane były z pierwszej komórki wybranego wiersza.

    QString text;
    const QModelIndex index = ui->tableView->selectionModel()->currentIndex();
    text = index.data(Qt::DisplayRole).toString();
    qDebug() << text;


  • Dokładniej przybliżę o co mi chodzi.
    Program pobiera z bazy dane i wyświetla w QTableView cztery kolumny ("Id", "Imię", Nazwisko", "telefon"). Po kliknięciu, na obojętnie którą komórkę wiersza, aktywuję cały wiersz. Przy aktywnym wierszu otwieram okno dialogowe np. do edycji danych - i tu jest mi potrzebny "id" z pierwszej komórki aktywnego wiersza(w otwartym oknie dialogowym mogę edytować rekord bazy o znanym "id").

    Problem rozwiązałem, stworzyłem listę indeksów aktywnego wiersza i przypisałem pierwszy element listy do stringu "tekst". Trochę mi to zajęło czasu, dlatego postanowiłem się tym podzielić. Może komuś się przyda.
    Mam pytanie, czy może jest bardziej elegancki sposób? :)

    QString text;
    const QModelIndexList indexes = ui->tableView->selectionModel()->selectedIndexes();
    text = indexes[0].data(Qt::DisplayRole).toString();
    qDebug() << text;
    
    dialogEdit = new DialogEdit(text,this);
    dialogEdit->setModal(true);
    dialogEdit->show();


  • @karlowic Jeśli dobrze rozumiem to chodzi Ci o sytuację, w której np ktoś klika n-tą kolumnę ale potrzebujesz dane z tego samego wiersza z innej kolumny niż kliknięta? Możesz użyć indeksu który masz, odwołać się do modelu. Zakładając że model jest z rodzaju table model (nie podałeś, jakiego używasz?) oferuje on metody sibling() które służą właśnie do uzyskania danych z innych kolumn tego samego rzędu.



  • Jestem początkujący i za bardzo nie łapię wszystkiego jak trzeba.
    Nie wiem czy SqlQueryModel to table model.
    Tworzę model i wyświetlam go w tableView:

    QSqlQueryModel *model = new QSqlQueryModel;
    model->setQuery(pytanie);
    model->setHeaderData(0, Qt::Horizontal, tr("id"));
    model->setHeaderData(1, Qt::Horizontal, tr("Imię"));
    model->setHeaderData(2, Qt::Horizontal, tr("Nazwisko"));
    model->setHeaderData(3, Qt::Horizontal, tr("nr telefonu"));
    ui->tableView->setModel(model);
    ui->tableView->setColumnWidth(0,40);
    ui->tableView->show();
    

    Teraz jak kliknę na komórkę określonego wiersza to mam operować na obiekcie - model czy na obiekcie ui->tableView?



  • @karlowic Wygodniej do table view podać table model o ile masz naprawdę coś, co wymaga dedykowanej kwerendy do bazy. Jeśli jednak chodzi tylko o pominięcie kilku kolumn wydaje mi się że wygodniej zrobić hide() na kolumnach niż cudować z kwerendą.



  • @artwaw Wydaję mi się, że kwerendę do bazy raczej potrzebuję. Ułatwia mi znalezienie konkretnego nazwiska w bazie. Cała metoda tak wygląda:

    void MainWindow::refresh()
    {
        QString relation = ui->lineEdit->text() + '%';
        QString column = ui->comboBox->currentText();
        QString pytanie = QString ("SELECT * FROM pacjenci WHERE %1 LIKE \"%2\" ORDER BY %1").arg(column, relation);
    
        QSqlQueryModel *model = new QSqlQueryModel;
        model->setQuery(pytanie);
        model->setHeaderData(0, Qt::Horizontal, tr("id"));
        model->setHeaderData(1, Qt::Horizontal, tr("Imię"));
        model->setHeaderData(2, Qt::Horizontal, tr("Nazwisko"));
        model->setHeaderData(3, Qt::Horizontal, tr("nr telefonu"));
    
        ui->tableView->setModel(model);
        ui->tableView->setColumnWidth(0,40);
        ui->tableView->show();
    }
    

    Po wpisaniu pierwszych dwóch-trzech liter zawęża liczba wyświetlanych rekordów.



  • @karlowic Rozumiem Twoje podejście ale się z nim nie zgadzam :)

    QueryModel jest dość prymitywny i nie widzę łatwego sposobu dojścia do danych, których potrzebujesz. Wykonałbym nieco więcej pracy i przeszedł na TableModel dla prostej tabeli lub nawet RelationalTableModel jeśli w tabeli są obecne foreign keys. W ten sposób iteracja po kolumnach staje się dość prosta.

    Dodatkowo: select * zwraca nieposortowany wynik (który jak widzę porządkujesz przez order by. Załatwiłbym to przez wsadzenie QSortFilterProxyModel pomiędzy model właściwy a widok - umożliwia filtrowanie a co najważniejsze sortowanie w samym widoku.

    QSqlTableModel posiada też metodę setFilter() która służy aplikowaniu warunków po where w Sql.

    Jeśli dobrze rozumiem jak chcesz to mieć skonstruowane da się rzecz opędzić bez robienia subclassingu. Wiem, że to trochę więcej pracy ale w efekcie, nawet stosując sam TableModel, dostajesz elastyczność w dostępie do danych i dobry punkt wyjścia, gdybyś chciał swoje narzędzie rozwijać dalej w przyszłości.
    I tak:

    • QSqlTableModel zamiast QSqlQueryModel;
    • setTable("pacjenci"); zamiast setQuery();
    • headers I dalej bez zmian.

    Opcjonalnie:

    • QSortFilterProxyModel przypisany do widoku zamiast TableModel, ten ostatni jako source.
    • parę drobnych zmian w ustawieniach widoku, żeby sortowanie działało od strzału (w opisie klasy jest jasno wytłumaczone).
      Lub:
    • QSqlTableModel::setFilter();

    Tak bym to zrobił w każdym razie.



  • @artwaw Trochę poszperałem, poczytałem i w pełni się z Tobą zgadzam. Nie wiedziałem, że istnieje taka alternatywa. Jak wspomniałem moja wiedza w zakresie środowiska Qt jest mizerna. Bawię się "programowaniem" w wolnym czasie dla przyjemności. Dziękuję za poświęcony mi czas i przekazaną mi wiedzę.



  • @karlowic Cała przyjemność po mojej stronie.


Log in to reply