|
Вопрос # 4 776/ вопрос открыт / |
|
Здравствуйте, уважаемые эксперты! Делаю программу для просмотра картинок... проблема такая -
в Thread 'e делаю так img1.picture.bitmap.loadfromfile(.....)
при этом если роликом слишком быстро крутить вылетает ошибка либо эта - Access Violation at Adress 0046829A in module Project1.exe. Write of Adress .....
либо - ccess Violation at Adress 00000000 in module Project1.exe. Write of Adress 000000 ....
либо - ошибка связанная с загрузкой картинки (редко) .. че-то там bitmap
Собственно если кто сможет - посоветуйте как избавиться от них...
поток обёрнут в try except on E:Exception do end;
Поток сделал для того чтобы программа не подгружала полностью всю картинку если допустим перелистовать побыстрей.
 |
Вопрос задал: eclipse (статус: Посетитель)
Вопрос отправлен: 1 декабря 2010, 20:41
Состояние вопроса: открыт, ответов: 1.
|
Ответ #1. Отвечает эксперт: Вадим К
Здравствуйте, eclipse!
Работать не с главного треда с компонентами формы плохо. Возможны самые различные спецэффекты. Может работать хорошо, а может... и диск попортить (на счет диска - это конечно маловероятно, но кто знает. придумать способ я то могу:) ).
Правильно работать так - доступ к элементам формы нужно синхронизировать. В Вашем случае - вызовом Synchronize (пример работы можно подсмотреть тут).
Но используя этот вызов реально не получаем никакого преимущества - вызов Synchronize так устроен, что он останавливает главный тред.
Что же делать в этой ситуации? Наверное самым простым решением было бы использование обычного таймера, который бы и менял кадры. Но вот только рекомендую завернуть процедуру таймера в такую конструкцию
var flag:boolean; //глобальный флаг. при старте выставить в false;
// в конструкторе формы выставить в true;
// процедура таймера
begin
if flag then exit;
flag := true;
// код отрисовки и другие манипуляции
flag := false;
end;
Эта конструкция не будет пускать дважды в процедуру таймера (фактически будут "пропускаться кадры"). Думаю, в этой задаче это будет оптимальным решением.
Если все таки хочется потоки, то можно. Поток будет посылать сообщение о переключении картинки, а уже форма подгружать нужную.
Разочарую - в данном случае скорости поток не прибавит. Скорости добавит, если подгрузить картинки в память.
Подгружать в потоке можно, если делать это на перед. то есть опережать отображение на несколько кадров, использовать очередь. Главный тред берет с очереди и отображает, а второй тред загружает картинки и кладет в очередь. Но это уже сложная задача (для Вас).
 |
Ответ отправил: Вадим К (статус: Академик)
Время отправки: 2 декабря 2010, 16:42
Оценка за ответ: 5
Комментарий к оценке: В принципе устраивает такой вариант.
|
Мини-форум вопроса
Всего сообщений: 14; последнее сообщение — 2 декабря 2010, 18:11; участников в обсуждении: 2.
|
Вадим К (статус: Академик), 2 декабря 2010, 12:20 [#1]:
может код показать? и просто так вызывать loadfromfile с треда не совсем безопасно.
Галочка "подтверждения прочтения" - вселенское зло.
|
|
eclipse (статус: Посетитель), 2 декабря 2010, 16:10 [#2]:
Процедура открытия файла:
procedure TForm1.suiImageButton1Click(Sender: TObject);
var i: Integer;
begin
for i:=0 to lst1.Items.Count - 1 do
if lst1.Items.Strings[i] = strings then
pic_num:= i;
if (pic_num = 0) and (suiCheckBox1.Checked = True) then
begin
strings:= lst1.Items.Strings[lst1.Items.Count - 1];
D:=TDownLoader.Create(true);
D.FreeOnTerminate:=true;
D.Resume;
end
else
begin
if pic_num <> 0 then
begin
strings:= lst1.Items.Strings[pic_num-1];
D:=TDownLoader.Create(true);
D.FreeOnTerminate:=true;
D.Resume;
end;
end;
end;
А вот сама основа:
procedure TDownLoader.Execute;
begin
if Paramstr(1) <> '' then
begin
try
Form1.img1.Picture.LoadFromFile(strings);
except
on E: Exception do
end;
if Form1.pnl1.Visible = True then
begin
Form1.lbl1.Caption:= IntToStr(pic_num) + ' / ' + IntToStr(Form1.lst1.Items.Count - 1);
Form1.lbl2.Caption:= Copy(strings, LastDelimiter('\', strings)+1, MaxInt);
end;
end;
end;
|
|
eclipse (статус: Посетитель), 2 декабря 2010, 16:50 [#3]:
Насчёт Flag я уже так делал... ничего хорошего... примерно то же самое... подгружать картинки наперёд вообще муторно да и прога тупит.
Хотя лучше с flag' ом. А сделал я в потоке потому, что так при перелистывании картинки сразу грузится новая не дожидаясь пока предыдущая загрузится.
|
|
Вадим К (статус: Академик), 2 декабря 2010, 17:05 [#4]:
а может следующую картинку подгружать не по факту нажатия, а сразу после отображения предыдущей?
С другой стороны, что у Вас там за картинки такие? мегабайт по 100?
Галочка "подтверждения прочтения" - вселенское зло.
|
|
eclipse (статус: Посетитель), 2 декабря 2010, 17:10 [#5]:
... нет не сто мегабайт... 1024x768, весят около метра.
Вот такая фишка реализована в ACDSee.
|
|
eclipse (статус: Посетитель), 2 декабря 2010, 17:19 [#6]:
А такой вопросик - как можно увеличивать картинку в image при этом чтобы она увеличивалась от центра в форме?
|
|
Вадим К (статус: Академик), 2 декабря 2010, 17:21 [#7]:
Тогда нужно подгружать картинку в треде в свой TBitmap (а если хочется и другие форматы, придется искать библиотеки).
А потом по мере подгрузки картинки (когда у нас уже будет немножко декодированных данных), отрисовывать их. с других тредов можно обращаться к канве (то есть рисовать на ней). Это особенность vcl. А также для треда должна быть переменная "стоп", тред проверяет ее при каждой "дорисовке" очередного кусочка и решает - идти дальше или нет. Но проблем тут будет много
Галочка "подтверждения прочтения" - вселенское зло.
|
|
eclipse (статус: Посетитель), 2 декабря 2010, 17:24 [#8]:
Опачки ! Вадим! А вот flag я оказывается не так использовал... попробовал по Вашему совету и всё заработало так как нужно!
Тока не понятен этот момент - if flag then exit; именно принцип работы.
|
|
eclipse (статус: Посетитель), 2 декабря 2010, 17:26 [#9]:
Даааа! с канвой я вообще храмаю!
|
|
eclipse (статус: Посетитель), 2 декабря 2010, 17:27 [#10]:
Вадим можете примерно накидать как увеличить или уменьшить... а я попробую порыться в нете чтоб под себя подмять.
|
|
Вадим К (статус: Академик), 2 декабря 2010, 17:34 [#11]:
флаг - все очень просто. если процедура таймера запускается редко, то условие не будет срабатывать, потом выставиться флажок, выполнится код и снимется флажок.
Если теперь так произойдет, что новый тик таймера придет, когда уже выполняется текущий, то первое условие сразу выкинет его. (да, таймеры работают немного не так, как ожидается по логике).
Этот код гарантирует, что в один момент времени будет выполняться не более одного обработчика таймера.
А вот по поводу увеличения я не совсем понял. хочется обычный zoom как просмотрщиках или какую то анимацию?
Галочка "подтверждения прочтения" - вселенское зло.
|
|
eclipse (статус: Посетитель), 2 декабря 2010, 17:58 [#12]:
Да вот свётаки что разграничивает простого программиста от опытного! Из-за таких мелочей получается полная картина.
Конечно обычный zoom... в сети есть примеры, но они какие-то кривые... или я сам кривой?!
Пытался сделать zoom свойством stretch... но это не то. Ну точнее от середины формы не могу поставить.
|
|
Вадим К (статус: Академик), 2 декабря 2010, 18:06 [#13]:
предлагаю пройти сюда и скачать компонент под названием TImageZoom и помедитировать над ним. Может что то и получиться
Галочка "подтверждения прочтения" - вселенское зло.
|
|
eclipse (статус: Посетитель), 2 декабря 2010, 18:11 [#14]:
Пипец! Я просто примного благодарен! С меня 1$! Как тока наберу пятёрку на letitbite. Если не против!
|
Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.
|