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

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

« первая   ‹ предыдущая   1   2   ›  »

Owner и Parent (04.12.2009) #

Многие начинающие Delphi программисты при динамическом создании компонент путаются со свойствами Owner и Parent. Попробую внести некоторую ясность.

Для начала определим, за что же отвечают эти свойства.

  • Parent (TWinControl) - родитель. Задаётся прямым указанием после создания компонента. Отвечает за отрисовку компонента.
  • Owner (TComponent) - владелец. Задаётся при создании компонента, как параметр конструктора Create. Отвечает за удаление компонента. Т.е. при уничтожении компонента, он вызывает уничтожение всех, у которых он указан в качестве владельца.

Среда Delphi, когда программист перетаскивает компоненты с панели компонентов на форму автоматически присваивает создаваемому компоненту владельцем Форму, а родителем тот компонент, на который осуществлено перетаскивание.

Для поиска компонент существуют методы:

  • TComponent.FindComponent(const AName: string): TComponent ищет среди компонент, у которых текущий указан в качестве владельца.
  • TWinControl.FindChildControl(const AName: string): TControl - ищет среди дочерних контролов. Тут необходимо уточнить, что если на панели Panel1, лежит другая панель Panel2, а не ней уже поле ввода EditName, то при вызове Panel1.FindChildControl(EditName) функция вернёт nil. Т.к. для Panel1 дочерним является только Panel2.

Часто удобно именно «динамическое» обращение к компонентам по их имени. Например, когда необходимо установить Enabled у всех TEdit на форме, или только на одной какой-то панели. Или же, только у компонент по списку имён, например, аналогичных названиям полей в запросе из БД. Или, если сохранены имена компонент по умолчания, то по номерам (диапазонам номеров)

Для примера приведу код процедуры, в которой осуществляется выравнивание пар контролов (метка TLabel и поле ввода TEdit) в зависимости от видимости полей ввода. Т.е. на форме, на Panel1 лежат все необходимые поля ввода, но при создании формы в зависимости от параметров часть из них скрывается. Возникла необходимость выровнить остальные по высоте.

  1. procedure TForm1.SetParamPosition;  
  2. var  
  3.   nTopEd, nTopLb: integer;  
  4.   i: integer;  
  5.   st: string;  
  6.   lb, ed: TControl;  
  7. begin  
  8.   // устанавливаем видимые компонеты по высоте.  
  9.   nTopEd := 22;  
  10.   nTopLb := 25;  
  11.   for i := 0 to 5 do  
  12.   begin  
  13.     case i of  
  14.       0: st := 'Group';  
  15.       1: st := 'SubGroup';  
  16.       2: st := 'Code';  
  17.       3: st := 'Name';  
  18.       4: st := 'Spec';  
  19.       5: st := 'Status';  
  20.     end;  
  21.     lb := TControl(FindComponent('lb' + st));  
  22.     ed := Panel1.FindChildControl('ed' + st);  
  23.     if Assigned(lb) and Assigned(ed) then  
  24.     begin  
  25.       lb.Visible := ed.Visible;  
  26.       lb.Top := nTopLb;  
  27.       ed.Top := nTopEd;  
  28.       if ed.Visible then  
  29.       begin  
  30.         nTopEd := nTopEd + ed.Height + 6;  
  31.         nTopLb := nTopLb + ed.Height + 6;  
  32.       end;  
  33.     end;  
  34.   end;  
  35. end;  

Формат mailto (11.01.2010) #

Время от времени мне необходимо открывать почтовую программу с заполненной темой. Такие задачи возникают и при разработке этого сайта, и в работе - при программировании на Delphi. Наверное почти все знают, что чтобы открыть почтовую программу с адресом надо вызвать "mailto:адрес", но у этой команды несколько больше параметров:

mailto:[ mail address ] [?] [subject=subject] [&cc=mail address] [&bcc=mail address] [&body=message body]

mail address — адрес получателя (несколько адресов разделённых запятой)
subject — тема сообщения
cc — копия (copy to)
bcc — скрытая копия (blind copy to)
body — само сообщение

Перевод Фамилии и Имени в транслитерацию (для банковских карт СберБанка) (09.12.2009) #

Возникла необходимость подготовить для Сбербанка список сотрудников нашей компании с указанием написания их фамилий в транслитерации по правилам Сбербанка. Возможно, данный код будет кому-то ещё полезен.

  1. function BankCardTranslit(sFam, sName: string): string;  
  2. var  
  3.   aChar:array [charof string;  
  4.   stFamE, stNameE: string;  
  5.     
  6.   function GetChar(c: char): string;  
  7.   begin  
  8.     Result := '';  
  9.     if (c = 'Ь'or (c = 'Ъ'then Exit;  
  10.     Result := c;  
  11.     if not (c in ['A'..'Z''0'..'9']) then  
  12.       Result := aChar[c];  
  13.   end;  
  14.     
  15.   function ToEnglish(ast: string): string;  
  16.   var i: integer;  
  17.       st: string;  
  18.   begin  
  19.     i := 1; Result := '';  
  20.     while i <= Length(ast) do  
  21.     begin  
  22.       if i < Length(ast) then  
  23.       begin  
  24.         st := ast[i] + ast[i+1];  
  25.         if (st = 'КС'then begin Result := Result+'X'; i := i + 2; Continue; end;  
  26.         if (st = 'ЬЯ'or (st = 'ИЯ'then begin Result := Result + 'IA'; i := i + 2; Continue; end;  
  27.         if (st = 'ИЙ'then begin Result := Result + 'Y'; i := i + 2; Continue; end;  
  28.         if (st = 'ЫЙ'then begin Result := Result + 'YY'; i := i + 2; Continue; end;  
  29.       end;  
  30.       Result := Result + GetChar(ast[i]);  
  31.       Inc(i);  
  32.     end;  
  33.   end;  
  34. begin  
  35.   sFam := Trim(AnsiUpperCase(sFam));  
  36.   sName := Trim(AnsiUpperCase(sName));  
  37.   aChar['А'] := 'A';  
  38.   aChar['Б'] := 'B';  
  39.   aChar['В'] := 'V';  
  40.   aChar['Г'] := 'G';  
  41.   aChar['Д'] := 'D';  
  42.   aChar['Е'] := 'E';  
  43.   aChar['Ё'] := 'E';  
  44.   aChar['Ж'] := 'ZH';  
  45.   aChar['З'] := 'Z';  
  46.   aChar['И'] := 'I';  
  47.   aChar['Й'] := 'Y';  
  48.   aChar['К'] := 'K';  
  49.   aChar['Л'] := 'L';  
  50.   aChar['М'] := 'M';  
  51.   aChar['Н'] := 'N';  
  52.   aChar['О'] := 'O';  
  53.   aChar['П'] := 'P';  
  54.   aChar['Р'] := 'R';  
  55.   aChar['С'] := 'S';  
  56.   aChar['Т'] := 'T';  
  57.   aChar['У'] := 'U';  
  58.   aChar['Ф'] := 'F';  
  59.   aChar['Х'] := 'KH';  
  60.   aChar['Ц'] := 'TS';  
  61.   aChar['Ч'] := 'CH';  
  62.   aChar['Ш'] := 'SH';  
  63.   aChar['Щ'] := 'SHCH';  
  64.   aChar['Ъ'] := '';  
  65.   aChar['Ы'] := 'Y';  
  66.   aChar['Ь'] := '';  
  67.   aChar['Э'] := 'E';  
  68.   aChar['Ю'] := 'YU';  
  69.   aChar['Я'] := 'YA';  
  70.   // поиск имен  
  71.   if sName = 'АЛЕКСАНДР' then stNameE := 'ALEXANDER';  
  72.   if sName = 'ВЯЧЕСЛАВ' then stNameE := 'VJATCHESLAV';  
  73.   if sName = 'ВИКТОР' then stNameE := 'VICTOR';  
  74.   if sName = 'КУЗЬМА' then stNameE := 'KOUZMA';  
  75.   if sName = 'ЛЮБОВЬ' then stNameE := 'LIUBOV';  
  76.   if sName = 'ЛЮДМИЛА' then stNameE := 'LIUDMILA';  
  77.   if sName = 'НАДЕЖДА' then stNameE := 'NADEZDA';  
  78.   if sName = 'ФИЛИПП' then stNameE := 'PHILIPP';  
  79.   if sName = 'ЮЛИЯ' then stNameE := 'JULIA';  
  80.   if sName = 'ЮРИЙ' then stNameE := 'YURI';  
  81.   if sName = 'ЯКОВ' then stNameE := 'IAKOV';  
  82.   
  83.   stFamE := ToEnglish(sFam);  
  84.   if (stNameE = ''then stNameE := ToEnglish(sName);  
  85.   // Проверка допустимой длины: если фамилия длинная, то берем только первую букву имени  
  86.   if (Length(stFamE) + Length(stNameE) + 1) > 19 then stNameE := GetChar(sName[1]);  
  87.   Result := stFamE + ' ' + stNameE;  
  88. end;  

Удаление временных файлов (02.12.2009) #

Для удаления временных файлов в проектах на Delphi я использую приведённый ниже cmd-файл. Чтобы его создать нужно открыть блокнот и скопировать в него предложенный текст, при сохранении файла указать расширение ".cmd", а можно просто скачать мой файл. Так как часто файлы одного проекта для удобочитаемости размещены в нескольких директориях, то этот метод удобнее, чем перечисление директорий руками, так как сработает на любом проекте, достаточно положить этот файл в корневую папку проекта, и при его запуске все временные файлы будут удалены.

del /s *.~* 
del /s *.ddp  rem /s - для удаления в поддиректориях
pause         rem Для того чтобы увидеть результат удаления

Превод числа в формат номера колонки Excel (AB) (02.12.2009) #

То есть числа до 26 переводятся в соответствующие латинские буквы, а большие в две буквы. Использовал при "общении" с Excel для ввода значений калькулируемых полей (например, "=Sum(A1:A7)").

  1. function IntToABC(const aValue:Integer):string;  
  2. var n: integer;  
  3. begin  
  4.   n := aValue; Result := '';  
  5.   if n >= 676 then   
  6.   begin   
  7.     Result:='XX';   
  8.     Exit;   
  9.   end;  
  10.   if n >= 26  then   
  11.   begin   
  12.     Result := Chr(Ord('A') + (n div 26) - 1);   
  13.     n := n mod 26;   
  14.   end;  
  15.   Result := Result + Chr(Ord('A') + n);  
  16. end;  

Чистый номер телефона (11.01.2010) #

Из строки содержащей номер телефона выкидываются все посторонние символы: скобки, дефисы пробелы - всё кроме цифр.

  1. function PhoneNumberSkobkiRemove(ast: string): string;  
  2. var i: integer;  
  3.     st: string;  
  4. begin  
  5.   st := '';  
  6.   for i := 1 to Length(ast) do  
  7.     if (ast[i] in ['0'..'9']) then st := st + ast[i];  
  8.   Result := st;  
  9. end;  

Комментарии

Серёга (24.05.2012)
Очень помогла эта функция в своё время
Рад, что пригодилась.

Выбор имени файла с просмотром списка открытых ранее (08.12.2009) #

Работа организована на стандартных компонентах (TOpenDialog, TComboBox, TButton). TComboBox можно заменить TEdit, но тогда возможно отобразить только имя последнего открытого файла, в то время как ComboBox позволяет выбрать из списка.
Моменты связанные с сохранением списка имён открытых файлов здесь не рассматриваются.

Пример использования:
Пример

Ниже приведён код обработчика события OnClick для кнопки. Обозначения: dlgOpen: TOpenDialog (не забудьте добавить Dialogs в секцию Uses), CBFile:TComboBox.

  1. procedure TForm1.btnOpenDlgClick(Sender: TObject);  
  2. var st: string;  
  3. begin  
  4.   // dlgOpen.FilterIndex := 1; // устанавливаем фильтр если надо  
  5.   if FileExists(CBFile.Text) then // если файл введенный в ComboBox существует  
  6.   begin  
  7.     // настраиваем OpenDialog по нему  
  8.     dlgOpen.InitialDir := ExtractFilePath(CBFile.Text);  
  9.     dlgOpen.FileName := CBFile.Text;  
  10.   end  
  11.   else  
  12.   begin  
  13.     // если файл не найден, то пытаемся установить имя директории из него  
  14.     dlgOpen.FileName := '';  
  15.     st := CBFile.Text;  
  16.     // в цикле удаляем с конца строки текст, до момента нахождения такого пути на диске  
  17.     while not ((DirectoryExists(st)) or (Length(st) = 3or (st = '')) do  
  18.     st := ExtractFileDir(st);  
  19.     if not DirectoryExists(st) then st := '';  
  20.     // если пути такого на диске нет, то указываем в качестве начального путь к программе  
  21.     if st = '' then st := ExtractFilePath(Application.ExeName);  
  22.     // указываем имя начальной директории для OpenDialog  
  23.     dlgOpen.InitialDir := st;  
  24.   end// if  
  25.   // Открываем OpenDialog. Если нажали OK - записываем имя файла в ComboBox  
  26.   if dlgOpen.Execute then  
  27.     CBFile.Text := dlgOpen.FileName;  
  28. end;  

Алгоритм: если нашли файл введённый "руками" в ComboBox, то открываем диалог выбора файла с выбранным этим файлом, если не нашли выбираем ближайшую существующую на диске "родительскую" директорию и открываем диалог. Если пути введённого в ComboBox на диске нет, или ComboBox.Text пустой, то в качестве начальной директории используем путь к программе.

В список ComboBox я добавляю имя нового файла в момент начала работы с файлом. Это позволяет не сохранять пользовательские "блуждания" по диску. Сохранять рекомендую в INI-файлы (не зачем реестр Windows забивать своим хламом) - запись при закрытии окна, чтения при создании.

PS: знаю, что некоторые скажут, есть же библиотеки компонентов, в которых схожие функции реализованы, например, JVCL. Но мне кажется правильнее не использовать "сторонних" компонентов в приложениях, тем более в крупных, т.к. простая перекомпиляция на новом компьютере может занять у вас массу сил и времени.

Сохранение всех исключений (Exception) в файл (11.01.2010) #

Добавляем процедуру аналогичную нижеследующей, где stCompName - имя компьютера, stUserName - имя пользователя программы, или Windows, если необходимо указываем другие параметры. Файл с описанием ошибок создаётся в директории с программой, с расширением ".err". Не забудьте прописать её в любой из секций (например, private) объявления формы.

  1. procedure TForm1.LogException(Sender: TObject; E: Exception);  
  2. var FileName: string;  
  3.     F: TextFile;  
  4. begin  
  5.   FileName := ChangeFileExt(Application.ExeName,'.err');  
  6.   AssignFile(f, FileName);  
  7.   if FileExists(FileName) then Append(f)   
  8.     else Rewrite(f);  
  9.   try  
  10.     Writeln(f, #09, stCompName, #09, stUserName, #09, DateTimeToStr(now), #09, e.ClassName, #09, e.message);  
  11.   finally  
  12.     CloseFile(f);  
  13.   end;  
  14.   Application.ShowException(E);  
  15. end;  

В процедуру создания главной формы приложения (onCreate) добавляем следующую строку (лучше в начале):

  1. Application.OnException := LogException;  

Комментарии

Решение половинчатое. Есть еще и программы без Application (ага - консольные;) или вообще без GUI и консоли). Вообще лучше отдельный логгер написать и использовать, где надо.

« первая   ‹ предыдущая   1   2   ›  »

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