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

Евгений Корепов

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

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

  • Посещение

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

    100

Сообщения, опубликованные Евгений Корепов

  1.  

    Да, видимо где то между обновлениями XE5, XE7, XE8 я протупил :-(

     

    Странно, а зачем ты 8-ку обновлял с 4-ки? 

     

    Да в том то и дело что не обновлял, я купил обновление XE7, за пару недель до выхода восьмёрки (даже не подозревал что новая версия на подходе), и 30 апреля сего года мне Embarcadero прислала письмо, что мол так как вы редкостный мудила, умудрились купить старый продукт перед выходом нового, то дарим вам обновление до XE8 (причем ссылка на обновление была валидна всего сутки). Дареному коню зубы не смотрят, я естественно принял щедрый подарок ;-)

  2.  

    DELPHI 10 SEATTLE ENTERPRISE - НОВАЯ ЛИЦЕНЗИЯ NAMED - 143 547,00 руб

    Ну а кто говорит про новую лицензию???? Я же только обновляю ранее купленную! Это в разы дешевле.

     

    А подскажите про "Recharge Renewal", кто может этим обновлением воспользоваться? Мне в аллсофте отказали в праве его приобрести. У меня "Delphi XE8 Professional Named User (Upgrade from XE4 or later) - ESD", сказали что с "Delphi XE8 Professional Named User" нельзя перейти на "ОБНОВЛЕНИЕ (RECHARGE RENEWAL) ТОЛЬКО С DELPHI XE8 PROFESSIONAL RECHARGE NAMED".

    А ведь всего 16 579,00 руб., счастье было так близко ;-( Обновление "ОБНОВЛЕНИЕ NAMED (UPGRADE)" за  31 447,00 руб., да плюс обновление "MOBILE ADD-ON PACK", не потяну, ибо частный разработчик, занимаюсь этим в качестве хобби для души.

  3. Примеры кода так и остались уродскими, добавление readme.html не особо помогло. Вот к примеру "\Studio\17.0\Samples\Object Pascal\Multi-Device Samples\Device Sensors and Services\CapitalIAP" демонстрирующий "in-app payment and advertisement services". Неужели для этого нужен проект из пяти форм на тысячу строк кода? К теме относится несколько десятков строк, остальное - мешающий пониманию мусор. 

  4. TSensorManager - за пол года наконец то допилили AmbientLight и HumanProximity (в XE8 были заглушки). Остальные сенсоры, к примеру Temperature, остались за кадром. 

     

    LinearAccelerometer3D сломали - демо-пример наглухо виснет при FActiveSensor.Stop;

  5. Подскажите как добраться до кнопки очистки содержимого TSearchBox? Сам TSearchBox у TListView благодаря теме "Можно ли программно передать фокус на SearchBox и очистить строку?" доступен без проблем, но кнопка не обнаруживается в ListViewProducts.SearchEdit.Children.Items :-(

     

    Хочу изменить логику ее появления - сделать видимой всегда, когда есть текст в ListViewProducts.SearchEdit.Text. По умолчанию ее поведение малость загадочное - она исчезание при любой возможности (потеря фокуса, Resize, смена ориентации и т.д.). Что бы очистить поле поиска, пользователю приходится в данный момент производить следующие манипуляции:

    1. Кликнуть на SearchBox
    Ввести любой символ Нажать на появившуюся "кнопку с крестиком"

    Пока написан костыль на все возможные манипуляции - добавляю пробел в конец SearchBox, удаляю добавленный пробел, но иногда он не срабатывает и вводит пользователя в ступор.

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

    Сейчас пытаюсь отказаться от встроенного в TListView TSearchBox, сделать отдельное поле ввода поиска, но с наскока не пойму как передавать строку фильтрации в TListView.

  6. вместо tagString можно использовать Model.Data, это более концептуально верно

    Хм, а можно подробнее? С наскока нагуглить ничего не удалось, а собственные знания у меня пока в зачаточном состоянии :-)

  7. Посмотрел на код и решил еще на пару строк сократить, совместил проверку на "пусто" и минус в одном условии

    procedure TFormMain.Edit1ChangeTracking(Sender: TObject);
    Var FEdit : TEdit;
        FFloat : Single;
    begin
      If Not (Sender is TEdit) Then // Защитимся от не выспавшегося самого себя
        Exit;
      FEdit:=(Sender as TEdit); // Для удобства...
      FEdit.Text:=FEdit.Text.Replace(' ',''); // Убираем случайные пробелы
      if (FEdit.Text.IsEmpty) or (FEdit.Text.Equals('-')) then // Если пусто (ничего не введено или все удалено) или только минус, ничего не делаем
        Exit;
      FEdit.Text:=FEdit.Text.Replace('.',','); // Заменяйм точку запятой
      if FEdit.Text.Equals(',') then // Если введен разделитель, добавляем перед ним ноль для красоты (не обязательно)
      begin
        FEdit.Text:='0,';
        FEdit.CaretPosition:=FEdit.CaretPosition+1; // без этого курсор останется между нулём и запятой
      end;
      if TryStrToFloat(FEdit.Text,FFloat) Then // Пробуем преобразовать в число
        FEdit.TagString:=FEdit.Text // Если удалось, сохраняем в временном хранилище
      Else
        FEdit.Text:=FEdit.TagString; // Если не удалось, восстанавливаем из временного хранилища
    end;
    
  8. Намучавшись с не работающим FilterChar и кучей способов ввода по маске, сделал свой способ. По моему мнению самый простой.

    Код позволяет вводить только числа, включая дробные и отрицательные.

    procedure TFormMain.Edit1ChangeTracking(Sender: TObject);
    Var FEdit : TEdit;
        FFloat : Single;
    begin
      If Not (Sender is TEdit) Then // Защитимся от не выспавшегося самого себя
        Exit;
      FEdit:=(Sender as TEdit); // Для удобства...
      FEdit.Text:=FEdit.Text.Replace(' ',''); // Убираем случайные пробелы
      if FEdit.Text.IsEmpty then // Если пусто (ничего не введено или все удалено), ничего не делаем
        Exit;
      FEdit.Text:=FEdit.Text.Replace('.',','); // Заменяйм точку запятой
      if FEdit.Text.Equals(',') then // Если введен разделитель, добавляем перед ним ноль для красоты (не обязательно)
      begin
        FEdit.Text:='0,';
        FEdit.CaretPosition:=FEdit.CaretPosition+1; // без этого курсор останется между нулём и запятой
      end;
      if FEdit.Text.Equals('-') then // Если введен только минус, не пытамся его драконить
        Exit;
      if TryStrToFloat(FEdit.Text,FFloat) Then // Пробуем преобразовать в число
        FEdit.TagString:=FEdit.Text // Если удалось, сохраняем в временном хранилище
      Else
        FEdit.Text:=FEdit.TagString; // Если не удалось, восстанавливаем из временного хранилища
    end;
    

    В качестве временного хранилища использовано TagString, дабы не разводить глобальных переменных.

    Возможно понадобиться очистка временного хранилища при многократном использовании:

    procedure TFormMain.Edit1Enter(Sender: TObject);
    begin
      If Not (Sender is TEdit) Then
        Exit;
      (Sender as TEdit).TagString:='';
    end;
    
    

    Буду рад услышать замечания и предложения.

  9. Да-да. Пишите java-класс с событием onReceive, в котором пишем код, запускающий приложение. В манифесте подписываемся на сообщения системы, указывая имя java-класса .

     

    Работает так:

    1) Система запустилась и послала всем подписанным приложениям сообщение об окончании запуска

    2) Ваше приложение, а точнее класс который вы написали, с событием onReceive, получает сообщение и запускает ваше приложение

    Т.е. средствами Delphi это не сделать? Только отдельный класс на java и морока с модификацией classes.dex? Я надеялся что мне поможет компонент турецкого коллеги http://brsatalay.blogspot.com.tr/2014/10/delphi-android-broadcast-receiver.html . По крайней мере с другими броадкастами он отлично справляется.

    А почему тогда получаю ошибку "В приложении Таком-то произошла ошибка"? Или это просто симптом отсутствия обработчика BOOT_COMPLETED?

  10. Пытаюсь сделать автозагрузку приложения в андроид, но не выходит каменная чаша.

    Приложение пустое. Даю права на "Receive boot completed", в манифесте делаю следующие изменения (выделил комментариями с "*******"):

    <?xml version="1.0" encoding="utf-8"?>
    <!-- BEGIN_INCLUDE(manifest) -->
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
            package="%package%"
            android:versionCode="%versionCode%"
            android:versionName="%versionName%"
            android:installLocation="%installLocation%">
    
        <!-- This is the platform API where NativeActivity was introduced. -->
        <uses-sdk android:minSdkVersion="%minSdkVersion%" android:targetSdkVersion="%targetSdkVersion%" />
    <%uses-permission%>
        <uses-feature android:glEsVersion="0x00020000" android:required="True"/>
        <application android:persistent="%persistent%" 
            android:restoreAnyVersion="%restoreAnyVersion%" 
            android:label="%label%" 
            android:debuggable="%debuggable%" 
            android:largeHeap="%largeHeap%"
            android:icon="%icon%"
            android:theme="%theme%"
            android:hardwareAccelerated="%hardwareAccelerated%">
    
    <%application-meta-data%>
            <!-- Our activity is a subclass of the built-in NativeActivity framework class.
                 This will take care of integrating with our NDK code. -->
            <activity android:name="com.embarcadero.firemonkey.FMXNativeActivity"
                    android:label="%activityLabel%"
                    android:configChanges="orientation|keyboard|keyboardHidden"
                    android:launchMode="singleTask">
                <!-- Tell NativeActivity the name of our .so -->
                <meta-data android:name="android.app.lib_name"
                    android:value="%libNameValue%" />
                <intent-filter>  
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter> 
            </activity>
            <%activity%>
            <receiver android:name="com.embarcadero.firemonkey.notifications.FMXNotificationAlarm" />
    <!-- *********************************************************************** -->
            <receiver android:name=".BootReceiver" android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
               <intent-filter>
                    <action android:name="android.intent.action.BOOT_COMPLETED" />
                    <category android:name="android.intent.category.DEFAULT" />
              </intent-filter>
            </receiver>
    <!-- *********************************************************************** -->
            <%receivers%>
        </application>
    </manifest>
    <!-- END_INCLUDE(manifest) -->
    
    

    При включении телефона получаю ошибку "В приложении Таком-то произошла ошибка". До TForm.onCreate точно не доходит.

    Что я делаю не так? Помогите пожалуйста.

  11. Ответ по Update1:

     

    Regarding your question on installing Delphi XE8 update 1.

     
    If you have installed the general update then this will not show as an update as it is considered a hotfix update and not a full detailed update.
     
    Please note this case will be closed on Monday 20th July if no response is received.
     
    Best Regards
     
    Peter Manning
    EMEA Technical Support Engineer

    Ответ по FilterChar 

     

    It looks like on Android this problematic, because on the FilterChar property for TEdit there is this comment in the source code:

        ///<remarks>On Android due to platform limitations text is filtered only after pressing ENTER key or after control
        ///losing focus.</remarks>
    So it seems to be working as designed.
     
    brgds
     
    Roy.
  12.  

    Сейчас сделал поиск по файлам "*.bak", и единственное что изменил Update1 для Андроид, это System.RegularExpressionsAPI в "Embarcadero\Studio\16.0\lib\android" и "Embarcadero\Studio\16.0\source\rtl\common". Все, остальной список изменений остался виртуальным.

    Я что то делаю не так? 

    что то я суть потерял, какой поиск? ты о чем?

     

    Когда накатывается Update1, он просто заменяет файлы в папке "Embarcadero\Studio\16.0", старому файлу добавляется расширение "bak". К примеру в папке "Embarcadero\Studio\16.0\source\rtl\common" новый файл System.RegularExpressionsAPI.pas, старый соответственно System.RegularExpressionsAPI.pas.bak.

  13. Сейчас сделал поиск по файлам "*.bak", и единственное что изменил Update1 для Андроид, это System.RegularExpressionsAPI в "Embarcadero\Studio\16.0\lib\android" и "Embarcadero\Studio\16.0\source\rtl\common". Все, остальной список изменений остался виртуальным.

    Я что то делаю не так? 

  14. эээ, у меня она и на XE8 работает...

    Именно на Андроид? На каких версиях и устройствах?

    У меня на Samsung GT-I9100 (4.1.2) и HTC One M7 (5.0.2) не работает.

     

    P.S. Устал уже, вместо создания приложений, бороться с глюками среды. Большая часть времени уходит на костылинг :-(

  15.  

    Согласно http://edn.embarcadero.com/article/44358 проблему http://qc.embarcadero.com/wc/qcmain.aspx?d=122372 пофиксили.

    Но сейчас проверил - ничего не изменилось. FilterChar как не работал на андроиде, так и не работает.

     

    Или я туплю? Delphi XE8 с установленным Update 1? в окне About, раздел  Installed Updates вообще должно писать что то? Или эмбаркадеро больше не утруждает себя такими мелочами?

    у меня написано update 1

     

    Хм, странно. У меня пишет "No Updates Installed". А повторная попытка установки "delphicbuilder_xe8_update1_general.exe" выдаёт "All files successfully updated.  Press "Finish" to exit the installer."

  16. Согласно http://edn.embarcadero.com/article/44358 проблему http://qc.embarcadero.com/wc/qcmain.aspx?d=122372 пофиксили.

    Но сейчас проверил - ничего не изменилось. FilterChar как не работал на андроиде, так и не работает.

     

    Или я туплю? Delphi XE8 с установленным Update 1? в окне About, раздел  Installed Updates вообще должно писать что то? Или эмбаркадеро больше не утруждает себя такими мелочами?

  17. Поговорив с сотрудником Embarcadero, приобрел Update Subscription. Теперь все в порядке. Просто им нужно научиться доносить информацию до своих клиентов и поставлять Allsoft.ru полный прайс-лист.

    Огласите ценник в рублях

  18. Наступил на грабли, может кому поможет информация.

    Следующий код перехватывает в Windows глобальный фокус рабочего стола в не зависимости от состояния окна. Т.е. Если окно активно, свернуто, скрыто, скрыто из панели задач (в моём случае висело в системном трее), то фокус перехватывается 100%. Особенно много гневных отзывов получил от клиентов играющих в игрушки - выбрасывало из игры на рабочий стол ;-)

          Application.Title:='trololo';
          FormMain.Caption:='trololo';
          FormMain.Border.StyleChanged;
    

    Досконально разбираться было некогда, основной подозреваемый - "FormMain.Border.StyleChanged;"

     

  19.  

     

    Отправляю список файлов по WiFi, программа стопориться до конца отправки, как этого избежать?(

    Вы используете два вложенных цикла с непредсказуемым временем выполнения - этим и замораживаете приложение. Попробуйте к примеру Application.ProcessMessages внутри циклов. И TetheringAppProfile1 отправляет в отдельном потоке, он здесь не при чём.

  20. Для одного проекта писал такое пару месяцев назад, пользуйтесь.Под windows, при клике на сообщение, оно превращается в readonly TMemo - дабы можно было скопировать нужное из сообщения. При наличии URL в сообщении, сбоку появляется кнопка открыть - лучше ничего для открытия ссылок не придумал. Надо бы сделать диалог выбора для открытия одной из нескольких ссылок, но руки пока не доходят. Пощупать чат вживую можно в приложении https://play.google.com/store/apps/details?id=ru.flintnet.InternetAgent , для активации и загрузки примера чата отсканируйте  приложением qr-код с страницы  http://internetagent.flintnet.ru/

     

    Screenshot004_resize.png

    unit ChatBox;
    
    interface
    
    uses
      System.SysUtils, System.Classes, FMX.Types, FMX.Controls, FMX.Layouts,System.Types,
      FMX.StdCtrls,FMX.Edit,FMX.Memo,FMX.TextLayout,System.UITypes,FMX.Graphics,FMX.Objects,
      FMX.Effects,FMX.Styles.Objects;
    
    type
      TMessagePos = (msgLeft,msgRight);
      TEventText = procedure(PURL: String) of object;
    
      TChatBox = class(TVertScrollBox)
      private
        FTextLyout : TTextLayout;
        FLastMessageId : Integer;
        FMsgWidthPercentage : Integer;
        FOnURLButtonClick : TEventText;
        FCalloutLength : Single;
        FCalloutXRadius : Single;
        FCalloutYRadius : Single;
        FMessageFontSize : Single;
        FMemo : TMemo;
        procedure ButtonClick(Sender: TObject);
        procedure MyMsgContainerOnClick(Sender: TObject);
        procedure MyMsgContainerOnExit(Sender: TObject);
        function FCreateMsgBlock(AOwner: TComponent; PMessageId : Integer;
          PDate, PAutor, PMessage : String; PMessagePos : TMessagePos) : TLayout;
        function CalculateTextItemHeight(Sender: TObject) : Single;
        procedure LayoutResize(Sender: TObject);
        function ExtractURL(pString : String) : String;
        procedure Memo1ApplyStyleLookup(Sender: TObject);
      public
        property LastMessageId : Integer read FLastMessageId;
        property MsgWidthPercentage : Integer read FMsgWidthPercentage write FMsgWidthPercentage default 80;
        constructor Create(AOwner: TComponent); override;
        destructor Destroy; override;
        Procedure AddMessage(pMessageId : Integer; PDate, PAutor, PMessage : String; PMessagePos : TMessagePos);
        procedure ClearChildren(AChatBox: TChatBox);
        procedure ScrollBottomSmoothly;
        procedure ScrollBottom;
      published
        property OnURLButtonClick : TEventText read FonURLButtonClick write FonURLButtonClick;
        property CalloutLength : Single read FCalloutLength write FCalloutLength;
        property CalloutXRadius : Single read FCalloutXRadius write FCalloutXRadius;
        property CalloutYRadius : Single read FCalloutYRadius write FCalloutYRadius;
        property MessageFontSize : Single read FMessageFontSize write FMessageFontSize;
      end;
    
      TOpenChatBox = class(TChatBox);
    
    Procedure Register;
    
    implementation
    
    procedure Register;
    begin
      RegisterComponents('EKorepov', [TChatBox]);
    end;
    
    constructor TChatBox.Create(AOwner: TComponent);
    begin
      inherited create(Aowner);
      FLastMessageId:=-1;
      FTextLyout := TTextLayoutManager.DefaultTextLayout.Create;
      FMemo:=TMemo.Create(Aowner);
      FMemo.TextSettings.WordWrap:=True;
      FMemo.ReadOnly:=True;
      FMemo.Align:=TAlignLayout.Client;
      FMemo.OnExit:=MyMsgContainerOnExit;
      FMemo.OnApplyStyleLookup:=Memo1ApplyStyleLookup;
      FMemo.StyledSettings:=FMemo.StyledSettings-[TStyledSetting.Size];
      With Self as TVertScrollBox do
      begin
        AniCalculations.Animation := True;
        AniCalculations.BoundsAnimation := True;
        AniCalculations.TouchTracking := [ttVertical];
      end;
    end;
    
    destructor TChatBox.Destroy;
    begin
      FreeAndNil(FMemo);
      FreeAndNil(FTextLyout);
      inherited Destroy;
    end;
    
    procedure TChatBox.ScrollBottomSmoothly;
    begin
      AniCalculations.MouseWheel(0, ContentBounds.Height+5);
    end;
    
    procedure TChatBox.ScrollBottom;
    begin
      ScrollBy(0, -ContentBounds.Height);
    end;
    
    procedure TChatBox.ButtonClick(Sender: TObject);
    Var URL : String;
    begin
      URL:=TButton(Sender).HelpKeyword;
      if Assigned(FonURLButtonClick) then
        FonURLButtonClick(URL);
    end;
    
    procedure TChatBox.Memo1ApplyStyleLookup(Sender: TObject);
    begin
    end;
    
    procedure TChatBox.MyMsgContainerOnClick(Sender: TObject);
    begin
      FMemo.TextSettings:=TLabel(Sender).TextSettings;
      FMemo.Lines.Text:=TLabel(Sender).Text;
      TLabel(Sender).AddObject(FMemo);
    end;
    
    procedure TChatBox.MyMsgContainerOnExit(Sender: TObject);
    begin
      if (Sender is TMemo) then
        if Assigned(TMemo(Sender).Parent) then
          if (TMemo(Sender).Parent is TLabel) then
            TLabel(TMemo(Sender).Parent).RemoveObject(TMemo(Sender));
    end;
    
    procedure TChatBox.ClearChildren(AChatBox: TChatBox);
    begin
      Assert(AChatBox <> nil);
      TOpenChatBox(AChatBox).Content.DeleteChildren;
      AChatBox.Repaint;
    end;
    
    function TChatBox.CalculateTextItemHeight(Sender: TObject) : Single;
    var Item: TLabel;
    begin
      Result:=0;
      if (Sender is TLabel) then
      begin
        Item := TLabel(Sender);
        FTextLyout.BeginUpdate;
        try
          FTextLyout.Text := Item.Text;
          FTextLyout.MaxSize := TPointF.Create(Item.Width-Item.Margins.Left-Item.Margins.Right-10, 1000);
          FTextLyout.Font := Item.Font;
          FTextLyout.WordWrap:= Item.WordWrap;
          FTextLyout.HorizontalAlign:= Item.TextSettings.HorzAlign;
          FTextLyout.VerticalAlign:= Item.TextSettings.VertAlign;
        finally
          FTextLyout.EndUpdate;
        end;
        Result:= FTextLyout.Height+10;
      end;
    end;
    
    procedure TChatBox.LayoutResize(Sender: TObject);
    Var Item : TLabel;
        CalloutRectangle : TCalloutRectangle;
        Layout : TLayout;
        I : Integer;
    begin
      Layout:=TLayout(Sender);
      for I := 0 to Layout.Children.Count-1 do
      begin
        If Layout.Children.Items[I] is TCalloutRectangle Then
        begin
          CalloutRectangle:=TCalloutRectangle(Layout.Children.Items[I]);
          Item:=TLabel(CalloutRectangle.Children.Items[0]);
          CalloutRectangle.Width:=(Layout.Width / 100) * FMsgWidthPercentage;
          Layout.Height:=CalculateTextItemHeight(Item);
        end;
        If Layout.Children.Items[I] is TButton Then
        begin
          TButton(Layout.Children.Items[I]).Width:=(Layout.Width / 100) * (100-FMsgWidthPercentage-5);
        end;
      end;
    end;
    
    Procedure TChatBox.AddMessage(pMessageId : Integer; PDate, PAutor, PMessage : String; PMessagePos : TMessagePos);
    Var lcLayout : TLayout;
    begin
      PDate:=Trim(PDate);
      PAutor:=Trim(PAutor);
      PMessage:=Trim(PMessage);
      FLastMessageId:=PMessageId;
      lcLayout:=FCreateMsgBlock((Self as TVertScrollBox), PMessageId, PDate, PAutor, PMessage, PMessagePos);
      Self.AddObject(lcLayout);
    end;
    
    function TChatBox.FCreateMsgBlock(AOwner: TComponent; PMessageId : Integer; PDate, PAutor, PMessage : String;
                                      PMessagePos : TMessagePos) : TLayout;
    Var lcLayout,lcLayout2 : TLayout;
        Item : TLabel;
        Button : TButton;
        CalloutRectangle : TCalloutRectangle;
        lcHeight : Single;
        URL : String;
    begin
      lcLayout:=TLayout.Create(AOwner);
      lcLayout.Tag:=pMessageId;
      lcLayout.Align:=TAlignLayout.Top;
      lcLayout.Width:=200;
      lcLayout.Position.X:=0;
      lcLayout.Position.Y:= ((AOwner as TVertScrollBox).ContentBounds.Height+10);
      lcLayout.Margins.Bottom:=10;
      CalloutRectangle:=TCalloutRectangle.Create(lcLayout);
      CalloutRectangle.XRadius:=FCalloutXRadius;
      CalloutRectangle.YRadius:=FCalloutYRadius;
      CalloutRectangle.CalloutWidth:=10;
      CalloutRectangle.CalloutOffset:=-3-FCalloutYRadius-CalloutRectangle.CalloutWidth;
      CalloutRectangle.Width:=((AOwner as TVertScrollBox).Width / 100) * FMsgWidthPercentage;
      CalloutRectangle.HitTest:=False;
      case PMessagePos of
        msgRight :
        begin
          CalloutRectangle.Align:=TAlignLayout.Right;
          CalloutRectangle.CalloutPosition:=TCalloutPosition.Right;
          CalloutRectangle.Padding.Right:=CalloutRectangle.CalloutLength+CalloutRectangle.XRadius;
          CalloutRectangle.Padding.Left:=CalloutRectangle.XRadius;
        end;
        msgLeft :
        begin
          CalloutRectangle.Align:=TAlignLayout.Left;
          CalloutRectangle.CalloutPosition:=TCalloutPosition.Left;
          CalloutRectangle.Padding.Left:=CalloutRectangle.CalloutLength+CalloutRectangle.XRadius;
          CalloutRectangle.Padding.Right:=CalloutRectangle.XRadius;
        end;
      end;
      CalloutRectangle.Padding.Top:=1;
      CalloutRectangle.Padding.Bottom:=1;
      lcLayout.AddObject(CalloutRectangle);
    
      Item:=TLabel.Create(CalloutRectangle);
      Item.TextSettings.Font.Size:=MessageFontSize;
    
      CalloutRectangle.AddObject(Item);
      Item.Align:=TAlignLayout.Client;
    {$IFDEF MSWINDOWS}
      Item.OnClick:=MyMsgContainerOnClick;
    {$ENDIF MSWINDOWS}
    
      Item.Text:=PDate+' '+PAutor+#10+PMessage;
      Item.HitTest:=True;
      Item.WordWrap:=True;
      lcHeight:=CalculateTextItemHeight(Item);
      lcLayout.Height:=lcHeight;
      URL:=ExtractURL(pMessage);
      Item.StyledSettings:=Item.StyledSettings- [TStyledSetting.Size,TStyledSetting.Style];
    
      if Not URL.IsEmpty then
      begin
        lcLayout2:=TLayout.Create(lcLayout);
        lcLayout2.Align:=TAlignLayout.Client;
        lcLayout2.Margins.Left:=5;
        lcLayout2.Margins.Right:=5;
        lcLayout.AddObject(lcLayout2);
        Button:=TButton.Create(lcLayout2);
        Button.Text:='Открыть';
        Button.Align:=TAlignLayout.Center;
        Button.HelpKeyword:=URL;
        Button.OnClick:=ButtonClick;
        lcLayout2.AddObject(Button);
      end;
      lcLayout.OnResize:=LayoutResize;
      Result:=lcLayout;
    end;
    
    function TChatBox.ExtractURL(pString : String) : String;
    Var S : String;
    begin
      Result:='';
      if Not pString.Contains('http') then
        Exit;
      S:=pString.Substring(Pos('http',pString)-1);
      S:=S.Remove(S.IndexOfAny([' ',',']));
      Result:=S.TrimRight(['.']);
    end;
    
    
    end.
    
  21. Как то так? 

    Var mes : TIdBytes;
    begin
    SetLength(mes,3);
    mes[0] = 0x0A;
    mes[1] = 0x23;
    mes[2] = 0xBC;
    ifTCPClient.Connect(IP,Port);
    if  ifTCPClient.Connected Then
    idTCPClient.IOHandler.Write(mes,Length(mes));  
    ...

    Код "mes[0] = 0x0A;" не стал менять для наглядности, а TIdBytes = array of Byte;

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

    Багов хватает, полностью согласен. Последней версии без багов была Delphi7 наверное ;-)  Но кроме исправления багов в новых версиях, есть и новые фичи. 

    Кстати было бы не плохо, если бы Embarcadero платила за багрепорты символические деньги, список исправлений Update1 просто смехотворный. За последние пару месяцев, только мой личный список исправления исходного кода близок к десятку. Но писать багрепорты лениво и к тому же тоскливо - хостинг  Embarcadero, по старой силиконовой традиции, располагается на арифмометре устаревшей модели в гараже одного из владельцев. Загрузка страниц по несколько минут это жесть (интернет канал у меня 800 мегабит).

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