Ответы пользователя по тегу Delphi
  • Почему Embarcadero ODBC работает, а Qt ODBC буксует? И есть ли замена?

    @Mercury13 Автор вопроса
    Программист на «си с крестами» и не только
    Опять приходится отвечать самому.
    В Qt ODBC крайне тормозной, используй другую библиотеку!
    Ответ написан
  • Возможно смешной вопрос, но - в Delphi существует аналог "методов-раширений C#"?

    @Mercury13
    Программист на «си с крестами» и не только
    Метод-расширение: XE3+, helper class.
    docwiki.embarcadero.com/RADStudio/Tokyo/en/Class_a...

    Условная компиляция: ещё со времён Трубо-паскаля, директивы компилятора
    {$IFDEF DEBUG}
    {$ENDIF}
    docwiki.embarcadero.com/RADStudio/Tokyo/en/Conditi...
    Ответ написан
  • Что одновременно компонент DrawGrid позволяет отображать?

    @Mercury13
    Программист на «си с крестами» и не только
    Этот компонент позволяет отобразить всё, что можно нарисовать программно: картинки, тексты, списки, формулы и прочее. Форма — это не только рисование, но и размещение объекта со своим оконным дескриптором, так что отпадает. «Вычисления» — это слишком общий термин, но если придумаешь, как нарисовать схему/формулу вычислений, то пожалуйста. А остальное катит.
    Ответ написан
  • Какие действия несут эти знаки @ & % # ^ в delphi или pascal?

    @Mercury13
    Программист на «си с крестами» и не только
    Это символ не Delphi, а Win32. Как налаживается горячая клавиша в других ОС — я не в курсе, но в Qt под всеми ОС горячая клавиша задаётся точно так же, амперсандом. В текстовой системе Turbo Vision было ~H~otkey.
    Никакого особого смысла эти символы в окнах Win32 не несут. Но могут нести где-то в других местах, сами понимаете:
    • на некоторых сайтах #hashtag или @user
    • в строках типа printf процент — это символ подстановки типа «Привет, %s»
    • а какой смысл несут все эти символы в Паскале — вы и так должна знать.
    Ответ написан
  • Что делает эта строка?

    @Mercury13
    Программист на «си с крестами» и не только
    Связывает визуальные элементы навигации по БД с невизуальным источником данных.
    Устанавливает заголовок формы (у вас кодировка глючит).
    Запускает форму в модальном режиме.
    Ответ написан
  • Как написать визуализацию алгоритма сортировки в delphi?

    @Mercury13
    Программист на «си с крестами» и не только
    longclaps написал, как всё это дело должно выглядеть внешне.
    Внутренне это реализуется просто.
    1. В OnPaint какого-нибудь компонента (PaintBox, скажем) при определённых условиях выводим визуализацию.
    2. Блокируем весь пользовательский интерфейс (кроме какой-нибудь кнопки «Стоп»).
    3. Каждый раз, когда надо что-то увидеть, делаем paintBox.Repaint, Application.ProcessMessages и небольшую задержку.
    4. При нажатии кнопки «Стоп» ставим какую-то переменную в true. Сортировка реагирует на эту переменную и останавливает цикл: либо простым Exit, либо аварией Abort и последующей реакцией на EAbort.

    Если есть желание сравнить несколько алгоритмов сортировки, стоит сделать функцию типа DoSwap(i, j : integer), которая меняет местами элементы, устанавливает всё, что надо для визуализации, инициирует перерисовку и делает задержку.
    Ответ написан
  • Как нарисовать на курсоре в RunTime?

    @Mercury13
    Программист на «си с крестами» и не только
    Попробуйте Brush.Color := $FF000000 or clBlue;. Велика вероятность, что механизмы работы с 32-битными изображениями тут слабоваты.
    Ответ написан
  • Как заполнить двумерный массив?

    @Mercury13
    Программист на «си с крестами» и не только
    var // ну или const
    masMask: array[1..3, 1..3] of string = (
      ( '11', '12', '13' ), ( '21', '22', '23' ), ( '31', '32', '33' )
    );

    ВНИМАНИЕ! Я не проверял, как оно работает, когда это локальная переменная (var).

    UPD. Проверил, нельзя. Var работает только если массив глобальный. Const, разумеется, работает всегда, ибо создаёт глобальный массив и запрещает туда писать. Если же нужно инициализировать локальный var, надо объявить тип
    type TSomeTable = array[1..3, 1..3] of string;
    создать какую-то константу
    const masStart: TSomeTable = …;
    var masMask : TSomeTable;

    а затем в начале masMask := masStart;

    UPD2. Для чего объявить тип? Читайте правила эквивалентности типов в Паскале, они жёстче, чем в Си. И тот учебник, по которому я учил Паскаль (Зуев), особо упоминает, что два одинаковых array не эквивалентны.

    UPD3.
    months = (jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec);
     — это не массив! Это перечисляемый тип. Кстати, из-за правил пересечения идентификаторов очень не советую писать типы и перечисляемые константы без венгерской записи, к тому же название months сбивает с толку. Лучше будет TMonth = (monJan, monFeb, …);.
    Ответ написан
  • Как возвести число в отрицательную степень, не использую функцию Power?

    @Mercury13
    Программист на «си с крестами» и не только
    Число в отрицательную степень или отрицательное число в степень?
    Отрицательное число можно возводить только в целую степень (уже с рациональной ни фига не понятно, а как мы получили понятие «действительная степень»? — дополнили рациональную по непрерывности).
    Тут вам надо возвести −1 в степень n, и проще всего
    IfThen(Odd(n), -1, 1)

    Для этого ряда так подходит. Но если перед нами ряд для синуса, который вычисляется рекуррентно, то
    x2 := Sqr(x);
    ...
    yNew := -yOld * x2 / ((n - 1) * n);
    Ответ написан
  • В какой версии Delphi появились хелперы?

    @Mercury13 Автор вопроса
    Программист на «си с крестами» и не только
    Опять отвечаю сам. XE3.
    Ответ написан
  • Как вычислить корень n-ой степени?

    @Mercury13
    Программист на «си с крестами» и не только
    Итак, надо решить такую задачу.
    xb = a, a > 0, или xb — a = 0

    Метод Ньютона говорит:
    xn+1 = xn − f(x) / f′(x)
    xn+1 = xn − (xnb — a) / (b·xnb−1) = (xn − a/(xnb−1))/b
    Поскольку функция возрастает и выпукла вниз, x1 лучше брать завышенный. Идеал — хаки с дробными числами (например, заполучить порядок и взять начальным приближением 2[ord/b] для отрицательного порядка и 2[ord/b] + 1 для неотрицательного.

    [x] — усечение дробного числа, при целом b [ord/b] = ord div b. Чтобы заполучить порядок, похимичить с ним и снова собрать в машинное дробное, можно воспользоваться функциями Delphi Frexp и Ldexp, они очень быстры.

    Заканчивать когда |xn+1 − xn| меньше e. Поскольку у метода сходимость квадратичная, почти гарантированно получим нужную нам точность.

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

    И последнее. Поверь мне, прекрасная леди, никто не будет решать тебе учебную задачу до конца.
    Ответ написан
  • Какой компонент использовать для работы с Excel в RAD Studio 10.1 Berlin (Delphi)?

    @Mercury13
    Программист на «си с крестами» и не только
    Можно загуглить NativeExcel — он распространялся с исходниками, и вполне найдётся хакнутая версия.
    Есть, правда, несколько не слишком удачных вещей в NativeExcel, и если модуль приглянется, спросите меня, что в нём можно улучшить. Вкратце.
    1. Портирование WideString → UnicodeString.
    2. Портирование Delphi ZLib port → Embarcadero Zlib interface.
    3. Разглючка для Zip’ов LOo.
    4. Разглючка для XML LOo.
    5. Разглючка с цветами XLSX. LOo тут, как ни странно, ни к чему, но однажды попадался такой XLSX.
    6. Разглючка с распознаванием bool (тоже LOo).

    UPD. Сам NativeExcel три года как брошенный, его домен с недавних пор ничей — надеюсь, автор коммерческой библиотеки будет не сильно против.
    Ответ написан
  • Почему линия не прорисовывается с права?

    @Mercury13
    Программист на «си с крестами» и не только
    UPD2. Запомните уж, рисование на форме надо делать только в OnPaint. Сверни-разверни окно — линия исчезнет Код будет примерно такой.
    TForm1 = class(TForm)
       ...
      private
        MyLabel,MyLabel2:TLabel;  // тут они занулятся автоматически, да и фэншуйнее
        ...
      end;
    
    procedure TForm1.Button1Click(Sender: TObject);
    begin
    ...
    MyLabel2.Caption:='3';
    Invalidate;   // Запросить перерисовку
    end;
    
    procedure TForm1.FormPaint(Sender: TObject);  // Событие OnPaint
    begin
      if MyLabel <> nil then
        with Canvas do begin
          Pen.Color:=clRed;
          MoveTo(MyLabel.left,MyLabel.top+(MyLabel.Font.Size+MyLabel.Font.Size div 2) div 2);
          LineTo(MyLabel2.left,MyLabel2.top+(MyLabel2.Font.Size+MyLabel2.Font.Size div 2) div 2);
        end;
    end;

    А для расчёта ваших выносок вариантов несколько.
    1. Нарисовать цифру во внеэкранный буфер и рассчитать размеры реально закрашенной части.
    2. Получить метрику шрифта, по ней прикинуть размеры типичной «заглавной» цифры. Справа убрать пиксель межбуквенного пространства, плюс внести какую-то поправку на «узкую» единичку.

    UPD3. В чём было дело? А в том, что TGraphicControl (к коим относится и TLabel) — это абстракция Delphi, не имеющая аналога в Windows. Он просто берёт тот TWinControl, на котором находится, в случае Transparent рисует фон под собой через WM_PAINT, а затем рисует себя. При этом чёрточка, нарисованная НЕ через OnPaint, стирается.

    UPD4. Полный порядок, рисование через OnPaint — это всё, что надо было. TGraphicControl умный и обходится без лишних перерисовок.

    Ну и наконец «хорошие качества» вашего кода.
    MyLabel := TLabel.Create(Form1);
    MyLabel.Parent := Form1;
    Лучше использовать Self, а не Form1.

    Form1: TForm1;
       p,c,z,j:integer;
    Если бы эти переменные были нужны, лучше было бы их внести в Form1. Если бы…

    function rez(p:integer): integer;
       begin
       c:=p+20;
    
       end;
    Мы тут, очевидно, рассчитываем габариты наших надписей. А нельзя это сделать без побочных эффектов?

    UPD. Это только макет и будет глючить на высоких DPI. Пожалуйста, если хотите такое широкой публике — усложните расчёты.
    Ответ написан
  • Как мне записать конечный результат деления?

    @Mercury13
    Программист на «си с крестами» и не только
    В зависимости от того, какого происхождения числа, можно поступать так.

    1. Работать с погрешностью. Например.
    q := X1 / X2;
    if abs(q - Round(q)) < 1e-5 then ...

    Я в основном сейчас на «си с крестами» и непривычка не брать условие в скобки :)

    2. Работать в рациональных числах.
    type
      TRatio = record
        Num, Den : integer;
      end;

    Думаю, сами сможете написать операции ±×/ и, если надо, сокращение.

    3. Работать в фиксированной запятой — например, перевести рубли в копейки.
    var
      X1 : integer = 100;
      X2 : integer = 20;
    
    if X1 mod X2 = 0 then ...


    4. Работать в десятичной длинной арифметике. Это уже совсем «большая пушка», и может быть что-то типа
    type
      TDecFloat = record
        mantissa : uint64;  // например, от 1e17 до 1e18
        order : integer;
        sign : boolean;
      end;

    Примерно так можно сделать калькулятор, работающий в десятичной системе и переводящий в extended и обратно, если, например, нужно взять синус. Погрешность перевода для трансцендентных функций, разумеется, будет, зато 0,2 в такой системе — это точное 0,2, и это важно для калькуляторов: он вычислит в точности то, что человек вычислит ручкой на бумаге.

    ВНИМАНИЕ! Для методов 2,3,4 придётся переработать всю цепочку, через которую появляются 1 и 0,2. В float/double нет числа 0,2, и точка.
    Ответ написан
  • Как добавить перенос на новую строку?

    @Mercury13
    Программист на «си с крестами» и не только
    Я добавлю к Александр .
    В отличие от Си, где условие цикла каждый раз вычисляется полностью, в Паскале вторая граница for вычисляется один раз и запоминается.
    Потому длина строки меняется, а мы ходим до самой первой.

    К тому же вы неправильно решаете задачу. Никакой там не одной строкой. В ответе сервера концы строк LF, а надо CR+LF. Вот функция (крайне неоптимизированная), которая приводит концы строк к единому виду независимо от того, какие там стоят.
    function NormalizeEol(const s : string) : string;
    begin
      Result := StringReplace(s, #13#10, #10, [rfReplaceAll]);
      Result := StringReplace(Result, #13, #10, [rfReplaceAll]);
      Result := StringReplace(Result, #10, #13#10, [rfReplaceAll]);
    end;
    Ответ написан
  • Почему в текст запроса вставляется exec?

    @Mercury13
    Программист на «си с крестами» и не только
    Это связано с версией клиента MS SQL. Несколько вариантов переписать триггер.
    ALTER TABLE table_name DISABLE TRIGGER tr_name
    ALTER  TRIGGER trigger_name  DISABLE
    Ответ написан
  • Какую версию Indy 10 использовать для Delphi 7 под Windows 10?

    @Mercury13
    Программист на «си с крестами» и не только
    Многие библиотеки OpenSSL требуют какие-то свои DLL (например, MSVC). Если программа внутренняя, это не так важно, а вот если её распространять… Особенно когда программа написана на чём-то другом, кроме MSVC: например, MinGW или Delphi.
    Я накопал вот такие сборки — они выполнены устаревшей версией MSVC и не требуют ничего особенного.
    https://indy.fulgan.com/SSL/
    (Сам я использую MinGW, и поскольку OpenSSL вызывается через cURL, который тоже не мой, без бутылки не поймёшь, кто виноват и что делать.)
    Ответ написан
  • Как создать событие закрытия формы из другого Юнита?

    @Mercury13
    Программист на «си с крестами» и не только
    1. Перемести «uses соответствующую форму» из интерфейса в implementation. Такие циклические обращения разрешены.
    Правило хорошего тона: что угодно — uses, const, var — желательно держать в implementation, если только они не нужны интерфейсу.
    Впрочем, подобный циклический «комок грязи» говорит о том, что архитектура программы плохо продумана, и для больших программ это нежелательно.

    2. Явно неверный код Form3.Create(self);
    Если создать форму — то правильно Form3 := TForm3.Create(self);
    Если кто-то создал, а ты повторно вызвал конструктор — зачем такое?
    Ответ написан
  • Как работать с двусвязными списками в 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, затем в целое». В промышленной программе этого не хватало.
    Ответ написан