crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

2 страниц V   1 2 >  
Ответить в данную темуНачать новую тему
Elfinit
  опции профиля:
сообщение 17.3.2009, 14:15
Сообщение #1


Участник
**

Группа: Участник
Сообщений: 127
Регистрация: 17.3.2009
Из: Казань
Пользователь №: 619

Спасибо сказали: 7 раз(а)




Репутация:   1  


Вобщем, ситуация такая. Прога для создания фотоальбомов.
Основной функциональный элемент - это собсно область просмотра фоток (QGraphicsView, в которую грузится некий наследник QGraphicsScene).
В области отображаются миникопии фоток. Прокрутка, просмотр каждой, одновременное масштабирование всех (как в пикасе например) - это всё более или менее есть.
Проблема в следующем:
Альбомов, само собой, может быть несколько. Ооочень хочется чтобы каждый альбом (хотя бы те первые фотки, которые должны быть сейчас видны) отображались моментально. Что происходит при открытии альбома и как поставлено сейчас:
1. Очищается текущий выбранный альбом (картинки на сцене и некоторые служебные объекта, выграженные из БД). Уже тут - можно ли это выделить в отдельный поток?
2. Запускается поток для загрузки фоток (п1)
3. В п1 из базы запрашиватся фотки выбранного альбома (количество и собственно фотки).
4. В п1 запускается поток п2, который будет заполнять миникопии собственно изображениями.
5. В п1 вычисляются размеры сцены с учётом текущего размера миникопии, количества фоток (строк и столбцов на сцене), размеров окна и т.п., всё это отправлется грубо говоря сцене, типа "на, готовься".
6. В перебираются все строки, полученные из базы, формируются объекты-PhotoData (перечисление свойств и т.п.), сразу после формирования отправляются сцене для формирования заготовки для миникопии (вообще, миникопия на сцене - это некий наследник QGraphicsPixmapItem). В поток п2 отправляется требование создать нужные картинки для миникопии.
7. п2 формирует (точнее, считывает с диска, они уже были созданы при добавлении фоток в альбом) 2 изображения - плохое и хорошее. 2 нужно для быстрого масштабирования, суть не в этом. Формирует значит 2 штуки QImage и отправляет ссылки сцене, типа "вставь в такую-то заготовку".
И так пока не кончается фотки.

Что происходит:
Поскольку формирование "заготовок" (пустых миникопий) происходит очень быстро, пользовательский интерфейс "замораживается" до тех пор, пока не сформируется всё (не успевает "отлипнуть" после очередной). Подгрузка изображений - тут проблем уже не возникает, пользовательский интерфейс доступен и постепенно все заготовки заполняются (как в Windows в режиме "эскизы страниц"). К тому же, на случай, если заготовка стала видна, но ещё не подгружено изображение, оно подгружается "форсированно" основным потоком. Т.о. гарантируется, что первые фотки, которые должны быть сразу видны, будут загружены. Проблема, повторяюсь, в "замораживании" пользовательского интерфейса на время формирования заготовок, разметки сцены. Проблема принципиальна для большого числа фоток. Так, для полутора тысяч заморозка происходит на 7-10 секунд.
Qt не позволяет "ковыряться" в UI из других потоков, поэтому приходится заниматься пересылками данных м/у потоками. К тому же, при получении картинок надо из QImage делать QPixmap, т.к. в дочерних потоках "опасно" работать с QPixmap.

И ещё - для QGraphicsView сделал отрисовку OpenGL, это не сильно ускорило процесс.

Вот как-то так. Для наглядности прилагаю скрин окна.
Эскизы прикрепленных изображений
 Р В Р’ Р в‚¬Р В РЎВ˜Р В Р’µР Р…ьшено Р Т‘Р С• 41%
Прикрепленное изображение
448 x 313 (38.16 килобайт)
 
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
BRE
  опции профиля:
сообщение 17.3.2009, 14:25
Сообщение #2


Профессионал
*****

Группа: Участник
Сообщений: 1112
Регистрация: 6.3.2009
Из: Ростов-на-Дону
Пользователь №: 591

Спасибо сказали: 264 раз(а)




Репутация:   44  


Я правильно понял, сначала на сцену добавляются пустые элементы (скажем 1000 штук) + начинается процесс загрузки (заполнения) их эскизами?
И в этот момент интерфейс "подвисает"?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Elfinit
  опции профиля:
сообщение 17.3.2009, 14:46
Сообщение #3


Участник
**

Группа: Участник
Сообщений: 127
Регистрация: 17.3.2009
Из: Казань
Пользователь №: 619

Спасибо сказали: 7 раз(а)




Репутация:   1  


Да, почти.
Примерно так:

while (q.next())
    {       
        PhotoData *photo = new PhotoData(q.value(0).toLongLong(&isOK));
        album->appendPhoto(photo);        
        emit photoReady(photo,album,true);
        upl->uploadPhoto(photo,counter);
        counter++;
    }


photoReady - сигнал к тому, чтобы сформировать заготовку.

Заготовка формируется как-то так (за исключением принципиально неважного):
void AlbumScene::addPhoto(PhotoData *photo, bool fast)
{   
        int row = photo_count / photo_cols;
        int col = photo_count - row*photo_cols;         

        ThumbnailItem *ti = new ThumbnailItem(this,photo,fast);

        qreal xl = (int)(cellWidth/2 - ti->pixmap().width()/2);
        qreal yl = (int)(cellHeight/2 - ti->pixmap().height()/2);

        qreal x = table_x_margin + xl + col*cellWidth;
        qreal y = table_y_margin + yl + row*cellHeight;

        ti->setPos(x,y);
        ti->setTablePos(row,col);

        addItem(ti);
}


Т.е. формируется и сразу добавляется на сцену. В том случае, если заготовка оказывается в видимой области - форсированно заполняется.

upl - второй вспомогательный поток, занимающийся заполнением заготовок содержимым. Как-то так:

while (photos.size() || doAction)
    {
        if (killme)
            break;
        if (!photos.size())
        {            
            msleep(rand() % 256);
            continue;
        }

        PhotoIndexPair *p = photos.at(0);

        QImage th = p->photo->getThumbnailImage();
        QImage mc = p->photo->getMinicopyImage();

        emit photoReady(th,mc,p->index);       

        photos.removeOne(p);
        delete p;
    }

    emit allReady();


Зависание происходит на то время, пока первый поток перебирает все фотки и "сигналит" о формировании заготовок. Как только все заготовки сделаны - всё отвисает (прокрутив вниз, можно видеть, как в незаполненные заготовки загружаются фотки).
Причина редактирования: пульзуйся тэгом code
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 17.3.2009, 14:51
Сообщение #4


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9669
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


Elfinit, справка по кнопкам
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
BRE
  опции профиля:
сообщение 17.3.2009, 14:52
Сообщение #5


Профессионал
*****

Группа: Участник
Сообщений: 1112
Регистрация: 6.3.2009
Из: Ростов-на-Дону
Пользователь №: 591

Спасибо сказали: 264 раз(а)




Репутация:   44  


Цитата(Elfinit @ 17.3.2009, 14:46) *
CODE

while (q.next())
{
PhotoData *photo = new PhotoData(q.value(0).toLongLong(&isOK));
album->appendPhoto(photo);
emit photoReady(photo,album,true);
upl->uploadPhoto(photo,counter);
counter++;
}

В примитиве в этот цикл можно добавить обработку событий, тогода GUI "отмерзнет".
Добавь: QApplication::processEvents();
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Elfinit
  опции профиля:
сообщение 17.3.2009, 14:59
Сообщение #6


Участник
**

Группа: Участник
Сообщений: 127
Регистрация: 17.3.2009
Из: Казань
Пользователь №: 619

Спасибо сказали: 7 раз(а)




Репутация:   1  


Пробовал - никакого эффекта. 1326 фоток - "отмерзание" через ~8 секунд.
Там ведь не просто длинный цикл с вычислениями, в этом цикле отсылаются сигналы на изменение UI, что и немедленно происходит.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
BRE
  опции профиля:
сообщение 17.3.2009, 15:05
Сообщение #7


Профессионал
*****

Группа: Участник
Сообщений: 1112
Регистрация: 6.3.2009
Из: Ростов-на-Дону
Пользователь №: 591

Спасибо сказали: 264 раз(а)




Репутация:   44  


Цитата(Elfinit @ 17.3.2009, 14:59) *
Пробовал - никакого эффекта. 1326 фоток - "отмерзание" через ~8 секунд.

Подожди, этот цикл крутиться в основном потоке или в потоке 1 (как ты его назвал)?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Elfinit
  опции профиля:
сообщение 17.3.2009, 15:20
Сообщение #8


Участник
**

Группа: Участник
Сообщений: 127
Регистрация: 17.3.2009
Из: Казань
Пользователь №: 619

Спасибо сказали: 7 раз(а)




Репутация:   1  


В потоке1. В основном он создаётся:
 AlbumLoaderThread *loader = new AlbumLoaderThread(....какие-то параметры....);
// соединение сигналов/слотов
 loader->start();

Поток2 создаётся в потоке1.

Добавил в цикл
msleep(10);

Действительно, успевает отмёзрнуть - менее чем через секунду (причём независимо от размера альбома) всё становится доступным. Но это, по-моему, не совсем элегантное лечение.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 17.3.2009, 15:21
Сообщение #9


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9669
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


Цитата(Elfinit @ 17.3.2009, 17:15) *
пользовательский интерфейс "замораживается" до тех пор, пока не сформируется всё (не успевает "отлипнуть" после очередной).
помоему эта статья близка к теме
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
BRE
  опции профиля:
сообщение 17.3.2009, 15:34
Сообщение #10


Профессионал
*****

Группа: Участник
Сообщений: 1112
Регистрация: 6.3.2009
Из: Ростов-на-Дону
Пользователь №: 591

Спасибо сказали: 264 раз(а)




Репутация:   44  


Цитата(Elfinit @ 17.3.2009, 15:20) *
Добавил в цикл
msleep(10);

Действительно, успевает отмёзрнуть - менее чем через секунду (причём независимо от размера альбома) всё становится доступным. Но это, по-моему, не совсем элегантное лечение.

Я думаю происходит следующее:
Поток AlbumLoaderThread очень быстро эмитет сигнал photoReady, т.к. сигналы идут между потоками, они превращаются в события, которые кладутся в очередь главного потока. При переключении на главный поток, за отведенное время все эти события не успевают обработаться, после этого происходит опять переключение на поток AlbumLoader и он напихивает очередную партию события и т.д.
Включения msleep улучшает положение, но это не выход, т.к. на некоторых машинах этого времени будет много и поток будет простаивать, а на другой мало и опять получаться тормоза.
Можно попробовать сделать двух стороннее информирование, т.е. AlbumLoader отправил партию картинок и ждет пока главный поток, не сообщит ему, что они все добавлены на сцену.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ViGOur
  опции профиля:
сообщение 17.3.2009, 15:43
Сообщение #11


Мастер
******

Группа: Модератор
Сообщений: 3296
Регистрация: 9.10.2007
Из: Москва
Пользователь №: 4

Спасибо сказали: 231 раз(а)




Репутация:   40  


Уже не раз говорилось:
Цитата
Есть замечательное правило, слот выполняется в том потоке, в котором был создан его объект.
Ты наверняка не следовал этому правилу. :)

Потому и происходит подвисание из-за загрузки картинок не во второстепенном, а в главном потоке.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Elfinit
  опции профиля:
сообщение 17.3.2009, 15:53
Сообщение #12


Участник
**

Группа: Участник
Сообщений: 127
Регистрация: 17.3.2009
Из: Казань
Пользователь №: 619

Спасибо сказали: 7 раз(а)




Репутация:   1  


Цитата(ViGOur @ 17.3.2009, 15:43) *
Уже не раз говорилось:
Цитата
Есть замечательное правило, слот выполняется в том потоке, в котором был создан его объект.
Ты наверняка не следовал этому правилу. :)

Потому и происходит подвисание из-за загрузки картинок не во второстепенном, а в главном потоке.


Объект сцены создаётся в основном потоке и photoReady пересылается на него. Объект-наследник QGraphicsPixmapItem (который выше известен как ThumbnailItem) создаётся именно там. Во второстепенном потоке его создавать нельзя (понятно,почему). Создаётся он изначально без картинки и просто добавляется на сцену. Пересылка в основной поток объектов QImage проблем и зависаний не вызывает. А загрузка их происходит во второстепенном потоке (поток2).

Цитата(BRE @ 17.3.2009, 15:34) *
Цитата(Elfinit @ 17.3.2009, 15:20) *
Добавил в цикл
msleep(10);

Действительно, успевает отмёзрнуть - менее чем через секунду (причём независимо от размера альбома) всё становится доступным. Но это, по-моему, не совсем элегантное лечение.

Я думаю происходит следующее:
Поток AlbumLoaderThread очень быстро эмитет сигнал photoReady, т.к. сигналы идут между потоками, они превращаются в события, которые кладутся в очередь главного потока. При переключении на главный поток, за отведенное время все эти события не успевают обработаться, после этого происходит опять переключение на поток AlbumLoader и он напихивает очередную партию события и т.д.
Включения msleep улучшает положение, но это не выход, т.к. на некоторых машинах этого времени будет много и поток будет простаивать, а на другой мало и опять получаться тормоза.
Можно попробовать сделать двух стороннее информирование, т.е. AlbumLoader отправил партию картинок и ждет пока главный поток, не сообщит ему, что они все добавлены на сцену.


Двухсторонне информирование это типа отправил N фоток (а как определить это N) и уснул либо на M мсек (а как его определить?), либо до тех пор, пока основной поток не сообщит, что снова готов принимать?
А можно как-то оценить (определить,вычислить), сколько событий может обработать поток в заданный промежуток времени?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
BRE
  опции профиля:
сообщение 17.3.2009, 16:24
Сообщение #13


Профессионал
*****

Группа: Участник
Сообщений: 1112
Регистрация: 6.3.2009
Из: Ростов-на-Дону
Пользователь №: 591

Спасибо сказали: 264 раз(а)




Репутация:   44  


Цитата(Elfinit @ 17.3.2009, 15:53) *
Двухсторонне информирование это типа отправил N фоток (а как определить это N) и уснул либо на M мсек (а как его определить?), либо до тех пор, пока основной поток не сообщит, что снова готов принимать?
А можно как-то оценить (определить,вычислить), сколько событий может обработать поток в заданный промежуток времени?

Вычислять ничего не надо.
Например, можно попробовать так:
AlbumLoader лочит мьютекс и готовит один ряд эскизов, после этого освобождает мьютекс и посылает сигнал "Блок картинок готов".
Главный поток, после получения сигнала, лочит тот же мьютекс и начинает добавлять эскизы в сцену, после освобождает мьютекс.
Т.е. пока мьютекс залочен в главном потоке (добавляются картинки на сцену), второй будет ожидать завершение этого процесса.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Elfinit
  опции профиля:
сообщение 17.3.2009, 16:38
Сообщение #14


Участник
**

Группа: Участник
Сообщений: 127
Регистрация: 17.3.2009
Из: Казань
Пользователь №: 619

Спасибо сказали: 7 раз(а)




Репутация:   1  


Цитата(BRE @ 17.3.2009, 16:24) *
Цитата(Elfinit @ 17.3.2009, 15:53) *
Двухсторонне информирование это типа отправил N фоток (а как определить это N) и уснул либо на M мсек (а как его определить?), либо до тех пор, пока основной поток не сообщит, что снова готов принимать?
А можно как-то оценить (определить,вычислить), сколько событий может обработать поток в заданный промежуток времени?

Вычислять ничего не надо.
Например, можно попробовать так:
AlbumLoader лочит мьютекс и готовит один ряд эскизов, после этого освобождает мьютекс и посылает сигнал "Блок картинок готов".
Главный поток, после получения сигнала, лочит тот же мьютекс и начинает добавлять эскизы в сцену, после освобождает мьютекс.
Т.е. пока мьютекс залочен в главном потоке (добавляются картинки на сцену), второй будет ожидать завершение этого процесса.

Спс, интересно,надо попробовать))
Но всё-таки надо же как-то оценивать количество картинок, которое должно быть в блоке....А если удастся получить такую оценку, то можно просто усыплять поток на некоторое время через каждые N отправленных photoReady
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
BRE
  опции профиля:
сообщение 17.3.2009, 16:53
Сообщение #15


Профессионал
*****

Группа: Участник
Сообщений: 1112
Регистрация: 6.3.2009
Из: Ростов-на-Дону
Пользователь №: 591

Спасибо сказали: 264 раз(а)




Репутация:   44  


Цитата(Elfinit @ 17.3.2009, 16:38) *
Но всё-таки надо же как-то оценивать количество картинок, которое должно быть в блоке....А если удастся получить такую оценку, то можно просто усыплять поток на некоторое время через каждые N отправленных photoReady

Ты попробуй: один ряд, три ряда, все видимые, ...

Небольшая поправочка:
Наверное лучше не блокировать поток AlbumLoaderThread на все время добавления картинок на сцену, пусть он создает объекты PhotoData, а когда их наберется на новый блок, лочить мьютекс, добавлять в коллекцию, освобождает мьютекс и отсылает сигнал.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 17.3.2009, 17:11
Сообщение #16


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9669
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


по опыту пользования смотрелок, как пользователь, я рассудил бы так:
процесс загрузки миниатюр, для картинок, должен быть паралелен, т.к. я могу в сотый раз в ходить в один и тот же каталог и зарание знать, что именно мне надо и где это примерно находится (сколько прокрутить линейку прокрутки в случае большого числа файлов). И я хочу иметь быструю навигацию (это не значит, что я хочу быстро увидеть все миниатюры).
Предположим, что я хочу попасть в такую точку в дереве:
\
|--folder_1
|     |--folder_2
|     |     |--file_2_1
|     |     .
|     |     .
|     |     .
|     |     |--file_2_105   -- Эту картинку хочу!
|     |     .
|     |     .
|     |     .
|     |     |--file_2_1305
|     |--file_1
|     .
|     .
|     .
|     |--file_1200
здесь видно, что я сначало вхожу в каталог folder_1, в котором 1200 файлов (по ним начинает строится миниатюры), а я почти сразу лезу в каталог folder_2, в котором 1305 файлов (по ним тоже начинают строится миниатюры), однако я прокручивю этот список к предпологаемому мету интерисующей меня миниатюры, следовательно процесс построения миниатюр должен иметь некий фокус - что стрить в первую очередь.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Elfinit
  опции профиля:
сообщение 17.3.2009, 17:31
Сообщение #17


Участник
**

Группа: Участник
Сообщений: 127
Регистрация: 17.3.2009
Из: Казань
Пользователь №: 619

Спасибо сказали: 7 раз(а)




Репутация:   1  


Litkevich Yuriy, Такая штука уже имеется - если пользователь прокрутит сцену до места, где картинки ещё не подгрузились, они загружаются в эскиз "форсированно", тупо в paint (у каждого эскиза есть флаг isLoaded, если он false, то подгружается)
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 17.3.2009, 18:09
Сообщение #18


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9669
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


Elfinit, нет нужды цитировать все мое сообщение
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

2 страниц V   1 2 >
Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0


RSS Рейтинг@Mail.ru Текстовая версия Сейчас: 28.5.2025, 21:19