Перейти к содержанию
  • Регистрация

Вопрос

На незначительном количестве устройств, менее 0,1%, получаю ошибку "Bitmap size too big" при AImage.Bitmap.LoadFromStream(AMemoryStream). Подозреваю что ошибка происходит на слабых устройствах. Картинка 250х250 png. Код выполняется в основном потоке (в интернетах были упоминания что глючит эта операция в отдельном потоке на каких то версиях Delphi).

Как предотвратить подобное? Можно как то определить максимальный размер картинки для текущего устройства? Или может дело не в свободной памяти, а в чем то еще?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Рекомендуемые сообщения

  • 0

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

кстати, да была такая проблема. с фотика шла картинка которая не могла загружаться в битмап из за своих размеров. НО! при этом другие программы ее спокойно показывали и работали с этой картинкой. интеерсно почему на яве программы могли с ней работать а огнеобезьяна упирается в ограничения. 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
1 час назад, haword сказал:

кстати, да была такая проблема. с фотика шла картинка которая не могла загружаться в битмап из за своих размеров. НО! при этом другие программы ее спокойно показывали и работали с этой картинкой. интересно почему на яве программы могли с ней работать а огнеобезьяна упирается в ограничения. 

Причин несколько:

  1. Ява сама не может отобразить большие изображения так же. Но там причина ограничение по потребляемой памяти. Поэтому если открыть документацию, то можно увидеть специальные методы и рекомендации для сжатия размера для отображения на экран. Вместо того, что выводить картинку в 10 МгП на экран, апи выдает картинку 64 на 64 или тд.
  2. В FireMonkey есть два типа для работы с изображениями. 
    1. TBitmap - построен на использовании текстур. Отсюда и идет ограничение на размер в зависимости от аппаратной части девайса.
    2. TBitmapSurface - не зависит ни от чего, кроме, как от памяти. Этот тип полностью совместим с TBitmap - это значит, что можно копировать изображения друг в друга. Это тип создан для хранения, как раз больших изображений.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Можно я уточню?
Можно спокойно забыть про TBitmap и везде использовать TBitmapSurface ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
В 3/29/2016 в 11:55, Brovin Yaroslav сказал:

На тестовом устройстве с помощью кода

Var MaxWidthHeight: Integer;
begin
  MaxWidthHeight := TCanvasManager.DefaultCanvas.GetAttribute(TCanvasAttribute.MaxBitmapSize);

получаю значение 4096. В каких попугаях это число? Судя по MaxWidthHeight это высота изображения? Как получить тогда ширину? Или его размер в байтах? Хотя это врядли, на этом устройстве успешно загружаются картинки в 200 килобайт.

 

В 3/29/2016 в 13:29, Brovin Yaroslav сказал:

Причин несколько:

  1. Ява сама не может отобразить большие изображения так же. Но там причина ограничение по потребляемой памяти. Поэтому если открыть документацию, то можно увидеть специальные методы и рекомендации для сжатия размера для отображения на экран. Вместо того, что выводить картинку в 10 МгП на экран, апи выдает картинку 64 на 64 или тд.
  2. В FireMonkey есть два типа для работы с изображениями. 
    1. TBitmap - построен на использовании текстур. Отсюда и идет ограничение на размер в зависимости от аппаратной части девайса.
    2. TBitmapSurface - не зависит ни от чего, кроме, как от памяти. Этот тип полностью совместим с TBitmap - это значит, что можно копировать изображения друг в друга. Это тип создан для хранения, как раз больших изображений.

Подскажите наиболее правильный путь в моей ситуации - на форме лежит TImage и нужно загрузить в него картинку:

  1. Проверять максимальный размер картинки, если загрузить не удастся, то отлупливать пользователя фразой "Нищебродам вход воспрещен".
  2. Переписать класс TImage на использование TBitmapSurface вместо TBitmap
  3. Загружать картинку сначала в TBitmapSurface, изменять размер и копировать в визуальный Image.Bitmap. Вот тут облом - если не ошибаюсь TBitmapSurface не умеет абсолютно ничего, никаких  LoadFromStream (как в него вообще загрузить внешнее изображение?) только readonly свойства и методы.
Изменено пользователем Евгений Корепов

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

скорей всего 4096x4096 это размер в пикселях

а в битах думаю вот так 4096x4096x24/32(смотря какая глубина цвета используется)

Изменено пользователем ZuBy

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
В 29.03.2016 в 17:27, Евгений Корепов сказал:

Подскажите наиболее правильный путь в моей ситуации - на форме лежит TImage и нужно загрузить в него картинку:

  1. Проверять максимальный размер картинки, если загрузить не удастся, то отлупливать пользователя фразой "Нищебродам вход воспрещен".
  2. Переписать класс TImage на использование TBitmapSurface вместо TBitmap
  3. Загружать картинку сначала в TBitmapSurface, изменять размер и копировать в визуальный Image.Bitmap. Вот тут облом - если не ошибаюсь TBitmapSurface не умеет абсолютно ничего, никаких  LoadFromStream (как в него вообще загрузить внешнее изображение?) только readonly свойства и методы.
  1. Нет. Это значит, что не нужно загружать 4 Мб фотографию в TImage с целью отобразить ее в итоге в размере 400х200.
  2. Нет, просто присваивайте в Bitmap TBtmapSurface. Bitmap.Assign(BitmapSurface)
  3. Методы по загрузки из файлов и потоков есть. Смотрите TBitmapCodecManager

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
6 часов назад, Brovin Yaroslav сказал:
  1. Нет. Это значит, что не нужно загружать 4 Мб фотографию в TImage с целью отобразить ее в итоге в размере 400х200.
  2. Нет, просто присваивайте в Bitmap TBtmapSurface. Bitmap.Assign(BitmapSurface)
  3. Методы по загрузки из файлов и потоков есть. Смотрите TBitmapCodecManager

Огромное вам спасибо! Стало много понятнее. Повторюсь: картинки 250х250 png. Сделал процедуру:

Uses FMX.Graphics, FMX.Surfaces, FMX.Types;


function GetMaxImageSize : Integer;
begin
  Result:=TCanvasManager.DefaultCanvas.GetAttribute(TCanvasAttribute.MaxBitmapSize);
end;

procedure CheckAndLoadFromStream(const AStream : TStream; const ABitmap : TBitmap);
Var MaxImageSize : Integer;
    ABitmapSurface : TBitmapSurface;
begin
  ABitmapSurface:=TBitmapSurface.Create;
  AStream.Position:=0;
  TBitmapCodecManager.LoadFromStream(AStream,ABitmapSurface);
  MaxImageSize:=GetMaxImageSize;
//  MaxImageSize:=64;
  if ABitmapSurface.Height>MaxImageSize then
    ABitmapSurface.SetSize(MaxImageSize,MaxImageSize,ABitmapSurface.PixelFormat);
  if Assigned(ABitmap) then
    ABitmap.Assign(ABitmapSurface);
  ABitmapSurface.Free;
end;

Все отлично работает, до момента раскоментирования строчки   "MaxImageSize:=64" (имитация слабого устройства) - процедура ABitmapSurface.SetSize устанавливает новый размер, но изображение при этом теряется, на форме, в TImage пустота. Видимо я что то не так делаю :-( Перебрал все возможные ABitmapSurface.PixelFormat - результата нет.

Следующий код

  ABitmapSurface:=TBitmapSurface.Create;
  TBitmapCodecManager.LoadFromFile('d:\source.png',ABitmapSurface);
  MaxImageSize:=250;
  ABitmapSurface.SetSize(MaxImageSize,MaxImageSize);
  TBitmapCodecManager.SaveToFile('d:\source_resize.png', ABitmapSurface);

Из файла source.png размером 79642 байта делает файл source_resize.png размером 351 байт. Изображение исчезает.

Что я делаю не так? Заранее благодарю за ответ!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Сам себе отвечаю, процедура procedure TBitmapSurface.SetSize(const AWidth, AHeight: Integer; const APixelFormat: TPixelFormat), судя по коду:

procedure TBitmapSurface.SetSize(const AWidth, AHeight: Integer; const APixelFormat: TPixelFormat);
var  NumOfBytes: Integer;
begin
  FPixelFormat := APixelFormat;
  if FPixelFormat = TPixelFormat.None then
    FPixelFormat := TPixelFormat.BGRA;

  FBytesPerPixel := PixelFormatBytes[FPixelFormat];

  FWidth := Max(AWidth, 0);
  FHeight := Max(AHeight, 0);
  FPitch := FWidth * FBytesPerPixel;
  NumOfBytes := FWidth * FHeight * FBytesPerPixel;

  ReallocMem(FBits, NumOfBytes);
  FillChar(FBits^, NumOfBytes, 0);
end;

изменяет размер и просто забивает нулями содержимое Bitmap. Пойду копать дальше...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Ура! Заработало с TBitmapSurface.StretchFrom :

  ABitmapSurface:=TBitmapSurface.Create;
  ABitmapSurfaceResize:=TBitmapSurface.Create;
  TBitmapCodecManager.LoadFromFile('d:\source.png',ABitmapSurface); // png 250x250
  MaxImageSize:=50;
  ABitmapSurfaceResize.StretchFrom(ABitmapSurface,MaxImageSize,MaxImageSize);
  TBitmapCodecManager.SaveToFile('d:\source_resize.png', ABitmapSurfaceResize);

Все работает отменно :-)

Итоговый код для загрузки картинки из потока и устранения ошибки "Bitmap size too big":

Uses FMX.Graphics,  FMX.Surfaces;


function GetMaxImageSize : Integer;
begin
  Result:=TCanvasManager.DefaultCanvas.GetAttribute(TCanvasAttribute.MaxBitmapSize);
end;

procedure CheckAndLoadFromStream(const AStream : TStream; const ABitmap : TBitmap);
Var MaxImageSize : Integer;
    ABitmapSurface,ABitmapSurfaceResize : TBitmapSurface;
begin
  ABitmapSurface:=TBitmapSurface.Create;
  AStream.Position:=0;
  TBitmapCodecManager.LoadFromStream(AStream,ABitmapSurface);
  MaxImageSize:=GetMaxImageSize;
  if ABitmapSurface.Height>MaxImageSize then
  begin
    ABitmapSurfaceResize:=TBitmapSurface.Create;
    ABitmapSurfaceResize.StretchFrom(ABitmapSurface,MaxImageSize,MaxImageSize);
    if Assigned(ABitmap) then
      ABitmap.Assign(ABitmapSurfaceResize);
    ABitmapSurfaceResize.Free;
  end
  Else
    if Assigned(ABitmap) then
      ABitmap.Assign(ABitmapSurface);
  ABitmapSurface.Free;
end;

Всем спасибо за помощь! Особая благодарность Ярославу! 

P.S. Процедура для частного случая с квадратным изображением. Для меня осталось не до конца ясным значение возвращаемое TCanvasManager.DefaultCanvas.GetAttribute(TCanvasAttribute.MaxBitmapSize), исходил из догадки что это максимальный размер изображения по вертикали в пикселях. Может Ярослав поставит все точки и разъяснит этот вопрос?

Изменено пользователем Евгений Корепов

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
5 часов назад, Евгений Корепов сказал:

P.S. Процедура для частного случая с квадратным изображением. Для меня осталось не до конца ясным значение возвращаемое TCanvasManager.DefaultCanvas.GetAttribute(TCanvasAttribute.MaxBitmapSize), исходил из догадки что это максимальный размер изображения по вертикали в пикселях. Может Ярослав поставит все точки и разъяснит этот вопрос?

Если я правильно помню, то это сторона квадрата в пикселях. Если возвращает 1000, то это значит, что допустимо хранение изображение размером до 1000 х 1000. На самом деле TBitmap в своей основе использует текстуру для хранения картинки. Поэтому этот размер и ограничение зависит от графического процессора.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

К сожалению я рано радовался. Три недели тестов показали что ошибка "Bitmap size too big" продолжает появляться у не значительной части пользователей.

Вышеприведенный код по видимому работает. Но ошибка появляется там где размер изображения заведомо меньше GetMaxImageSize

 end
  Else
    if Assigned(ABitmap) then
      ABitmap.Assign(ABitmapSurface); // Вот здесь ошибка

Продолжаю наблюдение...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Да ошибка подтвердилась. MaxImageSize=4096, но  ABitmap.Assign(ABitmapSurface) выдает ошибку "Bitmap size too big" при загрузке картинки 250x250

Больше идей у меня нет...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Вот и у меня вылезла эта ошибка ."Bitmap size too big". Причем ошибка коварная, появляется не всегда и из-за этого непонятно почему и как ее отловить.

BigBitmap.png

 

Подозреваю что проблема происходит здесь (к ListView прикреплен ImageList с 2 картинками 44х44):

var
  k:integer;
  Al:TAl;
  IItem:TListItemImage;
  TItem:TListItemText;
begin
      Lsv.BeginUpdate;
      for k := 0 to Lsv.ItemCount-1 do
      begin        
        IItem:=Lsv.Items[k].Objects.FindDrawable('Imp1') as TListItemImage;
        TItem:=Lsv.Items[k].Objects.FindDrawable('TxtNumber') as TListItemText;

        Al:=GetAlFromList(Lsv.Items[k].Tag);
        if Al.Tip=0 then
        begin                                    
          if IItem<>nil then IItem.ImageIndex:=0; 
          if TItem<>nil then TItem.TextColor:=$FFFF0000;
        end
        else
        begin
          if IItem<>nil then IItem.ImageIndex:=1; 
          if TItem<>nil then TItem.TextColor:=$FF0000FE;
        end
      end;
      Lsv.EndUpdate;
end;

Продолжаю выяснять откуда ноги растут.

 

Изменено пользователем Rusland

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Сделаю предположение что ВОЗМОЖНО данная ошибка вылезает при невозможности выделить память под очередную текстуру

Изменено пользователем Error

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

скажите, кто-нибудь разобрался с проблемой?

у меня все тоже - 

 ABitmap.Assign(ABitmapSurfaceResize);

даже ПОСЛЕ преобразования размеров выдает ошибку  Bitmap size too big

в FMX ужасно раздражает что на корректную работу строчки TBitmap().LoadFromFile(filename) можно потратить больше суток, причем не факт что в новой версии все будет работать стабильно

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Я смирился. У меня в приложении с ~20000 пользователями ошибка вылезает у 290 :-( Т.е. это примерно 1.5%. 

Изменено пользователем Евгений Корепов

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

понял... ну тут единственный тогда выход что мне видится переписывать с ХЕ6 TImage и TBitmap, там оно работало, у меня глюк появился с переходом на ХЕ8-ХЕ10

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
В 31.03.2016 в 15:53, Brovin Yaroslav сказал:

Если я правильно помню, то это сторона квадрата в пикселях. Если возвращает 1000, то это значит, что допустимо хранение изображение размером до 1000 х 1000

Опытным путем выяснил что это не так. Это максимальная сторона изображения, а пропорции его не должны превышать пропорции монитора (может десктопа?).

Т.е. если TCanvasManager.DefaultCanvas.GetAttribute(TCanvasAttribute.MaxBitmapSize) возвращает 8192, то для монитора с разрешением 1440х900 можно создать битмапку размером не больше чем 8192х5120,  в противном случае получаю ошибки "Cannot create texture for 'TCanvasD2D'" или "Stack overflow"

 

Позже попробую поэкспериментировать на десктопе, растянутом на 2 монитора с портретной и ландшафтной ориентацией.

Изменено пользователем dnekrasov

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
В 19.05.2016 в 22:57, Евгений Корепов сказал:

Я смирился. У меня в приложении с ~20000 пользователями ошибка вылезает у 290 :-( Т.е. это примерно 1.5%. 

попробуй переставь

ABitmapSurfaceResize:=TBitmapSurface.Create;

после 

ABitmapSurface:=TBitmapSurface.Create;

и

после определения максимальных длины и ширины  - сделай ABitmapSurfaceResize.SetSize

у меня по крайней мере заработало.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

в общем итоговая процедура получилась у меня вот так, при этом заработало там где до этого не работало

procedure CheckAndLoadFromStream(FileName:string; const ABitmap : TBitmap);
var
  MaxImageSize : Integer;
  ABitmapSurface,ABitmapSurfaceResize : TBitmapSurface;
  mxH,mxW:integer;
begin
  ABitmapSurface:=TBitmapSurface.Create;
  ABitmapSurfaceResize:=TBitmapSurface.Create;
  TBitmapCodecManager.LoadFromFile(FileName,ABitmapSurface);
  MaxImageSize:=TCanvasManager.DefaultCanvas.GetAttribute(TCanvasAttribute.MaxBitmapSize);
  if (ABitmapSurface.Height>MaxImageSize) or (ABitmapSurface.Width>MaxImageSize) then
  begin
    if ABitmapSurface.Height>ABitmapSurface.Width then
    begin
      mxH:=MaxImageSize;
      mxW:=Round(mxH/ABitmapSurface.Height*ABitmapSurface.Height);
    end else
      begin
        mxW:=MaxImageSize;
        mxH:=Round(mxW/ABitmapSurface.Width*ABitmapSurface.Height);
      end;
  end else
    begin
      mxW:=ABitmapSurface.Width;
      mxH:=ABitmapSurface.Height;
    end;
  ABitmapSurfaceResize.SetSize(mxW,mxH);
  ABitmapSurfaceResize.StretchFrom(ABitmapSurface,mxW,mxH);
  FreeAndNil(ABitmapSurface);
  ABitmap.SetSize(mxW,mxH);
  ABitmap.Assign(ABitmapSurfaceResize);
  FreeAndNil(ABitmapSurfaceResize);
end;
Изменено пользователем tromani

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

К сожалению этот код выполняется неимоверно долго. На моём HTC One, загрузка с локального хранилища 30 картинок 250х250 производится за 15-20 секунд. Прямая операция Assigned(ABitmap) происходит фактически мгновенно. Так что ради полутора процентов пользователей, замедлять работу приложения на два порядка я не готов.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Посмотрел исходники, оказывается там все это уже есть:

unit FMX.Graphics;

procedure TBitmap.AssignFromSurface(const Source: TBitmapSurface);
var
  BitmapData: TBitmapData;
  MaxSize: Integer;
  ResampledSurface: TBitmapSurface;
  I: Integer;
  SourceRect: TRectF;
begin
  MaxSize := CanvasClass.GetAttribute(TCanvasAttribute.MaxBitmapSize);
  if (Source.Width > MaxSize) or (Source.Height > MaxSize) then
  begin
    SourceRect := TRectF.Create(0, 0, Source.Width, Source.Height);
    SourceRect.Fit(TRectF.Create(0, 0, MaxSize, MaxSize));
    ResampledSurface := TBitmapSurface.Create;
    try
      ResampledSurface.StretchFrom(Source, Trunc(SourceRect.Width), Trunc(SourceRect.Height), PixelFormat);
      AssignFromSurface(ResampledSurface);
    finally
      ResampledSurface.Free;
    end;
  end
  else
  begin
    SetSize(Source.Width, Source.Height);
    if Map(TMapAccess.Write, BitmapData) then
    try
      for I := 0 to TBitmapSurface(Source).Height - 1 do
        Move(TBitmapSurface(Source).Scanline[I]^, BitmapData.GetScanline(I)^, BitmapData.BytesPerLine);
    finally
      Unmap(BitmapData);
    end;
  end;
end;

Так что весь мой код не имеет смысла. В процедуре можно ограничится следующим кодом:

procedure TFormMain.CheckAndLoadFromStream(const AStream : TStream; const ABitmap : TBitmap);
Var ABitmapSurface : TBitmapSurface;
begin
  ABitmapSurface:=TBitmapSurface.Create;
  AStream.Position:=0;
  TBitmapCodecManager.LoadFromStream(AStream,ABitmapSurface);
  if Assigned(ABitmap) then
    ABitmap.Assign(ABitmapSurface);
  FreeAndNil(ABitmapSurface);
end;

Ну и изредка глючить он будет по прежнему...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

хм... ну очевидно что медленность работы вызвана 

ABitmapSurfaceResize.StretchFrom(ABitmapSurface,mxW,mxH);

в любом случае, поменяй код так чтоб эта часть вызывалась только тогда когда надо, в ином случае делай .Assign это решит проблему.

 

Я конечно не знаю как у вас происходит но меня очень напрягает когда 2-3% скачавших приложение ставят оценку 1 потому что что-то не заработало или они не разобрались как работает

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить на вопрос...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.


  • Похожий контент

    • От Эрик Шакиров
      Привет всем! Кто нибудь может подсказать как реализовать анимацию переходов между формами в Android без использования TabControl? Или подсказать в какую сторону "рыть"
    • От Павел Блажеев
      Добрый день. Очень нужна Ваша помощь. 
      Мне необходимо сделать координатную сетку в виде точек. При масштабировании панели количество точек должно изменяться . 
      Хочу все это сделать на канве панели. Унаследовал класс и переопределил procedure   Paint; override;
        Tfield = class(TPanel)
            Constructor Create( parent: TFmxObject);
              procedure   Paint; override;
              Procedure   OnMyClick (Sender: TObject);
          end;

      В теле метода я пробовал рисовать. Экспериментировал и столкнулся с такой проблемой. Ничего не отображается. Нет никаких изменений.
      Если я наследую не от Tpanel а от Timage то часть кода работает а часть работает очень криво. Очень хочу разобраться почему .
      {Отображается сразу}
      for a:=1 to 1000 do
            begin
              self.Canvas.Fill.Color:=  TAlphaColors.Crimson;
               self.Canvas.FillEllipse(rect(1,1,10,10),self.AbsoluteOpacity);
               self.Canvas.FillEllipse(rect(round(self.Width-9),round(self.Height-9),round(self.Width), round(self.Height)),self.AbsoluteOpacity);
               self.Canvas.FillEllipse(rect(round(self.Width-9),1,round(self.Width), 9),self.AbsoluteOpacity);
               self.Canvas.FillEllipse(rect(1,round(self.Height-9),10, round(self.Height)),self.AbsoluteOpacity);
            end;
       
      {Отображается только после того как я проскролю Scrollbox на котором лежит панель в крайнее нижнее правое положение}
            self.Canvas.Stroke.Color:=  TAlphaColors.Crimson;
            self.Canvas.Stroke.Thickness:=7;
             Canvas.BeginScene;
            self.Canvas.DrawLine(PointF(20, 20), PointF(100, 50), self.AbsoluteOpacity);
             Canvas.EndScene;
      Подскажите пожалуйста, почему не работает такое с панелью?  Как правильно рисовать на панели? 
      Почему в случае с имейджем все работает так некорректно?  Почему работает только после скрола? 
      Каким способом мне лучше сделать координатную сетку? состоящую из точек как в режиме Design?

       


    • От Светлана
      Ну всё в принципе как всегда, либо я барашка, либо лыжи не едут)
      А всё просто - я хочу, чтобы пока данные с сервера загружались по клику кнопки, пользователю элементарно был отклик в виде крутящейся какой нибудь фигни и он видел, что процесс идёт и что прога не зависла и никуда лишний раз не тыкал.
      Пока что для тестов сделала элементарно кнопку Update (speedbutton с image), данные элементарно грузятся и отображаются в GridPanel, а поверх него, чтоб пользователь и не смог куда либо тыкнуть, замостила панелькой с Image, вращаемой по таймеру (всё это дело наверху Visible:=false). И когда клацаем по кнопке Update, то панельку сверху грида делаю отображаемой и запускаю таймер, потом этот же обработчик/процедура грузит данные, а по окончанию останавливаем таймер и скрываем полупрозрачну, еще кстати, панельку. Аля вот так:
      procedure TForm1.SB_DataUpdateClick(Sender: TObject); begin //отображаем лого загрузки P_showLoad.Visible := true; Timer_load_rotate.Enabled := true; //с запуском таймера GetDeD_List(DE_set.Date); //процедура загрузки и отображения чего нам надо, которая весьма долго выполняется //и скрывае лого загрузки Timer_load_rotate.Enabled := false; //уже в обратном порядке P_showLoad.Visible := false; end; иии... ни черта не происходит как я хочу(
      Это лого вообще в итоге не отображается, а если убрать его скрытие, то оно у нас отобразится уже только тогда, когда всё загрузится. Логика мне стала подсказывать, что следовало его как то отобразить выполнив в параллельном асинхронном потоке аля так:
      procedure TForm1.SB_DataUpdateClick(Sender: TObject); begin TThread.Queue(TThread.Current, //TThread.Queue TThread.Synchronize ForceQueue procedure() begin P_showLoad.Visible := true; Timer_load_rotate.Enabled := true; end); GetDeD_List(DE_set.Date); //процедура загрузки и отображения чего нам надо, которая весьма долго выполняется end; И опять оно отображается только после того, как всё загрузится и проработает вся процедура. И уже чего только не пробовала и Synchronize и ForceQueue; и через TTask.Run и |task := TTask.Create(procedure () ... и т.д.| ничего не подходит, вот хоть убейся это всё дело будет отображаться только после полной отработки процедуры клика. Может я не в том направлении вообще рою и это как то по другому делается? Может я еще пока отлаживаю на Win32, а не всё на android, а там вот пара вариантов и норм на нём работают? Но чтот я никак не могу понять, что к чему... должно же быть как то просто, а я чтот никак не могу понять как(
    • От ComAlex
      Goоgle Play перестает поддерживать 32-bit Android-приложения c 01.08.2019.
      А выкладывать в Goоgle Play новые УЖЕ нельзя.
      Последние же Delphi XE не позволяют создать 64-bit Android-приложения.
      Кто знает, когда появится новая версия с поддержкой 64 - bit? Говорили, что в конце лета, но лето кончилось
    • От ComAlex
      Здравствуйте, господа программисты!
      Пытаюсь протестировать Android приложение на любом эмуляторе.
      Всегда одна ошибка "Unable to create process: Performing Streamed Install"
      Понимаю, что ссылок много по данной теме в интернете, но ни одна не помогла.
      Использую Embarsadero Delphi 10.3
      При компиляции на реальный телефон всё работает
      При компиляции на эмулятор даже пустого приложения выдается та же ошибка
      "Unable to create process: Performing Streamed Install"
      В чем проблема? Хотя бы в какую сторону копать?
    • От Дмитрий Потапов
      Задался идеей написания IPTV приложения "для себя", в котором при желании смог бы реализовать что-то необходимое и удалить то, что не нужно.
      Собственно вопрос в другом: Я написал простое приложение, которое отлавливает коды кнопок с пульта, приложение по сути самое банальное, использует OnKeyDown и OnKeyUp (чисто для теста). И по нажатию на кнопку на пульте высылает например в Memo или ListBox Информацию о нажатой кнопке (включая ее код).
      Но суть в том, что далеко не все кнопки таким образом распознаются. Для примера:
      Кнопки громкости, назад, домой, увеличение\уменьшение громкости, стрелки(влево, вправо, вверх, вниз) и центральная кнопка (по совместительству OK).
      Цифры все определяются, как одна - 0
      Кнопки, которые не определяются (не срабатывает событие, ибо если был бы неизвестен код, то думаю, в таком случае получил бы все, кроме кода кнопки), но по нажатию кнопки, которая не определяется приложением - ничего не происходит вообще.
       
      Вопрос: Есть ли возможность как-то "научить" приложение распознавать эти кнопки? (Я где-то читал, может даже и здесь, что это все так реализовано именно на уровне самого FireMonkey, будто этих кнопок вообще не существует).
      Если эта тема уже поднималась на форуме или вопрос очень просто решается - извиняюсь)
      Решение: http://fire-monkey.ru/topic/5624-как-отловить-кнопки-пульта-ду/?do=findComment&comment=36399
       
    • От Татьяна
      Здравствуйте!
      Как можно из Android приложения узнать электронный адрес пользователя gmail (если он был настроен, конечно). Где-то же он сохраняется, если Google Play знает.
    • От msp888
      Всем привет! 
      У меня уже несколько лет работают приложения под Windows и под Andriod, в которых выполняется обмен данными по локальной сети по протоколу TCP-IP. Теперь вот мне понадобился прием multicast-пакетов по протоколу UDP. Под Windows всё работает замечательно, а вот под Android ничего принять не могу... 
      Подскажите чего не хватает, или дайте ссылку на пример, где уже реализовано подобное...
      Вот выдержки из кода:
      // переменные FSocket:TSocket; FiAR:IAsyncResult; FasyncWE:TMultiWaitEvent; data:TBytes; res:TWaitResult; WifiLock: JWifiManager_WifiLock; MulticastLock: JWifiManager_MulticastLock; ... // регистрация в группе procedure AddMemberShip(MultiAddr, InterfaceAddr:Cardinal); var Mreq:ip_mreq; begin fillchar(Mreq, SizeOf(Mreq), 0); move(MultiAddr, Mreq.IMR_MultiAddr.S_addr, SizeOf(Mreq.IMR_MultiAddr.S_addr)); move(InterfaceAddr, Mreq.IMR_Interface.S_addr, SizeOf(Mreq.IMR_Interface.S_addr)); CheckSocketResult(setsocketoption(FSocket.Handle, IPPROTO_IP, IP_ADD_MEMBERSHIP, Mreq, SizeOf(Mreq)), 'setsockopt:IP_ADD_MEMBERSHIP'); end; ... // permission... ACCESS_COARSE_LOCATION ACCESS_FINE_LOCATION ACCESS_NETWORK_STATE ACCESS_WIFI_STATE CHANGE_CONFIGURATION CHANGE_NETWORK_STATE CHANGE_WIFI_MULTICAST_STATE CHANGE_WIFI_STATE INTERNET READ_CALENDAR READ_EXTERNAL_STORAGE WRITE_CALENDAR WRITE_EXTERNAL_STORAGE WAKE_LOCK ... // настройка wi-fi WifiLock.acquire; MulticastLock.acquire; ... // создание и настройка сокета FSocket:=TSocket.Create(TSocketType.UDP); FSocket.Bind(TNetEndpoint.Create(ServerIP, ServerPort)); AddMemberShip(TIPAddress.Create(239, 78, 1, 1).Addr.S_addr, ServerIP.Addr.S_addr); AddMemberShip(TIPAddress.Create(239, 78, 1, 2).Addr.S_addr, ServerIP.Addr.S_addr); AddMemberShip(TIPAddress.Create(239, 78, 1, 78).Addr.S_addr, ServerIP.Addr.S_addr); ... // Прием данных в потоке... FiAR:=FSocket.BeginReceiveFrom; FasyncWE:=FiAR.AsyncWaitEvent; res:=FasyncWE.WaitFor; if res = wrSignaled then data:=FSocket.EndReceiveBytesFrom(FiAR); // Прием  
    • От Serg Sib
      RAD 10.2.3 Delphi , Win 10x64 Pro 1803
      Подскажите, с помощью чего можно осуществить трансформацию изображения по опорным точкам (по углам)?
      Возможно, что не напрямую сам TImage, а при помощи работы с Canvas на его Bitmap.
      Пока удалось добиться подобной трансформации, заполнив нужным изображением полигон и, меняя координаты его вершин, делать нужные корректировки.
      var MyBrushBitmap: TBrushBitmap; Image1.Bitmap.Canvas.Fill.Kind := TBrushKind.Bitmap; Image1.Bitmap.Canvas.Fill.Bitmap := MyBrushBitmap; Image1.Bitmap.Canvas.Fill.Bitmap.WrapMode := TWrapMode.TileStretch; Image1.Bitmap.Canvas.FillPolygon(MyPolygon, 50); Однако, изображение частично обрезается при этом.
      В интернете поиском находил пример подобной трансформации на VCL, (перетаскиванием вершин мышью), но не смог приспособить этот пример для платформы FireMonkey.
    • От Brovin Yaroslav
      Хочу поделиться с вами знаковой новостью для развития библиотеки FGX Native. Официально выпущено первое Андроид приложение в Google Play Market. 
      Это приложение разработано Станиславом(@sinuke) для учащихся лицея по специальности "Почтовая связь". Оно одновременно является и полным конспектом, который всегда под рукой, и системой проверки своих знаний.
      Полностью разработано на Delphi и стандартных компонентах альфа версии FGX Native 0.9.7.0 в Delphi 10.3 Community Edition. Быстрые списки, гибкая разметка, продвинутая навигация, анимации переходов, поддержка тем и многое другое. Это лишь малая часть того, что было задействовано из текущих возможностей библиотеки.
      Приложение опубликовано в Google Play Market. Вы можете уже прямо сейчас скачать и протестировать приложение самостоятельно, загрузив его по ссылке (https://play.google.com/store/apps/details?id=com.sinukeapps.post).
      Оставляйте свои комментарии и предложения. Они помогут сделать приложение лучше, а FGX Native еще удобнее и стабильнее.
      Релиз первого приложения с использование библиотеки FGX Native - это результат огромной работы, проделанной за эти годы. В тоже время, это сигнал того, что библиотека обладает достаточным минимумом для создания типовых Андроид приложений.
      Ну, и пожалуй самое приятное, это то, что библиотека готова к бета тестированию, которое откроется в ближайшее время.  О начале закрытого бета тестирования будет сообщено позже.
      Отдельное спасибо участникам закрытого альфа тестирования за поддержку, тестирование и идеи по улучшению библиотеки. В настоящее время участниками тестирования ведутся и другие интересные проекты на базе FGX Native, о которых я расскажу позже.
      Следите за новостями.
      Приложение: https://play.google.com/store/apps/details?id=com.sinukeapps.post Автор: Станислав Игнатович @sinuke Минимальные системные требования: Android 5.0 и arm v7         
  • Последние посетители   0 пользователей онлайн

    Ни одного зарегистрированного пользователя не просматривает данную страницу

×
×
  • Создать...