Советы по Delphi

         

FAQ 5 VCL (2 из 2)


"Какой объем текста может содержать компонент Delphi Memo?"

Элементы редактирования Microsoft, интегрированные в Windows и применяющиеся в Delphi компонентах-обертках TEdit и TMemo, имеют ограничение по объему текста, равное 32К. Delphi классы-оболочки имеют специальный механизм, позволяющий каждому элементу управления типа Edit или Memo, размещенному на форме, содержать до 32К текста. При нормальной ситуации суммарный предел всех элементов редактирования приложения ограничен 32К.

"Как мне сделать так, чтобы определенное поле в компоненте TGrid не выводилось?"

Это может быть сделано с помощью простого удаления поля из списка полей Fields Editor или установки свойства поля Visible в False.

"Существует ли способ задания заднего фона в виде изображений в приложениях MDI?"

Существует демонстрационный пример, показывающий как это можно сделать, он расположен в секции VCL (5) форума Delphi под именем MDI_BGRD.ZIP.

"Существует ли в Delphi денежный компонент?"

Нет, но существует компонент редактирования денежных сумм в секции VCL форума Delphi под именем CURREDIT.ZIP.

"Где мне найти информацию о типах данных VBX (например, TBasicString) и функции для работы с ними?"

Во-первых, все поддерживаемые типы данных VBX и функции для работы с ними находятся в модуле VBXCtrls, но он хранится в виде объектного файла. Тем не менее, Delphi имеет секцию интерфейса данного модуля, находящуюся в каталоге \DELPHI\DOC под именем VBXCTRLS.INT. Реально это единственный источник информации о содержании модуля VBXCtrls.

"Какие вопросы я должен учесть при создании приложения, ориентированного на работу при различных разрешениях экрана (масштабирование форм)?"

При разработке приложения для различных режимов разрешения вам необходимо учитывать следующие рекомендации:

  • Заранее, в самом начале этапа разработки, решите для себя - собираетесь ли вы разрешать масштабировать форму или нет. Преимущество запрета масштабирования в том, что вам ничего не нужно менять во время выполнения приложения. Недостаток запрета масштабирования - во время выполнения приложения никаких изменений не происходит (ваша форма может быть слишком малой или слишком большой для работы в некоторых режимах при отсутствии масштабирования).
  • Если вы НЕ собираетесь масштабировать форму, установите свойство Scaled в False.
  • В противном случае, установите свойство формы Scaled в True.


  • Установите AutoScroll в False. AutoScroll = True означает 'не изменять размер окна формы во время выполнения приложения', что приводит к "плохому виду" формы, если ее содержимое меняет размер.
  • Установите шрифты формы в масштабируемые TrueType-шрифты типа Arial. MS San Serif также подойдет в качестве альтернативы, только помните, это не TrueType, а bitmapped-шрифт. Только Arial может правильно изменять свою высоту с дискретностью 1 пиксел. Примечание: Если используемый шрифт не установлен на машине пользователя, Windows выбирает альтернативный шрифт из данной линейки (семьи) шрифтов. Размеры нового шрифта могут отличаться от размеров оригинального шрифта, что также может вызвать проблемы.
  • Установите свойство формы Position во что-нибудь другое, чем poDesigned. poDesigned всегда показывает форму в первозданном виде, и, если форма разрабатывалась в разрешении 1280x1024, то вы можете себе представить, что будет при разрешении 640x480?
  • Не "слепляйте" на форме элементы управления, оставляйте между ними, по крайней мере, 4 пикселя, в противном случае, при изменении месторасположения границы на 1 пиксель (это происходит при масштабировании), элементы управления наедут друг на друга.
  • Для однострочных компонентов Label, у которых свойство Aligned равно alLeft или alRight, установите AutoSize в True. В противном случае, установите AutoSize в False.
  • Убедитесь в том, что компоненты Label имеют достаточный запас по ширине (требуется, примерно, 25%) от длины текущего текста. (При переводе вашего приложения на другие языки вам необходимо примерно 30%-ный запас от текущей ширины текста). Если AutoSize - False, убедитесь, что ширины компонента Label достаточно для размещения реального текста. Если AutoSize - True, убедитесь, что на компоненту Label достаточно места (например, на форме) для размещения всего текста плюс небольшой запас для его роста при смене шрифтов.
  • В случае многострочного текста и компонентов Label с переносом слов, убедитесь, что в нижней части у вас имеется, по крайней мере, еще одна строчка. Она необходима вам для того, чтобы не допустить переполнения строки, если размер шрифта увеличивается при масштабировании. Не думайте, что, если вы используете большие шрифты и переполнения не возникает, то эта проблема снята - кто-нибудь может использовать шрифты с еще большим размером, чем у вас!
  • Будьте осторожными при открытии проекта в IDE с другим разрешением. Свойство формы PixelsPerInch будет изменено как только вы откроете форму, и сохранено в DFM-файле при сохранении проекта. Лучше всего запускать приложение отдельно от IDE, а редактировать его при одном разрешении. Редактируя формы при различных разрешениях и размерах шрифтов, вы инициируете проблему "дрейфа" компонентов по форме и изменения их размера.
  • Говоря о дрейфе компонент, не следует многократно масштабировать форму, как во время разработки, так и во время выполнения приложения. Каждое изменение размеров сопровождается ошибками округления, которые достаточно быстро накапливаются с тех пор, как координаты стали строго целочисленными. Поскольку при калькулировании новых размеров дробная часть отбрасывается, вновь пересчитанные размеры оказываются меньше, а координаты элементов управления северо-западнее. Если вы решили разрешить пользователю изменять масштабы форм, начинайте масштабирование с последней загруженной/созданной формы, этим вы уменьшите накапливаемые при масштабировании ошибки.
  • Старайтесь не изменять значение свойства формы PixelsPerInch.
  • В общих словах, нет необходимости разрабатывать формы для всех возможных режимов, перед окончательным релизом вашего приложения вы должны оценить поведение формы в пограничных режимах - 640x480 с маленькими и большими шрифтами, и при высоком разрешении и, также, с маленькими и большими шрифтами. Это должно быть частью ваших регулярных проверок на предмет системной совместимости, для ведения так называемой тестирующей контрольной таблицы.
  • Обратите пристальное внимание на "однострочные компоненты TMemo" - типа TDBLookupCombo. Системные многострочные редакторы всегда выводят только целые строки текста - если ширина элемента управления слишком мала для своего шрифта, то TMemo вообще ничего не показывает (TEdit показывает обрезанный текст). Размер таких компонентов лучше сделать на несколько пикселей больше, чем на несколько пикселей меньше, тем самым можно определеть наличие в компоненте оставшейся части текста.
  • Обратите внимание на то, что масштабирование во время проектирования и во время выполнения программы отличается коэффициентом и зависит от высоты шрифта, а не от экранного разрешения в пикселях. Помните также, что "начало" компонент будет изменяться в зависимости от масштаба формы, и для их "броуновского" движения также необходимо небольшое пространство.
"Как мне избавиться от заставки ReportSmith при запуске генерации моего отчета?"

Добавьте следующую строку в секцию [RS_RunTime] файла RS_RUN.INI, это позволит избежать появления логотипа при запуске ReportSmith: ShowAboutBox=0 "Как мне создать окно с несколькими секциями изменяемого размера?"

Следующие шаги помогут вам создать простое окно с несколькими секциями.

  1. Разместите на форме компонент Memo и установите его свойство Align в alTop.
  2. Разместите на форме панель и установите ее свойство Align в alTop.
  3. Установите у панели свойство Height в величину 6 или 7.
  4. Установите у панели свойство DragMode в dmAutomatic.
  5. Установите у панели свойство DragCursor в crVSplit.
  6. Установите у панели свойство Cursor в crVSplit.
  7. Добавьте на форму другой компонент Memo и установите его свойство Align в alClient.
  8. Создайте общий для компонентов Memo и Panel обработчик события OnDragOver как показано ниже:

    procedure TForm1.Memo1DragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean); begin Accept := False; if Source = Panel1 then begin Accept := True; Memo1.Height := Y + (Sender as TControl).Top; end; end;

"Как мне определить текущую колонку и строку курсора в компоненте TMemo?

C помощью сообщений Windows API EM_LINEFROMCHAR и EM_LINEINDEX вы можете определить строку и положение курсора в строке (начало SelStart):

    var LineNum: longint; CharsBeforeLine: longint; begin LineNum := SendMessage(Memo1.Handle, EM_LINEFROMCHAR, Memo1.SelStart,0); CharsBeforeLine := SendMessage(Memo1.Handle, EM_LINEINDEX, LineNum, 0); Label1.Caption := 'Строка ' + IntToStr(LineNum +1) Lebel2.Caption := 'Позиция ' + IntToStr((Memo1.SelStart - CharsBeforeLine) + 1); end;

Как мне получить количество пикселей на дюйм, поддерживаемое принтером?

Если необходима величина в пикселах, можно воспользоваться API функцией GetDeviceCaps(). Для примера:

    VertPixelsPerInch := GetDeviceCaps(Printer.Handle, LogPixelsX); HorzPixelsPerInch := GetDeviceCaps(Printer.Handle, LogPixelsY);

"Возможно ли хранение целочисленной величины вместе со строкой в объекте списка TString или каком-либо свойстве?"

Да, но это потребует некоторых преобразований типов. Компонент TString вместе с массивом строк имеет массив объектов, который может использоваться с целью хранения целочисленных данных: типом данных для массива объектов служит TObject. В сущности, он хранит значение указателя размером 4 байта. Поэтому для хранения в нем целочисленной величины необходимо приведение типа значения. Для примера, следующий код добавляет строку и целое число 100 к свойству items (объект TString) компонента Listbox:

    Listbox1.Items.AddObject('Текстовая строка', TObject(100));

Для получения значения сделайте следующее:

    Result := LongInt( Listbox1.Items.Objects[0] );

Здесь подразумевается, что Result имеет тип Longint и значение хранится в объекте с индексом 0.

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

Если вам необходимо хранить более одного значения, создайте новый, производный от TObject, класс и сделайте необходимые объявления:

    type ManyValues = class(TObject) Value1 : Integer; Value2 : Integer; end; ...

Возможно ли получить доступ к компонентам по их имени (например, 'SpeedButton' + IntToStr(i) )?

Да, это возможно. Следующий пример использует метод FindComponent формы Form1 для выключения первых 10 компонентов SpeedButton по их имени.

    for I := 1 to 10 do with Form1.FindComponent('SpeedButton' + IntToStr(i)) as TSpeedButton do Enabled := False;

Как вы создаете 'модальную' форму в MDI-приложении? Когда мое приложение вызывает метод ShowModal, я получаю ошибку "Can't Show Modal when Visible is set true" (не могу показать в модальном режиме, поскольку свойство видимости установлено в истину). При попытке установить Visible в False, я получаю ошибку с сообщением о том, что на дочерней MDI форме я не могу установить свойство Visible в False.

По технологии, первая форма проекта (главная форма) создается со свойством Visible, установленным в True, а все остальные формы при создании имеют свойство Visible, установленное в False. С другой стороны, дочерняя MDI форма не может быть невидимой, поэтому ее свойство Visible установлено в True. Когда вы изменяете стиль формы на fsNormal, свойство Visible имеет значение True, поэтому в False его необходимо установить вручную.

Возможно ли изменения размера шрифта компонентов, размещенных на форме, задаваемого по умолчанию?

Просто добавьте форму с установленным по желанию свойством Font в галерею. Причина: располагаемые на форме компоненты рефлекторно принимают настройки шрифта родительской формы. Кроме того, вы можете установить вашу новую форму как главную форму по умолчанию и также поместить ее в галерею (Options | Gallery...).

Как мне определить каталог, из которого запущено мое приложение?

Следующая функция извлекает путь из свойства ExeName глобального объекта Application:

    function GetExePath : String; var LastBackSlashPos, Index : Integer; begin Result := Application.ExeName; for Index := 1 to length(Result) do if Result[Index] = '\' then LastBackSlashPos := Index; { вычитаем 1 для невключения последней косой черты } Result[0] := chr(LastBackSlashPos - 1); end;

Как мне изменить Font.Style на нормальный после вызова Canvas.Font.Style := [fsBold]? В справке указаны стили ([fsBold],[fsItalic] и др.], но не указан нормальный стиль.

Просто определите пустое множество для набора стилей:

    Canvas.Font.Style := [];

или просто исключите стиль жирного шрифта следующим образом:

    Canvas.Font.Style := Canvas.Font.Style - [fsBold];

Как мне совершить некоторые действия после того, как форма будет нормально показана? Похоже, что все события формы (OnCreate, OnPaint и др.) происходят еще до того, как форма станет видимой.

В обработчике события OnPaint вы можете добавить "Visible := True" и делать все что хотите.

В каком количестве компоненты используют GDI ресурсы?

Потомки TGraphicControl типа TLabel и TBevel не используют свободные системные ресурсы вообще. Используют их потомки TWinControl типа TEdit и TPanel. Также каждая радио-кнопка в TRadioGroup является окном, т.е. имеет дескриптор окна.

Почему TTabbedNotebook использует так много системных ресерсов, если в отдельный момент видна только одна его страница?

Даже если показывается только одна страница, все остальные страницы со всеми надлежащими компонентами также уже созданы, расходуя при этом системные ресурсы. Этому есть одно решение: вместо использования страниц NoteBook используйте для каждой страницы отдельные формы, которые создаются и уничтожаются в зависимости от щелчка пользователя на соответствующей закладке. Вот основные шаги для достижения цели:

Во-первых, каждой дочерней форме необходимо задать ее параметры создания как показано ниже:

    ... private { Private declarations } PROCEDURE CreateParams(VAR Params: TCreateParams); override; ... procedure TForm2.CreateParams(VAR Params: TCreateParams); begin Inherited CreateParams(Params); with Params do begin WndParent := Application.MainForm.Handle; Style := (Style OR WS_CHILD) AND NOT (WS_POPUP); end; end;

Свойство дочерней формы BorderStyle должно быть установлено в bsNone. В главной форме создайте закрытое поле данных с типом TForm. Инициализируйте его при наступлении события OnActivate, НЕ OnCreate. Теперь при каждом щелчке на закладке "смены страниц" освобождаем текущую дочернюю форму и создаем новую необходимого типа. Например, при наступлении события OnActivate:

    Child := TForm2.Create(Self); with Child do begin Parent := Self; Align := alClient; Visible := True; end;

Когда вы создаете дочернюю страницу при нажатиях на закладках, делайте это так, как показано выше. Естественно, вам понадобиться использовать главную форму для хранения данных о состоянии элементов управления дочернего окна, поскольку при его освобождении данные теряются.

Как мне отменить выбор одного или нескольких элементов в компоненте Listbox или ComboBox?

    Listbox1.ItemIndex := -1;

Почему, при вызове диалогового окна, например, MessageBox(), из обработчика события OnExit, мерцающий курсор исчезает при закрытии диалога?

Это стандартное поведение Windows. Форсирование дополнительного изменения фокуса (например, с помощью ShowMessage) в течение обработки события, связанного с фокусом, (например, OnExit) может вызвать непредсказуемые действия со стороны Windows. Это Windows, которое управляет передачей фокуса, и это Windows, которое может вызвать неадекватную реакцию, если вы заставляете его изменить фокус в середине этого процесса.

Почему я получаю исключительную ситуацию 'EInvalidOperation: Cannot make a visible window modal' (не могу сделать модальное окно видимым), если я открываю форму с помощью метода Showmodal? Форма при этом не открывается.

Убедитесь, что свойство формы Visible не устанавливается в True во время проектирования или во время выполнения программы. [000894]



Содержание раздела