Перейти к содержанию
Fire Monkey от А до Я

DirtyBorov

Пользователи
  • Постов

    71
  • Зарегистрирован

  • Посещение

  • Победитель дней

    6

Сообщения, опубликованные DirtyBorov

  1. В 03.11.2016 в 19:04, ZuBy сказал:

    если вам не понятен этот код

    
    For i:=0 to List.Count-1 do
    with List.Items[i] do
    begin
    	Position.Y:=Position.Y+0.5;
    end;

    то его можно переписать следующим образом

    
    for i:=0 to List.Count-1 do
        List.Items[i].Position.Y := List.Items[i].Position.Y+0.5;

     

    UPDATE: http://delphicode.org/delphi/with.htm

    Еще пару вариантов. 
    1. Можно немного сократить, не указывая Items (почему - ищите в "корнях" property)

    for i:=0 to List.Count-1 do
        List[i].Position.Y := List[i].Position.Y+0.5;

    2. Можно использовать такой вариант
     

    var
      c: TCircle;
    begin
      for c in List do
        c.Position.Y := c.Position.Y + 0.5;
    end;

     

  2. В 03.11.2016 в 22:49, ZuBy сказал:

    ну почему сразу не используйте, нужно просто знать как с этим работать.

    например вот в таких конструкциях очень удобно, не требуется заводить переменную

    
    with TStringList.Create do
    begin
      Text := 'ТЕКСТ';
      SaveToFile('c:\file.txt');
      Free;
    end;

     

    Все же более правильный вариант будет такой:

    with TStringList.Create do
    try
      Text := 'ТЕКСТ';
      SaveToFile('c:\file.txt');
    finally  
      Free;
    end;

    Иначе, если при каких то проблемах с файлом, Free не будет вызван и мы получим утечку.

  3. 2 минуты назад, Kitty сказал:

    чтобы увидеть дробную часть:

    double x = 3.2

    Да не ужели? :) Ни когда бы не догадался... я же всего то 20 лет программирую.  Это сарказм.
    еще могу показать пару вариантов. Например:
    Label1->Caption = 15 / 3;
    или так

    double x = 15, y = 3;

    Label1->Caption = x / y;

    Улавливаете ход мысли? 

  4. 1 час назад, wamaco сказал:

    все просто:

    не явное преобразование

    Это я  уже понял, немного поигравшись с разными вариантами. 

    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
      int x = 3.2;
      Label1->Caption = x; // выведет 3
    }

    Просто я уже очень давно не писал на С++. Не пойму когда и для чего это сделали. В чем профит? Ведь С++ строго типизированый язык. На мой взгляд это только добавит неявных ошибок. Или я не прав?

  5. Сегодня один товарищ сломал мне мозг вот таким кодом:

    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
      int x = 2;
      Label1->Caption = x;
    }

    И компилятор это схавал! Как?!  Может мне кто нибудь подсказать почему целое, без преобразования присвоилось в лейбу? 
    код проверялся на XE10.1

  6. 3 часа назад, zairkz сказал:

    Что именно не работает?? Все работает. 

    Предполагаю что вы столкнулись с невозможностью определения "было ли установлено соединения" если звоните вы. Так?

    При любых звонках, в memo  падает только Phone is IDLE и Phone is OFFHOOK. Других сообщений нет.  На сколько я понял, факт установки соединения под Android не отловить. Или я не прав?

    В идеале, хотелось бы отследить состояние исходящего звонка. Т.е. набор, соединение, отбой. 

  7. 8 часов назад, chaplin.u@gmail.com сказал:

    подскажите пожалуйста метод получения строки из массива шестнадцатиричных чисел ( 01, 02 ..0А, 0В,). Для визуального контроля.

    Допили для себя:

    /// AHex - строка вида "A1,B2,C3" 
    /// Del - резделитель
    function HexToBytes(const AHex: string; const Del: string = ','): TBytes;
    var
      i: Integer;
      S: TStringDynArray;
    begin
      S := SplitString(Trim(AHex),Del);
      SetLength(Result, Length(S));
      for i := Low(S) to High(S) do
        Result[i] := StrToIntDef('$'+S[i],0);
    end;
    
    function BytesToStr(const ABytes: TBytes): string;
    var
     i: integer;
    begin
      Result := EmptyStr;
      for I := Length(ABytes)-1 Downto 0 do
       Result :=  Chr(ABytes[I] + 48) + Result;
    end;

     

  8. Доброго времени.

    Delphi Berlin. Попробовал воспроизвести пример http://docwiki.embarcadero.com/RADStudio/Seattle/en/Mobile_Tutorial:_Using_the_Phone_Dialer_on_Mobile_Devices_(iOS_and_Android)

    Выяснилось что событие OnCallStateChanged не вызывается (Android). Пробовал пример из поставки. Просмотрел как описано в разных книгах - везде одно и тоже. Но не работает. 

    Как же получить статус звонка?

  9. Из своего опыта (не про Delphi конкретно), приведу реальный пример. Доводилось работать на удаленке в одной международной компании. Уверен все о ней знают и пользуются ее продуктами (без названия, ок?).  Так вот в нашей интранете мелкого городского провайдера, лежала подборка их крякнутого софта. Я конечно "стуканул" руководителю и предложил "наехать" на местную контору что бы убрали пиратский софт. Но неожиданно получил от "самого главного боса" нагоняй: "Не вздумай им писать! Пусть софт лежит! Пусть люди им пользуются! Да, именно пиратским. Финансовые потери не сопоставимы с прибылью от популяризации. Пиратство - гарантированная, бесплатная реклама. Тот, кому действительно наш софт нужен - заплатит. Кто не готов платить (например школьники) - не заставишь. По этому оставь маркетинг профессионалам, а сам занимайся поставленными задачами."  

    С тех пор я не лезу в маркетинг. :)

  10. 2 часа назад, krapotkin сказал:

    может, у вас оно перезапускается много раз само из себя??

    Именно. Возможно в расчетах что то дергается что приводи к повторному событию.  А вообще прав  ZuBy, без исходников можно долго гадать и предлагать самые фантастические решения. А на деле все может оказаться просто. :)

  11. Событие OnResize может происходить несколько раз подряд. Код в этом событии должен быть как можно короче. Расчет большого количества динамических объектов в этом событии - плохая идея. Лучше действительно воспользоваться отдельным потоком (а для ускорения можно несколько). На вскидку, алгоритм примерно такой:  в событии OnResize запускаете поток, в который передаете размеры фрейма. В потоке делает расчеты и генерируете свое событие, которое обрабатывает фрейм - отображает эти самые объекты или их данные.  Конечно конкретная реализация зависит от задачи

  12. FMX еще довольно молодой фремворк. Тут порой не хватает самых элементарных вещей. Как вариант вы можете создать на Github нужную вам либу, наверняка это может еще кому то пригодится. Совместными усилиями можно создать отличную вещь. Ну а что бы не быть зависимым от версии - пишите абстрактный код. Не надо привязываться к конкретному компоненту. 

  13. 36 минут назад, Сысоев Максим сказал:

    Да и со старту нет необходимости заботиться об освобождении памяти для таска, достаточно описать Task таким образом: 

    var LTask:ITask;

     

    Да, я в курсе - это всего лишь уточнение. Тут тоже можно использовать например так:

    var LTask: IAsyncTask;

    LTask :=  AsyncTask;

    LTask.Run (...);

    ...

    LTask.Terminate; // досрочно завершаем поток

    В ITask exception глушится, что не всегда хорошо. Тут его можно обработать очень просто, если есть нужда. Процедуры тут изначально синхронизированны и в подавляющем большинстве это как раз то что нужно - не нужно постоянно писать код синхронизации (хотя он и тривиален).

    Сам же модуль был написан еще до появления ITask, так что я как то исторически привык использовать именно его. Однако у ITask есть свои преимущества и они неоспоримы. Это всего лишь альтернатива для некоторых случаев.

  14. Хочу поделится своим модулем, некой альтернативой TTask, которой я пользуюсь уже довольно продолжительное время.  Возможно кому то будет полезно. 

    AsyncTask это глобальная функция в модуле, которая возвращает интерфейс IAsyncTask. По этой причине нет нужды специально создавать объект и заботится о его удалении.

    Пример использования:

    procedure GetAsyncRequest(const aUrl: string);
    var
      LResult: string;
    begin
    
      AsyncTask.Run(
      procedure
      begin
        // это основной метод потока, он не синхронизирован. От сюда нельзя обращатся к визуальным компонентам 
        // или переменным вне функции без синхронизации (если необходимо)
        LResult := HttpRequest.Get(aUrl);
      end,
    
      procedure
      begin
        // Эта процедура выполнится при успешном завершении потока (без exception). 
        // Процедура синхронизированна, по этому тут можно обращатся к любым визуальным компонентам
        ShowMessage(LResult);
      end,
    
      procedure(E: Exception)
      begin
        // Эта процедура выполнится только если во время работы потока произошла ошибка
        ShowException(E);
      end,
    
      procedure
      begin
        // Эта процедура выполнится в любом случае (после завершения потока), в не зависимости была ошибка или нет
        ShowMessage(LResult);
      end
      );
    
    // обратите внимание, что обязательно задать только первую процедуру, остальные можно не указывать или передать вместо них nil. Например так:
      AsyncTask.Run(
      procedure
      begin
        ...
      end,
    
      nil,
    
      procedure(E: Exception)
      begin
        ShowException(E);
      end);

     

    Async.Task.pas.zip

  15. 12 часов назад, POV сказал:

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

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

  16. 11 часов назад, krapotkin сказал:

    я практически везде использую динамически создаваемые фреймы. вообще никаких проблем не встречал

    главное - четко помнить, что данные должны храниться в модели данных, а интерфейс - работать с этой моделью

    при этом некоторые вещи в рамках программы являются глобальными синглтонами, например, объект, содержащий настройки программы и данные текущего залогиненного юзера. ну и часто - главная форма программы.

    код при создании фреймов не в точности, но похож на приведенный в старте темы

    Совершенно согласен - динамическое создание фреймов на мой взгляд намного лучше (как и форм). К тому же, если используется модель данных вне формы (фрейма), то тогда вообще нет ни каких проблем. И чаще всего, при использовании моделей типа MVC, MVP и .т.п - код значительно упрощается! Главное становится более надежным, понятным и коротким. Можно легко и не напряженно менять или добавлять формы без вмешательства в логику. Особенно хорошо это проявляется в командной работе, когда не опытный разработчик (или новый человек в команде), может не вдаваясь в код сложной бизнес логики за пару часов прикрутить например отчет или новый view. К тому же, понятие такого подхода абстрагирует разработчика от конкретного языка. В дальнейшем такой подход можно использовать на любом языке.

    К сожалению архитектура Delphi часто подталкивает к "формошлепству", что в общем то не  плохо работает в небольших приложениях. Но когда программа становится несколько сложней чем "Hello world", это становится проблемой. Самое печальное то, что в массе книг по Delphi как раз таки и учат формошлепству. В духе "щелкните два раза по кнопке и получите готовый обработчик события". Я не встречал ни одной книги (кроме нескольких уже довольно устаревших статей), где бы показывалось как использовать MVC или MVP в Delphi. Если не прав - ткните носом.

    Да, код полностью идентичный приведенный топикастером, за исключением использования дженериков. Но я и не стремился доказать что мой код лучше. Всего лишь показал как делаю я.  Этот намеренно простейший шаблон приложения. Не самый лучший. Но на мой взгляд он все таки отделяет "мух от котлет" (данные от форм) и возможно кому то поможет понять что на Delphi тоже можно и нужно использовать MVC. Конечно в реальном приложении обычно все на много сложней. Хотя лично у меня есть парочка довольно мудреных приложений которые используют именно такую архитектуру и прекрасно работают, периодически претерпевая изменения без каких либо серьезных проблем.

    Часто слышу высказывания в духе "зачем мне усложнять? Я быстро накидаю форму с логикой и получу деньги". По своему опыту скажу - вы ошибаетесь. Да, вы быстро и легко накидаете форму, которая что то будет делать и даже как то работать. Но если вы в дальнейшем будете сопровождать свое творение, то очень скоро убедитесь в том что это полный отстой. Особенно если программа будет продолжать наращивать функционал. Не питайте иллюзий. Пишите сразу правильно - это в дальнейшем сэкономит вам время и нервы. Как говорится в одном знаменитом мульте: "лучше сейчас час потерять, зато потом за пять минут долететь" ))

  17. 8 часов назад, kami сказал:

    Уточнение: интерфейс не должен работать с данными с управляемым временем жизни. К примеру, вы не можете передать между exe и dll IXMLDocument и его составляющие, поскольку этот интерфейс работает с типом string.

    Разумеется. Типы данных характерные для Delphi не должны использоваться. Об этом так же написано много. Но лично я не вижу в этом проблем. Гораздо чаще, почему то путают другие вещи: прочитав что объекты передавать нельзя, народ пытается передать указатель! т.е. вместо TObject, делают что то вроде Pointer(Object). Или даже integer(Object). Очень странно. Это ведь то же самое что и передача объекта. Такое чувство что народ совершенно не понимает что такое указатель. 

  18. Можно попробовать через TMemoryStream. В FMX я не пробовал грид копировать (да и в VCL с большими данными тоже). Но вообще с компонентами попроще такой трюк работает. Например я частенько использую его для сохранения настроек в базе данных (в BLOB).

    Алгоритм примерно такой:

    в первой форме делаем

    var MS: TMemoryStream;

    MS.WriteComponent(Grid);

    Потом передаем этот stream во вторую форму, а там делаем

    MS.Position := 0;

    MS.ReadComponent(Grid).

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

    Но вообще, как уже заметили, 1000 строк это уже как то много. Тут либо надо кеширование придумать, что бы одновременно в таблице было не больше строк чем помещается на экран, а остальные подгружались по мере прокрутки. Либо, что намного проще, использовать базу данных. 

     

  19. Сначала попытался объяснить как я переключаю фреймы, но потом подумал и решил что проще будет сделать пример (см. приложенный архив).  Мне не очень нравится идея создавать все фреймы сразу. На мой взгляд ( и не только на мой, существует понятие MVC, MVP, MVVP),  фреймы это только отображение данных, а сами данные лучше контролировать в другом месте. По этому в моем примере, есть контроллер данных (TDataModule), в котором (в реальной программе) прописана вся бизнес-логика. Во фреймах же и в формах, только код, который относится непосредственно к этому фрейму (форме).

    Еще небольшой совет:  контроллер совсем не обязательно должен быть TDataModule, это может быть обычный класс - синглтон. Но я традиционно использую его, потому что в реальной программе он может служить контейнером для каких то невизуальных компонентов. Например в него я помещаю компонент TfgApplicationEvents из набора FGX(http://fire-monkey.ru/forum/177-fgx/) от Ярослава Бровина.

    Если в программе используется база данных, то я не помещаю в контроллер компоненты доступа к данным. Для этого я делаю отдельный модуль. 

    Так же, рекомендую посмотреть в сторону компонента TFrameStand (его можно найти в GetIt).

    FrameSelector.zip

  20. 20 часов назад, Gingercat сказал:

    Если все так печально, почему это все работает в пределах одной версии? И вообще - что значит невозможно? Тонны кода работают на передаче именно классов и экземпляров, а вы завляете что это не верно? Или я чего то не понимаю

    Похоже вы действительно чего то не понимаете. Объекты нельзя предавать. Про это написано тонны статей. :) Если хотите передавать именно объекты, тогда вам нужно использовать Package (BPL), вместо обычных dll. Но в этом случае вы будете привязаны к конкретной версии Delphi, а про другие языки можно будет забыть (Ни кто кроме Dlphi не умеет делать BPL).

    Обычный способ передачи либо Handle, либо через interface

     

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