rysowanie obrazów w widoku

0

Mam widok do którego dodałem ItemDelegate

class Delegate : public QStyledItemDelegate
{
...
}
    Delegate *delegate = new Delegate;
   QStandardItemModel *model = new  QStandardItemModel (ROW_COUNT, 3);
   ui->listView->setItemDelegate(delegate);

Podczas rysowanie potrzebuje narysować QImage, tylko że musze czekać na obraz bo jest generowany na urządzeniu embedded i musze poczekać na wynik
od 200ms do 3 minut
Jak rysować obrazy z opóźnieniem wtedy gdy już będą gotowe ? tak aby głowny watek nie dostawał czkawki ?

Przykładowy kod
https://github.com/mariuszmaximus/mvc_delayed_image

źródłem obrazu jest funkcja która generuje przykładowe obraz z opóźnieniem 200ms

QImage getImage(int id)
{
    auto saveImage=[](int id){

        int w{128};
        int h{64};

        float raw_fg_col = 999;
        float raw_bg_col = 0;
        std::string str=std::to_string(id);
        typedef cimg_library::CImg <uint8_t> im_float_type;

        im_float_type img;
        img.resize(w,h);
        img.rand(0,128);

        img.draw_text(0,0,str.c_str(),&raw_fg_col,&raw_bg_col, 1, 32);
        auto s = std::to_string(id)+".bmp";
        img.save_bmp( s.c_str() );
    };

    saveImage(id);
    QString fname =  QString::number(id)+".bmp";
    QImage image(fname);

    std::this_thread::sleep_for(std::chrono::milliseconds(200));

    return image;
}

narysowanie takiego widoku trwa parę sekund (16*0,2s)
screenshot-20240321192700.png

1

Ładowanie obrazka wrzucasz do QThread z użyciem moveToThread i podłączasz sygnał finished() tam gdzie potrzebujesz. Szczegółów synchronizacji nie pamiętam, ale jestem pewien że jest sporo przykładów w sieci.

1

Zrobiłem zgodnie z sugestiami @several,
potrzeba obrazka trafia do wątku wiec nie blokuje rysowania UI (zamiast obrazka rysuje poczekalnik) ,
wątek konczy wysyła sygnał ,
emit dataChanged aby przerysować wersję z obrazem

0

A co do tego ma QStyledItemDelegate?
IMO problemem jest użycie QStandardItemModel.

Robisz swój model. I ładujesz obrazki leniwie.
W sensie w funkcji: QVariant TwojModel::data(const QModelIndex &index, int role = Qt::DisplayRole) const dla Qt::DecorationRole (lub dla role pod którym ukrywasz ten obrazek bo używasz własnego QStyledItemDelegate).

  • jak nie masz jeszcze obrazka, spradzasz czy nie jeszce zlecania na załadowanie jak nie to zlecasz jego załadowanie i zwracasz inny obrazek reprezentujący brak obrazka
  • jak obrazek się załaduje emitujesz dataChanged dla tego indeksu

Dzięki temu będziesz ładował tylko te obrazki, które właśnie mają być pokazane.

W dalszej części, można dodać logikę, sprawdzania, kiedy ostatnio obrazek był użyty i na tej podstawie zwalniać pamięć, dla obrazków, które najdawniej nie były wyświetlane.

1

@MarekR22: po zastanowieniu stwierdzam że Twoje podejście jest lepsze, ja inicjuje pobieranie w moim Delegate::paint() dodatkowo też nie trzymam miniatur w modelu tylko poza nim w postaci std::map<int,QImage> , wiec mam co poprawić ;) Dziękuje !

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