Created using
htm2chm 3.0

Download it NOW!


Вопросы и Ответы

1. | Как отобразить растровое изображение, чтобы определенный его цвет был "прозрачным"?
2. | Как вставить растровое изображение в компонент TListBox?
3. | Можно ли получить горизонтальную полосу прокрутки в компоненте TListBox?
4. | Как определить при разработке компонента в какой стадии он находится, в стадии проектирования или в стадии выполнения?
5. | Можно ли из Delphi рисовать в любой части экрана или в чужом окне?
6. | Как определить количество свободной памяти?
7. | При выполнении длинного цикла происходит останов Windows. Как этого избежать?
8. | Можно ли при обработке нажатий нескольких кнопок обойтись одним обработчиком события?
9. | В каких случаях и для чего нужно поле Tag?
10. | Как считать состояние и программно переключить Caps Lock, Num Lock и Scroll Lock?
11. | Можно ли в Delphi вывести строку повернутую под любым углом?
12. | Как одной процедурой осуществить вывод и в окно и на принтер?
13. | Где находятся системные иконки Windows используемые в диалоговых окнах типа MessageDlg?
14. | Как используя поля Hint создать строку подсказки?
15. | Возможно ли в компоненте TMemo отменить неверно произведенные действия при редактировании текста?
16. | Почему не получается создать окно StayOnTop (всегда наверху)?
17. | Как определить работает ли уже данное приложение или это первая его копия?
18. | Можно ли в Delphi создать хранитель экрана совместимый со стандартными хранителями Windows?
19. | Как заполнить форму кистью с растровым изображением?
20. | Возможно ли в среде Delphi открыть еще одно окно редактора?
21. | Как получить
22. | Как заполнить форму ЛЮБЫМ растровым изображением?
23. | Для API функций необходим формат строк типа PChar. Как его получить из строк типа String?
24. | Можно ли получить позицию курсора в компоненте TMemo?
25. | Несколько удобных функций для ввода и вывода строки.
26. | Как получить растровое изображение формы?
27. | Почему при запуске MDI приложения автоматически создается дочерняя форма?
28. | При создании проекта появляется много различных файлов. Что это за файлы?
29. | Как преобразовать в текст содержимое переменных любого типа, причем, тип и их количество заранее не известно?
30. | Какие файлы, кроме EXE, нужны для работы откомпилированной программы на компьютере, где пакет Delphi не установлен?
31. | Можно ли нарисовать курсор мыши как обычную картинку?
32. | Как во время работы приложения загружать новый шрифт?
33. | Существет ли способ ограничения максимального и минимального размера окна?
34. | Как получить список доступных шрифтов?
35. | Как использовать метку (TLabel) для передачи фокуса объекту?
36. | Каким образом работать с иконками расположенными в панели задач Win'95?
37. | Как получить данные из COM порта?
38. | Как из приложения получить псевдонимы DBE, определенные в Database Engine Configuration?
39. | Почему при нажатии на кнопку TBitBtn происходит закрытие формы?
40. | После установки Delphi 2 перестала правильно работать справка в первой версии Delphi. Что делать?
41. | Как изменить цвет ячейки TDBGrid в зависимости от текущего значения?
42. | Можно ли изменить величину табуляции в TMemo?
43. | Как в приложении узнать версии Windows и DOS?
44. | Как определить работает ли уже данное приложение или это первая его копия?
45. | Можно ли заставить Database Desktop отображать в таблицах русские символы?
46. | Возможно ли определить общую ширину всех видимых полей TDBGrid во время работы приложения?
47. | Как установить часы компьютера?
48. | Как определить какие приложения уже запущены?
49. | Можно ли убрать окно с экрана и из панели задач?
50. | Почему происходит искажение некоторых русских символов в таблице Paradox?
51. | Можно ли программно установить произвольную строку в первую позицию TListBox?
52. | Как отключить обработку ошибок самой средой Delphi?
53. | Есть ли возможность перевести сообщения которые выдаются во время выполнения на те или иные ситуации?
54. | Как представить число его прописным эквивалентом?
55. | Можно ли получить растровое изображение формы с заголовком и рамкой?
56. | Как вызвать Pop-Up меню не используя правую кнопку мыши?
57. | Несколько советов по компиляции и отладке приложений.
58. | Как заставить перерисоваться весь экран?
59. | Как создать кнопку во время работы приложения?


Вопрос и Ответ 1

Вопросы и Ответы

      1. Как отобразить растровое изображение, чтобы определенный его цвет был "прозрачным"?

      Эффект "прозрачного" фона достигается методом BrushCopy объекта Canvas:

      Пример:

      В качестве фонового, для изображения, цвета выбирается цвет его левой нижней точки (именно эта точка является "фоновой" при рисовании глифов для кнопок в Delphi).

      ............

      BrushCopy(Bounds(10, 10, Bitmap.Width, Bitmap.Height), Bitmap, Bounds(0, 0, Bitmap.Width, Bitmap.Height), Bitmap.Canvas.Pixels[0, Bitmap.Height - 1]);

      ............

...последняя страница следующая...
оглавление


Вопросы и Ответы

      2. Как вставить растровое изображение в компонент ListBox?

      Для этого необходимо установить в инспекторе объектов поле Style в lbOwnerDrawFixed, при фиксированной высоте строки, или в lbOwnerDrawVariable, при переменной, и установить собственный обработчик события для OnDrawItem. В этом обработчике и надо рисовать растровое изображение.

      Пример:

      Рисуются изображения размером 32*16 (размер стандартного глифа для Delphi). Очень полезно при поиске нужного изображения для кнопок!

      Установить в инспекторе объектов для ListBox поле ItemHeight = 19, а поле Color = clBtnFace.

      ............

      {
    Загрузить список файлов в ListBox1 при нажатии на
    кнопку Load (например)}
procedure TForm1.bLoadClick(Sender: TObject);
VAR S : String;
begin

        ListBox1.Clear;{чистим список}
S := '*.bmp'#0; {задаем
      шаблон}
ListBox1.Perform(LB_DIR, DDL_ReadWrite,
      Longint(@S[1])); {заполняем список}

      end;

      ............

      {Отобразить
    изображения и имена файлов в ListBox}
procedure TForm1.ListBox1DrawItem(Control: TWinControl;
    Index: Integer; Rect: TRect; State: DrawState);
VAR

        Bitmap
      : TBitmap;
Offset : Integer;
BMPRect: TRect;

      begin

        WITH (Control AS TListBox).Canvas DO BEGIN

          FillRect(Rect);
          Bitmap := TBitmap.Create;
          Bitmap.LoadFromFile(ListBox1.Items[Index]);
          Offset := 0;
          IF Bitmap <> NIL THEN BEGIN

            BMPRect
          := Bounds(Rect.Left+2, Rect.Top+2, (Rect.Bottom-Rect.Top-2)*2, Rect.Bottom-Rect.Top-2);
{StretchDraw(BMPRect, Bitmap); Можно просто
          нарисовать, но лучше сначала убрать фон}
BrushCopy(BMPRect,Bitmap, Bounds(0, 0, Bitmap.Width,
          Bitmap.Height), Bitmap.Canvas.Pixels[0, Bitmap.Height-1]);
Offset := (Rect.Bottom-Rect.Top+1)*2;

          END;
          TextOut(Rect.Left+Offset, Rect.Top, ListBox1.Items[Index]);
          Bitmap.Free;

        END;

      end;

      ............

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

...предыдущая страница следующая...


Вопрос и Ответ 3

Вопросы и Ответы

      3. Можно ли получить горизонтальную полосу прокрутки в компоненте ListBox?

      Можно. Для этого компоненте ListBox в нужный момент посылается сообщение LB_SetHorizontalextent, указывающее на необходимость отобразить горизонтальную полосу прокрутки.

      Пример:

      ............

      ListBox1.Perform(LB_SetHorizontalextent, 400, Longint(0));

      ............

      где:

        400 - размер области прокручивания в пикселах,
        Longint(0) - параметр не используется.


Вопрос и Ответ 4

Вопросы и Ответы

      4. Как определить при разработке компонента в какой стадии он находится, в стадии проектирования или в стадии выполнения?

      Все компоненты являются наследниками класса TComponent и обладают свойством ComponentState. Данное свойство содержит набор значений, указывающих на текущее состояние компонента.

      Флаг | Состояние компонента
csDesigning | Компонент находится в стадии проектирования.
csDestroying | Компонент сейчас будет разрушен.
csLoading | Компонент загружается из файла формы.
csReading | Компонент считывает значения своих свойств из потока.
csWriting | Компонент записывает значения своих свойств в поток.

      Пример:

      ............

      if cdDesigning in ComponentState then begin

        ............

      end
      else begin

        ............
        end

      ............

      Необходимость узнать, в какой стадии находится компонент, возникает при большом объеме отображаемых данных или при их сложности, что делает проектирование более удобным. Некоторые компоненты должны срабатывать только на стадии выполнения, иначе последствия могут быть самыми неожиданными, например при работе компонент с портами COM и LPT.

      Так же, в последнее время, появились двигающиеся по форме компоненты. Всякие летающие рисунки и надписи. И те компоненты которые не проверяют ComponentState бывает довольно сложно поймать и (удалить) отредактировать, да и под ногами они путаются...


Вопрос и Ответ 5

Вопросы и Ответы

      5. Можно ли из Delphi рисовать в любой части экрана или в чужом окне?

      Для этого надо воспользоваться функциями API. Получить контекст чужого окна, либо всего экрана:

      function GetDC(Wnd: HWnd): HDC;

      где Wnd - указатель на нужное окно, или 0 для получения контекста всего экрана.

      И далее, пользуясь функциями API, нарисовать все что надо.

      Пример:

      ............

      PROCEDURE DrawOnScreen;
      VAR ScreenDC: hDC;
      BEGIN

        ScreenDC := GetDC(0); {получить контекст экрана}
Ellipse(ScreenDC, 0, 0, 200, 200); {нарисовать}
ReleaseDC(0,ScreenDC); {освободить
      контекст}

      END;

      ............

      Не забывайте после своих манипуляций посылать пострадавшим (или всем) окнам сообщение о необходимости перерисовки, для восстановления их первоначального вида.


Вопрос и Ответ 6

Вопросы и Ответы

      6. Как определить количество свободной памяти?

      Для определения количества свободной физической памяти в байтах можно использовать функцию:

      function MemAvail: LongInt;

      но чаще всего, интерес представляет не количество свободных байт, а количество свободных системных ресурсов. Даже при почти полностью свободной памяти может не хватить, этих самых, системных ресурсов.

      Для определения количества свободных системных ресурсов в процентах используется функция GetFreeSystemResources:

      function GetFreeSystemResources(SysResource: Word): Word;

      Параметр SysResource | Описание
GFSR_SYSTEMRESOURCES | Количество свободных системных ресурсов в процентах.
GFSR_GDIRESOURCES | Количество свободных GDI ресурсов в процентах. GDI ресурсы включают указатели контекста, кисти, карандаши, области, шрифты и битовые изображения.
GFSR_USERRESOURCES | Количество свободных пользовательских ресурсов в процентах. Эти ресурсы включают указатели окон и меню.

      Пример:

      ............

      Label1.Caption := IntToStr(MemAvail DIV 1024)+' Kb';
      Label2.Caption := IntToStr(GetFreeSystemResources(GFSR_SYSTEMRESOURCES))+'%';

      ............


Вопрос и Ответ 7

Вопросы и Ответы

      7. При выполнении длинного цикла происходит останов Windows. Как этого избежать?

      В Windows API данная проблема решается вызовом в длинном цикле функции:

      function Yield: Bool;

      которая останавливает выполнение текущей задачи и запускает ждущую задачу. Но в Delphi эта функция не работает, она заменена на аналогичный метод ProcessMessages объекта TApplication.

      Пример:

      ............

      WHILE NOT EOF(F) DO BEGIN

        Read(F, i);
        Application.ProcessMessages;

      END;

      ............


Вопрос и Ответ 8

Вопросы и Ответы

      8. Можно ли при обработке нажатий нескольких кнопок обойтись одним обработчиком события?

      Предположим, Вы пишете калькулятор и у Вас десять цифровых кнопок от 0 до 9. Теперь Вы создаете только один обработчик нажатия кнопки и присваиваете его остальным девяти кнопкам. При вызове обработчика в параметре Sender передается указатель на компонент вызвавший этот обработчик. Для получения доступа к полям и методам указанного компонента необходимо указать Delphi к какому типу относится этот компонент - командой AS.

      Пример:

      ............

      VAR Target: String;

      ............

      procedure TForm1.ButtonAllClick(Sender: TObject);
      begin

        WITH Sender AS TSpeedButton DO
        Target := Target+Caption;

      end;

      ............


Вопрос и Ответ 9

Вопросы и Ответы

      9. В каких случаях и для чего нужно поле Tag?

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

    Tag: LongInt.


Вопрос и Ответ 10

Вопросы и Ответы

      10. Как считать состояние и программно переключить Caps Lock, Num Lock и Scroll Lock?

      Для этого надо воспользоваться процедурами API:

      procedure GetKeyboardState(var KeyState: TKeyboardState); и
      procedure SetKeyboardState(var KeyState: TKeyboardState);

      которые возвращают и устанавливают, соответственно, состояния всех клавиш. Некоторые коды клавиш приведены в таблице:

      Клавиша | Код | Клавиша | Код | Клавиша | Код
Caps Lock | 020 | Shift | 016 | Insert | 045
NumLock | 144 | Contrl | 017 | Delete | 046
Scroll Lock | 145 | Alt | 018 | Tab | 009

      Пример:

      Меняем состояния клавиш Caps Lock, Num Lock и Scroll Lock на противоположное:

      ............

      VAR KS: TKeyboardState;
      begin

        GetKeyboardState(KS);
        KS[020] := KS[020] XOR 1;
        KS[144] := KS[144] XOR 1;
        KS[145] := KS[145] XOR 1;
        SetKeyboardState(KS);

      end;

      ............


Вопрос и Ответ 11

Вопросы и Ответы

      11. Можно ли в Delphi вывести строку повернутую под любым углом?

      Стандартные средства Delphi не позволяют использовать вывод строки текста под произвольным углом, так как в модуле Graphics поля отвечающие за угол поворота строки принудительно обнуляются. Это приводит к необходимости использовать средства API.

      Наверное, лучший способ - это исправить модуль Graphics и разрешить использование произвольного угла поворота во всех объектах сразу. Но такой путь потребует перекомпиляции нескольких модулей и приведет к некорректной работе ваших кодов с другими версиями Delphi. Другой способ - написать процедуру вывода под углом и пользоваться ею при необходимости.

      Чтобы не нарушать существующий порядок вывода строки на экран, будем следовать следующим правилам:

      1. Все параметры шрифта, кроме угла - брать из объекта Font;
      2. Рисовать в контексте Canvas.

      Пример:

      ............

      PROCEDURE FreeTextOut(Canvas: TCanvas; X, Y, A: Integer; S: String);
      VAR

        OldFont, NewFont: hFont;
        lf : TLogFont;

      BEGIN

        {Создаем описание для нового шрифта.}
        WITH lf, Canvas DO BEGIN

          {Устанавливаем текущие для объекта Font
        параметры, кроме углов.}
lfHeight := Font.Height;
lfWidth := 0;
lfEscapement := A*10; {Угол наклона строки
        в 0.1 градуса}
lfOrientation := A*10; {Угол
        наклона символов в строке в 0.1 градуса}
if fsBold in Font.Style then lfWeight := FW_BOLD

            else lfWeight := FW_NORMAL;

          lfItalic
        := Byte(fsItalic in Font.Style);
lfUnderline := Byte(fsUnderline in Font.Style);
lfStrikeOut := Byte(fsStrikeOut in Font.Style);
lfCharSet := DEFAULT_CHARSET;
StrPCopy(lfFaceName, Font.Name);
lfQuality := DEFAULT_QUALITY;
lfOutPrecision := OUT_DEFAULT_PRECIS;
lfClipPrecision := CLIP_DEFAULT_PRECIS;
lfPitchAndFamily := DEFAULT_PITCH;

        end;
{Создаем новый
      шрифт}
NewFont := CreateFontIndirect(lf);
{Выбираем новый шрифт в контекст
      отображения}
OldFont := SelectObject(Canvas.Handle, NewFont);
{Выводим текст на экран ПОД
      ЗАДАННЫМ УГЛОМ}
Canvas.TextOut(X, Y, S);
{Восстанавливаем в контексте
      старый шрифт}
SelectObject(Canvas.Handle, OldFont);
{Удаляем новый шрифт}
DeleteObject(NewFont);

      END;

      ............

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

      Процедура работает аналогично процедуре TextOut, единственное - ей необходимо явно передавать контекст отображения:

    procedure FreeTextOut(Canvas: TCanvas; X, Y, A: Integer; S: String);

      где

      • Canvas - контекст (канва) отображения;
      • X, Y - соответствующие координаты;
      • A - угол поворота строки (в углах);
      • S - выводимая строка.

      Пример:

      ............

      FreeTextOut(Canvas, 100, 100, 45, 'Пример вывода под углом');

      ............

      P.S. Поворачивать можно только векторные и масштабируемые (True Type) шрифты. А шрифт System, используемый Delphi по умолчанию - растровый!


Вопрос и Ответ 12

Вопросы и Ответы

      12. Как одной процедурой осуществить вывод и в окно и на принтер?

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

      Вывод | Контекст | Ширина | Высота
в окно | Printers.Canvas | ClientWidth | ClientHeight
на принтер | Canvas | PageWidth | PageHeight

      Пример:

      ............

      {вывод
    рисунка в контекст Cv}
PROCEDURE TForm1.Draw(Cv: TCanvas; W, H : Integer);
VAR k: Integer;
BEGIN

        k := W DIV 40; {вычисление коэффициента - от ширины листа}
        WITH Cv DO BEGIN {рисование в предоставленном контексте}

          Font.Name
        := 'Times New Roman Cyr';
Font.Size := k*6;
Font.Color := clOlive;
TextOut(k*10, k*6, 'Delphi');
Font.Size := k*4;
Font.Color := clBlue;
TextOut(k*11, k*15, 'для всех');
Pen.Color := clRed;
Pen.Width := k div 2;
MoveTo(k*15, k*22);
LineTo(k*34, k*21);

        END;

      END;

      ............

      {вывод информации в окно}
      procedure TForm1.FormPaint(Sender: TObject);
      begin

        Draw(Canvas, ClientWidth, ClientHeight);

      end;

      ............

      {вывод информации на принтер}
      procedure TForm1.mPrintClick(Sender: TObject);
      begin

        WITH Printer DO BEGIN

          BeginDoc;
          Draw(Printer.Canvas, PageWidth, PageHeight);
          EndDoc;

        END;

      end;

      ............

      Для работы с принтером не забудте добавить модуль Printers в строку Uses....


Вопрос и Ответ 13

Вопросы и Ответы

      13. Где находятся системные иконки Windows используемые в диалоговых окнах типа MessageDlg?

      Windows содержит ряд предопределенных иконок, использующихся в диалоговых окнах MessageBox (или MessageDlg для Delphi). Вы можете пользоваться предопределенными иконками в своих окнах, загружая их с помощью функции:

      function LoadIcon(Instance: THandle; IconName: PChar): HIcon;

      Если параметр Instance сделать равным нулю, то второй параметр будет указывать на имя предопределенной иконки:

      Иконка | Назначение
IDI_APPLICATION | Используется по умолчанию.
IDI_EXCLAMATION | Используется при предупреждениях.
IDI_HAND | Используется при ошибках.
IDI_ASTERISK | Используется в информационных сообщениях.
IDI_QUESTION | Используется при задании вопросов.

      Пример:

      Иконка-предупреждение выводится в компонент Image1: TImage, который уже размещен на форме.

      ............

      procedure TForm1.FormCreate(Sender: TObject);
      VAR Ico: TIcon;
      begin

        {Создание объекта типа TIcon}
        Ico := TIcon.Create;
        try

          {IDI_EXCLAMATION}
{Загрузка в объект TIcon
        иконки-предупреждения}
Ico.Handle := LoadIcon(0, PChar(IDI_EXCLAMATION));
{Вывод иконки в компонент Image1}
Image1.Picture.Graphic := Ico;

        finally

          {Освобождение ресурсов занятых объектом TIcon}
          Ico.Free;

        end;

      end;

      ............


Вопрос и Ответ 14

Вопросы и Ответы

      14. Как используя поля Hint создать строку подсказки?

      Для отображения текста подсказки любого объекта, в строке подсказки, в зависимости от того над каким элементом управления или пунктом меню находится мышь, необходимо следующее:

      1. создать процедуру, которая будет выводить подсказку на экран;
      2. присвоить обработчику события Hint объекта Application эту процедуру.

      В строку подсказки будет выводиться любой текст, находящийся в поле Hint, независимо от состояния ShowHint. Можно использовать две различных подсказки для одного элемента или пункта меню. Они должны разделяться символом '|'. Первая часть появится рядом с элементом (если ShowHint=True), а вторая - в строке подсказки. В случае одного варианта - он будет использоваться в обоих случаях.

      Пример:

      Для вывода текста подсказки используется Label1.

      ............

      {описание собственной процедуры AppHint}

        public

          PROCEDURE AppHint(Sender: TObject);

      ............

      {присвоение событию Hint имени нашей процедуры AppHint}
      procedure TForm1.FormCreate(Sender: TObject);
      begin

        Application.OnHint := AppHint;

      end;

      ............

      {вывод подсказки на экран}
      PROCEDURE TForm1.AppHint(Sender: TObject);
      BEGIN

        Label1.Caption := Application.Hint;

      END;

      ............


Вопрос и Ответ 15

Вопросы и Ответы

      15. Возможно ли в компоненте TMemo отменить неверно произведенные действия при редактировании текста?

      В компоненте TMemo предусмотрена возможность отмены неверных действий при редактировании. Для этого надо послать сообщение о необходимости произвести отмену действий. Компонент TMemo поддерживает три сообщения:

      Сообщение | Описание
EM_CANUNDO | Возвращает флаг состояния операции отмены. Если операцию произвести нельзя - возвращается ноль, если можно - значение отлично от нуля.
EM_UNDO | Производит операцию отмены.
EM_EMPTYUNDOBUFFER | Обнуляет флаг состояния операции отмены.

      Пример:

      ............

      {Операция отмены для компонента Memo1 с проверкой флага отмены}
      procedure TForm1.bUndoClick(Sender: TObject);
      begin

        IF Memo1.Perform(EM_CANUNDO, 0, 0) <> 0 THEN

          Memo1.Perform(EM_UNDO, 0, 0);

      end;

      ............

      {Операция очистки флага состояния операции отмены с проверкой флага}
      procedure TForm1.bUndoClearClick(Sender: TObject);
      begin

        IF Memo1.Perform(EM_CANUNDO, 0, 0) <> 0 THEN

          Memo1.Perform(EM_EMPTYUNDOBUFFER, 0, 0);

      end;

      ............


Вопрос и Ответ 16

Вопросы и Ответы

      16. Почему не получается создать окно StayOnTop (всегда наверху)?

      Создать окно которое всегда будет наверху (не будет перекрываться другими окнами) несложно, для этого достаточно полю FormStyle объекта TForm присвоить значение fsStayOnTop. И это прекрасно работает... до тех пор пока Вам не понадобится несколько раз сделать окно то нормальным, то снова StayOnTop. Если это делать процедурами RestoreTopMosts и NormalizeTopMosts иногда происходит необъяснимое игнорирование второй процедуры и Ваше окно остается навсегда (до завершения) в положении "...наверху".

      Для предотвращения подобного стоит пользоваться процедурой API:

      procedure SetWindowPos(Wnd: HWnd; WndInsertAfter: HWnd; X, Y, cx, cy: Integer; Flags: Word);

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

      Пример:

      ............

      VAR isTopMost: Boolean;

      ............

      procedure TForm1.bTopMostClick(Sender: TObject);
      begin

        IF isTopMost THEN

          {Окно в состояние - всегда наверху}
          SetWindowPos(Application.Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE Or SWP_NOMOVE)

        ELSE

          {Окно в нормальное состояние}
          SetWindowPos(Application.Handle, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE Or SWP_NOMOVE)

        isTopMost := NOT isTopMost;

      end;

      ............


Вопрос и Ответ 17

Вопросы и Ответы

      17. Как определить работает ли уже данное приложение или это первая его копия?

      Каждый экземпляр программы имеет ссылку на свою предыдущую копию - hPrevInst: hWnd (см. "Вопрос и Ответ 44"). Ее можно проверить перед созданием приложения и при необходимости отреагировать соответствующим образом.

      Если запущена только одна копия, то эта ссылка равна нулю.

      Пример:

      ............

      procedure TForm1.FormCreate(Sender: TObject);
      begin

        {Проверяем есть ли указатель на предыдущую копию приложения}
        IF hPrevInst <> 0 THEN BEGIN

          {Если есть, то выдаем сообщение и выходим}
          MessageDlg('Программа уже запущена!', mtError, [mbOk], 0);
          Halt;

        END;
        {Иначе - ничего не делаем (не мешаем созданию формы)}

      end;

      ............

      P.S. Для выхода необходимо использовать Halt, а не Close, как хотелось бы, так как форма еще не создана и закрывать нечего.


Вопрос и Ответ 18

Вопросы и Ответы

      18. Можно ли в Delphi создать хранитель экрана совместимый со стандартными хранителями Windows?

      Конечно можно! Для этого необходимо выполнить следующие шаги:

      1. В файл проекта (*.DPR) добавить строку {$D SCRNSAVE <название хранителя>} после строки подключения модулей (Uses...).
      2. У окна формы убрать системное меню, кнопки и придать свойству WindowState значение wsMaximize.
      3. Предусмотреть выход из хранителя при нажатии на клавиши клавиатуры, мыши и при перемещении курсора мыши.
      4. Проверить параметры с которым был вызван хранитель и если это /c - показать окно настройки хранителя, а иначе (можно проверять на /s, а можно и не проверять) сам хранитель.
      5. Скомпилировать хранитель экрана.
      6. Переименовать *.EXE файл в файл *.SCR и скопировать его в каталог WINDOWS\SYSTEM\.
      7. Установить новый хранитель в настройках системы!

      Название хранителя может состоять из нескольких слов с пробелами, на любом языке.

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

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

      Старайтесь сделать свой хранитель как можно меньше и быстрее. Иначе ваши долго работающие (в фоновом режиме) приложения будут работать еше дольше!

      Пример:

      Данный пример довольно большой и стоит скопировать его архив, а здесь рассмотрены основные моменты.

      ............

      {в файле *.DPR}
      {$D SCRNSAVE Пример хранителя экрана}

      ............

      {проверить переданные параметры}
      IF (ParamStr(1) = '/c') OR (ParamStr(1) = '/C') THEN

        ............

      ............

      {скрыть курсор мыши}
      ShowCursor(False);

      ............

      {восстановить курсор мыши}
      ShowCursor(True);

      ............


Вопрос и Ответ 19

Вопросы и Ответы

      19. Как заполнить форму растровым изображением?

      Для заполнения формы растровым изображением необходимо создать кисть и загрузить в нее это изображение. В Delphi у каждой формы уже имеется кисть Form1.Brush, но она может закрашивать фон только цветом, а нам необходимо создать кисть из растрового изображения командой:

      Form1.Brush.Bitmap := TBitMap.Create;

      Размер изображения для кисти должен быть равен 8х8 точек, это ограничение накладывается Windows. Обойти его можно лишь рисованием фона вручную, в методе Paint (см. "Вопрос и Ответ 22").

      Пример:

      ............

      procedure TForm1.FormCreate(Sender: TObject);
      begin

        {Создание кисти}
        Form1.Brush.Bitmap := TBitMap.Create;
        {Загрузка в кисть растрового изображения}
        Form1.Brush.Bitmap.LoadFromFile('brush.bmp');

      end;

      ............

      procedure TForm1.FormDestroy(Sender: TObject);
      begin

        {Освобождение кисти}
        Form1.Brush.Bitmap.Free;

      end;

      ............


Вопрос и Ответ 20

Вопросы и Ответы

      20. Возможно ли в среде Delphi открыть еще одно окно редактора?

      Для этого войдите в пункт меню "View" и выполните пункт подменю - "New Edit Window". Новое окно будет расположено в точности над предыдущим. Но если Вы его переместите в другое положение, то будут доступны оба окна редактора, каждое из которых будет иметь "многостраничную" структуру.

      Такой подход особенно удобен при большом количестве модулей в проекте.


Вопрос и Ответ 21

Вопросы и Ответы

      21. Как получить иконку из .EXE или .DLL файла?

      Процесс получения иконок из .EXE, .DLL или .ICO файлов полностью идентичен. Различие только в том, что в .ICO файле может храниться только одна иконка, а в .EXE и .DLL несколько. Для получения иконок из файлов, в модуле ShellAPI, есть функция:

      function ExtractIcon(Inst: THandle; FileName: PChar; IconIndex: Word): HIcon;

      где

        Inst - указатель на приложение вызвавшее функцию,
        FileName - имя файла из которого необходимо получить иконку,
        IconIndex - номер необходимой иконки.

      Если функция возвращает значение не равное нулю, то в файле есть следующая иконка.

      Пример:

      В данном примере в компонент Image1 выводится иконка запущенного файла.

      ............

      USES ShellAPI;

      ............

      procedure TForm1.FormCreate(Sender: TObject);
      VAR A: ARRAY [0..78] OF Char;
      begin

        {Получение
      имени запущенного файла}
StrPCopy(A, ParamStr(0));
{Вывод на экран нулевой иконки
      из файла}
Image1.Picture.Icon.Handle := ExtractIcon(HInstance, A,
      0);

      end;

      ............


Вопрос и Ответ 22

Вопросы и Ответы

      22. Как заполнить форму ЛЮБЫМ растровым изображением?

      Стандартные средства Windows позволяют заполнять форму только изображением размером 8х8 точек (см. "Вопрос и Ответ 19"). Для заполнения формы растровым изображением любого размера необходимо в методе Paint заполнять всю форму нужным растровым изображением вручную.

      Пример:

      ............

        ............
        public

          bmp: TBitMap; {Объект TBitMap}
          kX, kY: Integer; {Количество целых изображений по X и Y}

        end;

      ............

      procedure TForm1.FormCreate(Sender: TObject);

        begin bmp := TBitMap.Create; {Создаем объект TBitMap}
        bmp.LoadFromFile('fon.bmp'); {Загружаем в него изображение}

      end;

      ............

      {Вызывается при изменении размеров окна (и при его создании тоже)}
      procedure TForm1.FormResize(Sender: TObject);
      begin

        {Проверяем загружено или нет изображение}
        IF bmp.Handle <> 0 THEN BEGIN

          {Вычисляем какое целое число раз поместится изображение на экране по вертикали и горизонтали}
          kX := Width DIV bmp.Width;
          kY := Height DIV bmp.Height;
          Refresh; {Перерисовываем окно}

        END;

      end;

      ............

      procedure TForm1.FormPaint(Sender: TObject);
      VAR X, Y: Integer;
      begin

        {Проверяем загружено или нет изображение}
        IF bmp.Handle <> 0 THEN

          FOR X := 0 TO kX DO {Количество изображений по X плюс одно}

            FOR Y := 0 TO kY DO {Количество изображений по Y плюс одно}

              Canvas.Draw(X*bmp.Width, Y*bmp.Height, bmp); {Рисуем}

      end;

      ............

      procedure TForm1.FormDestroy(Sender: TObject);
      begin

        bmp.Free; {Удаляем объект TBitMap}

      end;

      ............


Вопрос и Ответ 23

Вопросы и Ответы

      23. Для API функций необходим формат строк типа PChar. Как его получить из строк типа String?

      Для перевода строк из типа PChar в тип String, и обратно, есть две основные функции:

      function StrPCopy(Dest: PChar; Source: String):
    PChar; {Из String в PChar}
function StrPas(Str: PChar): String; {Из PChar в String}

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

      1. Добавить в конец строки типа String символ #0;
      2. Передать вместо PChar адрес первого символа строки типа String.

      Пример:

      ............

      VAR S: String;

      ............

        +#0;
        ExtractIcon(HInstance, @S[1], 0);

      ............


Вопрос и Ответ 24

Вопросы и Ответы

      24. Можно ли получить позицию курсора в компоненте TMemo?

      В компоненте TMemo предусмотрено получение позиции курсора через механизм сообщений. Для получения позиции необходимо послать два сообщения. Первое -

      LineNum := Memo1.Perform(EM_LINEFROMCHAR, Memo1.SelStart, 0);

      для получения номера строки в которой находится курсор. И второе -

      CharNum := Memo1.Perform(EM_LINEINDEX, LineNum, 0);

      для получения позиции курсора в заданной строке. Будте внимательны, так как номер строки и позиция в строке отсчитываются от нуля.

      Пример:

      ............

      {Получаем позицию курсора при щелчке мыши на компоненте}
      procedure TForm1.Memo1Click(Sender: TObject);
      VAR

        LineNum : LongInt;
        CharNum : LongInt;

      begin

        {Получаем
      номер строки}
LineNum := Memo1.Perform(EM_LINEFROMCHAR, Memo1.SelStart,
      0);
{Получаем позицию в строке}
CharNum := Memo1.Perform(EM_LINEINDEX, LineNum, 0);
{Выводим позицию на экран}
Label1.Caption := IntToStr(LineNum+1)+' : '+

          IntToStr((Memo1.SelStart-CharNum)+1);

      end;

      ............

      {Получаем позицию курсора при отпускании клавиши на клавиатуре}
      procedure TForm1.Memo1KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
      begin

        Memo1Click(Self);

      end;

      ............


Вопрос и Ответ 25

Вопросы и Ответы

      25. Несколько удобных функций для ввода и вывода строки.

      Часто в программе требуется вывести сообщение или ввести строку символов, для этого в Delphi предусмотрено несколько удобных функций. Вот некоторые из них:

      procedure ShowMessage(const Msg: string);

      процедура выводит сообщение Msg в окно, расположенное в центре экрана;

      procedure ShowMessagePos(const Msg: string; X, Y: Integer);

      процедура выводит сообщение Msg в окно, верхний левый угол которого расположен в точке с координатами X и Y;

      function InputBox(const ACaption, APrompt, ADefault: string): string;

      функция возвращает введенную строку символов (окно появляется в центре экрана).
      Передаваемые параметры:

      • ACaption - заголовок окна;
      • APrompt - пояснение к вводимой строке;
      • ADefault - строка возвращаемая по умолчанию.

      Пример:

      ............

      ShowMessage('Пример простого сообщения.'+#10+ 'Данное сообщение выводится всегда в центре экрана.');

      ............

      ShowMessagePos('Пример сообщения с указанием его положения на экране.', Form1.Left+Button2.Left, Form1.Top+Button2.Top);

      ............

      Button1.Caption := InputBox('Delphi для всех', 'Введите строку:', Button1.Caption);

      ............


Вопрос и Ответ 26

Вопросы и Ответы

      26. Как получить растровое изображение формы?

      В компоненте TForm уже есть метод возвращающий растровое изображение формы, так что, для получения изображения достаточно вызвать его:

      function GetFormImage: TBitmap;

      Будте внимательны, поскольку данный метод не может получать изображения VBX компонент - на их месте будет пустое пространство. Это связано с различными методами реализации VCL и VBX компонент.

      Пример:

      ............

      Image1.Picture.BitMap := GetFormImage;

      ............


Вопрос и Ответ 27

Вопросы и Ответы

      27. Почему при запуске MDI приложения автоматически создается дочерняя форма?

      При создании новой формы, Delphi добавляет, строку инициализирующую, ее в файл проекта (*.dpr):

      Application.CreateForm(TForm2, Form2); {Для примера}

      Когда приложение запускается, то сразу создаются все формы описанные в файле проекта, но видимой становится только форма созданная первой. Все остальные формы - невидимы. Такого свойства нет у дочерних форм MDI, они всегда остаются видимыми.

      Это легко обойти, убрав из файла проекта (*.dpr) строки создающие дочерние формы MDI.

      Чтобы отредактировать файл проекта, выберите из меню View пункт Project Source.

      Пример


Вопрос и Ответ 28

Вопросы и Ответы

      28. При создании проекта появляется много различных файлов. Что это за файлы?

      Имеется следующий список расширений файлов создаваемых Delphi:

      • DPR - файл проекта Delphi. Это - фактически, главная программа приложения.
      • ~DP - резервный DPR файл. Создается, если включено резервное сохранение.
      • PAS - исходный код модуля или формы. Главная программа находится в файле DPR.
      • ~PA - резервный PAS файл. Создается, если включено резервное сохранение.
      • DFM - эти файлы связаны с файлами PAS. DFM - это двоичные файлы в которых содержатся начальные данные для компонент (это те свойства, которые Вы устанавливаете в Object Inspector). Вы не можете редактировать файл DFM текстовым редактором, но если откроете этот файл в Delphi, то увидете текстовую версию его содержимого.
      • ~DF - резервный DFM файл. Создается, если включено резервное сохранение.
      • DCU - откомпилированный модуль, подобен файлу OBJ.
      • DSM - файл с информацией используемой внутренним отладчиком. Этот файл создается каждый раз, когда Вы компилируете проект.
      • OPT - опции проекта. Это настройки компилятора и компоновщика, для данного проекта. Их можно вызвать в меню Options/Project.
      • RES - файл ресурсов Windows. Создается Delphi автоматически и требуется для компиляции. Вы можете не пользоваться этим файлом, но удалять его не следует.
      • EXE - откомпилированный проект. Исполняемая Windows-программа.


Вопрос и Ответ 29

Вопросы и Ответы

      29. Как преобразовать в текст содержимое переменных любого типа, причем, тип и их количество заранее не известно?

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

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

      Пример:

      ............

      {Функция
    преобразования разнотипных данных в строку}
FUNCTION TForm1.AllToStr(CONST Value: ARRAY OF CONST):
    STRING;
CONST BString: ARRAY [Boolean] OF STRING = ('False',
    'True');
VAR

        i: Integer;
        S: STRING;

      BEGIN

        Result := '';
        FOR i := Low(Value) TO High(Value) DO

          WITH TVarRec(Value[i]) DO BEGIN

            CASE VType OF

              vtInteger
            : S := IntToStr(VInteger);
vtBoolean : S := BString[VBoolean];
vtChar : S := VChar;
vtExtended : S := FloatToStr(VExtended^);
vtString : S := VString^;
vtPointer : S := IntToHex(LongInt(VPointer), 8);
vtPChar : S := StrPas(VPChar);
vtObject : S := vObject.ClassName;
vtClass : S := vClass.ClassName;

            END;
            AppendStr(Result, S);

          END;

      END;

      ............

      {Пример
    использование функции AllToStr}
procedure TForm1.Button1Click(Sender: TObject);
VAR a, b: Integer;
begin

        a
      := 10; b := 20;
Label1.Caption := AllToStr([ a, '+', b, '=', a+b, #9, a,
      '/', b, '=', a/b ]);

      end;

      ............


Вопрос и Ответ 30

Вопросы и Ответы

      30. Какие файлы, кроме EXE, нужны для работы откомпилированной программы на компьютере, где пакет Delphi не установлен?

      Ни одного! Все, что нужно, содержится в EXE файле. Это не относится к другим файлам, которые Вы создали сами (HLP файлы, файлы с данными и т.д.), они естественно необходимы. В случае, если в своем приложении Вы используете VBX компоненты, то Вам понадобится файл BIVBX11.DLL. А также файлы в которых содержатся используемые VBX компоненты (*.VBX).

      Если Вы работаете с базами данных, то необходима поддержка баз данных (Borland Database Engine). Два установочных диска находятся на Delphi CD. Там же находится и пять дисков с поддержкой генератора отчетов (ReportSmith), в случае, если Вы используете и его.

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


Вопрос и Ответ 31

Вопросы и Ответы

      31. Можно ли нарисовать курсор мыши как обычную картинку?

      Специальной функции для рисования курсора мыши нет. Но формат данных курсора и иконки одинаков, поэтому, можно воспользоваться функцией рисования иконки, только загружать надо изображение курсора. Для загрузки изображения курсора необходимо воспользоваться функцией:

      function LoadCursor(Instance: THandle; IconName: PChar): HCursor;

      формат ее полностью идентичен функции LoadIcon (см. "Вопрос и Ответ 13").

      Пример:

      Курсор в виде песочных часов выводится в компонент Image1: TImage, который уже размещен на форме.

      ............

      procedure TForm1.FormCreate(Sender: TObject);
      VAR Ico: TIcon;
      begin

        {Создание объекта типа TIcon}
        Ico := TIcon.Create;
        try

          {IDC_WAIT}
{Загрузка в объект TIcon курсора в
        виде песочных часов}
Ico.Handle := LoadCursor(0, PChar(IDC_WAIT));
{Вывод иконки в компонент Image1}
Image1.Picture.Graphic := Ico;

        finally

          {Освобождение ресурсов занятых объектом TIcon}
          Ico.Free;

        end;

      end;

      ............


Вопрос и Ответ 32

Вопросы и Ответы

      32. Как во время работы приложения загружать новый шрифт?

      Большое количество одновременно установленных шрифтов замедляет работу Windows. Поэтому, при использовании специфических шрифтов, бывает полезно загружать их только на время работы приложения, а после работы удалять их из памяти. Для этого используются две функции:

      function AddFontResource(Filename: PChar): Integer; и

      function RemoveFontResource(Filename: PChar): Bool;

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

      Пример:

      Использование гипотетического шрифта "newfont.ttf" с именем "New Font Name".

      ............

      {Загрузка нового шрифта}
      procedure TForm1.FormCreate(Sender: TObject);
      begin

        IF AddFontResource('newfont.ttf') <> 0 THEN

          SendMessage($FFFF, wm_FontChange, 0, 0);

      end;

      ............

      {Использование нового шрифта}
      procedure TForm1.FormPaint(Sender: TObject);
      begin

        Canvas.Font.Name := 'New Font Name';
        Canvas.TextOut(10, 10, 'Привет!');

      end;

      ............

      {Удаление нового шрифта из памяти}
      procedure TForm1.FormClose(Sender: TObject);
      begin

        IF RemoveFontResource('newfont.ttf') THEN

          SendMessage($FFFF, wm_FontChange, 0, 0);

      end;

      ............


Вопрос и Ответ 33

Вопросы и Ответы

      33. Существет ли способ ограничения максимального и минимального размера окна?

      Перед изменением размера окна Windows посылает сообщение wm_GetMinMaxInfo, перехватив которое, можно устанавливать необходимые размеры окна.

      Ограничение на размеры окна содержатся в структуре типа TMinMaxInfo. Для установки новых ограничений достаточно изменить соответствующие значения. В таблице описаны используемые поля данной структуры:

      Поле | Описание
ptMaxSize | Размер окна при его максимизации.
ptMaxPosition | Положение левого верхнего угла окна при его максимизации.
ptMaxTrackSize | Максимальный размер окна при увеличении его размеров.
ptMinTrackSize | Минимальный размер окна при уменьшении его размеров.

      Пример:

      ............

      public

        ............
        PROCEDURE WMGetMinMaxInfo(VAR M: TWMGetMinMaxInfo); MESSAGE WM_GetMinMaxInfo;

      end;

      ............

      {Установка новых ограничений}
      PROCEDURE TForm1.WMGetMinMaxInfo(VAR M: TWMGetMinMaxInfo);
      BEGIN

        {Выполнение
      предварительно определенного метода}
inherited;
{координата X}
M.MinMaxInfo^.PTMaxSize.X := 400;
M.MinMaxInfo^.PTMaxPosition.X := 100;
M.MinMaxInfo^.PTMaxTrackSize.X := 500;
M.MinMaxInfo^.PTMinTrackSize.X := 300;
{координата Y}
M.MinMaxInfo^.PTMaxSize.Y := 250;
M.MinMaxInfo^.PTMaxPosition.Y := 100;
M.MinMaxInfo^.PTMaxTrackSize.Y := 300;
M.MinMaxInfo^.PTMinTrackSize.Y := 200;

      END;

      ............


Вопрос и Ответ 34

Вопросы и Ответы

      34. Как получить список доступных шрифтов?

      Вы можете получить два списка доступных шрифтов. Один список для экранных шрифтов, а второй - для шрифтов принтера. Списки доступных шрифтов находятся в свойствах:

      property Fonts: TStrings;

      объектов TScreen и TPrinter, соответственно.

      Пример:

      ............

      procedure TForm1.FormCreate(Sender: TObject);
      begin

        ListBox1.Items := Screen.Fonts;
        ListBox2.Items := Printer.Fonts;

      end;

      ............

      P.S. Не забудте добавить модуль Printers в строку Uses....


Вопрос и Ответ 35

Вопросы и Ответы

      35. Как использовать метку (Label) для передачи фокуса объекту?

      Передачу фокуса, при помощи метки, можно осуществлять в двух случаях. При нажатии на клавиатуре определенной комбинации клавиш и при щелчке мышкой на метке.

      В первом случае, необходимо определить комбинацию клавиш с помощью символа "&" в поле Caption (например: П&араметры => Alt+а). Во втором - передавать фокус при щелчке мышью на метке. Для того, чтобы одна процедура обрабатывала события от всех Ваших меток, необходимо присвоить ее событиям OnClick всех меток.

      Передача фокуса будет работать, только, если правильно установлено свойство FocusControl.

      Пример:

      ............

      procedure TForm1.LabelClick(Sender: TObject);
      begin

        (Sender AS TLabel).FocusControl.SetFocus;

      end;

      ............


Вопрос и Ответ 36

Вопросы и Ответы

      36. Каким образом работать с иконками расположенными в панели задач Win'95?

      Функция работы с, так называемыми, нотификационными иконками, которые находятся в правой части панели задач Windows'95, определена в модуле ShellAPI:

      function Shell_NotifyIcon(dwMessage: DWORD; lpData: PNotifyIconData): BOOL;

      В зависимости от переданного сообщения в параметре dwMessage, эта функция может добавлять, модифицировать или удалять иконки, данные о которых передаются в параметре lpData. Поддерживаются три сообщения:

      Сообщение | Описание
NIM_ADD | Добавить иконку в панель задач.
NIM_MODIFY | Изменить параметры иконки в панели задач.
NIM_DELETE | Удалить иконку из панели задач.

      Для работы с нотификационными иконками необходимо правильно заполнить поля данных, которые содержатся в структуре TNotifyIconData:

      Поле

      Тип

      Описание

      cbSize

      DWORD

              Размер передаваемой структуры.

      Wnd

      HWND

              Указатель на главное окно программы.

      uID

      UINT

              Идентификатор иконки.

      uFlags

      UINT

      Устанавливаемые флаги:

      Флаг | Назначение
NIF_MESSAGE | Посылать сообщение при щелчке мыши.
NIF_ICON | Отображать иконку в панели задач.
NIF_TIP | Показывать подсказку (Hint).

      uCallbackMessage

      UINT

              Номер сообщения посылаемого иконкой при щелчке на ней мышью.

      hIcon

      HICON

              Указатель на используемую иконку.

      szTip

      array [0..63] of WideChar

              Подсказка (Hint).

      Пример:

      ............

      uses ShellAPI;

      var NID :TNotifyIconData;

      ............

      {Добавление}
      procedure TForm1.bAddClick(Sender: TObject);
      begin

        {Установка необходимых значений в поля структуры TNotifyIconData}
        WITH NID DO BEGIN

          uFlags
        := NIF_ICON OR NIF_TIP OR NIF_MESSAGE;
cbSize := SizeOf(NID);
uID := 123;
Wnd := Handle;
szTip := 'Пример подсказки'+#0;
hIcon := Application.Icon.Handle;
uCallBackMessage := WM_USER+10;

        END;
        {Добавление иконки в панель задач}
        IF Shell_NotifyIcon(NIM_ADD,@NID) THEN MessageBeep(0);

      end;

      ............

      {Изменение}
      procedure TForm1.bModifyClick(Sender: TObject);
      begin

        {Установка новых значений в поля структуры TNotifyIconData}
        WITH NID DO BEGIN

          szTip := 'Пример подсказки 1'+#0;
          hIcon := LoadIcon(0,IDI_ASTERISK);

        END;
        {Изменение иконки в панели задач}
        IF Shell_NotifyIcon(NIM_MODIFY,@NID) THEN MessageBeep(0);

      end;

      ............

      {Удаление иконки из панели задач}
      procedure TForm1.bDeleteClick(Sender: TObject);
      begin

        IF Shell_NotifyIcon(NIM_DELETE,@NID) THEN MessageBeep(0);

      end;

      ............

      {Процедура
    реакции на события передаваемые иконкой}
procedure TForm1.WndProc(var M: TMessage);
var CursorPos: TPoint;
begin

        {Проверка на принадлежность сообщения иконке}
        IF M.Msg = WM_USER+10 THEN
        {Реакция на необходимые события}
        CASE M.LParam OF

          WM_RBUTTONUP :

            BEGIN

              GetCursorPos(CursorPos);
              PopupMenu1.Popup(CursorPos.X, CursorPos.Y);

            END;

          WM_LBUTTONDBLCLK :

            ShowMessage('Двойной щелчок мыши!');

        END;
        {Передача необработанных сообщений дальше}
        INHERITED WndProc(M);

      end;

      ............

      P.S. Использование нотификационных иконок в Delphi вызывает некоторые сложности, так как, необходимо прятать окно и оставлять на экране только иконку, а простое использование свойства Visible не дает необходимого результата. Выход из этого положения видится, только, в отказе от использования объекта TApplication и работе с функциями API напрямую. Данный подход хорош еще и тем, что эти программы постоянно находятся в памяти, а использование в них объектно-ориентированной библиотеки Delphi будет отнимать слишком много ресурсов.


Вопрос и Ответ 37

Вопросы и Ответы

      37. Как получить данные из COM порта?

      Работа с портами в Delphi ни чем, принципиально, не отличается от работы с портами в других языках программирования. Можно использовать определенный массив Port, который позволяет считывать и записывать значения, но его использование не всегда оправдано, поскольку не обеспечивает необходимой гибкости и полученный код работает довольно медленно. Лучший результат дает использование процедур написанных на ассемблере.

      Базовые адреса двух COM портов, для справки:

        COM1 - 3F8h
        COM2 - 2F8h

      Пример:

      Простейший вид процедур посылки и получения данных.

      ............

      {процедура посылки данных в порт}
      procedure PortOut(Port: Word; Data: Byte); assembler;
      asm

        MOV DX,Port;
        MOV AL,Data
        OUT DX,AL

      end;

      ............

      {функция получения данных из порта}
      function PortIn(Port: Word): Byte; assembler;
      asm

        MOV DX,Port;
        IN AL,DX

      end;

      ............


Вопрос и Ответ 38

Вопросы и Ответы

      38. Как из приложения получить псевдонимы DBE, определенные в Database Engine Configuration?

      Список определенных псевдонимов находится в объекте Session. Получить его можно с помощью следующей процедуры:

      procedure GetAliasNames(List: TStrings);

      в качестве единственного параметра передается переменная типа TString. В ней после выполнения процедуры будет содержатся список псевдонимов.

      Чтобы получить параметры (тип и путь) определенные для псевдонима, можно воспользоваться процедурой DbiGetDatabaseDesc, которая, по имени псевдонима, заполняет структуру типа DBDesc необходимыми значениями.

      Пример:

      ............

      USES

        DB, DBITypes, DBIProcs;

      ............

      {получение списка псевдонимов}
      procedure TForm1.FormCreate(Sender: TObject);
      begin

        Session.GetAliasNames(ListBox1.Items);

      end;

      ............

      {получение параметров для выбранного псевдонима}
      procedure TForm1.ListBox1Click(Sender: TObject);
      VAR

        tStr: ARRAY[0..31] OF Char;
        Desc: DBDesc;

      begin

        IF ListBox1.Items.Count = 0 THEN Exit;
        StrPLCopy(tStr, ListBox1.Items.Strings[ListBox1.ItemIndex], High(tStr));
        DbiGetDatabaseDesc(tStr, @Desc);
        WITH Desc DO BEGIN

          Caption
        := 'Alias - '+StrPas(Desc.szName);
eType.Text := StrPas(Desc.szDbType);
ePath.Text := StrPas(Desc.szPhyName);

        END;

      end;

      ............


Вопрос и Ответ 39

Вопросы и Ответы

      39. Почему при нажатии на кнопку TBitBtn происходит закрытие формы?

      Кнопки типа TBitBtn единственные, из стандартных для Delphi, которые могут, при нажатии, закрывать форму и возвращать код завершения в функцию создавшую форму (это свойство не работает с главной формой):

      function ShowModal: Integer;

      Поэтому, если свойство ModalResult установлено в значение отличное от mrNone, то происходит "непроизвольное" закрытие формы, при нажатии на эту кнопку.

      Для предотвращения нежелательных действий, будте внимательны при задании свойств этих кнопок.


Вопрос и Ответ 40

Вопросы и Ответы

      40. После установки Delphi 2 перестала правильно работать справка в первой версии Delphi. Что делать?

      Действительно, после установки второй версии Delphi, в систему, где уже установленна первая версия, перестает правильно работать справка в последней. Это связано с тем, что Delphi 2 регестрирует свой файл delphi.hlp (и соответственно путь к нему), и Windows после этого, почти всегда, обращается именно к этому файлу.

      Для предотвращения подобного, необходимо явно указать где находится файл delphi.hlp из первой версии Delphi. Эта информация хранится в файле winhelp.ini, в разделе [Files].

      Пример:

      Красным цветом выделена строка которую необходимо добавить в файл winhelp.ini. (Обратите внимание на свой путь, он может отличаться от указанного в примере)

        [Files]
        DELPHI.HLP=C:\DELPHI\BIN
        WINAPI.HLP=C:\DELPHI\BIN
        CWH.HLP=C:\DELPHI\BIN
        LOCALSQL.HLP=C:\DELPHI\BIN
        VQB.HLP=C:\DELPHI\BIN
        BDECFG.HLP=C:\DELPHI\IDAPI
        DBD.HLP=C:\DELPHI\DBD


Вопрос и Ответ 41

Вопросы и Ответы

      41. Как изменить цвет ячейки TDBGrid в зависимости от текущего значения?

      Для изменения цвета некоторых ячеек таблицы TDBGrid необходимо определить реакцию на событие DBGrid1DrawDataCell и проверив необходимые условия, перерисовать ячейку вручную (если в этом есть необходимость).

      Все необходимые данные для отрисовки передаются в параметрах процедуры.

      Пример:

      Отрисовка белых букв на красном фоне если, перерисовывается поле 'First_I', ячейка не в фокусе и значение поля меньше нуля.

      ............

      procedure TForm1.DBGrid1DrawDataCell(Sender: TObject; const Rect: TRect; Field: TField; State: TGridDrawState);
      begin

        WITH DBGrid1.Canvas DO

          IF (Field.FieldName = 'First_I') AND (NOT (gdFocused in State))

              AND (Field.AsInteger < 0) THEN BEGIN

            Brush.Color
          := clRed;
Font.Color := clWhite;
DBGrid1.DefaultDrawDataCell(Rect, Field, State);

          END;

      end;

      ............


Вопрос и Ответ 42

Вопросы и Ответы

      42. Можно ли изменить величину табуляции в TMemo?

      Можно. Для этого надо послать сообщение EM_SetTabStops компоненте TMemo, в котором необходимо указать два параметра. Количество передаваемых значений и величины табуляций.

      Если первый параметр равняется нулю, то второй параметр игнорируется и величина табуляции сбрасывается в значение по умолчанию (32). Иначе, устанавливается величина указанная во втором параметре, причем, при единичном значении все величины табуляций будут равны, а при большем значении величины берутся из переданного массива.

      Пример:

      ............

      {Установка одной величины табуляции}
      procedure TForm1.FormCreate(Sender: TObject);
      CONST

        TabInc: LongInt = 40;

      begin

        SendMessage(Memo1.Handle, EM_SetTabStops, 1, Longint(@TabInc));

      end;

      ............

      {Установка двух величин табуляции}
      procedure TForm1.FormCreate(Sender: TObject);
      CONST

        TabInc: Array [1..2] of LongInt = (10, 30);

      begin

        SendMessage(Memo1.Handle, EM_SetTabStops, 2, Longint(@TabInc));

      end;

      ............


Вопрос и Ответ 43

Вопросы и Ответы

      43. Как в приложении узнать версии Windows и DOS?

      Для этого, можно воспользоваться следующей функцией:

      function GetVersion: LongInt;

      она возвращает в старшем слове версию DOS, а в младшем - версию Windows.

      Пример:

      ............

      procedure TForm1.FormCreate(Sender: TObject);
      VAR

        WinV: Word;
        DosV: Word;

      begin

        WinV := GetVersion AND $0000FFFF;
        DosV := GetVersion SHR 16;
        Label1.Caption := IntToStr(Hi(DosV))+'.'+IntToStr(Lo(DosV));
        Label2.Caption := IntToStr(Lo(WinV))+'.'+IntToStr(Hi(WinV));

      end;

      ............


Вопрос и Ответ 44

Вопросы и Ответы

      44. Как определить работает ли уже данное приложение или это первая его копия?

      В Delphi 2.0 не поддерживается переменная hPrevInst (см. "Вопрос и Ответ 17") и определение первая это копия приложения или нет становится нетривиальной задачей.

      Наиболее простой путь - перебор всех окон и при совпадении заголовка окна с Application.Title считать, что приложение уже запущено. Единственное, необходимо помнить, что в момент проверки Вы обнаружите и собственное окно (окно проверяющего приложения) и дочернее окно среды Delphi (в момент разработки приложения, для Delphi 1.0).

      Пример:

      ............

      procedure TForm1.FormCreate(Sender: TObject);
      VAR

        Wnd : hWnd;
        buff: ARRAY [0..127] OF Char;
        WC: TWndClass;

      begin

        Wnd := GetWindow(Handle, gw_HWndFirst);
        WHILE Wnd <> 0 DO BEGIN

          {Если не собственное и не дочернее окно}
          IF (Wnd <> Application.Handle) AND (GetWindow(Wnd, gw_Owner) = 0) THEN BEGIN

            GetWindowText(Wnd, buff, sizeof(buff));
            {Если заголовок совпадает, то...}
            IF StrPas(buff) = Application.Title THEN BEGIN

              MessageDlg('Приложение уже загружено', mtWarning, [mbOk], 0);
              Halt;

            END;

          END;
          Wnd := GetWindow(Wnd, gw_hWndNext);

        END;

      end;

      ............


Вопрос и Ответ 45

Вопросы и Ответы

      45. Можно ли заставить Database Desktop отображать в таблицах русские символы?

      В Windows' 95 этого добиться очень легко. Достаточно в файл win.ini в раздел [FontSubstitutes] добавить строку:

      Arial=Arial Cyr

      Это дает результат и в Delphi и в Delphi 2.0. Но, к сожалению, в Windows 3.1 этот способ не срабатывает и Вам придется найти (или сделать самим) шрифт Arial в котором будут русские символы.


Вопрос и Ответ 46

Вопросы и Ответы

      46. Возможно ли определить общую ширину всех видимых полей TDBGrid во время работы приложения?

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

      Ширина одной разделительной линии равна одному пикселу, ширина столбца индикации - примерно 11-15 (в зависимости от различных факторов), ширина полосы прокрутки является системной информацией.

      Пример:

      ............

      function TForm1.GridWidth(DBG: TDBGrid):Integer;
      CONST

        cMEASURE_CHAR = '0';
        iEXTRA_COL_PIX = 4;
        iINDICATOR_WIDE = 15;

      VAR

        i, iColumns, iColWidth, iTitleWidth, iCharWidth : Integer;

      BEGIN

        {Ширина вертикальной полосы
      прокрутки}
Result := GetSystemMetrics(SM_CXVSCROLL);
iColumns := 0;
{Ширина видимых столбцов}
iCharWidth := DBG.Canvas.TextWidth(cMEASURE_CHAR);
WITH DBG.DataSource.DataSet DO

          FOR i := 0 TO FieldCount-1 DO

            WITH Fields[i] DO

              IF Visible THEN BEGIN

                iColWidth := iCharWidth*DisplayWidth;
                IF dgTitles IN DBG.Options THEN BEGIN

                  iTitleWidth := DBG.Canvas.TextWidth(DisplayLabel);
                  IF iColWidth

                END;
                Inc(iColumns, 1);
                Inc(Result, iColWidth+iEXTRA_COL_PIX);

              END;

        {Ширина столбца индикатора}
        IF dgIndicator IN DBG.Options THEN BEGIN

          Inc(iColumns, 1);
          Inc(Result, iINDICATOR_WIDE);

        END;
        {Ширина всех разделительных линий}
        IF dgColLines IN DBG.Options THEN

          Inc(Result, iColumns)

        ELSE Inc(Result, 1);

      END;

      ............


Вопрос и Ответ 47

Вопросы и Ответы

      47. Как установить часы компьютера?

      Для установки часов можно воспользоваться функцией 2DH прерывания 21H. В CH помещаются часы, в CL - минуты, в DH - секунды, а в DL - сотые доли секунды.

      Пример:

      ............

      PROCEDURE SetTime(Hour, Min, Sec: Word); ASSEMBLER;
      ASM

        MOV CH, BYTE PTR Hour
        MOV CL, BYTE PTR Min
        MOV DH, BYTE PTR Sec
        MOV DL, 0
        MOV AH, 2DH
        INT 21H

      END;

      ............


Вопрос и Ответ 48

Вопросы и Ответы

      48. Как определить какие приложения уже запущены?

      Для получения списка запущенных приложений необходимо, с помощью функции:

      function GetWindow(Wnd: HWnd; Cmd: Word): HWnd;

      передав первым параметром ссылку на окно своего приложения, а вторым - константу GW_HWNDFIRST, получить ссылку на первое окно в списке окон. И затем, с помощью этой же функции, но передавая уже ссылку на найденное окно и константу GW_HWNDNEXT получить следующую ссылку и так, до тех пор, пока функция не вернет значение равное нулю.

      В процессе получения ссылок следует проверять:

      • имеет ли окно заголовок;
      • видимо ли окно;
      • не дочернее ли окно (если необходимо).

      Пример:

      ............

      procedure TForm1.Button1Click(Sender: TObject);
      VAR

        Wnd : hWnd;
        buff: ARRAY [0..127] OF Char;

      begin

        ListBox1.Clear;
        Wnd := GetWindow(Handle, gw_HWndFirst);
        WHILE Wnd <> 0 DO BEGIN {Не показываем:}

          IF (Wnd <> Application.Handle) AND {-Собственное окно}

            IsWindowVisible(Wnd) AND {-Невидимые окна}
            (GetWindow(Wnd, gw_Owner) = 0) AND {-Дочернии окна}
            (GetWindowText(Wnd, buff, sizeof(buff)) <> 0) {-Окна без заголовков}

          THEN BEGIN

            GetWindowText(Wnd, buff, sizeof(buff));
            ListBox1.Items.Add(StrPas(buff));

          END;
          Wnd := GetWindow(Wnd, gw_hWndNext);

        END;
        ListBox1.ItemIndex := 0;

      end;

      ............


Вопрос и Ответ 49

Вопросы и Ответы

      49. Можно ли убрать окно с экрана и из панели задач?

      Можно, для этого достаточно вызвать метод:

      Form1.Hide;

      для возвращения окна на экран вызывается метод:

      Form1.Show;

      Будте внимательны, так как скрытые окна не получают сообщений от клавиатуры и мыши.


Вопрос и Ответ 50

Вопросы и Ответы

      50. Почему происходит искажение некоторых русских символов в таблице Paradox?

      Это может происходить из-за неправильно установленного языка таблицы.

      Для корректной работы с базами данных Paradox, на русском языке, необходимо установить язык таблицы "Paradox Cyrr 866". Остальные языки не поддерживают кириллицу и не будут верно с ней работать.


Вопрос и Ответ 51

Вопросы и Ответы

      51. Можно ли программно установить произвольную строку в первую позицию TListBox?

      Для установки любой строки в произвольную позицию в окне TListBox можно послать сообщение:

      SendMessage(ListBox1.Handle, lb_SetTopIndex, SpinEdit1.Value-1, 0);

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

      Строки нумеруются с нуля.

      Пример:

      ............

      procedure TForm1.SpinEdit1Change(Sender: TObject);
      begin

        TRY

          SendMessage(ListBox1.Handle, lb_SetTopIndex, SpinEdit1.Value-1,0);

        FINALLY
        END;

      end;

      ............


Вопрос и Ответ 52

Вопросы и Ответы

      52. Как отключить обработку ошибок самой средой Delphi?

      Для Delphi 1.0

        Войдите в меню Option и выберите пункт Environment. В появившемся диалоговом окне откройте страницу Preferences и уберите флажок Break on exception.

      Для Delphi 2.0

        Войдите в меню Tools и выберите пункт Options. В появившемся диалоговом окне откройте страницу Preferences и уберите флажок Break on exception.


Вопрос и Ответ 53

Вопросы и Ответы

      53. Есть ли возможность перевести сообщения которые выдаются во время выполнения на те или иные ситуации?

      Сообщения на все ситуации происходящие во время выполнения приложения и во время разработки, находятся в файлах ресурсов (*.RES) в каталоге DELPHI\LIB\. Наиболее интересными представляются файлы CONSTS.RES и DBCONSTS.RES, которые содержат, соответственно, основные сообщения приложения и сообщения баз данных. В файле CONSTS.RES содержатся, так же, все надписи на кнопках и заголовки для окон типа MessageBox.

      Для редактирования подойдет любой редактор ресурсов, например Resource Workshop, который может работать со строковыми ресурсами. Будте внимательны, так как формат ресурсов Win 3.1 и Win 95 несколько различается. После изменения RES-файлов достаточно будет перекомпилировать проект.


Вопрос и Ответ 54

Вопросы и Ответы

      54. Как представить число его прописным эквивалентом?

      Простых путей решения этой проблемы не существует и приходится писать процедуру разбора числа. Задача сводится к разбору числа на триады (...1,234,567) начиная с конца, а уже в них происходит конечный разбор трехзначного числа и формирование его прописного эквивалента с учетом добавления "тысяч", "миллионов" и т.д.

      Единственное, необходимо помнить о роде "добавки" (одна тысяча, один миллион) и разницы написания (одна тысяча, две тысячи и пять тысяч)...

      Пример:

      ............

      CONST

        MAX3 = 5; {Максимальное количество триад}

        A11: ARRAY[1..2] OF STRING[20] = ('одна ', 'две ');

        A1: ARRAY[0..19] OF STRING [20] = ('', 'один ', 'два ','три ', 'четыре ', 'пять ', 'шесть ', 'семь ', 'восемь ', 'девять ', 'десять ', 'одиннадцать ', 'двенадцать ', 'тринадцать ', 'четырнадцать ', 'пятнадцать ', 'шестнадцать ', 'семнадцать ', 'восемнадцать ', 'девятнадцать ');

        A10: ARRAY[0..9] OF STRING [20] = ('', 'десять ', 'двадцать ', 'тридцать ', 'сорок ', 'пятьдесят ', 'шестьдесят ', 'семьдесят ', 'восемьдесят ', 'девяносто ');

        A100: ARRAY[0..9] OF STRING[20]= ('', 'сто ', 'двести ', 'триста ', 'четыреста ', 'пятьсот ', 'шестьсот ', 'семьсот ', 'восемьсот ', 'девятьсот ');

        {четвертым параметром является обозначение мужского или женского рода,

          где '0' - женский род;
          '1' - мужской род.

        Это дает возможность, например, изменяя "рубли" на "штуки" просто поменять '1' на '0' не меняя кода.}
        A0: ARRAY[0..MAX3-1, 0..3] OF STRING[20]= (('рубль', 'рубля', 'рублей', '1'), ('тысяча', 'тысячи', 'тысяч', '0'), ('миллион', 'миллиона', 'миллионов', '1'), ('миллиард', 'миллиарда', 'миллиардов', '1'), ('триллион', 'триллиона', 'триллионов', '1'));

      procedure TForm1.Edit1Change(Sender: TObject);
      VAR

        Value: LongInt;
        i100, i10, i1: Integer;
        V, p, n, i: Integer;

      begin

        TRY

          Value := StrToInt(Edit1.Text);
          Memo1.Clear;
          n := 0;
          {Обработка отрицательного значения и нуля}
          IF Value <0 THEN BEGIN

            Memo1.Lines.Add('минус');
            Value := -Value;

          END
          ELSE

            IF Value = 0 THEN Memo1.Lines.Add('ноль')
            ELSE Memo1.Lines.Add('');

          REPEAT

            {Разбивка на триады с конца}
            V := Value MOD 1000;
            Value := Value DIV 1000;
            {Обработка}
            IF (V > 0) OR (n = 0) THEN BEGIN

              i100 := V DIV 100;
              V := V-(i100*100);
              IF V >= 20 THEN BEGIN

                i1 := V MOD 10;
                V := V DIV 10;
                i10 := V MOD 10;

              END
              ELSE BEGIN

                i1 := V;
                i10 := 0;

              END;
              CASE i1 OF

                1: p := 0;
                2..4: p := 1;
                ELSE p := 2;

              END;
              {Изменение в зависимости от женского или мужского рода}
              IF (A0[n,3] = '0') AND ((i1 = 1) OR (i1 = 2)) THEN

                Memo1.Lines.Insert(1, A100[i100]+A10[i10]+A11[i1]+A0[n,p])

              ELSE

                Memo1.Lines.Insert(1, A100[i100]+A10[i10]+A1[i1]+A0[n,p]);

            END;
            Inc(n);
            {Проверка выхода за максимальное количество триад}
            IF n > MAX3 THEN Exit;

          UNTIL Value <= 0;

        EXCEPT

          Memo1.Clear;
          Memo1.Lines.Add('Ошибка');

        END

      end;

      ............


Вопрос и Ответ 55

Вопросы и Ответы

      55. Можно ли получить растровое изображение формы с заголовком и рамкой?

      Стандартные средства Delphi позволяют получать растровое изображение только внутренней части окна. Для получения изображения всего окна с заголовком и рамкой необходимо воспользоваться функциями API.

      Во-первых, получаем контекст всего окна функцией:

      function GetWindowDC(Wnd: HWnd): HDC;

      Затем копируем растровое изображение окна в компонент TImage (для примера). И освобождаем полученный контекст окна:

      function ReleaseDC(Wnd: HWnd; DC: HDC): Integer;

      Пример:

      ............

      procedure TForm1.Button1Click(Sender: TObject);
      VAR DC: hDC;
      begin

        DC := GetWindowDC(Handle);
        Image1.Picture.BitMap.Height := Height;
        Image1.Picture.BitMap.Width := Width;
        BitBlt(Image1.Picture.BitMap.Canvas.Handle, 0, 0, Width, Height, DC, 0, 0, SRCCOPY);
        ReleaseDC(Handle, DC);

      end;

      ............


Вопрос и Ответ 56

Вопросы и Ответы

      56. Как вызвать Pop-Up меню не используя правую кнопку мыши?

      Для вызова меню нужно воспользоваться методом Popup объекта TPopupMenu:

      procedure Popup(X, Y: Integer);

      X и Y задаются в координатах экрана.

      Пример:

      ............

      procedure TForm1.Button1Click(Sender: TObject);
      begin

        PopupMenu1.PopUp(Left+5, Top+5);

      end;

      ............


Вопрос и Ответ 57

Вопросы и Ответы

      57. Несколько советов по компиляции и отладке приложений.

      Иногда, чаще у начинающих, после многократного добавления и удаления большого числа различных компонент происходит появление необъяснимых и порой нелепых сообщений о несуществующих ошибках. Такое трудно объяснить, но бороться с этим очень просто. Достаточно полностью перекомпилировать весь проект (меню "Compile", пункт "Build All") и он начинает опять прекрасно работать. Только не списывайте на компилятор свои ошибки!

      При отладке приложений с базами данных часто бывает такое - происходит ошибка в базе данных, ее отлавливает (если не отключено) среда и останавливает приложение выдав на экран сообщение об ошибке. Пользователь исправляет ошибку и начинает компилировать проект заново и... Delphi "вешается" намертво прихватив с собой и Windows. Это тоже не поддается разумному объяснению, но легко предотвращается. При выдаче сообщения средой об ошибке в базе данных уберите окно с сообщением и заново запустите приложение, командой RUN, после появления сообщения об этой же ошибке самим приложением можно смело его закрывать и исправлять.


Вопрос и Ответ 58

Вопросы и Ответы

      58. Как заставить перерисоваться весь экран?

      Добиться обновления содержимого всего экрана можно различными способами, но наверное, самый правильный - это воспользоваться функцией RepaintScreen из библиотеки USER.

      procedure RepaintScreen; external 'USER' index 275;

      Данная функция не требут передачи каких-либо параметров - она просто заставляет обновить содержимое всех окон и видимую область рабочего стола.

      Пример:

      unit Unit1;

      interface

      uses

        SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;

    • type

        TForm1 = class(TForm)

          Button1: TButton;
          procedure Button1Click(Sender: TObject);
          private
          { Private declarations }
          public
          { Public declarations }

        end;

      var

        Form1: TForm1;

      procedure RepaintScreen;

      implementation

      {$R *.DFM}

      procedure RepaintScreen; external 'USER' index 275;

      procedure TForm1.Button1Click(Sender: TObject);
      begin

        RepaintScreen;

      end;

      end.


Вопрос и Ответ 59

Вопросы и Ответы

      59. Как создать кнопку во время работы приложения?

      Для создания кнопки, во время работы приложения, необходимо выполнить всего два шага:

      • Создать кнопку;
      • Установить необходимые свойства этой кнопки.

      При правильном создании объекта, в данном случае кнопки, этот объект при уничтожении формы будет автоматически уничтожен, но желательно всегда самим уничтожать все объекты созданные в процессе работы приложения. Это убережет Вас от многих проблем.

      Пример:

      ............

        ............
        public

          { Public declarations }
          MyButton: TButton;
          PROCEDURE MyButtonDown(Sender: TObject);

        end;

    • ............

      procedure TForm1.FormCreate(Sender: TObject);
      begin

        MyButton := TButton.Create(Self);
        WITH MyButton DO BEGIN

          Parent := Self;
          Caption := 'Кнопка';
          Left := 0;
          Top := 0;
          OnClick := MyButtonDown;

        END;

      end;

      ............

      PROCEDURE TForm1.MyButtonDown(Sender: TObject);
      BEGIN

        WITH Sender AS TButton DO

          MessageDlg('Нажата '+Caption, mtInformation, [mbOk], 0);

      END;

      ............

      procedure TForm1.FormDestroy(Sender: TObject);
      begin

        MyButton.Free;

      end;

      ............

      P.S. Таким же образом создаются и другие компоненты.

...предыдущая страница первая...