Главная страница  Карта сайта  Печать  Написать письмо  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 лежат все необходимые поля ввода, но при создании формы в зависимости от параметров часть из них скрывается. Возникла необходимость выровнить остальные по высоте.

procedure TForm1.SetParamPosition;
var
  nTopEd, nTopLb: integer;
  i: integer;
  st: string;
  lb, ed: TControl;
begin
  // устанавливаем видимые компонеты по высоте.
  nTopEd := 22;
  nTopLb := 25;
  for i := 0 to 5 do
  begin
    case i of
      0: st := 'Group';
      1: st := 'SubGroup';
      2: st := 'Code';
      3: st := 'Name';
      4: st := 'Spec';
      5: st := 'Status';
    end;
    lb := TControl(FindComponent('lb' + st));
    ed := Panel1.FindChildControl('ed' + st);
    if Assigned(lb) and Assigned(ed) then
    begin
      lb.Visible := ed.Visible;
      lb.Top := nTopLb;
      ed.Top := nTopEd;
      if ed.Visible then
      begin
        nTopEd := nTopEd + ed.Height + 6;
        nTopLb := nTopLb + ed.Height + 6;
      end;
    end;
  end;
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) #

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

function BankCardTranslit(sFam, sName: string): string;
var
  aChar:array [char] of string;
  stFamE, stNameE: string;
  
  function GetChar(c: char): string;
  begin
    Result := '';
    if (c = 'Ь') or (c = 'Ъ') then Exit;
    Result := c;
    if not (c in ['A'..'Z', '0'..'9']) then
      Result := aChar[c];
  end;
  
  function ToEnglish(ast: string): string;
  var i: integer;
      st: string;
  begin
    i := 1; Result := '';
    while i <= Length(ast) do
    begin
      if i < Length(ast) then
      begin
        st := ast[i] + ast[i+1];
        if (st = 'КС') then begin Result := Result+'X'; i := i + 2; Continue; end;
        if (st = 'ЬЯ') or (st = 'ИЯ') then begin Result := Result + 'IA'; i := i + 2; Continue; end;
        if (st = 'ИЙ') then begin Result := Result + 'Y'; i := i + 2; Continue; end;
        if (st = 'ЫЙ') then begin Result := Result + 'YY'; i := i + 2; Continue; end;
      end;
      Result := Result + GetChar(ast[i]);
      Inc(i);
    end;
  end;
begin
  sFam := Trim(AnsiUpperCase(sFam));
  sName := Trim(AnsiUpperCase(sName));
  aChar['А'] := 'A';
  aChar['Б'] := 'B';
  aChar['В'] := 'V';
  aChar['Г'] := 'G';
  aChar['Д'] := 'D';
  aChar['Е'] := 'E';
  aChar['Ё'] := 'E';
  aChar['Ж'] := 'ZH';
  aChar['З'] := 'Z';
  aChar['И'] := 'I';
  aChar['Й'] := 'Y';
  aChar['К'] := 'K';
  aChar['Л'] := 'L';
  aChar['М'] := 'M';
  aChar['Н'] := 'N';
  aChar['О'] := 'O';
  aChar['П'] := 'P';
  aChar['Р'] := 'R';
  aChar['С'] := 'S';
  aChar['Т'] := 'T';
  aChar['У'] := 'U';
  aChar['Ф'] := 'F';
  aChar['Х'] := 'KH';
  aChar['Ц'] := 'TS';
  aChar['Ч'] := 'CH';
  aChar['Ш'] := 'SH';
  aChar['Щ'] := 'SHCH';
  aChar['Ъ'] := '';
  aChar['Ы'] := 'Y';
  aChar['Ь'] := '';
  aChar['Э'] := 'E';
  aChar['Ю'] := 'YU';
  aChar['Я'] := 'YA';
  // поиск имен
  if sName = 'АЛЕКСАНДР' then stNameE := 'ALEXANDER';
  if sName = 'ВЯЧЕСЛАВ' then stNameE := 'VJATCHESLAV';
  if sName = 'ВИКТОР' then stNameE := 'VICTOR';
  if sName = 'КУЗЬМА' then stNameE := 'KOUZMA';
  if sName = 'ЛЮБОВЬ' then stNameE := 'LIUBOV';
  if sName = 'ЛЮДМИЛА' then stNameE := 'LIUDMILA';
  if sName = 'НАДЕЖДА' then stNameE := 'NADEZDA';
  if sName = 'ФИЛИПП' then stNameE := 'PHILIPP';
  if sName = 'ЮЛИЯ' then stNameE := 'JULIA';
  if sName = 'ЮРИЙ' then stNameE := 'YURI';
  if sName = 'ЯКОВ' then stNameE := 'IAKOV';

  stFamE := ToEnglish(sFam);
  if (stNameE = '') then stNameE := ToEnglish(sName);
  // Проверка допустимой длины: если фамилия длинная, то берем только первую букву имени
  if (Length(stFamE) + Length(stNameE) + 1) > 19 then stNameE := GetChar(sName[1]);
  Result := stFamE + ' ' + stNameE;
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)").

function IntToABC(const aValue:Integer):string;
var n: integer;
begin
  n := aValue; Result := '';
  if n >= 676 then 
  begin 
    Result:='XX'; 
    Exit; 
  end;
  if n >= 26  then 
  begin 
    Result := Chr(Ord('A') + (n div 26) - 1); 
    n := n mod 26; 
  end;
  Result := Result + Chr(Ord('A') + n);
end;

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

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

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

Комментарии

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

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

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

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

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

procedure TForm1.btnOpenDlgClick(Sender: TObject);
var st: string;
begin
  // dlgOpen.FilterIndex := 1; // устанавливаем фильтр если надо
  if FileExists(CBFile.Text) then // если файл введенный в ComboBox существует
  begin
    // настраиваем OpenDialog по нему
    dlgOpen.InitialDir := ExtractFilePath(CBFile.Text);
    dlgOpen.FileName := CBFile.Text;
  end
  else
  begin
    // если файл не найден, то пытаемся установить имя директории из него
    dlgOpen.FileName := '';
    st := CBFile.Text;
    // в цикле удаляем с конца строки текст, до момента нахождения такого пути на диске
    while not ((DirectoryExists(st)) or (Length(st) = 3) or (st = '')) do
    st := ExtractFileDir(st);
    if not DirectoryExists(st) then st := '';
    // если пути такого на диске нет, то указываем в качестве начального путь к программе
    if st = '' then st := ExtractFilePath(Application.ExeName);
    // указываем имя начальной директории для OpenDialog
    dlgOpen.InitialDir := st;
  end; // if
  // Открываем OpenDialog. Если нажали OK - записываем имя файла в ComboBox
  if dlgOpen.Execute then
    CBFile.Text := dlgOpen.FileName;
end;

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

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

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

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

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

procedure TForm1.LogException(Sender: TObject; E: Exception);
var FileName: string;
    F: TextFile;
begin
  FileName := ChangeFileExt(Application.ExeName,'.err');
  AssignFile(f, FileName);
  if FileExists(FileName) then Append(f) 
    else Rewrite(f);
  try
    Writeln(f, #09, stCompName, #09, stUserName, #09, DateTimeToStr(now), #09, e.ClassName, #09, e.message);
  finally
    CloseFile(f);
  end;
  Application.ShowException(E);
end;

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

  Application.OnException := LogException;

Комментарии

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

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

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