QComboBox - jak przyspieszyć

0

Dzień dobry,

zastanawiam się jak przyspieszyć obiekt typu QComboBox. Mam do wrzucenia do takiego kombosa 50tyś. elementów. O ile wrzucanie elementów trwa krótko to ich wyświetlenie skutkuje już pojawieniem się efektu zawieszenia programu na 5, może 10 sekund.

Robię tak:

Tworzę sobie QStringListę na podstawie przejechania iteratorem listy głównej listy danych mojej aplikacji.
Ze strukturki BazaDanych::Encja wybieram tylko dwa pola (typ, album) i składam z nich QStringa, którego wrzucam sformatowanego na listę, której wskaźnik przekazuję do funkcji wypełniającej QCB..

QStringList *BazaDanych::zwrocTypAlbum(){
    QList<BazaDanych::Encja *>::Iterator it;
    for(it = this->lista.begin(); it != this->lista.end(); ++it)
        this->daneTypAlbum->push_back("[ " + (*it)->typ + " ]-[ " + (*it)->album + " ]");
    return this->daneTypAlbum;
}

Później w programie wrzucam wskaźnik do listy this->daneTypAlbum do funkcji addItem() comboboksa:

void OknoUsuwania::wypelnij(){
    this->ui->cbLista->clear();
    this->ui->cbLista->addItems(*this->bd->zwrocTypAlbum());
}

Dla rozjaśnienia powyższego zamieszczam klasę mojej bazy danych:

#ifndef BAZADANYCH_H
#define BAZADANYCH_H

#include <QString>
#include <QList>
#include <QStringList>
#include <fstream>

class BazaDanych
{
public:
    BazaDanych();
    // Wywaliłem z deklaracji klasy metody nie mające znaczenia w temacie posta.
    QStringList *zwrocTypAlbum();
    ~BazaDanych();

private:
    struct Encja{
        QString typ;
        QString album;
        QString podgladK;
        QString podgladS;
        QString uwagi;
    } *en;

    QList<Encja *> lista;
    unsigned ilosc;
    QStringList *daneTypAlbum;
};

#endif // BAZADANYCH_H

Da się jakoś przyspieszyć wyświetlanie elementów? A może QComboBox nie jest po prostu fizycznie w stanie wyświetlić taką ilość elementów... :/

Pozdrawiam
Grzegorz

0

50k to chyba naprawdę dużo, myślę że nie o takim użyciu myśleli twórcy...
Może spróbuj zrobić 2 comboBoxy, 1 z wyborem pierwszej litery, drugi właściwy, wypełniany dopiero po wyborze z pierwszego? Nie wiem dokładnie co ma się tam znajdować, jeżeli mowa o np. miastach to podziel je najpierw na państwa. Produkty podziel najpierw na kategorie (przykłady tylko do zobrazowania idei). Aktualna lista nie tylko wyświetla się długo, ale musi być też strasznie niewygodna w użyciu przez użytkownika...

0

Niestety to jest bug QListView. Zamiast pokazywać tylko widoczne elementy, tworzone są wszystkie 50tysięcy.
Dawałem tu kod z wyszukiwaczem dla krzyżówek i natrafiłem dokładnie na taki sam problem (200tysięcy słów).
Zmiana QListView na QTableView rozwiązała ten problem, niestety ty tak nie możesz zrobić bo nie dobierzesz się do QListView wewnątrz QComboBox.
Zresztą QCombobox z 50k to bardzo dziwny przypadek. Nikt przecież nie będzie ręcznie przeszukiwał tak długiej listy.
Ty potrzebujesz raczej QLineEdit z QCompleter.

1

Po przeszukaniu dokumentacji już wiem jak obejść ten problem :).
QComboBox::setView(QAbstractItemView * itemView) to jest rozwiązanie.
Tak jak pisałem wcześniej, wciśnij tam QTableView i powinno działać szybko. Trzeba tylko zmienić ustawienia QTableView tak, by dobrze to wyglądało (wyłączyć nagłówek i numerowanie).
Dobrze by było też zrobić własny model danych. Popatrz mój kod dla wyszukiwawcza krzyżówek jako przykład jak zrobić taki model danych.

0

No i rzeczywiście działa to szybciej. Gdyby ktoś kiedyś szukał rozwiązania to zrobiłem tak:

  1. Zdefiniowałem, w klasie okienka, które posiada feralnego comboboksa, prywatne pole
QTableView *tw

.
2. W konstruktorze wspomnianej klasy zdefiniowałem sobie formatowanie tabeli:

    this->tw = new QTableView;
    tw->horizontalHeader()->setVisible(false);
    tw->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
    tw->verticalHeader()->setVisible(false);

    // Wstawienie formatowania do obiektu typu QComboBox
    this->ui->cbLista->setView(tw);
  1. Pozostało dodanie zwalniania pamięci do destruktora:
OknoUsuwania::~OknoUsuwania()
{
    delete this->tw;
    delete this->ui;
}

Trzeba tylko pamiętać, że z takim formatowaniem już nie zadziała połączenie typu:

connect(this->ui->cbLista,SIGNAL(highlighted(QString)),this,SLOT(wyswietlDane(QString)));

Trzeba zmienić sygnał emitowany z obiektu QComboBox na activated(QString)

Pozdrawiam
Grzesiek

[EDIT]
Można jeszcze zrobić tak w punkcie drugim:

this->tw = new QTableView(this);

Wtedy wskaźnik zostanie usunięty razem ze swoim rodzicem, czyli klasą okna, w której został utworzony. Nie trzeba usuwać go w destruktorze.

1 użytkowników online, w tym zalogowanych: 0, gości: 1