QComboBox - jak przyspieszyć

QComboBox - jak przyspieszyć
grzesiek51114
grzesiek51114
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad 4 lata
  • Postów:2442
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..

Kopiuj
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:

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

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

Kopiuj
#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

edytowany 4x, ostatnio: grzesiek51114
Zellus
  • Rejestracja:prawie 13 lat
  • Ostatnio:około 4 lata
  • Lokalizacja:Wrocław
  • Postów:474
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...

MarekR22
Moderator C/C++
  • Rejestracja:ponad 17 lat
  • Ostatnio:minuta
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.


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
edytowany 1x, ostatnio: MarekR22
MarekR22
Moderator C/C++
  • Rejestracja:ponad 17 lat
  • Ostatnio:minuta
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.


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
edytowany 2x, ostatnio: MarekR22
grzesiek51114
grzesiek51114
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad 4 lata
  • Postów:2442
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
Kopiuj
QTableView *tw

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

Kopiuj
    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:
Kopiuj
OknoUsuwania::~OknoUsuwania()
{
    delete this->tw;
    delete this->ui;
}

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

Kopiuj
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:

Kopiuj
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.

edytowany 2x, ostatnio: grzesiek51114
MarekR22
delete this-&gt;tw; jest zbędne. W dokumentacji setView stoi, że QComboBox przejmuje własność nad widokiem.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.