Форум по Delphi программированию

Delphi Sources



Вернуться   Форум по Delphi программированию > Все о Delphi > Графика и игры
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 01.08.2008, 23:55
diagnost diagnost вне форума
Прохожий
 
Регистрация: 01.08.2008
Сообщения: 19
Репутация: 10
По умолчанию Масштабирование Jpeg скроллбаром

На данный момент не нашел, как это делать правильно. Существующий вариант таков:
Код:
ImageWiring.AutoSize := true;//взято из интернета, ImageWiring: TImage 
  ImageWiring.AutoSize := false;//взято из интернета
  ImageWiring.Width := trunc(ImageWiring.Width*(1+(ScrollBarScaleImage.Position - 50)/80)); // стартовое положение скроллбара - 50, при этом масштаб 1:1
  ImageWiring.Height := trunc(ImageWiring.Height*(1+(ScrollBarScaleImage.Position - 50)/80));
  ImageWiring.Stretch := True;
  ScrollBarScaleImage.Hint := '1:' + FloatToStr(RoundTo((1+(ScrollBarScaleImage.Position - 50)/80), -2));//показывает размер изображения после передвижения ползунка

При подобном способе изображение дергается (перерисовка?) при изменении масштаба скроллбаром, получается некрасиво. Как добиться плавного изменения рисунка без подергиваний? И как показывать хинт скроллбара в процессе перемещения?

Последний раз редактировалось diagnost, 02.08.2008 в 00:32.
Ответить с цитированием
  #2  
Старый 04.08.2008, 22:23
diagnost diagnost вне форума
Прохожий
 
Регистрация: 01.08.2008
Сообщения: 19
Репутация: 10
По умолчанию

Задача далеко не банальна. Пробовал в ScrollBox поместить PaintBox и выводить изображение на PaintBox.Canvas. Обнаружил, что мерцание получается из-за изменения размера PaintBox при масштабировании картинки. Видимо, при изменении размера PaintBox сам PaintBox сначала перерисовывается с пустым канвасом цветом фона ScrollBox, и лишь после этого я канвас заполняю изображением при вызове процедуры типа Draw. Как это обойти, ума не приложу...
Код:
   PaintBox.Height:= ViewH; //заполнение PaintBox фоном - вывод фона на экран, причина мерцания
   PaintBox.Width := ViewW;//-"-
   PaintBox.Canvas.Draw(0,0,ScaledBmp)//вывод изображения на экран.

Последний раз редактировалось diagnost, 04.08.2008 в 22:25.
Ответить с цитированием
  #3  
Старый 04.08.2008, 23:01
san-46 san-46 вне форума
Активный
 
Регистрация: 25.04.2008
Сообщения: 383
Репутация: 33
По умолчанию

А можно поинтересоваться? Если скроллбар используется для масштабирования, то чем скроллируется TImage когда масштаб изображения выходит далеко за видимые размеры окна?
__________________
Не забывайте делать резервные копии
Ответить с цитированием
  #4  
Старый 04.08.2008, 23:08
diagnost diagnost вне форума
Прохожий
 
Регистрация: 01.08.2008
Сообщения: 19
Репутация: 10
По умолчанию

Скроллбоксом. Я помещал TImage в скроллбокс . Но, ИМХО, причина не в скроллбоксе, т.к. даже если изображение меньше скроллбокса и целиком в него влезает, оно подергивается при изменении масштаба.

Я полагаю, надо или найти способ запретить перерисовывать канвас при изменении размера PaintBox'а (если этот способ существует), или выводить поверх PaintBox'а изображение (типа нового слоя), в которое записывать нужные изменения канваса PaintBox'а (тут много проблем).

Последний раз редактировалось diagnost, 04.08.2008 в 23:28.
Ответить с цитированием
  #5  
Старый 04.08.2008, 23:23
san-46 san-46 вне форума
Активный
 
Регистрация: 25.04.2008
Сообщения: 383
Репутация: 33
По умолчанию

Обычно делают так. Масштаб изображения меняют какими-нибудь дополнительными управляющими компонентами: кнопками, "ползунком" (trackbar) и (или) мышой. А скроллбары (полосы внизу и справа) используют для прокрутки изображения чтоб просматривать любые части изображения.
ScrollBarScaleImage - это видимо какой-то свой компонент (типа trackbar'а), с помощью которого и меняется масштаб?.
__________________
Не забывайте делать резервные копии

Последний раз редактировалось san-46, 05.08.2008 в 00:08.
Ответить с цитированием
  #6  
Старый 05.08.2008, 00:51
diagnost diagnost вне форума
Прохожий
 
Регистрация: 01.08.2008
Сообщения: 19
Репутация: 10
По умолчанию

Прошу прощения за то, что плохо объясняю.
Да, я вместо trackbar'а использую отдельный скроллбар.У меня так все и есть, как написал san-46. ScrollBarScaleImage - это обычный скроллбар в стороне от скроллбокса (не принадлежащий скроллбоксу). Я его использую для масштабирования рисунка в скроллбоксе. При перемещении ползунка на моем "выносном" "дополнительном" скроллбаре я изменяю размеры PaintBox, который лежит в скроллбоксе. При этом происходит мерцание изображения (из-за изменения размера PaintBox).
Все работает (испробовал уже несколько разных способов, два описал в первом и втором сообщении этой темы), только мерцание некрасиво. Не могу избавиться. Пересмотрел много тем на этом форуме, проблему уже поднимали, решения не нашел.

Последний раз редактировалось diagnost, 05.08.2008 в 00:59.
Ответить с цитированием
  #7  
Старый 05.08.2008, 01:03
san-46 san-46 вне форума
Активный
 
Регистрация: 25.04.2008
Сообщения: 383
Репутация: 33
По умолчанию

Цитата:
...я изменяю размеры PaintBox
Как раз этого и нельзя делать - такая дискотека будет (особенно при больших масштабах), мало не покажется.

Вот поэкспериментировал - ничего не дергается, плавно увеличивает масштаб. (Это более правильный вариант).
Код:
var
  BS, BT : TBitmap;

procedure TForm1.FormCreate(Sender: TObject);
begin
  BS := TBitmap.Create;
  BS.LoadFromFile(<FileName>);
  BT := TBitmap.Create;
  PaintBox1.ControlStyle := PaintBox1.ControlStyle + [csOpaque]; //обязательно
end;

procedure TForm1.TrackBar1Change(Sender: TObject);
begin
  PaintBox1.Invalidate;
end;

procedure TForm1.PaintBox1Paint(Sender: TObject);
begin
  BT.Width := BS.Width + (TrackBar1.Position-1) * 2;
  BT.Height := BS.Height + (TrackBar1.Position-1) * 2;
  BT.Canvas.StretchDraw(Rect(0, 0, BT.Width, BT.Height), BS);
  PaintBox1.Canvas.CopyRect(PaintBox1.ClientRect, BT.Canvas, PaintBox1.ClientRect);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  BT.Free;
  BS.Free;
end;
Еще нужна проверка при уменьшении масштаба, если картинка становится меньше размера PaintBox. Думаю, что и как делать при этом придумать можно.
Да, еще. Код только масштабирует, но не прокручивает картинку. Для прокрутки код надо переделывать-доделывать.

Здесь, главное, идея. А идея в том, что исходная картинка храниться в памяти, не высовывается (BS). Хранить исходную обязательно.
Масштаб меняется изменением размеров промежуточного bitmap (BT) тоже в памяти. В него перегоняется исходная картинка, которая с помощью StretchDraw меняет свой размер. И последнее действие выводит ЧАСТЬ изображения на канву визуального компонент (здесь PainBox, можно на другие компоненты, которые имеют Canvas).

Ага, еще. Скроллбокс здесь не годится. Т.е. PaintBox вставлять в ScrollBox не получится. А систему отображения надо представить в виде окошка, через которое мы видим только часть картинки (CopyRect). При прокрутке (текущий масштаб) просто надо смещать прямоугольник с одним и тем же размером (размер визуального компонента) по вертикали и горизонтали. Как будто мы перемещаем наше окошко по большой картинке.

Как с jpeg не знаю, не пытался делать. Насколько помню, ничего особенного, почти все так же.
__________________
Не забывайте делать резервные копии

Последний раз редактировалось san-46, 05.08.2008 в 02:05.
Ответить с цитированием
  #8  
Старый 05.08.2008, 01:56
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,036
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Путем долгих проб пришел к варианту использования PaintBox и буферного битмапа. Всю отрисовку с переразмериванием выполняю на битмапе, а в PaintBox.OnDraw (так что-ли) переразмериваю сам PaintBox (если нужно) и делаю CopyRect, который выполняется быстро.
Ответить с цитированием
  #9  
Старый 05.08.2008, 02:06
diagnost diagnost вне форума
Прохожий
 
Регистрация: 01.08.2008
Сообщения: 19
Репутация: 10
По умолчанию

Да у меня почти один в один (разница в мелочах), дергается только при изменении размера PaintBox. Вот хотел попроще способ найти, а получается надо аналог городить скроллбокса
Код:
procedure PaintWiringImage;
begin
  with Form1 do begin
    PaintBoxImage.Canvas.Draw(0,0,BmpOnScreen);
  end;
end;

procedure ScaleWiringImage;
var
  ViewH, ViewW: integer;
  RScreen: TRect;
begin
  with Form1 do begin
    ViewH := Round(BmpFromFile.Height * TrackBarScaleImage.Position/100);
    ViewW := Round(BmpFromFile.Width * TrackBarScaleImage.Position/100);
    BmpOnScreen.Height:= ViewH;
    BmpOnScreen.Width := ViewW;
    RScreen := Rect(0,0,ViewW,ViewH);
    BmpOnScreen.Canvas.StretchDraw(RScreen, BmpFromFile);

    PaintBoxImage.Height:= ViewH;
    PaintBoxImage.Width := ViewW;

    PaintWiringImage;
  end;
end;

Последний раз редактировалось diagnost, 05.08.2008 в 02:25.
Ответить с цитированием
  #10  
Старый 05.08.2008, 02:11
san-46 san-46 вне форума
Активный
 
Регистрация: 25.04.2008
Сообщения: 383
Репутация: 33
По умолчанию

Цитата:
Сообщение от lmikle
...а в PaintBox.OnDraw (так что-ли) переразмериваю сам PaintBox (если нужно)...
А если не нужно "переразмеривать" (видимый компонент на форме - размер статический), а масштаб увеличивать надо?

Я достаточно много в свое время возился с графикой и, в т.ч. масштабированием. Если интересно, конечно, можете посмотреть компонент из этой оперы
http://www.delphisources.ru/pages/so...r-graphic.html

Цитата:
Сообщение от diagnost
Вот хотел попроще способ найти, а получается надо аналог городить скроллбокса.

А чем не устраивает мое предложение? Проще по-моему уже и некуда, а эффект впечатляющий.
Надо обратить внимание на строку PaintBox1.ControlStyle := PaintBox1.ControlStyle + [csOpaque];
Вроде мелочь, а именно в ней весь секрет "дерганья".
__________________
Не забывайте делать резервные копии

Последний раз редактировалось san-46, 05.08.2008 в 02:38.
Ответить с цитированием
  #11  
Старый 05.08.2008, 02:48
diagnost diagnost вне форума
Прохожий
 
Регистрация: 01.08.2008
Сообщения: 19
Репутация: 10
По умолчанию

1) Ну "проще уж некуда" это слишком сильно сказано. Окошко у меня расширяющееся, на панели сидит.
2) Свой скроллбокс не будет таким красивым, как в Виндоуз
3) Идея хорошая, буду пробовать, хоть и неохота, а деваться некуда
4) Не дергается у меня и без этой строчки.
5) Не очень нравится вот этот нюанс:
Код:
procedure TForm1.TrackBar1Change(Sender: TObject);
begin
  PaintBox1.Invalidate;
end;

procedure TForm1.PaintBox1Paint(Sender: TObject);
begin
  BT.Width := BS.Width + (TrackBar1.Position-1) * 2;
  BT.Height := BS.Height + (TrackBar1.Position-1) * 2;
  BT.Canvas.StretchDraw(Rect(0, 0, BT.Width, BT.Height), BS);
  PaintBox1.Canvas.CopyRect(PaintBox1.ClientRect, BT.Canvas, PaintBox1.ClientRect);
end;
Получается, что при перерисовке каждый раз много лишних операций происходит. Я предлагаю на OnPaint только копировать (см. мой вариант), без лишних вычислений.

Последний раз редактировалось diagnost, 05.08.2008 в 03:00.
Ответить с цитированием
  #12  
Старый 05.08.2008, 02:56
san-46 san-46 вне форума
Активный
 
Регистрация: 25.04.2008
Сообщения: 383
Репутация: 33
По умолчанию

>>4) Не дергается у меня и без этой строчки.
Если не дергается, то тема исчерпана? Изначально проблема была именно в плохой прорисовке, насколько помню.

А к какому событию прицеплена процедура ScaleWiringImage;?
__________________
Не забывайте делать резервные копии
Ответить с цитированием
  #13  
Старый 05.08.2008, 03:03
diagnost diagnost вне форума
Прохожий
 
Регистрация: 01.08.2008
Сообщения: 19
Репутация: 10
По умолчанию

Не дергается, если не менять размер PaintBox, а я его менял при масштабировании.

Код:
procedure TForm1.TrackBarScaleImageChange(Sender: TObject);
begin
  ScaleWiringImage;
end;

procedure TForm1.PaintBoxImagePaint(Sender: TObject);
begin
  PaintWiringImage;
end;

Задача - написать хороший просмотрщик эл. схем (wiring) автомобилей, с деревом, масштабированием, расшифровкой компонентов.

Последний раз редактировалось diagnost, 05.08.2008 в 03:07.
Ответить с цитированием
  #14  
Старый 05.08.2008, 03:17
san-46 san-46 вне форума
Активный
 
Регистрация: 25.04.2008
Сообщения: 383
Репутация: 33
По умолчанию

Не хилая задачка!!!
А укротить PaintBox при изменении его размеров не получиться. Пробовано, перепробовано.
Только дошло, что прокрутка должна быть в окне со скролбарами.
Действительно, штатные дельфийские скроллбары убогие до тошноты.
Правда можно на проект повесить XPManifest, но и преобразованные скроллбары при этом будут старого стиля (это когда размер движка в них как и кнопки со стрелками и не меняется).
__________________
Не забывайте делать резервные копии
Ответить с цитированием
  #15  
Старый 05.08.2008, 03:27
san-46 san-46 вне форума
Активный
 
Регистрация: 25.04.2008
Сообщения: 383
Репутация: 33
По умолчанию

>>Я предлагаю на OnPaint только копировать (см. мой вариант), без лишних вычислений.
Это не вычисления - это кошачьи слезы. Если посмотрите на код, который болтается у меня в линейном графике на событии OnPaint и, который действительно выполняет окаянное количество вычислений, сразу забудете о такой мелочи как перегонка двух bitmap.
А потом, это все равно ничего не даст. OnPaint, в действительности ничего не выводит, а только подготавливает все чего надо к выводу, поэтому никакого значения не имеет в какой части кода будут "вычисления" и "вывод изображения", все равно, пока это хозйство полностью не отработает никакого вывода не будет (который, кстати, после этого становиться только в очередь на визуальный вывод). Не партесь по поводу вычислений в OnPaint - делайте чего хотите в одном месте - это же удобнее.
__________________
Не забывайте делать резервные копии
Ответить с цитированием
Ответ


Delphi Sources

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 18:39.


 

Сайт

Форум

FAQ

RSS лента

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2023

ВКонтакте   Facebook   Twitter