Главная страница  Карта сайта  Печать  Написать письмо  RSS
Войти
Кнопка открытия главного меню
Персональный сайт
Стеллецкого Владимира
Обновлено: 19.11.2022 г.

Программирование на Delphi

«   ‹   1   2   следующая ›   последняя »

Новая программка (19.11.2022) #

Недавно выдалась возможность опять попрограммировать на Delphi (чему был очень рад) - надо было написать небольшую программу для упорядочивания и автоматизации бизнес-процесса основанного на работе пяти отделов компании. И хотя программа получилась довольно небольшая и в целом несложная, её написание заняло почти два месяца (и почти две сотни коммитов в систему контроля версий исходного кода Mercurial/HG, которую стараюсь использовать для всех своих проектов). Правда, учитывая текущую нагрузку и специфику работы (частенько приходится отвлекаться для решения текущих вопросов) это вроде бы не так уж и много.

Главное окно программы (в режиме полного доступа)

К сожалению, даже такую небольшую и вроде бы простую программу пришлось несколько раз почти полностью переделывать: менять структуру базы данных на MS SQL сервере, количество и внешний вид экранных форм и переписывать код. Это было вызвано несколькими значительными корректировками технического задания (ТЗ), которого, как это часто бывает, фактически не было - составлял его сам на основании изучения текущего алгоритма работы и опроса будущих пользователей программы. Но, несмотря на это, при очередном этапе внедрения выявлялись новые "редкие моменты", которые требовали корректировки отдельных частей уже разработанного приложения (и иногда довольно значительной). Всё это дополнительно увеличивало сроки разработки, тестирования и внедрения этой программы.

Заодно решил попробовать показать ребёнку Delphi (для общего развития) и на этом простом примере показать, как на нём пишутся программы. Правда, сначала надо будет посмотреть, как работать с основными компонентами и немного изучить язык Delphi. Посмотрим, что выйдет из этой затеи.

Комментарии

swi, www (19.11.2022)
Всяческих успехов!
Особенно в просвещении подрастающего поколения!!!

PS готов его пообучать рефалу... Хоть это сейчас мало применимо... Но в дальнейшем... кто знает...
А другое мышление при программировании может пригодиться!
Спасибо.
Ещё раз повторюсь, что выйдет из этой затеи пока не ясно.

Касательно обучения РефАлу - предложу, но думаю, что сейчас ему будет тяжелова-то, так как уже изучает параллельно два новых языка: Pascal в школе и Java на курсах по программированию под Android.

Как получить доступ к Private полям класса в другом модуле? (20.05.2021) #

Во время недавнего собеседования, наряду с простыми вопросами по Delphi:

  • Разница между overload и override
  • Разница между Private, Protected, Public и Published
  • Разница между Parent и Owner (см. мою заметку)
  • Зачем нужны Virtual/Dynamic, Abstract и Inherited

Был задан довольно каверзный вопрос, на который, к сожалению, сходу ответить не смог (были только общие предположения):
Как получить доступ к Private полям класса в другом модуле (этот модуль редактировать нельзя)?

В итоге, довольно быстро нашёл две интересные статьи с решением этого вопроса:

И ещё одна статья - Хак №4: Доступ к protected методам, хотя и менее мне полезная (в целом этот подход знал и вроде бы даже использовал).

Ping из программы на Delphi (24.04.2020) #

Столкнулся с простой, на первый взгляд, задачей - надо было определить, что SQL-сервер вообще доступен (прежде чем пытаться к нему подключится, так как у такого подключения большой таймаут). Решил, что сделать это проще всего с помощью команды пинг (ping), и вспомнил, что уже в одном проекте реализовывал подобный функционал с помощью компонента TIdIcmpClient из пакета компонент Indy Clients. Добавил компонент, минимально настроил (фактически только имя сервера прописал). Запускаю - не работает. Выдаёт ошибку:

Project ... raised exception class EIdSocketError with message 'Socket Error # 10013
Access denied.'.

Проверил код - нет, всё правильно. Предположил, что возможно не запускается именно из под Delphi. Запускаю напрямую - тоже не работает. Полез в интернет искать информацию по данной ошибке, а в голове в это время крутится: "Но раньше, в том проекте, работало же!".

Через некоторое время нахожу информацию, что подобная проблема была раньше с Windows 2000 и решалась запуском программы от имени Администратора (были ещё версии про антивирус и файрвол). Запустил от имени Администратора - работает, но меня это не устроило, так как программа должна запускаться у пользователей с обычными правами. Продолжил поиски, в итоге, нашёл информацию, что при написании компонент Indy были использованы RAW сокеты, которые требуют админские права (вероятнее всего их проверку починили в одном из обновлений Microsoft, поэтому раньше работало, а теперь нет).

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

  1. Пришлось исправить несоответствие типов PChar и PAnsiChar, которые при компиляции выдавала установленная у меня Delphi 2010 (объявление переменой pac: PChar; и присвоение phe := GetHostByName(PChar(AIP));).
  2. Переделал процедуру TranslateStringToTInAddr в функцию, чтобы возвращать успешность преобразования имени сервера в его IP-адрес (и добавил проверку возвращаемого значения).

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

PS Получившийся у меня файл можно скачать здесь.

Автообновление приложения (26.12.2012) #

Часто даже довольно опытные разработчики пренебрегают элементарными удобствами в разрабатываемом ими приложении. Одним из таких несомненных удобств является какой-либо механизм автоматического обновления приложения (т.е. доставки новой версии программы пользователю).

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

  • Ручное обновление - подойдет только для самых не ленивых, так как мне очень быстро надоедает такой подход даже при 2-3 пользователях.
    Плюсы: ничего реализовывать не надо.
    Минусы: при выходе очередной версии программы необходимо вручную скопировать ее каждому пользователю (или обучить копированию самого пользователя).
  • Использование ярлыка на запуск из общедоступной папки.
    Плюсы: простота решения - создал ярлык каждому пользователю и готово.
    Минусы: необходимо разрешение на запуск из указанной папки; при наличии довольно большого количества пользователей сложно найти время, когда программа не запускается, чтобы выложить новую версию; приложение каждый раз копируется каждому пользователю, что может создать лишнюю нагрузку на сеть; в случае отсутствия папки (например, из-за сбоя) пользоваться приложением не сможет никто.
  • bat (cmd) файл, централизовано копирующий новую версию. Это своего рода "половинчатое" решение, т.к. во-первых его тоже как-то надо раздать пользователям, подготовить механизм для запуска, а также следует учесть, что и его может понадобиться обновить.
  • Реализация простейшей системы самообновления внутри распространяемой программы. Например:
    {$REGION 'АВТООБНОВЛЕНИЕ'}
    
    function GetUpdatePath: String;
    begin
      Result := '\\fileserver\application$\';
    end;
    
    procedure UpdateApplication;
    var
      FileName, Parametrs: string;
      h: HWND;
    begin
      h := Application.Handle;
      FileName := GetUpdatePath + ExtractFileName(Application.ExeName);
      if not FileExists(FileName) then
        Exit;
      if FileAge(Application.ExeName) = FileAge(FileName) then
        Exit;
    //  MessageDlg('Обновление программы...', mtInformation, [mbOK], 0);
      DeleteFile(Application.ExeName + 'old');
      RenameFile(Application.ExeName, Application.ExeName + 'old');
      CopyFile(PChar(FileName), PChar(Application.ExeName), False);
      ShellExecute(h, 'open', PChar(Application.ExeName), PChar(Parametrs), nil, SW_SHOWNORMAL);
      Application.Terminate;
    end;
    
    {$ENDREGION}
    
  • Отдельная программа обновлятор. На первых порах думаю это излишне сложное решение, оправданное только в случае большого количества дополнительных манипуляций проводимых при обновлении. Из плюсов могу отметить, что однажды реализованный и отлаженный, он практически не изменяется в течение цикла разработки приложения, что с большой вероятностью гарантирует обновление основного приложения.

Комментарии

swi, www (31.12.2012)
bat-файл может только обращаться к другому bat-файлу на сервере. В этом случае его обновлять не понадобится. :)

Обновление проектов из SVN (02.03.2014) #

На работе в качестве системы контроля версий исходного кода для текущих проектов используется Subversion (wiki). На своём компьютере я завел папку Projects, в которой собрал все проекты, с которыми работаю. С ростом количества проектов, возник вопрос автоматизации обновлений из центрального репозитория, и через некоторое время родился данный bat-файл:

@echo off
rem Обновление из репозитория
for %%n in (Project Project4Build Project2) do (
echo %%n
cd %%n
"PathToSVN\svn.exe" update
cd ..
echo. 
)
pause

Отдельно хочу отметить, что при появлении необходимости обновлять еще какой-либо проект (или, например, копию папки для сборки финальной или тестовой версии) все что необходимо, так это прописать имя папки в скобках после for %%n in и все.

PS: Новые проекты планируем вести на Mercurial (wiki) или Git (wiki)

Коварный SET LANGUAGE (03.04.2012) #

Вчера нашли ответ на давно мучившую нас проблему: время от времени у разных пользователей программы, в разных её частях возникала одинаковая ошибка:

"Ошибка преобразования даты или времени из символьной строки."

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

Неприятными моментами была неповторяемость, то есть после переоткрытия приложения всё работало нормально, и то, что запросы, которые вызывали ошибку, отлично выполнялись в редакторе запросов.

Причина ошибки была найдена, как это часто бывает, случайно. Обсуждая новый функционал залезли в один из модулей программы, потом вернулись в обсуждаемый, и тут бац - ошибка. Проанализировав только что открываемые модули нашли ответ: на одной из форм приложения в одном из запросов (TQuery) был примерно такой запрос:

SET LANGUAGE RUSSIAN
SELECT DATENAME(MONTH, GETDATE()) +' '+ CAST(YEAR(GETDATE()) AS Varchar)

Этот приём был использован для получения русского названия месяца, вот только вернуть значение по умолчанию забыли:

SET LANGUAGE US_ENGLISH

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

В среде разработки SQL запросов все отлично выполнялось, так как это была отдельная сессия, а поиску ошибки мешало то, что данный приём был использован всего в нескольких местах и выявить закономерность никак не удавалось.

ScreenShot (21.05.2010) #

Разбирая исходники наткнулся на решении задачки по регулярному сохранению снимков экрана (скриншотов):

procedure TMainForm.tmrScreenShotTimer(Sender: TObject);
var
  bmp: TBitmap;
  st: string;
begin
  bmp := TBitmap.Create;
  try
    bmp.Width := Screen.Width;
    bmp.Height := Screen.Height;
    BitBlt(bmp.Canvas.Handle, 0, 0, Screen.Width, Screen.Height,
           GetDC(0), 0, 0, SRCCOPY);
    st := ComputerName + ' - ' + DateTimeToStr(Now);
    // заменим точки и двоеточия на дефисы, чтобы не было проблем с именем файла.
    st := StringReplace(st, '.', '-', [rfReplaceAll]);
    st := StringReplace(st, ':', '-', [rfReplaceAll]);
    // мало ли сохранить не удастся
    try
      bmp.SaveToFile('\\fileserver\screenshotfolder$\' + st + '.bmp');
    except
    end;
  finally
    bmp.Free;
  end;
end;

GExperts (26.03.2010) #

Думаю, многие начинающие Delphi-программисты не знают о существовании очень удобной надстройки над средой разработки Delphi - GExperts, но я без неё свою работу в Delphi уже не представляю. Надстройка эта стабильная (Delphi с ней не тормозит и не "падает"), бесплатная, есть практически для каждой версии Delphi или C++Builder, а возможностей просто куча. Перечислю только наиболее мной востребованные:

  • Отображение списка всех процедур и функций в модуле с возможностью быстрого поиска по любой части названия и фильтрации по кассам (Ctrl + G);
  • Поиск следующего/предыдущего вхождения текста под курсором в коде (Ctrl + Shift + стрелка вверх/вниз);
  • Диалог для построения сообщений MessageDlg/MessageBox (Ctrl + D);
  • Переход к соответствующему разделителю (Ctrl + Shift + стрелка влево/вправо) - упрощает разбор скобок, кода показывая, где соответствующие, например, begin-end;
  • Комментирование/снятие комментария с выделенного кода (Ctrl + Alt + . / ,).
  • Автозамена (в разделе Code Proofreader). Например, я себе включил замену ":+", ";+" и ";=" на правильные ":=", что существенно ускорило разработку, сократив количество опечаток;
  • Смена регистра выделенного текста (Shift + Alt + C), правда в этом мне помогает ещё и Punto Switcher;
  • Библиотека частоиспользуемого кода;
  • Просмотр классов проекта;
  • Очистка директорий проекта от временных файлов и многое другое.

«   ‹   1   2   следующая ›   последняя »

  Вы 29 888 посетитель этой странички
с 02 марта 2006 года
© http://svv-home.ru
О сайте