|
Заметки о Делфи.
|
|||
---|---|---|---|
#18+
У меня сейчас на работе основной ЯП - Delphi. Хотя относительно давно на нем программирую, все равно какие-то новые штуки узнавал в последнее время. Буду тут писать. Первое. Есть в Delphi, как и в других языках, функция Format. Но есть и частные функции для форматирования вывода разных данных. Например для вывода чисел с плавающей запятой - FormatFloat. Я думал, что эта функция, когда задаешь кол-во знаков после запятой, просто обрезает остальные десятичные знаки. Сегодня узнал, что она всё-таки округляет до заданного кол-ва знаков. И это хорошо,что округляет. ) ... |
|||
:
Нравится:
Не нравится:
|
|||
22.01.2024, 21:53 |
|
Заметки о Делфи.
|
|||
---|---|---|---|
#18+
На днях узнал о синтаксической конструкции в Паскале Делфи, о которой раньше не знал. Смотрел чужой код и натолкнулся на конструкцию Код: Delphi 1.
Код: Delphi 1.
Пример: Код: Delphi 1. 2. 3. 4. 5. 6.
Код: Delphi 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11.
Но ещё, в коде, где я это увидел, имя переменной не совпадает ни с одним зарезервированным словом. Я предполагаю, что это появилось там в результате ряда ошибок и обстоятельств. Предполагаю. что человек скопировал код из Си. Это функция WinApi, видел пример её использования на Си, там как раз первый параметр передается по ссылке, передается вдрес, и в Си стоит амперсанд. Вероятно человек скопировал этот код и амперсанд тоже. Но в Delphi с одной сторроны адрес пишется @, а с другой - в этой импортированной функции первый параметр объявлен как var-параметр, т.е. он и так уже передается по ссылке, адрес писать не нужно. И в третьих, & в Delphi означает, что имя при парсинге не надо понимать, как зарезервированное слово. Т.е. скопированный так код изменил свой смысл, но так получилось, что результат скомпилировался и он даже правильный. Правда можно просто убрать этот амперсанд, он в данном случае не имеет смысла. ... |
|||
:
Изменено: 24.01.2024, 23:32 - s62
Нравится:
Не нравится:
|
|||
24.01.2024, 23:24 |
|
Заметки о Делфи.
|
|||
---|---|---|---|
#18+
Так себе конечно фича... ... |
|||
:
Нравится:
Не нравится:
|
|||
25.01.2024, 00:33 |
|
Заметки о Делфи.
|
|||
---|---|---|---|
#18+
Так себе конечно фича... ... |
|||
:
Изменено: 25.01.2024, 00:37 - s62
Нравится:
Не нравится:
|
|||
25.01.2024, 00:35 |
|
Заметки о Делфи.
|
|||
---|---|---|---|
#18+
В Delphi есть поддержка тем (оформления) Windows. И эта штука, что впрочем логично, не позволяет менять какие-то визуальные свойства тех или иных элементов управления. Например в элементе управления TPageControl: панель с закладками, цвет закладок в теме по-умолчанию в Windows 10 - белый. На белом не всегда хорошо видны поля ввода и т.д. Но цвет, просто задав в design-time какой-то произвольный, не поменяешь, если включена поддержка тем, нарисовано будет всё равно в стиле темы. Сегодня добавлял в полосу статуса окна (Status bar, полоска внизу), вывод еще одной информации, кроме которой там была. Там несколько панелей, на части выводится текст, на других рисуется типа индикаторов красный/зеленый. Панели есть двух типов - либо задаешь текст и он выводится на панели, либо она отрисовывается программно (свойство Style - psText или psOwnerDraw). И вот надо было добавить ещё одну панельку, в которой выводится текст красным цветом в некоторых ситуациях. Отлаживаю и обращаю внимание, что текстовые панели - жирным шрифтом. Почему? Начинаю искать - в свойствах этого нет, в коде этого тоже нет, из других потоков, которые через Synchronize вызывают разные процедуры в этом окне, тоже нет такого. Причем сначала после открытия окна - без жирного, без bold'а, а потом появляется он. И только через какое-то время догадался, что это - тема. Отключил в опциях проекта поддержку тем и жирный перестал появляться. Ну, потом включил назад. Ладно, раз такая тема, в смысле тема оформления :), то значит так, пусть уж будет, чтобы не выбиваться из стиля Windows. ... |
|||
:
Изменено: 05.02.2024, 18:35 - s62
Нравится:
Не нравится:
|
|||
05.02.2024, 18:30 |
|
Заметки о Делфи.
|
|||
---|---|---|---|
#18+
Знакомую фамилию увидел. Использовал в коде функцию CompareMem (сравнивает две области памяти), решил глянуть, как она реализована. Ну, как и ряд других функций, взята из проекта Fastcode, вероятно - адаптирована. А среди тех, кто принимал участие в написании, упомянут Александр Шарахов (только он там и упомянут). Александр не раз писал в разделе Delphi на sql.ru.
Цитата [игнорируется] (* ***** BEGIN LICENSE BLOCK ***** * * The function CompareMem is licensed under the CodeGear license terms. * * The initial developer of the original code is Fastcode * * Portions created by the initial developer are Copyright (C) 2002-2004 * the initial developer. All Rights Reserved. * * Contributor(s): Aleksandr Sharahov * * ***** END LICENSE BLOCK ***** *) ... |
|||
:
Изменено: 09.02.2024, 10:19 - s62
Нравится:
Не нравится:
|
|||
09.02.2024, 10:19 |
|
Заметки о Делфи.
|
|||
---|---|---|---|
#18+
В индексе TIOBE в феврале на 12 месте: https://www.tiobe.com/tiobe-index/ ... |
|||
:
Нравится:
Не нравится:
|
|||
15.02.2024, 08:49 |
|
Заметки о Делфи.
|
|||
---|---|---|---|
#18+
Висуал бейсик на 9м. ... |
|||
:
Нравится:
Не нравится:
|
|||
15.02.2024, 08:57 |
|
Заметки о Делфи.
|
|||
---|---|---|---|
#18+
Висуал бейсик на 9м. ... |
|||
:
Нравится:
Не нравится:
|
|||
20.02.2024, 12:02 |
|
Заметки о Делфи.
|
|||
---|---|---|---|
#18+
Висуал бейсик на 9м. под этим названием там другой язык ... |
|||
:
Изменено: 20.02.2024, 20:45 - Ифрит
Нравится:
Не нравится:
|
|||
20.02.2024, 20:45 |
|
Заметки о Делфи.
|
|||
---|---|---|---|
#18+
Висуал бейсик на 9м. https://www.tiobe.com/tiobe-index/visual-basic/ Есть рейтинги на stack overflow: https://survey.stackoverflow.co/2023/#section-most-popular-technologies-programming-scripting-and-markup-languages ... |
|||
:
Нравится:
Не нравится:
|
|||
20.02.2024, 20:59 |
|
Заметки о Делфи.
|
|
---|---|
#18+
Может все это знают и так, но вдруг кто-то не знает или забыл. Компилятор под Windows использует менеджер памяти, взятый из опенсорсного проекта FastMM. И у него есть такая фишка, он может при закрытии программы показать неосвобожденную память. ОС конечно всю виртуальную память процесса после его закрытия всё равно заберет, но тут можно видеть, какие объекты были созданы и не удалились. Делается это так: в файле проекта в начале после begin добавляется строчка: Код: Delphi 1. 2. 3. 4.
Код: Delphi 1. 2. 3. 4.
https://docwiki.embarcadero.com/RADStudio/Athens/en/Configuring_the_Memory_Manager ... |
|
:
|
|
29.02.2024, 14:25 |
|
Заметки о Делфи.
|
|
---|---|
#18+
Долгое время для измерения времени по-быстрому (хаха, прошу прощения за получившуюся игру слов) использовал функцию win32 API GetTickCount. Эта функция возвращает время в мсек от начала работы компьютера. Результат имеет тип Cardinal (беззнаковое 4 байтовое целое), так что он зацикливается после 49,7 примерно дней работы Windows. (Есть функция GetTickCount64, которая возвращает Int64). MS пишет: Цитата [игнорируется] Разрешение функции GetTickCount ограничено разрешением системного таймера, которое обычно находится в диапазоне от 10 до 16 миллисекундах. Код: Delphi 1. 2. 3. 4. 5. 6. 7. 8. 9.
Понятно, что тут не учитывается фактор многопоточности, что какое-то время поток, в котором выполняется код, мог спать в то время, когда (если) система выделила кусок (slice) времени другому или другим потокам. Но в последнее время часто, когда надо померить время, стал использовать точный таймер, для которого есть обертка в Delphi. Обертка в виде записи с методами. У этого таймера период обычно - 0.1 мксек, т.е. частота 10 000 000 гц. Код: Delphi 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13.
Код: Delphi 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13.
... |
|
:
|
|
19.03.2024, 12:04 |
|
Заметки о Делфи.
|
|
---|---|
#18+
На старости лет оценил полиморфизм в ООП. На нынешней работе это как-то отчетливо заметно. Программа работает с различным железом. И вот, разные модификации железа, даже разные способы подключения - это означает разные варианты обмена данными. Пока что хорошо решалось тем, что в классе-предке устройства (класс для обмена данными с оборудованием, которое выполняет определенную функцию, а конкретные модели и протоколы обмена могут быть разными) объявляются методы, которые потом будет использовать модуль, использующий эту железку. Часть - с реализацией, где делаются какие-то общие для всех вариантов вещи, часть - абстрактные методы. А в потомках реализуется тот или иной конкретный вариант функций обмена. И в модуле, где они используются, мы в зависимости от настроек, создаем экземпляр того или иного класса(-потомка). А используем методы, объявленные в предке. Буквально сегодня сделал в основном вот такое: раньше использовали через TCP/IP->преобразователь портов->RS-485 один модуль цифровых вводов-выводов, по протоколу DCOM, а сейчас в планах использовать другой модуль того же производителя, с управлением прямо по TCP/IP по протоколу Modbus. И вот была задача добавить работу с ним в программу, чтобы можно было работать или с одним, или с другим. Раньше были просто несколько переменных в модуле, теперь забацал классы. Ещё - разделение уровней, слоев обмена. За счет этого (писал код, который мне надо было потом модифицировать, другой человек) как-то, при переходе от обмена по одному каналу к нескольким вариантам, пришлось поменять буквально одну функцию, которая отправляла уже подготовленный пакет, в разных реализациях разный 1)по UDP, 2)по USB, 3)по TCP потом преобразователь портов, потом RS-485. Ну не только одну, ещё конструкторы-деструкторы, ещё наверное что-то. ... |
|
:
|
|
23.05.2024, 15:17 |
|
Заметки о Делфи.
|
|||
---|---|---|---|
#18+
Два урока из недавней практики. Известные вещи, но вот. 1) Делать обработку ошибок. Когда-то была большая статья или даже пару статей на эту тему в блоге у gunsmoker. Я, если в среднем, то наверное примерно так: в каких-то ключевых процедурах обработку ошибок типа try ...except пишу, но не во всех подряд процедурах и функциях. Недавно была ошибка, причину которой относительно долго не мог найти. Ошибка была у заказчика, у нас в офисе при работе программ в том же (вроде бы) окружении, как у заказчика, не воспроизводилась. И не сразу локализовал: исключение возникало в процедуре, из которой вызывались другие процедуры. Когда добавил обработку ошибок в них, то выяснилось, что ошибка, исключение возникает в одной из них. 2) Делать проверку входящих параметров. По сети от нашей же программы приходили пакеты заданного формата и вроде как с предопределенным содержанием, в частности кодом (номером) команды из определенного диапазона. Я с программным кодом этой второй программы был знаком, сам там один модуль писал, в другом или паре других делал кое-что. Вроде как должны были послаться только определенные в протоколе команды. Но оказалось, что приходит от неё по сети пакет с кодом (номером) команды, который не предусмотрен протоколом обмена. Из-за некоторых моментов в программном коде этой программы и в её настройках у клиента. Это не проверялось и приводило к некритичным последствия, но, тем не менее, не предусматривавшимся. Добавил проверку корректности кода (=номера) команды - сразу же выяснилось, откуда ошибка, о которой речь в первом пункте. ... |
|||
:
Нравится:
Не нравится:
|
|||
01.07.2024, 14:04 |
|
Заметки о Делфи.
|
|
---|---|
#18+
1) Делать обработку ошибок. Когда-то была большая статья или даже пару статей на эту тему в блоге у gunsmoker. Я, если в среднем, то наверное примерно так: в каких-то ключевых процедурах обработку ошибок типа try ...except пишу, но не во всех подряд процедурах и функциях. Недавно была ошибка, причину которой относительно долго не мог найти. Ошибка была у заказчика, у нас в офисе при работе программ в том же (вроде бы) окружении, как у заказчика, не воспроизводилась. И не сразу локализовал: исключение возникало в процедуре, из которой вызывались другие процедуры. Когда добавил обработку ошибок в них, то выяснилось, что ошибка, исключение возникает в одной из них. иначе это совсем лишняя заморочка. для всех других случаев, и особенно для программ выдаваемых на сторону, можно/стоит использовать, в зависимости от приемлемой лицензии - madExcept (например в PL/SQL Developer встроен), EurekaLog (тот же gunsmoker про неё писал) или набор классов того же функционала из jedi (в последних проектах использовал это решение) ... |
|
:
|
|
11.07.2024, 05:48 |
|
Заметки о Делфи.
|
|||
---|---|---|---|
#18+
1) Делать обработку ошибок. Когда-то была большая статья или даже пару статей на эту тему в блоге у gunsmoker. Я, если в среднем, то наверное примерно так: в каких-то ключевых процедурах обработку ошибок типа try ...except пишу, но не во всех подряд процедурах и функциях. Недавно была ошибка, причину которой относительно долго не мог найти. Ошибка была у заказчика, у нас в офисе при работе программ в том же (вроде бы) окружении, как у заказчика, не воспроизводилась. И не сразу локализовал: исключение возникало в процедуре, из которой вызывались другие процедуры. Когда добавил обработку ошибок в них, то выяснилось, что ошибка, исключение возникает в одной из них. иначе это совсем лишняя заморочка. для всех других случаев, и особенно для программ выдаваемых на сторону, можно/стоит использовать, в зависимости от приемлемой лицензии - madExcept (например в PL/SQL Developer встроен), EurekaLog (тот же gunsmoker про неё писал) или набор классов того же функционала из jedi (в последних проектах использовал это решение) Но есть некоторые моменты. Во-первых, если я правильно понял, EurekaLog, может и второе средство тоже, перехватывают исключение на "верхнем" уровне, примерное как Application.HandleException (который вызывает Application.OnException). Но в каких-то ситуациях хотелось бы перехватить и обработать исключение на более "низком" уровне, в процедуре, где оно возникло, чтобы меньше нарушался ход работы приложения. Ну, это может философский вопрос, может тут можно дискутировать. Но вот другой момент имеет отношение к программе, которой я сейчас больше других занимаюсь. Программа существенно многопоточная. Она работает с оборудованием, причем может с несколькими установками (на ряде фабрик так и есть). Работа с каждой установкой выполняется в отдельном потоке. Там идет постоянный сетевой обмен, причем не с одной железкой, что-то выводится в БД, есть реакции на возникновение внешних сигналов и наоборот подача сигналов на переключение устройств и т.д. Плюс ещё ряд потоков, какие-то временно создаваемые и потом удаляющиеся, какие-то относительно долго работающие, разные ситуации. В документации EurekaLog написано, что при работе с доп. потоками, если не обрабатывать исключения, а просто подключить её - это плохой вариант. Хороший вариант - исключения обрабатываются, как положено, а EuricaLog тогда выдаст дополнительную отладочную информацию. Т.е. даже если использовать эти библиотеки, мне все равно нужно как минимум обрабатывать исключения на уровне процедуры TThread.Execute. Да и безотносительно EurecaLog, исключения в потоке нужно обрабатывать в нем. Но там прилично кода, разбитого на ряд процедур и функций и логично на мой взгляд обрабатывать исключения и в них, в частности тогда мы сразу можем более детально локализовать ошибку. В обработчике исключения в лог пишется и имя процедуры, где оно возникло и информация об исключении. И вот до сих пор этого обычно хватало для выявления причин ошибок. Правда во многих случаях была возможность воспроизвести ситуацию в офисе, при работе программы под отладчиком. Мне кажется, что если писать надежный и переносимый код, то обработка возможных ошибок, в том числе исключений - нужная/полезная вещь. Я где-то использую генерацию исключений в случае каких-то нештатных ситуаций. Естественно, в предположении, что или в этой же функции оно будет обработано, или во внешней функции, вызывающей эту. Один из возможных вариантов. Предугадать, где может возникнуть исключение бывает и сложно заранее. Понятно, что где-то обрабатывать исключения нет смысла, например функции win32 API не генерируют исключения, а возвращают коды ошибок. Но зато твой собственный код в функции, где используется API может привести к какому-нибудь исключению. Мне кажется эти библиотеки полезны, но они - не панацея, всё равно стоит обрабатывать ошибки в коде программы. Как-то так. ... |
|||
:
Изменено: 11.07.2024, 21:23 - s62
Нравится:
Не нравится:
|
|||
11.07.2024, 21:12 |
|
Заметки о Делфи.
|
|||
---|---|---|---|
#18+
Как поменять местами закладки (TTabSheet) в TPageControl в design time? Надо открыть Structure view для страницы, там найти PageControl, выделить нужную закладку и наверху есть кнопки - переставить выше или ниже. И в интернете сейчас увидел, и, если не ошибаюсь, сам так когда-то делал, не зная этой возможности - открывал файл формы в текстовом виде и вручную правил его. ... |
|||
:
Изменено: 29.07.2024, 16:25 - s62
Нравится:
Не нравится:
|
|||
29.07.2024, 16:25 |
|
Заметки о Делфи.
|
|||
---|---|---|---|
#18+
Поправка:
Structure view для страницы ... |
|||
:
Изменено: 29.07.2024, 22:47 - s62
Нравится:
Не нравится:
|
|||
29.07.2024, 22:47 |
|
Заметки о Делфи.
|
|||
---|---|---|---|
#18+
Не совсем про Делфи. Надо было из таблицы в программе экспортировать данные в Эксель. Таблица в программе - просто StringGrid, т.е. таблица в окне программы (в программистских обсуждениях называют ещё по переводу с английского - сетка, наверное чтобы не путать с таблицей БД), где в ячейках текст. Раньше не надо видимо было, но недавно коллега, который работает с программой, начал делать там некоторые манипуляции с данными и ему понадобилось переносить их в Эксель. Из этой таблицы кем-то давно было написано сохранение в текстовый файл, визуально похожее на таблицу, но такое, что эксель открыть это не мог. Я сначала подумал про экспорт через OLE, но не захотел делать этот вариант, жестко завязанный на наличие установленного экселя. Решил сделать экспорт в XML - а XML может импортировать и Эксель, и например LibreOffice Calc, что может пригодиться в связи с импортозамещением. Сделал. Но тут коллега пишет, что вот бы через копипаст, как из БД. Под "из БД", как я понял, он понимает - из MS SSMS. Я ему ответил: Цитата [игнорируется] Я посмотрю насчет копирования через буфер обмена. Но там с точки зрения программирования, предполагаю, не так просто, у экселя же свой формат данных. В БД, т.е. в MS SQL Server Management Studio не знаю, как сделано, это же продукт MS. Но почитаю насчет копирования, может не так сложно. http://www.delphikingdom.com/asp/viewitem.asp?catalogid=313 Короче говоря, для экспорта в эксель данных из какой-нибудь таблички можно сделать так. Эксель принимает данные в буфере обмена в формате CSV. Т.е. берем данные, например область, выделенную в таблице. Формируем строку в формате CSV, ячейки разделяем TAB-ом (#9), строки таблицы - LF (#10). отправляем строку в буфер обмена. В Экселе делаем вставку. ... |
|||
:
Изменено: 04.08.2024, 13:52 - s62
Нравится:
Не нравится:
|
|||
02.08.2024, 16:29 |
|
Заметки о Делфи.
|
|||
---|---|---|---|
#18+
Администратор или Горбатый ёж дай пожалуйста модерку на тему, чтобы удобней редактировать и т.п., если что. ... |
|||
:
Изменено: 02.08.2024, 16:32 - s62
Нравится:
Не нравится:
|
|||
02.08.2024, 16:32 |
|
|
start [/forum/topic.php?fid=16&tid=15954]: |
0ms |
get settings: |
20ms |
get forum list: |
10ms |
check forum access: |
3ms |
check topic access: |
3ms |
track hit: |
31ms |
get topic data: |
7ms |
get forum data: |
2ms |
get page messages: |
1767ms |
get tp. blocked users: |
2ms |
others: | 7ms |
total: | 1852ms |
0 / 0 |