Ответы пользователя по тегу Delphi
  • Как работать с двусвязными списками в delphi?

    @Mercury13
    Программист на «си с крестами» и не только
    В Delphi языком записей — в точности так же.
    Языком классов…
    type  
      TCell = class
       public
        info: TReki; 
        next, previous: TCell;
      end; 
      TList = TCell;
      TPosition = TCell;

    Да, об именовании типов. В Си мы пишем Cell cell, а в Паскале cell : Cell нельзя, он регистронезависимый. Общепринято, что тип начинается на T, указатель — на P. Иногда добавляют другие префиксы (event — Ev, dynamic array —Da), но типы без префикса — плохой тон.
    Ответ написан
  • Как изменить формат данных передаваемых из Excel?

    @Mercury13
    Программист на «си с крестами» и не только
    Плавали, знаем. В массив поступает как раз то, что нужно. Причина в алгоритмах конвертации число→строка, и надо добавить такую штуку:
    «Если число — по типу Double, по факту точное целое и находится в определённых пределах, преобразовать его в Int64, а затем Int64 в строку».

    Сама проверка, является ли double точным целым, довольно сложна. У меня есть код для этого на Си++ (который, в свою очередь, является портом кода из Java). Портанёте на Delphi сами?

    enum {
        DOUBLE_MANTISSA_BITS = 52,
        DOUBLE_MIN_EXPONENT = -1022,
        DOUBLE_EXPONENT_BIAS = 1023,
    };
    
    #define UC8x(X,Y,Z,T) (static_cast<uint64_t>(0x##X##Y##Z##T##ULL))
    #define DOUBLE_MANTISSA_MASK     UC8x(000f, ffff, ffff, ffff)
    #define DOUBLE_EXPONENT_MASK     UC8x(7ff0, 0000, 0000, 0000)
    #define DOUBLE_EXPONENT_MASK_HI  UC4x(7ff0, 0000)
    #define DOUBLE_IMPLICIT_BIT (DOUBLE_MANTISSA_MASK + 1)
    
        union DoubleInt {
            double asDouble;
            uint64_t asInt;
            struct {
                uint32_t lo, hi;
            } asIntel;
        ....
       }
    
        int DoubleInt::exponent() const
        {
            return static_cast<int>((
                          static_cast<int64_t>(asInt & DOUBLE_EXPONENT_MASK) >>
                          (DOUBLE_MANTISSA_BITS)) - DOUBLE_EXPONENT_BIAS);
        }
    
        uint64_t DoubleInt::unsafeMantissa() const
        {
            int ex = exponent();
            uint64_t bits = asInt & DOUBLE_MANTISSA_MASK;
            return (ex == DOUBLE_MIN_EXPONENT - 1)
              ? bits << 1
              : bits | DOUBLE_IMPLICIT_BIT;
        }
    
        bool DoubleInt::isPreciseInteger() const
        {
            // функцию isFinite() намеренно упустил, ибо она есть «в коробке» Delphi.
            // А вот в Си++ есть не во всех реализациях…
            return isFinite()
                && (asDouble == 0.0 ||
                DOUBLE_MANTISSA_BITS - numberOfTrailingZeros(unsafeMantissa()) <= exponent());
        }
    
    int math::numberOfTrailingZeros(uint64_t i)
    {
        uint32_t x, y;
        if (i == 0u) return 64;
        int n = 63;
        y = static_cast<uint32_t>(i);
        if (y != 0) { n = n -32; x = y; } else x = (int)(i >> 32);
        y = x << 16; if (y != 0) { n = n -16; x = y; }
        y = x << 8;  if (y != 0) { n = n - 8; x = y; }
        y = x << 4;  if (y != 0) { n = n - 4; x = y; }
        y = x << 2;  if (y != 0) { n = n - 2; x = y; }
        return n - ((x << 1) >> 31);
    }
    
    bool math::isPreciseInteger(double x)
    {
        DoubleInt di;
        di.asDouble = x;
        return di.isPreciseInteger();
    }


    Может быть, вам сработают и упрощённые варианты вроде «столбец X — преобразовать в Int64, затем в целое». В промышленной программе этого не хватало.
    Ответ написан
    Комментировать
  • Консольное программа delphi?

    @Mercury13
    Программист на «си с крестами» и не только
    Для этого служат, извините, циклы. Самый простой способ — бесконечный цикл с break внутри
    repeat
      ваш код
      if [что-то там] then break;
      ваш код
    until false;
    Ответ написан
    Комментировать
  • Free Pascal ANSI или Unicode?

    @Mercury13
    Программист на «си с крестами» и не только
    Плавали, знаем. Долго видел на BCB6, а потом преобразовывал ANSI → UTF-16.
    1. Раз у нас UTF-16, придётся усложнить работу с путями и прочим (например, сокращение строк). Раньше символ был один char, стало — один-два WideChar.
    2. Где у нас низкоуровневые строки — придётся корректировать объёмы памяти. На всех языках, кроме Си и Си++, такого обычно мало: на Си нет своих строк, а в Си++ автодеструкторы.
    3. Где у нас сериализация — придётся перекодировать. В ANSI адресуемая единица (байт) совпадает с символом текста, в Юникоде уже нет.
    Ответ написан
    3 комментария
  • Объясните толком про интерфейсы в ООП (Delphi). Как их использовать?

    @Mercury13
    Программист на «си с крестами» и не только
    Интерфейсы в Delphi отвечают за две малосвязанных вещи.
    1. Множественное наследование. Об этом уже рассказали до меня, повторяться не буду.
    2. Подсчёт ссылок (для этого реализатор должен корректно поддерживать _AddRef и _Release, но это уже другой вопрос, и подходящая реализация есть в TInterfacedObject).
    Связано это с тем, что Delphi должен был поддерживать Microsoft COM, а там автоматическое управление через подсчёт ссылок.
    Так что интерфейсы часто приплетают только потому, что удобно работать с подсчётом ссылок.

    Вот, например, моя библиотека (обёртка cURL для Delphi) под названием curl4delphi: https://github.com/Mercury13/curl4delphi
    На что тут ICurl? А на то, что это объект с подсчётом ссылок, и для него не надо вызывать деструктор. Пропадает последняя ссылка — объект исчезает. Вот и всё.
    Из-за автодеструкторов, «киллер-фичи» Си++, я в Си++ так не поступал бы.
    Ответ написан
    Комментировать
  • Как узнать путь к Application Data текущего пользователя из службы?

    @Mercury13
    Программист на «си с крестами» и не только
    Служба может работать, даже если ни один пользователь не прилогинен к системе. Или если прилогинены двое (например, один оставил комп с работающим клиентом, подлогинился второй). Потому придётся переделать архитектуру службы — например, передавать настройки при установке связи клиента со службой.
    Ответ написан
    4 комментария
  • Как комментировать код в Delphi так, чтобы при запуске приложения на windows код от андроид не исполнялся?

    @Mercury13
    Программист на «си с крестами» и не только
    {$IFDEF MSWINDOWS}
    // тут код, специфичный для Windows
    {$ENDIF}


    И, аналогично, {$IFDEF ANDROID}

    Часто используют {$IF defined(MSWINDOWS)} — можно написать {$ELSEIF defined(ANDROID)}.
    Ответ написан
    1 комментарий
  • Как создать компонент в потоке и оставить его в delphi?

    @Mercury13
    Программист на «си с крестами» и не только
    Можно, только синхронно. Используй TThread.Synchronize. Код пишется с листа, не уверен, что действующий.
    procedure TMyThread.SyncCreateMemo;
    begin
     Memo:=TMemo.Create(Form6);
      Memo.Parent:=Form6;
      Memo.Left:=50;
      Memo.Top:=50;
      Memo.Width:=250;
      Memo.Height:=100;
      Memo.Text:='Мама я родился!';
    end;
    
    procedure TMyThread.Execute;
    begin
      Synchronize(SyncCreateMemo);
    end;


    Второй способ, более сложный и опасный — PostMessage. Здесь никаких задержек поток испытывать не будет. Но будьте осторожны — форма создаст компонент когда угодно и нельзя его заполнять сразу же.
    procedure TForm6.WmCreateMemo; // message WM_CREATEMEMO = WM_USER + 1
    begin
     Memo:=TMemo.Create(Form6);
      Memo.Parent:=Self;
      Memo.Left:=50;
      Memo.Top:=50;
      Memo.Width:=250;
      Memo.Height:=100;
      Memo.Text:='Мама я родился!';
    end;
    
    procedure TMyThread.Execute;
    begin
      PostMessage(Form6.Handle, WM_CREATEMEMO, 0, 0);
    end;


    Заполнять наш редактор тоже можно путём PostMessage, но тут тоже будьте осторожны: сообщения-то выполнятся по порядку, но никто не знает, до окончания потока или нет. Бывает и такое, что два сообщения ушли в очередь, но ещё не обработались. В общем, будьте предельно осторожны с временем жизни объекта.
    Ответ написан
    Комментировать
  • Как использовать кириллицу в параметрах запроса IdHTTP?

    @Mercury13
    Программист на «си с крестами» и не только
    1. Разобраться, в какой кодировке работает сервер (обычно UTF-8).
    2. Для путей — провести преобразование (Utf8Encode вроде). Не забудь, что Delphi 7 «из коробки» неюникодная.
    3. Для доменных имён — закодировать в PunyCode. Это уже сам как-то — думаю, есть библиотеки, но точно не в коробке.
    Ответ написан
    3 комментария
  • Delphi. Как Узнать номер диска по его букве?

    @Mercury13
    Программист на «си с крестами» и не только
    stackoverflow.com/questions/5501749/how-do-you-get...
    На Паскаль сам переведёшь? Внимание, работает только для фиксированных дисков.
    Ответ написан
    Комментировать
  • Код из Delphi в С++!?

    @Mercury13
    Программист на «си с крестами» и не только
    InStr/InSize — немного избыточно по дельфийским меркам и можно преобразоватть в const char* data / size_t length.

    Результат — ну std::string, разумеется. Или std::vector<char>. Что вместо SetLength — читай доку.

    InStr[i + 1] → data[i]. Остальные массивы нумеруются с нуля, всё как и было.

    Inc(j) → ++j.

    Мне кажется, этот код механически переписывался с Си на Паскаль и переписать обратно будет несложно.

    Ещё тут магическое число 16 — догадайся, на что заменять. Кстати, не стоит размазывать по коду две строки, связанные с j.
    Ответ написан
  • Как изменить класс компонента?

    @Mercury13
    Программист на «си с крестами» и не только
    Самый простой способ. Открываем DFM (ПКМ на форме, View as Text) и проводим Search-Replace.
    После этого вносим любые изменения в модуль (да хоть пробел добавляем и удаляем), и сохраняем. Автоматика будет спрашивать: заменить? — соглашаемся.

    Я изменял в Unit1.pas - type TPanel на sPanel и в Unit1.dfm TPanel на sPanel.
    Но при открытии пишет, что класс sPanel не найден, хотя в uses прописано sPanel.

    Если модуль называется sPanel, то сам компонент должен немного по-другому. TsPanel?

    UPD. Да, TsPanel, если это он.
    Ответ написан
    Комментировать
  • Как удалить файлы по маске в подкаталогах Delphi?

    @Mercury13
    Программист на «си с крестами» и не только
    Ну ясен перец.
    Каталоги надо искать по *, а файлы удалять по *.log.
    Ответ написан
    Комментировать
  • Преобразование дат в Delphi 7?

    @Mercury13
    Программист на «си с крестами» и не только
    Я давно не помню Delphi 7, но и там была версия StrToDate…
    function StrToDate ( const Date : string; const FormatSettings : TFormatSettings ) : TDateTime;

    Несколько форматов — несколько TFormatSettings.

    Далее. Выброс аварий — штука неэффективная и потому желательно, чтобы аварии вываливались действительно в авариях. Не знаю, есть ли в Delphi 7, но должна быть и такая функция.
    function TryStrToDate(const S: string; out Value: TDateTime; const AFormatSettings: TFormatSettings): Boolean;

    Она сигнализирует неудачу возвратом false.

    И наконец. Будь осторожен, в США принят формат даты через слэш, но MM/DD/YY. А ещё есть формат дат ISO, YYYY-MM-DD.
    Ответ написан
    Комментировать
  • Как заполняются многомерные массивы?

    @Mercury13
    Программист на «си с крестами» и не только
    New(Psh[4, 1]);
    Переводим на C#. Правда, тут есть одна загвоздка. Массивы в c# начинаются только с 0, и надо смотреть: либо заводить холостой 0-й элемент, либо корректировать индексы. Так что перед нами два варианта.
    Psh[4][1] = new short[393];
    Psh[3][0] = new short[392];
    (для примера работаю со вторым)

    function OpenA(FileName: ShortString; Mode: LongWord): integer;
    Stream OpenA(string FileName, FileAccess access);


    Как перевести ReadA? Это не так просто. Дело в том, что языки со стандартным промежуточным кодом (к ним относятся в первую очередь языки семейства Java и .NET) обычно пишут в порядке байтов Motorola. На Delphi файл писался в порядке Intel. Так что мы считываем 392 word’а, а затем смотрим, что делать: либо обернуть байты, либо сказать: теперь у нас новый стандарт — Motorola!

    if (!ReadA(Df[3][0], Psh[3][0], 392) {
      CloseA(Df[3, 0]);
      Psh[3][0] = null;
      return;
    }


    И последний рывок.
    Pkts[4, 1]:= @Psh[4, 1]^[9];
    Из-за отсутствия указателей (точнее, есть они, но мы же не хотим unsafe-кода) придётся Pkts разбивать на две части: ссылку на массив и смещение в массиве.
    Pkts[3][0].array = Psh[3][0];
    Pkts[3][0].offset = 8;
    Ответ написан
  • Как присвоить выражение boolean полю TObject?

    @Mercury13
    Программист на «си с крестами» и не только
    Попробую угадать задачу. Есть некое поле (назовём его UserData), но у нас-то пользовательские данные boolean!

    Решение 1. Прямое преобразование, невзирая на несовместимости типов.
    someObj.UserData := TObject(true);
    someBool := boolean(someObj.UserData);

    + Эффективнее всех.
    − Запрещено разыменовывать.

    Решение 2. Создать некий объект DummyObject. Обозначить nil=false, <>nil = true.
    someObj.UserData := dummyObject;
    someBool := (someObj.UserData <> nil);
    
    initialization
      dummyObject := TObject.Create;
    finalization
      dummyObject.Free;
    end.

    + Достаточно эффективно, можно разыменовывать.
    − Если в классе есть неотключаемое автоуничтожение UserData — облом!

    Решение 3. Создать класс TBoolObject.
    TBoolObject = class
    public
      Value : boolean;
      // конструкторы опущу, деструктор не нужен
    end.
    
    someObj.UserData := TBoolObject(true);
    someBool := (someObj.UserData as TBoolObject).Value;

    + Работает, когда в классе есть автоуничтожение UserData.
    − Иначе — овчина не стоит выделки, тогда нам эти объекты придётся уничтожать самим.

    Если же у вас тут экономия памяти и надо в одной памяти держать object или boolean, работает решение 4.
    TObjBool = record
    case integer of
    0 : ( asObj : TObject );
    1 : ( asBool : boolean );
    end;

    + Очень эффективно.
    − Программист сам должен следить за тем, что там: объект или буль.
    Ответ написан
    2 комментария
  • Почему такая разница в производительности SQLite в PHP и Delphi?

    @Mercury13
    Программист на «си с крестами» и не только
    1. Есть подозрение, что вы по какой-то причине в C++-версии не предкомпилируете запросы. Запрос компилируется каждый раз, когда вы его исполняете. Хотя это зависит от обёртки — простыми Си’шными функциями работать с SQLite ой как тяжко, все используют обёртки.
    2. Если компилируете SQLite классическим компилятором Embarcadero — он в несколько раз медленнее других. Хотя разницу в несколько порядков давать не может. Кстати, столь большие Си-файлы быстро заглючивают Embarcadero, и лучше SQLite отправить в статическую или динамическую библиотеку.
    Ответ написан
    1 комментарий
  • Как вывести таблицу в таком формате?

    @Mercury13
    Программист на «си с крестами» и не только
    Храните так, как подсказывает специфика ваших данных. Маловероятно, что это у вас нечто на все случаи жизни.

    Для вывода подходит, например, KGrid.
    Ответ написан
    Комментировать
  • Построение графика по точкам и последовательное соединение?

    @Mercury13
    Программист на «си с крестами» и не только
    Нужен то ли другой тип ряда, то ли другая настройка ряда. Подождите, поэкспериментирую.

    UPD. Два варианта.
    1. У ряда Line установить General→Options→Sort в None (aka XValues.Order=loNone), это позволит рисовать любые загогулины.
    2. Использовать другой тип ряда, Horizontal Line.

    UPD2. У ряда Fast Line тоже есть такие возможности.
    Ответ написан
  • Delphi 7, как сделать обработчик события нажатия клавиш CtRL+V?

    @Mercury13
    Программист на «си с крестами» и не только
    Вариант первый — отреагировать в событии OnKeyDown.
    Вариант второй — создать TActionList, в нём установить действие на Ctrl+V.

    Что лучше — зависит от того, что нужно. По всей форме должна действовать клавиша Ctrl+V или нет?

    Да, и не забудь про команду-заменитель, Shift+Ins. Должна действовать точно так же.
    Ctrl+X = Shift+Del
    Ctrl+C = Ctrl+Ins
    Ответ написан
    Комментировать