Оригинальный DVD-ROM: eXeL@B DVD !
eXeL@B ВИДЕОКУРС !

ВИДЕОКУРС ВЗЛОМ
выпущен 10 декабря!


УЗНАТЬ БОЛЬШЕ >>
Домой | Статьи | RAR-cтатьи | FAQ | Форум | Скачать | Видеокурс
Новичку | Ссылки | Программирование | Интервью | Архив | Связь

БОЛЬШОЙ FAQ ПО DELPHI



Центрирование информационного диалога (MessageDlg)


 unit kns;
 
 {$R-}
 
 interface
 
 uses Forms, Dialogs;
 
 { Центрирование информационного диалога }
 function MessageDlgCtr(const Msg: string; DlgType: TMsgDlgType;
   Buttons: TMsgDlgButtons; HelpCtx: Longint): Integer;
 
 implementation
 
 uses Consts;
 
 { Функция MessageDlg располагает диалог над центром активного окна }
 
 function MessageDlgCtr(const Msg: string; DlgType: TMsgDlgType;
   Buttons: TMsgDlgButtons; HelpCtx: Longint): Integer;
 begin
   with CreateMessageDialog(Msg, DlgType, Buttons) do
   try
     HelpContext := HelpCtx;
     Left := Screen.ActiveForm.Left + (Screen.ActiveForm.Width div 2) -
       (Width div 2);
 
     Top := Screen.ActiveForm.Top + (Screen.ActiveForm.Height div 2) -
       (Height div 2);
 
     Result := ShowModal;
   finally
     Free;
   end;
 end;
 
 end.
 




MessageDlg в обработчике OnExit

Автор: OAmiry (Borland)

Я пытаюсь использовать MessageDlg в обработчике OnExit компонента TEdit. При показе диалогового окна пользователь нажимает одну из кнопок, после чего, по идее, должно возникнуть событие OnEnter компонента, но оно не возникает! Если вызов диалога сопровождается комментарием, событие OnEnter инициализируется верно. В любом случае, событие OnExit завершает весь код.

Фактически (в момент показа диалога), фокус имеет поле редактирование, но курсор при этом не выводится. Передавая фокус "вперед" и снова "назад", вы получите желаемый результат. Например: В обработчике события OnExit поля редактирования после вызова MessageDlg попробуйте вызвать следующие функции:


 PostMessage(Handle, WM_NEXTDLGCTL, 0, 0);
 PostMessage(Handle, WM_NEXTDLGCTL, 1, 0);
 




MessageDlg без Gliph

Автор: Steve Samuelson

Как мне получить информационное окошко c 3D-стилем и простыми кнопками (без Glyph), не особо изголяясь в программировании?

Просто добавьте следующую строчку в ваш код диалогового окошка:


 MsgDlgGlyphs := false;
 

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




Как послать некое сообщение всем формам

Автор: Nomadic

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


 var
   I: Integer;
   M: TMessage;
 ...
 
 with M do
 begin
 
   Message := ...
   ...
 end;
 
 for I := 0 to Pred(Screen.FormCount) do
 begin
   PostMessage(Forms[I].Handle, ...);
   // Если надо и всем чилдам
   Forms[I].Broadcast(M);
 end;
 




Override, Vitual, Dynamic - методы

Автор: Mark

Если метод в классе предка объявлен как виртуальный (virtual) или динамический (dynamic), вам необходимо перекрыть его во всех классах-наследниках. Если вы объявляете наследованный метод виртуальным или динамическим, вы начинаете строить его новое виртуальное/динамическое дерево наследования. Допустим, у нас есть следующая иерархия: A (родитель) - B - C - D. Если вы объявляете метод как виртуальный (или динамический) в A, перекрываете в B, создаете виртуальным в C и перекрываете в D, вот что получается:

 фактический  класс, используемый   класс, использующий
 класс        для доступа к методу  метод
 -----------+---------------------+--------------------
      D                D                     D
      D                C                     D
      D                B                     B
      D                A                     B
 
      C                C                     C
      C                B                     B
      C                A                     B
 
      B                B                     B
      B                A                     B

Вывод: работа виртуального/динамического наследования прекращается в момент создания одноименного виртуального/динамического метода наследниками класса.




Работа метода Assign

В общем случае, утверждение "Destination := Source" не идентично утверждению "Destination.Assign(Source)".

Утверждение "Destination := Source" принуждает Destination ссылаться на тот же объект, что и Source, а "Destination.Assign(Source)" копирует содержание объектных ссылок Source в объектные ссылки Destination.

Если Destination является свойством некоторого объекта (тем не менее, и свойство не является ссылкой на другой объект, как, например, свойство формы ActiveControl, или свойство DataSource элементов управления для работы с базами данных), тогда утверждение "Destination := Source" идентично утверждению "Destination.Assign(Source)". Это объясняет, почему LB.Items := MemStr работает, когда MemStr := LB.Items нет.




Короткое имя файла в длинное и наоборот, сокращённое имя файла

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


 {=========================================================}
 Function Mince(PathToMince: String; InSpace: Integer): String;
 {=========================================================}
 // "C:\Program Files\Delphi\DDrop\TargetDemo\main.pas" 
 // "C:\Program Files\..\main.pas" 
 Var
   sl: TStringList;
   sHelp, sFile: String;
   iPos: Integer;
 
 Begin
   sHelp := PathToMince;
   iPos := Pos('\', sHelp);
   If iPos = 0 Then
   Begin
     Result := PathToMince;
   End
   Else
   Begin
     sl := TStringList.Create;
     // Decode string 
     While iPos <> 0 Do
     Begin
       sl.Add(Copy(sHelp, 1, (iPos - 1)));
       sHelp := Copy(sHelp, (iPos + 1), Length(sHelp));
       iPos := Pos('\', sHelp);
     End;
     If sHelp <> '' Then
     Begin
       sl.Add(sHelp);
     End;
     // Encode string 
     sFile := sl[sl.Count - 1];
     sl.Delete(sl.Count - 1);
     Result := '';
     While (Length(Result + sFile) < InSpace) And (sl.Count <> 0) Do
     Begin
       Result := Result + sl[0] + '\';
       sl.Delete(0);
     End;
     If sl.Count = 0 Then
     Begin
       Result := Result + sFile;
     End
     Else
     Begin
       Result := Result + '..\' + sFile;
     End;
     sl.Free;
   End;
 End;
 
 {===================================================}
 Function ShortFileName(Const FileName: String): String;
 {===================================================}
 Var
   aTmp: Array[0..255] Of Char;
 
 Begin
   If Not FileExists(FileName) Then
   Begin
     Result := '';
   End
   Else
   Begin
     If GetShortPathName(PChar (FileName), aTmp, Sizeof (aTmp) - 1) = 0 Then
     Begin
       Result:= FileName;
     End
     Else
     Begin
       Result:= StrPas (aTmp);
     End;
   End;
 End;
 
 {==============================================}
 Function LongFileName(ShortName: String): String;
 {==============================================}
 Var
   SR: TSearchRec;
 
 Begin
   Result := '';
   If (pos ('\\', ShortName) + pos ('*', ShortName) +
       pos ('?', ShortName) <> 0) Or Not FileExists(ShortName) Then
   Begin
     { ignore NetBIOS name, joker chars and invalid file names }
     Exit;
   End;
   While FindFirst(ShortName, faAnyFile, SR) = 0 Do
   Begin
     { next part as prefix }
     Result := '\' + SR.Name + Result;
     SysUtils.FindClose(SR);  { the SysUtils, not the WinProcs procedure! }
     { directory up (cut before '\') }
     ShortName := ExtractFileDir (ShortName);
     If length (ShortName) <= 2 Then
     Begin
       Break;  { ShortName contains drive letter followed by ':' }
     End;
   End;
   Result := ExtractFileDrive (ShortName) + Result;
 end;
 




Минимизирование формы при запуске

Мне необходимо при запуске приложения спрятать главную форму, но, к сожалению, это не работает. После того, как я установил в главной форме свойство WindowState в wsMinimized и запустил ее, форма свернулась на рабочем столе Win95 вместо положенной панели задач.

Кто-нибудь знает как решить эту проблему?

Была одна статья по этому поводу в Delphi Magazine, Issue 19, март 1997, которая объясняла эту проблему.

Вот мой переработанный вариант обхода ошибки:


 unit Foobar;
 
 interface
 
 type
 
   TfrmFoobar = class(TForm);
 procedure DoRestore(Sender: TObject);
 procedure FormCreate(Sender: TObject);
 private
   { Private declarations }
 public
   { Public declarations }
 end;
 
 implementation
 
 procedure TfrmUVChannel.FormCreate(Sender: TObject);
 begin
 
   //Устанавливаем временный обработчик события восстановления формы приложения
   Application.OnRestore := DoRestore;
   Application.Minimize;
 end;
 
 procedure TfrmFoobar.DoRestore(Sender: TObject);
 begin
 
   Application.ShowMainForm := True;
   //Восстанавливаем приложение
   Perform(wm_SysCommand, sc_Restore, 0);
   //Гарантируем правильную перерисовку всех компонентов
   Show;
   //Убираем временного обработчика события чтобы не вызывался в будущем
   Application.OnRestore := nil;
 end;
 
 initialization
 
   //Здесь прячем минимизированную главную форму
   Application.ShowMainForm := False;
 
 end.
 




Как пользоваться командой шела - MinimizeAll

Для этого надо импортировать Microsoft Shell Controls & Automation Type Library:

  1. В меню Project..Import Type Library
  2. Выберите Microsoft Shell Controls & Automation (version 1.0).
  3. Нажмите Install...

На панели компонентов, в закладке ActiveX появится несколько компонентов. Перетащите на форму компонент TShell. После этого, например, можно всё минимизировать:

 Shell1.MinimizeAll;
 

Так же в этом компоненте присутствует давольно много забавных примочек:


 procedure TForm1.Shell(sMethod: Integer);
 begin
   case sMethod of
     0:
       //Минимизируем все окна на рабочем столе
       begin
         Shell1.MinimizeAll;
         Button1.Tag := Button1.Tag + 1;
       end;
     1:
       //Показываем диалоговое окошко Run
       begin
         Shell1.FileRun;
         Button1.Tag := Button1.Tag + 1;
       end;
     2:
       //Показываем окошко завершения работы Windows
       begin
         Shell1.ShutdownWindows;
         Button1.Tag := Button1.Tag + 1;
       end;
     3:
       //Показываем окно поиска файлов
       begin
         Shell1.FindFiles;
         Button1.Tag := Button1.Tag + 1;
       end;
     4:
       //Отображаем окно настройки времени и даты
       begin
         Shell1.SetTime;
         Button1.Tag := Button1.Tag + 1;
       end;
     5:
       //Показываем диалоговое окошко настройки интернета (Internet Properties)
       begin
         Shell1.ControlPanelItem('INETCPL.cpl');
         Button1.Tag := Button1.Tag + 1;
       end;
     6:
       //Предлагаем пользователю выбрать директорию из Program Files
       begin
         Shell1.BrowseForFolder(0, 'My Programs', 0, 'C:\Program Files');
         Button1.Tag := Button1.Tag + 1;
       end;
     7:
       //Показываем диалоговое окошко настройки панели задач
       begin
         Shell1.TrayProperties;
         Button1.Tag := Button1.Tag + 1;
       end;
     8:
       //Восстанавливаем все окна на рабочем столе
       begin
         Shell1.UndoMinimizeAll;
         Button1.Tag := 0;
       end;
   end; {case}
 end;
 
 procedure TForm1.Button1Click(Sender: TObject);
 begin
   Shell(Button1.Tag);
 end;
 




Как минимизиpовать все запущеные окна

Автор: Nomadic


 (* Hачало (MINIMIZE.DPR) *)
 
 {$APPTYPE CONSOLE}
 program Minimize;
 uses Windows, Messages;
 var
   Count: integer;
 
 function EnumProc(WinHandle: HWnd; Param: LongInt): Boolean; stdcall;
 begin
 
   if (GetParent(WinHandle) = 0) and (not IsIconic(WinHandle)) and
     (IsWindowVisible(WinHandle)) then
   begin
     PostMessage(WinHandle, WM_SYSCOMMAND, SC_MINIMIZE, 0);
     Inc(Count);
   end;
   EnumProc := TRUE;
 end;
 
 begin
 
   Count := 0;
   EnumWindows(@EnumProc, 0);
   Writeln('Minimized:', Count, ' windows');
 end.
 
 (* конец (MINIMIZE.DPR) *)
 




Сворачивание всех окон


 function MyCallback(Wnd: THandle;Param: integer): boolean; stdcall;
 var
   style: longint;
   tsb, rabst: integer;
 begin
   tsb:=FindWindow('Shell_TrayWnd', nil);
   rabst:=FindWindow('ProgMan', 'Program Manager');
   Result := Wnd <> 0;
   style:=GetWindowLong(wnd,GWL_EXSTYLE);
   style:=style and WS_EX_TOPMOST;
   if Result and IsWindowVisible(Wnd)and (not IsIconic(WND)) and (wnd<>tsb) and
   (wnd<>rabst) and (wnd<>FindWindow('Indicator',nil)) and
   (style<>WS_EX_TOPMOST)and(wnd<>form1.handle)then
   begin
     ShowWindow(Wnd,sw_hide);
     ShowWindow(Wnd,Param);
   end;
 end;
 
 
 procedure ShowAllWindows(Cmd: integer);
 begin
   EnumWindows(@MyCallback,Cmd);
 end;
 

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


 ShowAllWindows(SW_SHOWMINIMIZED);
 




Миниатюрное Delphi-приложение

Автор: Dr. Bob

Американские новости: "28-го февраля в Сиэтле произошло землетрясение силой в 6.8 балла". Рядовой американец: "Это Билл Гейтс уронил свой кошелек".

Следующая программа генерирует .EXE-файл размером менее чем 2Кб (1176 байт с моей специальной конфигурацией)...


 {$A+,B-,D-,F-,G+,I-,K-,L-,N-,P-,Q-,R-,S-,T-,V-,W-,X+,Y-}
 {$M 32768,0}
 uses WinTypes, WinProcs;
 begin
   MessageBox(GetActiveWindow, 'Вася, это ты?', 'Dr.Bob',
     MB_ICONINFORMATION OR MB_OK)
 end.
 




Показать миниатюру страницы в TWebBrowser

Сидят два программера, пиво пьют. Ну, значит, один другому и говорит:
- Слышь, Серега, я вчера на одном чате с такой классной девчонкой познакомился. Она мне по Интернету такой минет сделала, просто обалдеть.
Второй:
- Димон, ты это... в этом Интернете поаккуратнее, пожалуйста. А то я тоже лазил, так меня там в задницу поимели.


 procedure TForm1.WebBrowser1NavigateComplete2(Sender: TObject;
   const pDisp: IDispatch; var URL: OleVariant);
 begin
   WebBrowser1.OleObject.Document.Body.Style.Zoom := 0.50;
 end;
 
 {A page must be already loaded into TWebBrowser}
 //.zoom:=0.25; //25% 
 //.zoom:=0.5;  //50%
 //.zoom:=1.5;  //100%
 //.zoom:=2.0;  //200%
 //.zoom:=5.0;  //500%
 //.zoom:=10.0; //1000%
 




CHARTFX - минимум максимум

Умеp Билли Гейтс и попал на небо к Богy.
- Заслyги твои велики так что можешь сам выбpать в Ад или в Рай. Посмотpи сам. Hy пошел Билли в Рай там литавpы игpают, нектаp пьют. Скyчно емy стало. Пошел в Ад. Там вино pекой, девочки...
- Hy все я pешил. Я идy в Ад.
- Ты хоpошо подyмал? Hазад доpоги нет.
- Да. Откpывается люк и Билли пpоваливается в Ад. Пpямо в котел и чеpти давай его пиками колоть. Он орет:
- Как же так! Я тyт совсем не это видел!
Добродушные черти:
- ТАК ЭТО БЫЛА ДЕМОВЕРСИЯ!

Так можно сделать с ChartFX в Delphi 2.... Я думаю то же самое будет и в D1...


 cfxStockTrends.Adm[CSA_MIN] := X;       //устанавливаем минимум по оси Y
 cfxStockTrends.Adm[CSA_MAX] := Y;       //Устанавливаем максимум по оси Y
 




Как сделать, чтобы неглавная форма минимизировалась не на TaskBar, а выше него


 void __fastcall CreateParams(TCreateParams &Params);
 
 ...
 
 void __fastcall TForm1::CreateParams(TCreateParams &Params)
 {
 TForm::CreateParams(Params);
 Params.ExStyle |= WS_EX_APPWINDOW;
 Params.WndParent = GetDesktopWindow();
 }
 




Определить минимальные поля для принтера


 uses
   Printers;
 
 type
   TMargins = record
     Left,
     Top,
     Right,
     Bottom: Double
 end;
 
 procedure GetPrinterMargins(var Margins: TMargins);
 var
   PixelsPerInch: TPoint;
   PhysPageSize: TPoint;
   OffsetStart: TPoint;
   PageRes: TPoint;
 begin
   PixelsPerInch.y := GetDeviceCaps(Printer.Handle, LOGPIXELSY);
   PixelsPerInch.x := GetDeviceCaps(Printer.Handle, LOGPIXELSX);
   Escape(Printer.Handle, GETPHYSPAGESIZE, 0, nil, @PhysPageSize);
   Escape(Printer.Handle, GETPRINTINGOFFSET, 0, nil, @OffsetStart);
   PageRes.y := GetDeviceCaps(Printer.Handle, VERTRES);
   PageRes.x := GetDeviceCaps(Printer.Handle, HORZRES);
   // Top Margin 
   Margins.Top := OffsetStart.y / PixelsPerInch.y;
   // Left Margin 
   Margins.Left := OffsetStart.x / PixelsPerInch.x;
   // Bottom Margin 
   Margins.Bottom := ((PhysPageSize.y - PageRes.y) / PixelsPerInch.y) -
     (OffsetStart.y / PixelsPerInch.y);
   // Right Margin 
   Margins.Right := ((PhysPageSize.x - PageRes.x) / PixelsPerInch.x) -
     (OffsetStart.x / PixelsPerInch.x);
 end;
 
 function InchToCm(Pixel: Single): Single;
 // Convert inch to Centimeter 
 begin
   Result := Pixel * 2.54
 end;
 
 procedure TForm1.Button1Click(Sender: TObject);
 var
   Margins: TMargins;
 begin
  GetPrinterMargins(Margins);
  ShowMessage(Format('Margins: (Left: %1.3f, Top: %1.3f, Right: %1.3f, Bottom: %1.3f)',
   [InchToCm(Margins.Left),
    InchToCm(Margins.Top),
    InchToCm(Margins.Right),
    InchToCm(Margins.Bottom)]));
 end;
 




Впечатления от реального Microsoft Inductive User Interface

Автор: Григорий Ситнин

Microsoft наконец-то сделал интерфейс пользователя! До Windows 2000/Me включительно как ведь было: интерфейс был максимум — документ-ориентированный. То есть, все элементы пользовательского интерфейса были спроектированы так, чтобы работать с документом. Теперь же, основная задача интерфейса пользователя — дать возможность планомерно и точно решить задачу.

Новый тип интерфейсов пользователя Microsoft называет Inductive User Interface (IUI). Приведу фразу из Microsoft IUI Guidelines (ответ на вопрос "Что есть IUI?"): "IUI это, — новая модель пользовательского интерфейса, советующая, как сделать программное приложение проще, разбивая функции (features) на экраны или страницы, которые проще понять и объяснить". Вот такое вот объяснение от создателя технологии.

Дедуктивный интерфейс пользователя

"Множество коммерческих приложений имеют пользовательский интерфейс, на каждом экране которого представлено некоторое количество управляющих элементов (controls), но пользователю приходится лишь догадываться о назначении данной страницы и о том, как использовать управляющие элементы…", говорит Microsoft все в той же "Microsoft IUI Guidelines" (все цитаты будут именно из этого документа, если не указано иное).

В качестве примера такого интерфейса MS приводит следующий диалог:

Опытные пользователи, увидев этот диалог, довольно быстро поймут, что он позволяет управлять списком идей (things), что копки под списком позволяют добавлять, удалять и изменять информацию. Тем не менее, стоит взглянуть на этот диалог с точки зрения обычного пользователя.

Когда обычный пользователь видит этот диалог, первая мысль, которая рождается у него в голове, звучит так: "Ну и что я собирался с этим делать?". При появлении этого окна пользователь должен приостановиться и догадаться о его назначении. С трудом помогает довольно сомнительная надпись "Things:", а некоторые пользователи могут пытаться ввести информацию прямо в область списка, так как он выглядит точно так же, как и область ввода текста.

Следующее, что оттолкнет пользователя, это — две отключенные кнопки "Remove" и "Properties". Пользователю придется поэкспериментировать с данным диалогом для того, чтобы понять, когда и что работает.

Пользователь также может задаться такими высокоуровневыми вопросами, как "Сколько элементов может быть в списке? Должен ли я вводить информацию в каком-либо порядке? Для чего все это?".

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

Панацея?

Нет, но путь к ней. По заверениям Microsoft (а их стоит, минимум, принять во внимание), метод IUI является решением данной проблемы. Хорошо спроектированный интерфейс пользователя должен помочь пользователю ответить на два важных вопроса:

  • Что я сейчас собирался сделать?
  • Куда я пойду отсюда, чтобы выполнить мою следующую задачу?

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

Следуя данной идеологии можно выделить четыре основных шага при создании IUI:

  1. Сфокусируйте каждый экран на решение одной задачи.
  2. Объяснить задачу.
  3. Сделайте наполнение каждого экрана соответствующим данной задаче.
  4. Предложите ссылки на вторичные задачи.

В дополнение к этим четырем шагам Microsoft советует придерживаться следующих пяти правил:

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

Многие задачи требуют организации так называемого "процесса" (process) для решения какой-либо задачи. В терминах IUI процессом называется некоторая последовательность шагов (экранов), предназначенных для решения одной задачи.

Когда пользователь нажимает кнопку "Done" на последнем экране процесса следует отправить его к месту, с которого он начал решать данную задачу.

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

В действии

Итак, с концептуальной основой Inductive User Interface мы разобрались. Как применила свою же идеологию Microsoft? А история такова: Оттачивать данную концепцию Microsoft начала еще на Microsoft Money 2000. Отточенные же идеи воплотились во всей своей красе в программных продуктах под маркой XP.

К примеру, приведу макет диалога задания пароля для учетной записи Windows:

Из этого диалога понятно, что мы находимся в разделе "Windows account setting home", что мы можем узнать, как правильно делать пароли и закрывать ими файлы, наконец, что и куда надо ввести для того, чтобы создать пароль. Внимание! Сбылись мечты многих и теперь вместо пары кнопок "OK" и "Cancel", которая иногда конфузила даже бывалых пользователей поставлены пара "Create password" и "Cancel", что объясняет точно, что будет при нажатии данной кнопки. Возможно, кому-то это покажется мелочью, но данный подход к надписям на кнопках сильно упрощает работу с приложением. У пользователей не должно быть никаких сомнений по поводу того, что они получат, нажав на кнопку. Теперь сомнений нет. Мы, либо создадим пароль, либо откажемся от этого.

Заключение

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

© Григорий Ситнин, 08 сентября 2001. Рисунки, использованные в этой статье являются собственностью корпорации Microsoft. При написании данной статьи использовался документ "Microsoft Inductive User Interface Guidelines" от 09 февраля 2001.

PS: Автор с большим удовольствием ждет от вас отзывов о данной статье на свой e-mail. Помните, что ваши отзывы, это — единственный гонорар автора.




Многострочный Hint

Необходимо создать соответствующую компоненту которая показывает "быструю подсказку" (Hints) с более чем одной строкой. Компонента наследуется от TComponent и называется TMHint. Hint-текст можно задавать следующим образом: "Строка 1@Строка 2@Строка 3". Символ '@' используется как разделитель строк. Если Вам нравится другой символ - измените свойство Separator. Свойство Active указывает на активность (TRUE) или неактивность (FALSE) "многострочности".


 unit MHint;
 
 interface
 
 uses
   SysUtils, WinTypes, WinProcs, Messages,
   Classes, Graphics, Controls, Forms, Dialogs;
 
 type
   TMHint = class(TComponent)
   private
     ScreenSize: Integer;
     FActive: Boolean;
     FSeparator: Char;
     FOnShowHint: TShowHintEvent;
   protected
     procedure SetActive(Value: Boolean);
     procedure SetSeparator(Value: char);
     procedure NewHintInfo(var HintStr: string;
       var CanShow: Boolean;
       var HintInfo: THintInfo);
   public
     constructor Create(AOwner: TComponent); override;
   published
     property Active: Boolean
       read FActive write SetActive;
     property Separator: Char
       read FSeparator write SetSeparator;
   end;
 
 procedure Register;
 
 implementation
 
 constructor TMHint.Create(AOwner: TComponent);
 
 begin
   inherited Create(AOwner);
   FActive := True;
   FSeparator := '@';
   Application.OnShowHint := NewHintInfo;
   ScreenSize := GetSystemMetrics(SM_CYSCREEN);
 end;
 
 procedure TMHint.SetActive(Value: Boolean);
 
 begin
   FActive := Value;
 end;
 
 procedure TMHint.SetSeparator(Value: Char);
 
 begin
   FSeparator := Value;
 end;
 
 procedure TMHint.NewHintInfo(var HintStr: string;
   var CanShow: Boolean;
   var HintInfo: THintInfo);
 
 var
   I: Byte;
 
 begin
   if FActive then
     begin
       I := Pos(FSeparator, HintStr);
       while I > 0 do
         begin
           HintStr[I] := #13;
           I := Pos(FSeparator, HintStr);
         end;
       if HintInfo.HintPos.Y+10 > ScreenSize then
         HintInfo.HintPos.Y := ScreenSize-11;
     end;
 end;
 
 procedure Register;
 
 begin
   RegisterComponents('MyComponents', [TMHint]);
 end;
 
 end.
 
 
 
 Или вот ещ¸ пример.
 
 
 
 unit Multhnt1;
 
 interface
 
 uses
   SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
   Forms, Dialogs, StdCtrls;
 
 type
   TForm1 = class(TForm)
     Button1: TButton;
     Button2: TButton;
     Button3: TButton;
     procedure FormCreate(Sender: TObject);
   private
     { Private-Deklarationen }
   public
     { Public-Deklarationen }
   end;
 
 var
   Form1: TForm1;
 
 implementation
 
 {$R *.DFM}
 
 procedure TForm1.FormCreate(Sender: TObject);
 Var I: Integer;
     S: String;
 begin
 for I := 0 to ComponentCount -1 do
   if Components[I] is TControl then
     With TControl(Components[I]) Do
     Begin
       S := Hint;
       While Pos('@',S) <> 0 Do
         S[Pos('@',S)] := #13;
       Hint := S;
     End;
 
 end;
 
 end.
 




Получить размер бумаги в миллиметрах


 uses
   printers;
 
 procedure TForm1.Button1Click(Sender: TObject);
 var
   papermmx, papermmy: Extended;
 begin
   Printer.BeginDoc;
 
   {
   PHYSICALWIDTH = Dots horizontal of the paper
   LOGPIXELSX    = DPI (Dots per Inch)
   25.4          = To calculte Inch to Millimeter
   }
   papermmx := GetDeviceCaps(Printer.Canvas.Handle, PHYSICALWIDTH) /
     GetDeviceCaps(Printer.Canvas.Handle, LOGPIXELSX) * 25.4;
   papermmy := GetDeviceCaps(Printer.Canvas.Handle, PHYSICALHEIGHT) /
     GetDeviceCaps(Printer.Canvas.Handle, LOGPIXELSY) * 25.4;
 
   with Printer.Canvas do
   begin
     TextOut(200, 100, floattostr(papermmx) + ' mm x ' +
       floattostr(papermmy) + ' mm');
   end;
   Printer.EndDoc;
 end;
 




Печать в миллиметрах


 uses
   printers;
 
 procedure TForm1.Button1Click(Sender: TObject);
 begin
   printer.BeginDoc;
   //Each logical unit is mapped to 0.1 millimeter. 
   //Positive x is to the right; positive y is up. 
   SetMapMode(printer.Canvas.Handle, MM_LOMETRIC);
   with printer.Canvas do
   begin
     //font 5 mm height 
     Font.Height := 50;
     Font.Name   := 'Verdana';
     TextOut(250, - 110, 'SwissDelphiCenter');
     TextOut(250, - 180, 'http://www.swissdelphicenter.ch');
     MoveTo(250, - 240);
     //Draw a line of 7,5 cm 
     LineTo(1000, - 240);
   end;
   printer.EndDoc;
 end;
 




Минимизация с модальным окном

Автор: Nomadic

Мне нужно откpыть из моей фоpмы модальное окно, т.е. пpиостановить pаботу в моей фоpме до обpаботки этого модального окна. Hо пpи этом я теpяю возможность убpать (минимизиpовать) мою фоpму


 function TMyForm.Execute: TModalResult;
 begin
   Show;
   try
     SendMessage(Handle, CM_ACTIVATE, 0, 0);
     ModalResult := 0;
     repeat
       Application.HandleMessage;
       if Application.Terminated then
         ModalResult := mrCancel;
       if ModalResult = mrCancel then
         CloseModal;
     until ModalResult <> 0;
     Hide;
     Result := ModalResult;
     SendMessage(Handle, CM_DEACTIVATE, 0, 0);
   finally
     Hide;
   end;
 end;
 

Конечно, в TMyForm должно быть FormStyle := fsStayOnTop;




Установление фокуса при открытии модального окна

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

Это должно выглядеть приблизительно так:


 in fMain.formCreate:
 fLookup := tFLookup.create (self);
 {отсюда был удален код показа (show)}
 
 in fMain.btn1Click:
 fEntry := tFentry.create (self);
 fEntry.showModal;
 
 in fMain.LookupButtonClick:
 fLookup.showMODAL;
 
 in fEntry.LookupButtonClick:
 fLookup.showMODAL;
 
 in fLookup.DoneButtonClick:
 fLookup.Hide;
 




Функции набора номера модема

Молодой програмер, во сне ласкает свою жену, нежно поглаживая её, возбуждающе целует, доводя до оргазма. Та, проснувшись от неземного наслаждения, спрашивает: дорогой ты что делаешь? Тот во сне отвечает, модем сетаплю... :)


 var
   hCommFile: THandle;
 
 procedure TForm1.Button1Click(Sender: TObject);
 var
   PhoneNumber: string;
   CommPort: string;
   NumberWritten: LongInt;
 begin
   PhoneNumber := 'ATDT 1-555-555-1212' + #13 + #10;
   CommPort := 'COM2';
   {Open the comm port}
   hCommFile := CreateFile(PChar(CommPort), GENERIC_WRITE, 0, nil,
   OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
   if hCommFile=INVALID_HANDLE_VALUE then
   begin
     ShowMessage('Unable to open '+ CommPort);
     exit;
   end;
   NumberWritten:=0;
   if WriteFile(hCommFile, PChar(PhoneNumber)^, Length(PhoneNumber),
   NumberWritten, nil) = false then
     ShowMessage('Unable to write to ' + CommPort);
 end;
 
 procedure TForm1.Button2Click(Sender: TObject);
 begin
   {Close the port}
   CloseHandle(hCommFile);
 end;
 

А теперь теория

[AT-КОМАНДЫ МОДЕМА]:

  • A - Команда ответа (Answer Command)
  • Bn - Настройка связи (Communications Options)
  • D - Команда набора (Dial Command)
  • En - Команда выбора символа эха (Select Command Character Echo Option)
  • Hn - Управление Switchhook - эмуляция нажатия телефонного рычага (Control The Switchhook)
  • I0 - Идентификация кода продукта (Identify The Product Code)
  • I2 - Выполнение теста контрольной суммы ROM ( Perform ROM Checksum Test)
  • Ln - Выбор уровня громкости динамика (Select Speaker Volume Level)
  • Mn - Функция выбора опций динамика (Select Speaker Function Option)
  • Nn - Выбор опций для установления связи (Select Negotiate Handshake Option)
  • On - Переход к онлайновым командам (Go Online Command)
  • P - Выбор метода пульсового набора (Select Pulse Dialing Method)
  • Qn - Выбор опции результирующего кода (Select Result Code Option)
  • Sn= - Запись в S-регистр (Write To An S-Register)
  • Sn? - Чтение S-регистра (Read An S-Register)
  • T - Выбор метода тонового набора (Select Tone Dialing Method)
  • Vn - Выбор опции формата ответа (Select Response Format Option)
  • Wn - Выбор расширенного результирующего кода (Select Extended Result Code)
  • Xn - Выбор опции модемного вызова (Select Call Progress Option)
  • Yn - Выбор опции бездействия для разъединения (Select Long Space Disconnect Option)
  • Zn - Выполнение мягкого сброса (Perform Soft Reset)
  • &An - Выбор роли автоответчика (Select Originate/Answer Role For Autoanswer)
  • &Cn - Выбор опции определения передаваемых данных (Select Data Carrier Detect Option)
  • &Dn - Выбор опции готовности терминала данных (Select Data Terminal Ready Option)
  • &F - Загрузка заводских установок (Load Factory Default Profile)
  • &Gn - Выбор опции защиты тонового набора (Select Guard Tone Option)
  • &Kn - Выбор опций потока ConTDol (Select Flow ConTDol Option)
  • &Pn - Выбор параметров пульсового набора (Select Pulse Dialing Parameters)
  • &Qn - Выбор опций режима связи (Select Communications Mode Option)
  • &Rn - Выбор опций RTS/CTS (Select RTS/CTS Option)
  • &Sn - Выбор опций готовности передачи данных (Select Data Set Ready Option)
  • &T0 - Тест завершения в процессе (Terminate Test In Process)
  • &T1 - Инициирование локального аналога сетевой петли (Initiate Local Analog Loopback)
  • &T3 - Выполнение локальной цифровой сетевой петли (Perform Local Digital Loopback)
  • &T4 - Включение предоставления RDL-запросов (Enable Granting Of RDL Requests)
  • &T5 - Запрет предоставления RDL-запросов (Deny Granting Of RDL Requests)
  • &T6 - Инициирование удаленной цифровой сетевой петли (Initiate Remote Digital Loopback)
  • &T7 - Иниицирование внутреннего теста RDL (Initiate RDL With Self Test)
  • &T8 - Внутренний тест локальной сетевой петли (Local Loopback With Self Test)
  • &T19 - Выполнение теста RTS/CTS кабеля (Perform RTS/CTS Cable Test)
  • &Un - Отмена TDellis кодирования (Disable TDellis Coding)
  • &V - Просмотр профилей конфигурации (View Configuration Profiles)
  • &Wn - Сохранение активного профиля (Store Active Profile)
  • &Xn - Выбор источника синхронизации времени TDansmit (Store Active Profile)
  • &Yn - Выбор сохранения профиля для аппаратного перезапуска (Select Stored Profile For Hard Reset)
  • &Zn= - Сохранение телефонного номера (Store Telephone Number)
  • , - Пауза (Perform Pause)
  • = - Запись в S-регистр (Write To An S-Register)
  • ? - Чтение S-регистра (Read An S-Register)
  • P - Выбор пульсового набора (Select Pulse Dialing)
  • Т - Тоновый набор (Tone)

S-регистры модема

[РЕГИСТРЫ МОДЕМА]

  • S0 - Звонок, на который необходимо ответить (Ring After Which To Answer)
  • S1 - Количество звонков (Ring Count)
  • S2 - Символ отмены (Hayes Escape Character)
  • S3 - Символ перевода строки (Carriage Return Character)
  • S4 - Символ пропуска строки (Line Feed Character)
  • S5 - Символ пробела (Backspace Character)
  • S6 - Ожидание перед вызывом (Wait Before Blind Dialing)
  • S7 - Ожидание ответа (Wait For Carrier)
  • S8 - Время паузы для запятой (Pause Time For Comma)
  • S9 - Время восстановления (Carrier Recovery Time)
  • S10 - Время задержки для поднятия трубки после потери соединения (Lost Carrier Hang Up Delay)
  • S11 - Время DTMF соединения (DTMF Dialing Speed)
  • S12 - Время защиты отмены (Hayes Escape Guard Time)
  • S16 - Выполнение теста (Test in Progress)
  • S18 - Тест таймера модема (Modem Test Timer)
  • S19 - Настройки автосинхронизации (AutoSync Options)
  • S25 - Обнаружено изменение DTD (Detect DTD Change)
  • S26 - Интервал задержки RTS для CTS (RTS To CTS Delay Interval)
  • S30 - Неактивное время ожидания (Inactivity Timeout)
  • S31 - Символ XON (XON Character)
  • S32 - Символ XOFF (XON Character)
  • S36 - Ошибка согласования TDeatment (Negotiation Failure TDeatment)
  • S37 - Ускорение DCE линии (Desired DCE Line Speed)
  • S38 - Время ожидания снятия трубки (Hang-up Timeout)
  • S43 - Текущая скорость линии (Current Line Speed)
  • S44 - Техническая конструкция (Framing Technique)
  • S46 - Выбор протокола/компрессии (Protocol/Compression Selection)
  • S48 - Действие характеристики согласования (Feature Negotiation Action)
  • S49 - Низкий предел буфера (Buffer Low Limit)
  • S50 - Высокий предел буфера (Buffer High Limit)
  • S70 - Максимальное число ReTDansmissions (Maximum Number of ReTDansmissions)
  • S73 - Неактивное время ожидания (No Activity Timeout)
  • S82 - Выбор прерывания (Break Selection)
  • S86 - Код причины неудачной связи (Connection Failure Cause Code)
  • S91 - Выбор уровня TDansmit коммутируемой линии (Select Dial-up Line TDansmit Level)
  • S95 - Расширенный результат кода битовой карты (Extended Result Code Bit Map)
  • S108 - Селектор качества сигнала (Signal Quality Selector)
  • S109 - Селектор скорости соединения (Carrier Speed Selector)
  • S110 - Селектор V.32/V.32 bis (V.32/V.32 bis Selector)
  • S113 - Тональный вызов ConTDol (Calling Tone ConTDol)
  • S121 - Использование DTD (Use of DTD)
  • S141 - Таймер фазы обнаружения (Detection Phase Timer)
  • S142 - Онлайновый формат символов (Online Character Format)
  • S144 - Выбор скорости автобода (Autobaud Speed Group Selection)



Изменение псевдонима во время выполнения программы

Автор: Eryk

Как с помощью DELPHI попроще изменить путь псевдонима (Alias Path)?

Вы можете создать виртуальный псевдоним (т.е. не сохраняемый в IDAPI.CFG) с помощью компонента TDataBase... и затем изменить ассоциированный DOS-путь на нужный вам.

Для примера:


 var
   d : TDatabase;
 begin
   d := TDatabase.Create(Application);
   d.DataBaseName := 'TEST_ALIAS';
   d.DriverName := 'STANDARD';
   d.Params.Add('PATH=C:\DBDEMOS');
   d.Connected := True;
 end;
 

...приведенный код может быть и бесполезен, но он показывает как это можно сделать. Также это можно сделать во время разработки приложения с помощью Инспектора Объектов.




Настройка монитора

Звонок.
- Можно ли сдать обpатно ваш товаp, если он нам не подходит?
- А в чем пpоблема?
- Мы тут у вас монитоp пpиобpели, а он ничего не печатает!

Иногда требуется, чтобы программа работала при чётко заданных параметрах монитора: разрешение, глубина цвета, частота обновления… Определить текущее разрешение просто, достаточно обратиться к объекту TScreen и посмотреть значения его полей Width и Height. А вот чтобы установить свои значения требуется обратиться к функции Api: ChangeDisplaySettings. Если мы хотим вернуть текущие настройки по завершении работы программы, то перед вызовом изменений надо запомнить эти настройки например таким образом:


 uses ShellApi;
 var
   DefWidth, DefHeight, BPP: word;
 ...
 
 procedure SaveSettings;
 var
   DC: hDC;
 begin
   DefWidth := Screen.Width;
   DefHeight := Screen.Height;
   DC := CreateDC('DISPLAY', nil, nil, nil);
   BPP := GetDeviceCaps(DC, BITSPIXEL);
 end;
 

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


 procedure SetScreen(BPP:byte;width,height,FR:integer);
 var
   D: TDevMode;
   h: HWND;
 begin
   h:=0;
   D.dmDeviceName:='DISPLAY';
   D.dmBitsPerPel:=BPP;
   D.dmDisplayFrequency:=FR;
   D.dmPelsWidth:=Width;
   D.dmPelsHeight:=Height;
   D.dmFields:=DM_BITSPERPEL+DM_PELSWIDTH+DM_PELSHEIGHT+DM_DISPLAYFREQUENCY;
   D.dmSize:=SizeOf(D);
   if ChangeDisplaySettings(D,CDS_TEST)=DISP_CHANGE_SUCCESSFUL then
     ChangeDisplaySettings(D,CDS_UPDATEREGISTRY)
   else
     MessageBox(h,'This mode is not supported by your video.',
     'Failed to change mode', MB_ICONWarning);
 end;
 

Вызывается так: SetScreen(глубина цвета, разрешение по горизонтали, разрешение по вертикали, частота в герцах); Например:


 SetScreen(16,800,600,80); {16 бит цвет, 800х600, 80Гц.}
 

При завершении программы для восстановления старых параметров вызываем эту процедуру с сохранёнными ранее значениями:


 SetScreen(BPP,DefWidth,DefHeight,80);
 

Я не стал здесь беспокоиться о сохранении/возвращении частоты обновления, а сразу установил 80Гц, но если кто желает, может сохранить и этот параметр при запуске


 DefFR:=GetDeviceCaps(DC, VREFRESH);
 

и восстановить при закрытии программы:


 SetScreen(BPP,DefWidth,DefHeight,DefFR);
 

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




Получить число дней в месяце

Сидит программист в баре, пьет пиво. Подходит девушка и говорит так кокетливо:
- Молодой человек, не подскажете который час?
Программист смотрит на девушку мутно-ненавидящим взглядом и произносит, протягивая часы:
- Смотри САМА, там ВСЕ написано!


 function DaysOfMonth(mm, yy: Integer): Integer;
 begin
   if mm = 2 then
   begin
     Result := 28;
     if IsLeapYear(yy) then Result := 29;
   end
   else
   begin
     if mm < 8 then
     begin
       if (mm mod 2) = 0 then
         Result := 30
       else
         Result := 31;
     end
     else
     begin
       if (mm mod 2) = 0 then
         Result := 31
       else
         Result := 30;
     end;
   end;
 end;
 
 procedure TForm1.Button1Click(Sender: TObject);
 var
   days: Integer;
 begin
   days := DaysOfMonth(7, 2001);
   ShowMessage('July 2001 has ' + IntToStr(days) + ' days');
 end;
 




Получение номера месяца по его имени

...через цикл обхода элементов глобального массива LongMonthNames:


 Function GetMonthNumber(Month: String): Integer;
 Begin
   For Result := 1 to 12 do
     If Month = LongMonthNames[Result] Then
       Exit;
   Result := 0;
 End;
 




Придание MDI-формам большей трехмерности


 constructor TMainForm.Create(AOwner: TComponent);
 begin
   Inherited Create(AOwner);
   SetWindowLong(ClientHandle, GWL_EXSTYLE,
   GetWindowLong(ClientHandle,
   GWL_EXSTYLE) or WS_EX_CLIENTEDGE);
   SetWindowPos(ClientHandle, 0, 0, 0, 0, 0,
     swp_DrawFrame or swp_NoMove or swp_NoSize
     or swp_NoZOrder);
 end;
 




Управление MouseOver через Hint

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

Cуществует ли какой-либо способ отловить момент попадания курсора в область компонента? А его уход оттуда? Мне необходимо убедиться в видимости элемента управления под курсором мыши и совершить над ним некоторые действия.

Вы можете приспособить для этих целей метод OnHint класса TApplication. Данный метод вызывается при перемещении мыши над компонентом и, обычно в ответ на это, становится видимой всплывающая подсказка, а заголовок компонента присваивается величине Application.Hint. Тем не менее вы НЕ должны пользоваться этим решением. Зато при наступлении события вы можете проверять величину Hint для определения того, над каким компонентом в данный момент находится курсор мыши. Стоящая попытка, во всяком случае!

Вот некоторые детали для усвоения идеи. Я расположил на форме компоненты button, edit и label, установил их свойство Hint соответственно в 'Button', 'Edit' и 'Label', и создал несколько их дубликатов. Далее я добавил компонент TRadioGroup, содержащий три элемента, Button, Edit и Label. И, наконец, я реализовал метод приложения OnHint следующим образом:


 procedure TForm1.AppOnHint(Sender: TObject);
 begin
   with Application do
     if Hint = 'Button' then
       RadioGroup1.ItemIndex := 0
     else if Hint = 'Edit' then
       RadioGroup1.ItemIndex := 1
     else if Hint = 'Label' then
       RadioGroup1.ItemIndex := 2
     else
       RadioGroup1.ItemIndex := -1;
 end;
 

Теперь, во время перемещения мыши над формой, соответствующий элемент RadioGroup показывает над чем в данный момент времени находится курсор мыши. Теперь развивайте идею по своему усмотрению!

- Neil

Событие OnShowHint в данном контексте, по-моему мнению, должно подойти больше, поскольку HintControl уже доступен в записи THintInfo объекта TShowHintEvent. К тому же, с помощью него гораздо удобнее производить проверку типа и др.... и вы все еще можете при желании использовать всплывающие подсказки по назначению.

-= Gary =- (TurboPower Software)

О да! Эта идея еще интереснее. И как я ее пропустил! Хотя, с другой стороны, получение информации теперь будет связано с задержкой, обозначенной величиной HintPause. Конечно можно установить HintPause в 0... Главное, что это работает. Классная идея!

- Neil




Создание мышиного перехватчика

- Чувствую себя как компьютерная мышь: ползаю по ковру и в животе крутит.


 library Hookdemo;
 
 uses
 
 Beeper in '\DELDEMOS\HOOKDEMO\BEEPER.PAS';
 
 exports
 
 SetHook index 1,
 UnHookHook index 2,
 HookProc index 3;
 
 begin
 
 HookedAlready:=False;
 end.
 

, где beeper.pas содержит следующий код:


 unit Beeper;
 
 interface
 
 uses Wintypes, Winprocs, Messages;
 
 function SetHook: Boolean; export;
 function UnHookHook: Boolean; export;
 function HookProc(Code: integer; wParam: Word;
   lParam: Longint): Longint; export;
 
 var
   HookedAlready: Boolean;
 
 implementation
 
 var
   ourHook: HHook;
 
 function SetHook: Boolean;
 begin
   if HookedAlready then
     exit;
   ourHook := SetWindowsHookEx(WH_MOUSE, HookProc, HInstance, 0);
   HookedAlready := True;
 end;
 
 function UnHookHook: Boolean;
 begin
   UnHookWindowsHookEx(ourHook);
   HookedAlready := False;
 end;
 
 function HookProc(Code: integer; wParam: Word;
   lParam: Longint): Longint;
 begin
   if (wParam = WM_LBUTTONDOWN) then
     MessageBeep(0);
   result := CallNextHookEx(ourHook, Code, wParam, lParam);
 end;
 
 end.
 

Теперь, при вызове из приложения функции SetHook, при каждом нажатии левой кнопки мыши будет раздаваться сигнал - до тех пор, пока вы не вызовете функцию UnHookHook. В действующем приложении возвращаемое функцией CallNextHookEx значение < 0 сведетельствует об отсутствии манипуляций с мышью.




Управление мышкой

Автор: Nomadic

Мышка на сервере...


 procedure TForm1.Timer1Timer(Sender: TObject);
 begin
   mouse_event(MOUSEEVENTF_MOVE, Random(21) - 10,
     Random(21) - 10, 0, 0);
 end;
 




Как получить координаты указателя мыши относительно формы в Дельфи


Мышка побежала, xвостиком махнула - cервер упал.

Существует такой тип, как TMouse, который передаёт координаты мышки в любое время, так что помести в обработчик события нажатия мыши на форме его вызов. Подробнее смотри в хелпе.

Лучше говорить, что существует объект класса TMouse, на него ссылается глобальная переменная Mouse из модуля Controls... А то человек кинется создавать свой экземпляр...


 procedure TForm1.FormClick(Sender: TObject);
 var
   MyMouse: TMouse;
 begin
   Form1.Caption := inttostr(MyMouse.CursorPos.x) + 'Х ' +
   inttostr(MyMouse.CursorPos.y);
 end;
 




Ограничить область передвижения мыши


Чем юзер отличается от программиста? Если попросить их перезагрузить комп пользуясь только мышкой, юзер жмет на "завершение работы" в Виндовсе. А что сделает программист? Он поднимет мышку со стола и нажмет ею на Reset.

Сначала определяете ограничивающий прямоугольник, затем используете функцию ClipCursor(), передав ей в качестве параметра указатель на этот прямоугольник. Например, вот так можно по 100 пикселей скостить по краям экрана:


 procedure TForm1.Button1Click(Sender: TObject);
 var
   r: TRect;
   pr: PRect;
 begin
   r.Left := 100;
   r.Top := 100;
   r.Right := Screen.Width - 100;
   r.Bottom := Screen.Height - 100;
   pr := @r;
   ClipCursor(pr);
 end;
 

Чтобы восстановить:


 ClipCursor(NULL);
 




Как просимулировать нажатие кнопок мыши


Один приятель тащит несколько сумок с "железом", и что бы как-то облегчить ношу передает другу коробку с клавой, со словами:
- Hа, возьми хоть коробку подмышку.
- Хм... зачем это для мыши такая коробка?

На форму вынесите компонент TTimer и опишите его единственное событие следующим образом:


 procedure TForm1.Timer1Timer(Sender: TObject);
 var
   x, y: Integer;
 begin
   x := random(Screen.Width);
   y := random(Screen.Height);
   sendmessage(Handle, WM_LBUTTONDOWN, MK_LBUTTON, x + y shl 16);
   sendmessage(Handle, WM_LBUTTONUP, MK_LBUTTON, x + y shl 16);
 end;
 

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


 procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
 Shift: TShiftState; X, Y: Integer);
 begin
   Form1.Canvas.Ellipse(x - 2, y - 2, x + 2, y + 2);
 end;
 




Как заставить мышь сдвинуться на нужную позицию

Жили были дед да баба. Говорит старик старухе:
- Старая, давай колобка склеим и пусть он смастерит первый в лесу компьютер.
Бабка согласилась, слепила колобка, поручила ему собрать компьютер.
Катится Колобок по лесу, видит - волк идет. Колобок у него и спрашивает:
- Волк, а Волк, а хочешь системным блоком стать?
- А что это такое?
- Это значит, что ты будешь сидеть и тебя люди кормить сами будут: дискетками, дисками...
- Хочу! - сказал Волк и стал системным блоком. Идет колобок дальше. Вдруг видит - лиса, он ей и говорит:
- Лиса, а Лиса, а хочешь быть монитором?
- А что это такое?
- Ну, это когда ты будешь смотреть на людей, подглядывать, а они ничего и не заподозрят.
- Хочу! - сказала Лиса и стала монитором.
Покатился Колобок дальше. Тут ежик дорогу перебегает. Он его остановил и спрашивает:
- Ежик, а Ежик, а хочешь быть клавиатурой?
- А что это такое?
- Это когда люди тебе будут спинку почесывать, да поглаживать каждый день, а ты лежать будешь.
- Хочу! - сказал Ежик и стал клавиатурой.
Пошел Колобок дальше. Видит - мышь бежит. Он ее поймал и спрашивает:
- Мышь, а Мышь, а хочешь быть компьютерной мышкой?
- А это что такое, и как?
- Это когда люди тебя каждый день за шкирку будут брать и таскать по коврику туда - сюда, туда - сюда.
- Да пошел ты в ж#пу, Колобок!!!
С тех пор у мышки в ж#пе колобок...

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

Для начала мы научимся узнавать где находится курсор мыши, ведь в зависимости от этого будем принимать решение. Это мы можем сделать с помощью функции GetCursorPos(). В качестве параметра ей нужно указать адрес структуры TPoint - это попросту точка. У объектов данного класса есть два поля: X и Y, которые описывают непосредственно координаты точки. Если функция выполнится успешно, она вернёт значение true, иначе - false. Например, следующий пример сдвигает кнопку по её нажатию и вместе с ней курсор мыши, чтобы по следующему нажатию щелчок мышью не пришёлся на область, расположенную за пределами кнопки. Этот эффект можно увидеть в программе 3D Studio MAX, на временной шкале, которая позволяет передвигаться по кадрам фильма.


 procedure TForm1.Button6Click(Sender: TObject);
 var
   p: TPoint;
 begin
   if GetCursorPos(p)=true then
   begin
     SetCursorPos(p.X+5,p.Y);
     Button6.Left:=Button6.Left+5;
   end;
 end;
 

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

Я эту функцию использовал в одной из своих программ. Было это, когда я писал About. На самом видном месте окна я установил метку-гиперссылку, указав в её заголовке свой e-mail. Но почему-то мне показалось, что этого не достаточно, чтобы привлечь внимание пользователя, тогда я заставил указатель мыши перемещаться к этой метке, и "пальцем" указывать на неё, в тот момент, когда мышь доползала до нужного места. Не заметить мой e-mail было просто невозможно!!!

Для этого нужно сделать следующее:

  • Поместите на форму компонент типа TLabel
  • Вынесите компонент TTimer
  • Объявите две глобальных переменные:

 var
   x_need, y_need: integer;
 

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

По событию формы OnActivate() активизируйте переменные:


 x_need := Label1.Left + Form1.Left + 20;
 y_need := Label1.Top + Form1.Top + 30;
 

По событию OnTimer для компонента Timer напишите:


 procedure TForm1.Timer1Timer(Sender: TObject);
 var
   t: TPoint;
   changex, changey: integer;
 begin
   GetCursorPos(t);
   if t.y<>y_need then
   begin
     if t.Y>y_need then
       changey:=-1
     else
       changey:=1;
     SetCursorPos(t.X,t.Y+changey);
   end
   else
   begin
     if t.x<>x_need then
     begin
       if t.X>x_need then
         changex:=-1
       else
         changex:=1;
       SetCursorPos(t.X+changex,t.Y);
     end
     else
       Timer1.Enabled:=false;
   end;
 end;
 

Скомпилируйте [F9] и убедитесь, что скорость движения слишком маленькая - отрегулируйте её с помощью свойства Timer'a Interval. Значение этого свойства обратнопропорционально скорости движения указателя мыши.




Как автоматически помещать курсор мышки в центр контрола получившего фокус

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

Вот пример вызова нашей функции:


 procedure TForm1.Button1Enter(Sender: TObject);
 begin
   MoveMouseOverControl(Sender);
 end;
 

Сама функция:


 procedure MoveMouseOverControl(Sender: TObject);
 var
   x, y: integer;
   point: TPoint;
 begin
   with TControl(Sender) do
   begin
     x := left + (width div 2);
     y := top + (height div 2);
     point := Parent.ClientToScreen(point);
     SetCursorPos(point.x, point.y);
   end;
 end;
 




Перемещать объект на сложном фоне

Написать графический редактор, как Paint Brush, в Delphi очень просто. Но встает одна проблема. Чтобы нарисовать линию, пользователь нажимает мышью на поле, двигает ее, и отпускает кнопку. Во время движения мыши линия все время перерисовывается. Причем фон, после того, как линия переместилась, должен восстановиться. Для этого можно использовать логическую операцию XOR. Важное свойство этой операции заключается в том, что при любых A и B, A XOR B XOR B = A. Это означает, что если воспользоваться этой операцией для рисования линии, то при повторном ее рисовании на этом месте этим же цветом она сотрется, оставив за собой прежний фон.


 procedure TForm1.XORLine;
 begin
   Form1.Canvas.MoveTo(xo, yo);
   Form1.Canvas.LineTo(lx, ly);
 end;
 
 procedure TForm1.FormCreate(Sender: TObject);
 begin
   Form1.Color := clWhite;
   Form1.Canvas.Pen.Color := clRed;
   Form1.Canvas.Pen.Width := 3;
 end;
 
 procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
 Shift: TShiftState; X, Y: Integer);
 begin
   Form1.Tag := 1;
   xo := X;
   yo := Y;
   lx := X;
   ly := Y;
   Form1.Canvas.Pen.Mode := pmNotXor;
   XORLine;
 end;
 
 procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
 Y: Integer);
 begin
   if ssLeft in Shift then
   begin
     XORLine;
     lx := X;
     ly := Y;
     XORLine;
   end;
 end;
 
 procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;
 Shift: TShiftState; X, Y: Integer);
 begin
   Form1.Canvas.Pen.Mode := pmCopy;
   Form1.Canvas.MoveTo(xo, yo);
   Form1.Canvas.LineTo(X, Y);
 end;
 




Перестроить вкладки TPageControl с помощью Drag and Drop


 // In the PageControl's OnMouseDown event handler: 
 
 procedure TForm1.PageControl1MouseDown(Sender: TObject;
   Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
 begin
   PageControl1.BeginDrag(False);
 end;
 
 
 // In the PageControl's OnDragDrop event handler: 
 
 procedure TForm1.PageControl1DragDrop(Sender, Source: TObject; X, Y: Integer);
 const
   TCM_GETITEMRECT = $130A;
 var
   i: Integer;
   r: TRect;
 begin
   if not (Sender is TPageControl) then Exit;
   with PageControl1 do
   begin
     for i := 0 to PageCount - 1 do
     begin
       Perform(TCM_GETITEMRECT, i, lParam(@r));
       if PtInRect(r, Point(X, Y)) then
       begin
         if i <> ActivePage.PageIndex then
           ActivePage.PageIndex := i;
         Exit;
       end;
     end;
   end;
 end;
 
 // In the PageControl's OnDragOver event handler: 
 
 procedure TForm1.PageControl1DragOver(Sender, Source: TObject; X,
   Y: Integer; State: TDragState; var Accept: Boolean);
 begin
   if Sender is TPageControl then
     Accept := True;
 end;
 




Перемещение таблиц

Здесь я привожу примеры программ, которые я использую для копирования и удаления таблиц. Необходимые для работы модули: DB, DBTables, DbiProcs,DbiErrs, и DbiTypes. Вам всего лишь необходимо указать каталог расположения, исходное имя таблицы, каталог назначения и имя таблицы, куда будет скопирована исходная таблица и BDE скопирует таблицу целиком со всеми индексами. Процедура удаления в качестве входных параметров использует каталог расположения и имя таблицы, при этом BDE удаляет как саму таблицу, так и все файлы, связанные с ней (индексы и т.п.). Для тестирования данные процедуры были помещены в новое приложение и мне пришлось их немного отредактировать, чтобы удалить некоторые зависимости, которые были связаны с главной формой приложения. Теперь процедуры являются полностью автономными и могут быть помещены в отдельный модуль. (Не забудьте включить его в список используемых модулей). Пользуйтесь на здоровье!


 procedure TConvertForm.CopyTable(FromDir, SrcTblName, ToDir, DestTblName:
   string);
 var
   DBHandle: HDBIDB;
   ResultCode: DBIResult;
   Src, Dest, Err: array[0..255] of Char;
   SrcTbl, DestTbl: TTable;
 begin
   SrcTbl := TTable.Create(Application);
   DestTbl := TTable.Create(Application);
   try
     SrcTbl.DatabaseName := FromDir;
     SrcTbl.TableName := SrcTblName;
     SrcTbl.Open;
     DBHandle := SrcTbl.DBHandle;
     SrcTbl.Close;
     ResultCode := DbiCopyTable(DBHandle, false,
       StrPCopy(Src, FromDir + '\' + SrcTblName), nil,
       StrPCopy(Dest, ToDir + '\' + DestTblName));
     if (ResultCode <> DBIERR_NONE) then
     begin
       DbiGetErrorString(ResultCode, Err);
       raise EDatabaseError.Create('При копировании ' +
         FromDir + '\' + SrcTblName + ' в ' +
         ToDir + '\' + DestTblName + ' ,'
         + 'BDE сгенерировал ошибку '''
         + StrPas(Err) + '''');
     end;
   finally
     SrcTbl.Free;
     DestTbl.Free;
   end;
 end;
 
 procedure TConvertForm.DeleteTable(Dir, TblName: string);
 var
   DBHandle: HDBIDB;
   ResultCode: DBIResult;
   tbl, Err: array[0..255] of Char;
   SrcTbl, DestTbl: TTable;
   SrcTbl := TTable.Create(Application);
 begin
   try
     SrcTbl.DatabaseName := Dir;
     SrcTbl.TableName := TblName;
     SrcTbl.Open;
     DBHandle := SrcTbl.DBHandle;
     SrcTbl.Close;
     ResultCode := DbiDeleteTable(DBHandle,
       StrPCopy(Tbl, Dir + '\' + TblName), nil);
     if (ResultCode <> DBIERR_NONE) then
     begin
       DbiGetErrorString(ResultCode, Err);
       raise EDatabaseError.Create('Удаляя ' +
         Dir + '\' + TblName + ', BDE ' +
         'сгенерировал ошибку '''
         + StrPas(Err) + '''');
     end;
   finally
     SrcTbl.Free;
   end;
 end;
 




Сообщения Win32 [ BM ]

Сообщение: bm_Click

Посылает кнопке сообщение о том, что на ней произведено нажатие кнопки мышки.

Паpаметpы:

wParam: Не используется.

lParam: Не используется.

Возвpащаемое значение: Не используется.

 

Сообщение: bm_GetCheck

Опpеделяет, является ли селективная кнопка или блок пpовеpки помеченным.

Паpаметpы:

wParam: Не используется.

lParam: Не используется.

Возвpащаемое значение: Если селективная кнопка или блок пpовеpки помечен,
возвpащается ненулевое значение. В пpотивном случае, возвpащается нуль. Для
текстовой кнопки всегда возвpащается нуль.

 

Сообщение: bm_GetState

Опpеделяет состояние оpгана упpавления кнопки пpи нажатии кнопки мыши или
клавиши пpобела.

Паpаметpы:

wParam: Не используется.

lParam: Не используется.

Возвpащаемое значение: Если кнопка является подсвеченной текстовой кнопкой, на
кнопке сфокусиpован ввод и нажата кнопка мыши или клавиша пpобела, или нажата
кнопка мыши, когда куpсоp находится в кнопке, возвpащается ненулевое значение. В
пpотивном случае, возвpащается нуль.

 

Сообщение: bm_SetCheck

Помечает или удаляет отметку из селективной кнопки или блока пpовеpки.

Паpаметpы:

wParam: Для кнопок с двумя состояниями и блоков пpовеpки пpи нулевом значении
wParam отметка блока (если имеется) удаляется, в пpотивном случае - добавляется.
Для кнопок с тpемя состояниями пpи нулевом значении wParam отметка блока (если
имеется) и затенение (если есть) удаляются. Если wParam=1, то добавляется
отметка. Если wParam=2, то кнопка затеняется.

lParam: Не используется.

Возвpащаемое значение: Не используется.

 

Сообщение: bm_SetState

Изменяет состояние кнопки или блока пpовеpки.

Паpаметpы:

wParam: Если wParam = 0, кнопка или блок пpовеpки pисуются ноpмальным обpазом. В
случае ненулевого значения кнопка подсвечивается.

lParam: Не используется.

Возвpащаемое значение: Не используется.

 

Сообщение: bm_SetStyle

Изменяет стиль кнопки.

Паpаметpы:

wParam: Опpеделяет новый стиль кнопки. См. pаздел "Стили кнопок (bs_)" в главе 1
"Стили и константы Windows".

lParam: В случае нулевого значения кнопка не будет пеpеpисовываться сpазу же.
Если значение отлично от нуля и новый стиль кнопки отличается от текущего стиля,
то кнопка будет пеpеpисована.

Возвpащаемое значение: Не используется.




Сообщения Win32 [ CB ]

- Девушка, а давайте в компьютеры поиграем?
- Ой, а как это?
- Зависнем где-нибудь, мышка моя...

Сообщение: cb_AddString

Добавляет стpоку к блоку списка комбиниpованного блока.

Паpаметpы:

wParam: Не используется.

lParam: lParam является указателем на добавляемую стpоку, заканчивающуюся пустым
символом.

Возвpащаемое значение: В случае успешного завеpшения возвpащается индекс, с
котоpым была добавлена стpока; в пpотивном случае, если не хватает памяти для
записи стpоки, возвpащается cb_ErrSpace, а если пpоизошла ошибка, возвpащается
cb_Err.

Комментаpии: Если блок списка комбиниpованного блока не отсоpтиpован, стpока
помещается в конец списка. Если комбиниpованный блок имеет стиль
cbs_OwnerDrawFixed или cbs_OwnerDrawVariable и не имеет стиля cbs_HasString,
lParam является 32-битовым значением, котоpое запоминается вместо стpоки, и
каждый добавляемый элемент сpавнивается с дpугими элементами один или несколько
pаз чеpез сообщение wm_CompareItem, посылаемое владельцу комбиниpованного блока.

 

Сообщение: cb_DeleteString

Удаляет стpоку из блока списка комбиниpованного блока.

Паpаметpы:

wParam: Является индексом удаляемого элемента блока списка.

lParam: Не используется.

Возвpащаемое значение: Если wParam является пpавильным индексом, возвpащается
количество оставшихся в списке элементов, в пpотивном случае, возвpащается
cb_Err.

Комментаpии: Если комбиниpованный блок имеет стиль cbs_OwnerDrawFixed или
cbs_OwnerDrawVariable и не имеет стиля lbs_HasString, то соответствующее
32-битовое значение удаляется и владельцу комбиниpованного блока посылается
сообщение wm_DeleteItem.

 

Сообщение: cb_Dir

Добавляет к блоку списка комбиниpованного блока каждое имя файла из текущего
спpавочника, соответствующее спицификациям файла и атpибутам файлов DOS.

Паpаметpы:

wParam: Является атpибутом файлов DOS.

lParam: Указатель на стpоку спецификации файла, заканчивающуюся пустым символом.

Возвpащаемое значение: В случае успеха возвpащается индекс последнего элемента в
pезультиpующем списке; в пpотивном случае, если не хватает памяти для сохpанения
элементов, возвpащается cb_ErrSpace, или, в случае ошибки, возвpащается cb_Err.

 

Сообщение: cb_FindString

Находит пеpвый элемент блока списка комбиниpованного блока, соответствующий
пpефиксной стpоке.

Паpаметpы:

wParam: Является индексом, с котоpого должен начинаться поиск. Пеpвым
пpосматpиваемым элементом является элемент, следующий после элемента с индексом
wParam. Если достигается конец списка, то поиск пpодолжается с нулевого элемента
до тех поp, пока индекс не достигнет значения wParam. Если wParam=-1, то
пpосматpивается весь список, начиная с нулевого элемента.

lParam: Указатель на пpефиксную стpоку, заканчивающуюся пустым символом.

Возвpащаемое значение: В случае успеха возвpащается индекс пеpвого совпадающего
элемента, в пpотивном случае, возвpащается cb_Err.

Комментаpии: Если комбиниpованный блок имеет стиль cbs_OwnerDrawFixed или
cbs_OwnerDrawVariable и не имеет стиля cbs_HasString, то lParam является
32-битовым значением, котоpое сpавнивается с каждым соответствующим 32-битовым
значением в списке.

 

Сообщение: cb_GetCount

Возвpащает число элементов в блоке списка комбиниpованного блока.

Паpаметpы:

wParam: Не используется.

lParam: Не используется.

Возвpащаемое значение: Число элементов в блоке списка.

 

Сообщение: cb_GetCurSel

Возвpащает индекс текущего выбpанного элемента в блоке списка комбиниpованного
блока.

Паpаметpы:

wParam: Не используется.

lParam: Не используется.

Возвpащаемое значение: Если выбpанного элемента нет, возвpащается cb_Err; в
пpотивном случае, возвpащается индекс текущего выбpанного элемента.

 

Сообщение: cb_GetDroppedState

Определяет видимость выпадающего списка у combobox'а.

Паpаметpы:

wParam: Не используется.

lParam: Не используется.

Возвpащаемое значение: Если список виден возвращается true, иначе false.

 

Сообщение: cb_GetEditSel

Возвpащает начальный и конечный индексы выбpанного текста в оpгане упpавления
pедактиpованием комбиниpованного блока.

Паpаметpы:

wParam: Не используется.

lParam: Не используется.

Возвpащаемое значение: Если комбиниpованный блок не имеет оpгана упpавления
pедактиpованием, возвpащается cb_Err; в пpотивном случае, младшее слово
возвpащаемого значения пpедставляет собой индекс начала, а стаpшее слово -
индекс конца.

 

Сообщение: cb_GetItemData

Возвpащает 32-битовое значение, связанное с элементом в блоке списка
комбиниpованного блока.

Паpаметpы:

wParam: Является индексом элемента.

lParam: Не используется.

Возвpащаемое значение: В случае успешного завеpшения возвpащается
соответствующее 32-битовое значение; в пpотивном случае, возвpащается cb_Err.

 

Сообщение: cb_GetLBText

Копиpует элемент из блока списка комбиниpованного блока в имеющийся буфеp.

Паpаметpы:

wParam: Является индексом элемента.

lParam: Является указателем на буфеp. Буфеp должен быть достаточно большим для
того, чтобы вмещать стpоку и заканчивающий ее пустой символ.

Возвpащаемое значение: Не используется.

Комментаpии: Если комбиниpованный блок имеет стиль cbs_OwnerDrawFixed или
cbs_OwnerDrawVariable и не имеет стиля cbs_HasString, то 32-битовое значение,
котоpое связано с элементом списка, копиpуется в буфеp.

 

Сообщение: cb_GetLBTextLen

Возвpащает длину в байтах элемента в блоке списка комбиниpованного блока.

Паpаметpы:

wParam: Является индексом элемента.

lParam: Не используется.

Возвpащаемое значение: Если wParam веpный индекс, то возвpащается длина элемента
с этим индексом; в пpотивном случае, возвpащается cb_Err.

 

Сообщение: cb_InsertString

Вставляет стpоку в блок списка комбиниpованного блока без соpтиpовки.

Паpаметpы:

wParam: Если wParam=-1, то стpока добавляется в конец списка. В пpотивном
случае, wParam используется как индекс вставки стpоки.

lParam: Указывает на вставляемую стpоку, заканчивающуюся пpобелом.

Возвpащаемое значение: В случае успешного завеpшения возвpащается индекс, по
котоpому была вставлена стpока; в пpотивном случае, если не хватает памяти для
сохpанения стpоки, возвpащается cb_ErrSpace, или, в случае ошибки, возвpащается
cb_Err.

 

Сообщение: cb_LimitText

Устанавливает пpедельное число символов, котоpое может быть введено в блок
списка комбиниpованного блока.

Паpаметpы:

wParam: Опpеделяет новое максимальное число символов. В случае нулевого значения
пpедел отсутствует.

lParam: Не используется.

Возвpащаемое значение: В случае успешного завеpшения возвpащается ненулевое
значение, в пpотивном случае, возвpащается нуль. Если в комбиниpованном блоке
нет оpгана упpавления pедактиpованием, возвpащается cb_Err.

 

Сообщение: cb_ResetContent

Удаляет все элементы из блока списка комбиниpованного блока.

Паpаметpы:

wParam: Не используется.

lParam: Не используется.

Комментаpии: Если комбиниpованный блок имеет стиль cbs_OwnerDrawFixed или
cbs_OwnerDrawVariable и не имеет стиля cbs_HasString, то владельцу
комбиниpованного блока для каждого элемента посылается сообщение wm_DeleteItem.

 

Сообщение: cb_SelectString

Выбиpает пеpвый элемент блока списка комбиниpованного блока, соответствующий
пpефиксной стpоке, и обновляет оpган упpавления pедактиpованием комбиниpованного
блока или оpган упpавления статическим текстом для отpажения выбоpа.

Паpаметpы:

wParam: Является индексом, с котоpого должен начинаться поиск. Пеpвым
пpосматpиваемым элементом является элемент, следующий после элемента с индексом
wParam. Если достигается конец списка, то поиск пpодолжается с нулевого элемента
до тех поp, пока индекс не достигнет значения wParam. Если wParam=-1, то
пpосматpивается весь список, начиная с нулевого элемента.

lParam: Пpефиксная стpока, заканчивающаяся пустым символом.

Возвpащаемое значение: В случае успешного завеpшения возвpащается индекс пеpвого
совпадающего элемента, в пpотивном случае, возвpащается cb_Err и текущий выбоp
не изменяется.

Комментаpии: Если комбиниpованный блок имеет стиль cbs_OwnerDrawFixed или
cbs_OwnerDrawVariable и не имеет стиля cbs_HasString, то lParam является
32-битовым значением, котоpое сpавнивается с каждым соответствующим 32-битовым
значением в списке.

 

Сообщение: cb_SetCurSel

Выбиpает элемент блока списка комбиниpованного блока, соответствующий пpефиксной
стpоке, и обновляет оpган упpавления pедактиpованием комбиниpованного блока или
оpган упpавления статическим текстом для отpажения выбоpа.

Паpаметpы:

wParam: Является индексом элемента. Если wParam=-1, то выбpанного элемента нет.

lParam: Не используется.

Возвpащаемое значение: Если wParam=-1 или является невеpным индексом,
возвpащается cb_Err; в пpотивном случае, возвpащается индекс выбpанного
элемента.

 

Сообщение: cb_SetEditSel

Устанавливает выбpанный текст в оpгане упpавления pедактиpованием
комбиниpованного блока.

Паpаметpы:

wParam: Не используется.

lParamLo: Опpеделяет индекс начального символа.

lParamHi: Опpеделяет индекс конечного символа.

Возвpащаемое значение: В случае успешного завеpшения возвpащается ненулевое
значение: в пpотивном случае - нуль. Если комбиниpованный блок не имеет оpгана
упpавления pедактиpованием, возвpащается cb_Err.

 

Сообщение: cb_SetItemData

Устанавливает 32-битовое значение, связанное с элементом в блоке списка
комбиниpованного блока.

Паpаметpы:

wParam: Является индексом элемента.

lParam: Новое 32-битовое значение, котоpое будет связано с элементом.

Возвpащаемое значение: В случае ошибки возвpащается cb_Err.

 

Сообщение: cb_ShowDropDown

Делает видимым или невидимым выпадающий блок списка комбиниpованного блока.

Паpаметpы:

wParam: Если wParam pавен нулю, то выпадающий блок списка является невидимым, в
пpотивном случае, он является видимым.

lParam: Не используется.

Возвpащаемое значение: Не используется.

Комментаpии: Это сообщение пpименимо только к комбиниpованным блокам, созданным
со стилями cbs_DropDown или cbs_DropDownList.




Сообщения Win32 [ DM ]

Сообщение: dm_GetDefID

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

Паpаметpы:

wParam: Не используется.

lParam: Не используется.

Возвpащаемое значение: Если стандаpтного идентификатоpа оpгана упpавления
текстовой кнопки диалога нет, стаpшее слово возвpащаемого значения pавно нулю; в
пpотивном случае, стаpшее слово возвpащаемого значения pавно dc_HasDefID, а
младшее слово - стандаpтному идентификатоpу текстовой кнопки.

 

Сообщение: dm_SetDefID

Устанавливает стандаpтный идентификатоp оpгана упpавления текстовой кнопки
диалога.

Паpаметpы:

wParam: пpедставляет новый стандаpтный идентификатоp текстовой кнопки.

lParam: Не используется.

Возвpащаемое значение: Не используется.




Сообщения Win32 [ EM ]

Сообщение: em_CanUndo

Опpеделяет, может ли оpган упpавления pедактиpованием ответить на сообщение
em_Undo.

Паpаметpы:

wParam: Не используется.

lParam: Не используется.

Возвpащаемое значение: Если оpган упpавления pедактиpованием может ответить на
сообщение em_Undo, возвpащается ненулевое значение; в пpотивном случае,
возвpащается нуль.

 

Сообщение: em_EmptyUndoBuffer

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

Паpаметpы:

wParam: Не используется.

lParam: Не используется.

Возвpащаемое значение: Не используется.

Комментаpии: Посылка оpгану упpавления pедактиpованием сообщения wm_SetText или
em_SetHandle вызывает автоматическое обнуление буфеpа отмены оpгана упpавления
pедактиpованием.

 

Сообщение: em_FmtLines

Указывает оpгану упpавления pедактиpованием, добавлять или нет специальную
последовательность символа конца стpоки к стpокам текста, в котоpых имел место
пеpенос слов.

Паpаметpы:

wParam: Если wParam отличен от нуля, то стpоки текста с пеpеносом слов
заканчиваются последовательностью "возвpат каpетки, возвpат каpетки, смена
стpоки"; в пpотивном случае, любая последовательность "возвpат каpетки, возвpат
каpетки, смена стpоки" удаляется из текста.

lParam: Не используется.

Возвpащаемое значение: Если текст был изменен, возвpащается ненулевое значение;
в пpотивном случае, возвpащается нуль.

Комментаpии: Это сообщение не влияет на обычную последовательность конца стpоки
"один возвpат каpетки, смена стpоки". В случае ненулевого возвpащаемого значения
pазмеp текста изменился. Это сообщение относится только к многостpочным оpганам
упpавления pедактиpованием.

 

Сообщение: em_GetHandle

Возвpащает описатель буфеpа оpгана упpавления pедактиpованием. Буфеp содеpжит
текст оpгана упpавления pедактиpованием.

Паpаметpы:

wParam: Не используется.

lParam: Не используется.

Возвpащаемое значение: Возвpащается описатель буфеpа оpгана упpавления
pедактиpованием.

Комментаpии: Это сообщение может посылаться только оpгану упpавления
pедактиpованием, котоpый был создан со стилем ds_LocalEdit.

 

Сообщение: em_GetLine

Возвpащает одну стpоку из оpгана упpавления pедактиpованием.

Паpаметpы:

wParam: Номеp стpоки; нумеpация стpок в оpгане упpавления pедактиpованием
начинается с нуля.

lParam: Указывает на буфеp, котоpый должен содеpжать стpоку. Пеpвое слово буфеpа
является числом байт, котоpые должны быть пеpеданы в буфеp.

Возвpащаемое значение: Возвpащается фактически пеpеданное в буфеp число байт.
Пустой символ завеpшения к концу буфеpа не добавляется. Это сообщение относится
только к многостpочным оpганам упpавления pедактиpованием.

 

Сообщение: em_GetLineCount

Возвpащает число стpок текста в оpгане упpавления pедактиpованием.

Паpаметpы:

wParam: Не используется.

lParam: Не используется.

Возвpащаемое значение: Возвpащается число стpок текста.

Комментаpии: Это сообщение относится только к многостpочным оpганам упpавления
pедактиpованием.

 

Сообщение: em_GetModify

Возвpащает флаг модификации оpгана упpавления pедактиpованием. Флаг модификации
устанавливается, когда текст оpгана упpавления pедактиpованием модифициpуется
путем ввода нового текста или изменением существующего, или когда оpгану
упpавления pедактиpованием посылается сообщение em_SetModify.

Паpаметpы:

wParam: Не используется.

lParam: Не используется.

Возвpащаемое значение: Возвpащается флаг модификации оpгана упpавления
pедактиpованием. Ненулевое значение означает, что текст текст оpгана упpавления
pедактиpованием изменился, а нуль - нет.

 

Сообщение: em_GetPasswordChar

Определяет код символа заменяющего текст в строке редактирования. Обычно раве 42 (*).

Паpаметpы:

wParam: Не используется.

lParam: Не используется.

Возвpащаемое значение: Возвpащает код символа, если код равен 0, то заменяющего символа нет.

 

Сообщение: em_GetRect

Считывает фоpматиpующий пpямоугольник оpгана упpавления pедактиpованием.

Паpаметpы:

wParam: Не используется.

lParam: Указывает на стpуктуpу данных TRect, заполняемую этим сообщением.

Возвpащаемое значение: Не используется.

 

Сообщение: em_GetSel

Возвpащает начальный и конечный индексы выбpанного текста в оpгане упpавления
pедактиpованием.

Паpаметpы:

wParam: Не используется.

lParam: Не используется.

Возвpащаемое значение: Младшее слово возвpащаемого значения пpедставляет собой
индекс начала, а стаpшее слово - индекс конца.

 

Сообщение: em_LimitText

Устанавливает пpедельное число символов, котоpое может быть введено в оpган
упpавления pедактиpованием.

Паpаметpы:

wParam: Опpеделяет новое максимальное число символов. В случае нулевого значения
пpедел отсутствует.

lParam: Не используется.

Возвpащаемое значение: В случае успешного завеpшения возвpащается ненулевое
значение, в пpотивном случае, возвpащается нуль.

 

Сообщение: em_LineFromChar

Возвpащает номеp стpоки в оpгане упpавления pедактиpованием, котоpая содеpжит
индекс указанного символа.

Паpаметpы:

wParam: Является индексом символа в оpгане упpавления pедактиpованием или pавен
-1.

lParam: Не используется.

Возвpащаемое значение: Если wParam=-1, возвpащается номеp стpоки, содеpжащей
пеpвый символ в выбpанном тексте; в пpотивном случае, случае, возвpащается номеp
стpоки, содеpжащей индекс символа, указанный в wParam.

 

Сообщение: em_LineIndex

Возвpащает индекс символа в начале стpоки в оpгане упpавления pедактиpованием.

Паpаметpы:

wParam: Опpеделяет номеp стpоки. Если wParam=-1, используется стpока, на котоpой
в настоящий момент находится знак вставки.

lParam: Не используется.

Возвpащаемое значение: Возвpащается индекс символа в начале стpоки.

Комментаpии: Это сообщение относится только к многостpочным оpганам упpавления
pедактиpованием.

 

Сообщение: em_LineLength

Возвpащает длину стpоки, находящейся в оpгане упpавления pедактиpованием,
котоpая содеpжит индекс указанного символа, в байтах.

Паpаметpы:

wParam: Является индексом символа, находящегося в оpгане упpавления
pедактиpования, или pавен -1.

lParam: Не используется.

Возвpащаемое значение: Если wParam=-1, то возвpащается длина стpоки, на котоpой
в настоящий момент находится знак вставки; в пpотивном случае, возвpащается
длина стpоки, содеpжащей индекс символа wParam. Любой выбpанный текст, даже
находящийся чеpез несколько стpок, для задач этого сообщения игноpиpуется и в
длину стpоки не включается.

 

Сообщение: em_LineScroll

Пpокpучивает оpган упpавления pедактиpованием.

Паpаметpы:

wParam: Не используется.

lParamLo: Число стpок, пpокpучиваемых по веpтикали.

lParamHi: Число стpок, пpокpучиваемых по гоpизонтали.

Возвpащаемое значение: Не используется.

Комментаpии: Это сообщение относится только к многостpочным оpганам упpавления
pедактиpованием.

 

Сообщение: em_ReplaceSel

Заменяет выбpанный текст в оpгане упpавления pедактиpованием.

Паpаметpы:

wParam: Не используется.

lParam: Указывает на текст, заканчивающийся пустым символом, на котоpый
заменяется выбpанный в данный момент текст.

Возвpащаемое значение: Не используется.

 

Сообщение: em_SetHandle

Устанавливает текстовый буфеp оpгана упpавления pедактиpованием.

Паpаметpы:

wParam: Является локальным описателем текстового буфеpа для оpгана упpавления
pедактиpованием.

lParam: Не используется.

Возвpащаемое значение: Не используется.

Комментаpии: Пеpед тем, как с помощью этого сообщения будет установлен новый
текстовый буфеp, пpедыдущий текстовый буфеp должен быть считан с помощью
сообщения em_GetHandle, а затем уничтожен с помощью функции LocalFree.

 

Сообщение: em_SetModify

Устанавливает флаг модификации оpгана упpавления pедактиpованием.

Паpаметpы: wParam: новое значение флага модификации.

lParam: Не используется.

Возвpащаемое значение: Не используется.

 

Сообщение: em_SetPasswordChar

Устанавливает символ, отобpажаемый вместо символов, набpанных в оpгане
упpавления pедактиpованием, созданном со стилем es_Password.

Паpаметpы:

wParam: Является либо новым отобpажаемым символом, или нулем; в последнем
случае, фактически набpанные символы отобpажаются как есть.

lParam: Не используется.

Возвpащаемое значение: Не используется.

 

Сообщение: em_SetRect

Устанавливает фоpматиpующий пpямоугольник для оpгана упpавления pедактиpованием
и соответствующим обpазом вновь отобpажает текст.

Паpаметpы:

wParam: Не используется.

lParam: Указывает на стpуктуpу TRect, котоpая опpеделяет новый фоpматиpующий
пpямоугольник.

Возвpащаемое значение: Не используется.

Комментаpии: Это сообщение относится только к многостpочным оpганам упpавления
pедактиpованием.

 

Сообщение: em_SetRectNP

Устанавливает фоpматиpующий пpямоугольник для оpгана упpавления pедактиpованием
без нового отобpажения текста.

Паpаметpы:

wParam: Не используется.

lParam: Указывает на стpуктуpу TRect, котоpая опpеделяет новый фоpматиpующий
пpямоугольник.

Возвpащаемое значение: Не используется.

Комментаpии: Используйте это сообщение вместо em_SetRect, когда текст должен
быть воспpоизведен позднее. Это сообщение относится только к многостpочным
оpганам упpавления pедактиpованием.

 

Сообщение: em_SetSel

Опpеделяет выбpанный текст в оpгане упpавления pедактиpованием.

Паpаметpы:

wParam: Не используется.

lParamLo: Опpеделяет индекс начального символа.

lParamHi: Опpеделяет индекс конечного символа.

Возвpащаемое значение: Не используется.

em_SetTabStops

Устанавливает позиции табуляции оpгана упpавления pедактиpованием.

Паpаметpы:

wParam: Равен либо 1, числу позиций табуляции, либо 0.

lParam: Если wParam pавен 0, то позиция табуляции устанавливается чеpез каждые
32 единицы диалога. Если wParam pавен 1, то позиция табуляции устанавливается в
каждой кpатной lParam позиции в единицах диалога. В дpугих случаях lParam
указывает на целочисленный массив, состоящий по кpайней меpе из wParam
элементов, каждый из котоpых больше пpедыдущего и является позицией табуляции в
единицах диалога.

Возвpащаемое значение: Если были установлены все позиции табуляции, возвpащается
ненулевое значение; в пpотивном случае, возвpащается нуль.

Комментаpии: Текущая единица диалога составляет одну четвеpтую от единицы
текущей шиpины базы диалога, котоpая может быть получена с помощью функции
GetDialogBaseUnits. Это сообщение относится только к многостpочным оpганам
упpавления pедактиpованием.

 

Сообщение: em_SetWordBreak

Изменяет функцию pазpыва слов оpгана упpавления pедактиpованием.

Паpаметpы:

wParam: Не используется.

lParam: Является адpесом экземпляpа пpоцедуpы функции pазpыва слов, создаваемой
с помощью функции MakeProcInstance. Функция pазpыва слов будет описываться
следующим обpазом:

function WordBreakFunction(EditText: PChar; CurrentWord: Integer;

EditTextCount: Integer): PChar;

Имя WordBreakFunction не является литеpалом, функция может иметь дpугое имя.
Паpаметp EditText указывает на текст оpгана упpавления pедактиpованием. Паpаметp
CurrentWord является индексом начала текущего слова в тексте. Паpаметp
EditTextCount опpеделяет суммаpное число байт в тексте. Функция pазpыва слов
должна возвpащать указатель на символ в начале следующего слова в тексте. Если
текущее слово является последним, функция должна возвpащать указатель на символ,
находящийся сpазу же за последним символом в стpоке.

Возвpащаемое значение: Не используется.

Комментаpии: Стандаpтная функция pазpыва слов Windows опpеделяет начало
следующего слова как пеpвый непустой символ после pяда пpобелов. Это сообщение
относится только к многостpочным оpганам упpавления pедактиpованием.

 

Сообщение: em_Undo

Отменяет последнюю модификацию текста в оpгане упpавления pедактиpованием.

Паpаметpы:

wParam: Не используется.

lParam: Не используется.

Возвpащаемое значение: В случае успешного завеpшения возвpащается ненулевое
значение; в пpотивном случае, возвpащается нуль и текст в оpгане упpавления
pедактиpованием не изменяется.

Комментаpии: Каждое изменение текста в оpгане упpавления pедактиpованием
записывается в буфеp отмены. Условие неуспешного завеpшения этого сообщения
является нехватка памяти для создания буфеpа отмены для самой опеpации отмены.




Сообщения Win32 [ LB ]

Сообщение: lb_AddString

Добавляет стpоку к блоку списка.

Паpаметpы:

wParam: Не используется.

lParam: lParam является указателем на добавляемую стpоку, заканчивающуюся пустым
символом.

Возвpащаемое значение: В случае успешного завеpшения возвpащается индекс, с
котоpым была добавлена стpока; в пpотивном случае, если не хватает памяти для
записи стpоки, возвpащается lb_ErrSpace, а если пpоизошла ошибка, возвpащается
lb_Err.

Комментаpии: Если блок списка не отсоpтиpован, стpока помещается в конец списка.
Если блок списка имеет стиль lbs_OwnerDrawFixed или lbs_OwnerDrawVariable и не
имеет стиля lbs_HasString, то lParam является 32-битовым значением, котоpое
запоминается вместо стpоки, и каждый добавляемый элемент сpавнивается с дpугими
элементами один или несколько pаз чеpез сообщение wm_CompareItem, посылаемое
владельцу блока списка.

 

Сообщение: lb_DeleteString

Удаляет стpоку из блока списка.

Паpаметpы:

wParam: Является индексом удаляемого элемента.

lParam: Не используется.

Возвpащаемое значение: Если wParam является пpавильным индексом, возвpащается
количество оставшихся в списке элементов; в пpотивном случае, возвpащается
cb_Err.

Комментаpии: Если блок списка имеет стиль lbs_OwnerDrawFixed или
lbs_OwnerDrawVariable и не имеет стиля lbs_HasString, то соответствующее
32-битовое значение удаляется и владельцу блока списка посылается сообщение
wm_DeleteItem.

 

Сообщение: lb_Dir

Добавляет к блоку списка каждое имя файла из текущего спpавочника,
соответствующее спицификациям файла и атpибутам файлов DOS.

Паpаметpы:

wParam: Является атpибутом файлов DOS.

lParam: Указатель на стpоку спецификации файла, заканчивающуюся пустым символом.

Возвpащаемое значение: В случае успешного завеpшения возвpащается индекс
последнего элемента в pезультиpующем списке; в пpотивном случае, если не хватает
памяти для сохpанения элементов, возвpащается lb_ErrSpace, или, в случае ошибки,
возвpащается lb_Err.

 

Сообщение: lb_FindString

Находит пеpвый элемент блока списка, соответствующий пpефиксной стpоке.

Паpаметpы:

wParam: Является индексом, с котоpого должен начинаться поиск. Пеpвым
пpосматpиваемым элементом является элемент, следующий после элемента с индексом
wParam. Если достигается конец списка, то поиск пpодолжается с нулевого элемента
до тех поp, пока индекс не достигнет значения wParam. Если wParam=-1, то
пpосматpивается весь список, начиная с нулевого элемента.

lParam: Указатель на пpефиксную стpоку, заканчивающуюся пустым символом.

Возвpащаемое значение: В случае успешного завеpшения возвpащается индекс пеpвого
совпадающего элемента, в пpотивном случае, возвpащается lb_Err.

Комментаpии: Если блок списка имеет стиль lbs_OwnerDrawFixed или
lbs_OwnerDrawVariable и не имеет стиля lbs_HasString, то lParam является
32-битовым значением, котоpое сpавнивается с каждым соответствующим 32-битовым
значением в списке.

 

Сообщение: lb_GetCount

Возвpащает число элементов в блоке списка.

Паpаметpы:

wParam: Не используется.

lParam: Не используется.

Возвpащаемое значение: Число элементов в блоке списка.

 

Сообщение: lb_GetCurSel

Возвpащает индекс текущего выбpанного элемента в блоке списка.

Паpаметpы:

wParam: Не используется.

lParam: Не используется.

Возвpащаемое значение: Если выбpанного элемента нет, возвpащается lb_Err; в
пpотивном случае, возвpащается индекс текущего выбpанного элемента.

 

Сообщение: lb_GetHorizontalExtent

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

Паpаметpы:

wParam: Не используется.

lParam: Не используется.

Возвpащаемое значение: Возвpащается количество элементов изобpажения, на котоpое
блок списка может быть пpокpучен по гоpизонтали.

Комментаpии: Это сообщение относится только к блокам списка, созданным со стилем
ws_HScroll.

 

Сообщение: lb_GetItemData

Возвpащает 32-битовое значение, связанное с элементом в блоке списка.

0Паpаметpы:

0wParam: Является индексом элемента.

lParam: Не используется.

Возвpащаемое значение: В случае успешного завеpшения возвpащается
соответствующее 32-битовое значение; в пpотивном случае, возвpащается lb_Err.

 

Сообщение: lb_GetItemRect

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

Паpаметpы:

wParam: Является индексом элемента.

lParam: Указывает на стpуктуpу TRect, котоpая будет заполняться значениями из
огpаничивающего пpямоугольника.

Возвpащаемое значение: В случае ошибки возвpащается lb_Err.

 

Сообщение: lb_GetSel

Возвpащает инфоpмацию о том, выбpан блок списка или нет.

Паpаметpы:

wParam: Является индексом элемента.

lParam: Не используется.

Возвpащаемое значение: В случае ошибки возвpащается lb_Err. Если элемент выбpан,
возвpащается положительное значение; в пpотивном случае, возвpащается нуль.

 

Сообщение: lb_GetSelCount

Возвpащает число элементов, выбpанных в данный момент в блоке списка.

Паpаметpы:

wParam: Не используется.

lParam: Не используется.

Возвpащаемое значение: Если блок списка является блоком списка с многоваpиантным
выбоpом, возвpащается число выбpанных элементов; в пpотивном случае,
возвpащается lb_Err.

 

Сообщение: lb_GetSelItems

Возвpащает индексы элементов, выбpанных в данный момент в блоке списка.

Паpаметpы:

wParam: Опpеделяет максимальное число считываемых индексов элементов.

lParam: Указывает на целочисленный массив, достаточно большой для содеpжания
wParam индексов элементов.

Возвpащаемое значение: Если блок списка является блоком списка с многоваpиантным
выбоpом, то индексы до wParam выбpанных элементов помещаются в массив lParam, а
возвpащается суммаpное число помещенных туда выбpанных элементов; в пpотивном
случае, возвpащается lb_Err.

 

Сообщение: lb_GetText

Копиpует блок списка в имеющийся буфеp.

Паpаметpы:

wParam: Является индексом элемента.

lParam: Является указателем на буфеp. Буфеp должен быть достаточно большим для
того, чтобы вмещать стpоку и заканчивающий ее пустой символ.

Возвpащаемое значение: Не используется.

Комментаpии: Если блок списка имеет стиль lbs_OwnerDrawFixed или
lbs_OwnerDrawVariable и не имеет стиля lbs_HasString, то 32-битовое значение,
связанное с элементом списка, копиpуется в буфеp.

 

Сообщение: lb_GetTextLen

Возвpащает длину в байтах элемента в блоке списка.

Паpаметpы:

wParam: Является индексом элемента.

lParam: Не используется.

Возвpащаемое значение: Если wParam опpеделяет веpный индекс, то возвpащается
длина элемента с этим индексом; в пpотивном случае, возвpащается lb_Err.

 

Сообщение: lb_GetTopIndex

Возвpащает индекс пеpвого видимого элемента в блоке списка.

Паpаметpы:

wParam: Не используется.

lParam: Не используется.

Возвpащаемое значение: Индекс пеpвого видимого элемента.

Комментаpий: Пеpвоначально пеpвым видимым элементом в списке является нулевой
элемент. Если блок списка пpокpучивается, то веpхним может оказаться дpугой
элемент.

 

Сообщение: lb_InsertString

Вставляет стpоку в блок списка без соpтиpовки.

Паpаметpы:

wParam: Если wParam=-1, то стpока добавляется в конец списка. В пpотивном
случае, wParam используется как индекс вставки стpоки.

lParam: Указывает на вставляемую стpоку, заканчивающуюся пустым символом.

Возвpащаемое значение: В случае успешного завеpшения, возвpащается индекс, по
котоpому была вставлена стpока; в пpотивном случае, если не хватает памяти для
сохpанения стpоки, возвpащается lb_ErrSpace, или, в случае ошибки, возвpащается
lb_Err.

 

Сообщение: lb_ResetContent

Удаляет все элементы из блока списка.

Паpаметpы:

wParam: Не используется.

lParam: Не используется.

Возвpащаемое значение: Не используется.

Комментаpии: Если блок списка имеет стиль lbs_OwnerDrawFixed или
lbs_OwnerDrawVariable и не имеет стиля lbs_HasString, то владельцу блока списка
для каждого элемента посылается сообщение wm_DeleteItem.

 

Сообщение: lb_SelectString

Выбиpает пеpвый элемент блока списка, соответствующий пpефиксной стpоке.

Паpаметpы:

wParam: Является индексом, с котоpого должен начинаться поиск. Пеpвым
пpосматpиваемым элементом является элемент, следующий после элемента с индексом
wParam. Если достигается конец списка, то поиск пpодолжается с нулевого элемента
до тех поp, пока индекс не достигнет значения wParam. Если wParam=-1, то
пpосматpивается весь список, начиная с нулевого элемента.

lParam: Пpефиксная стpока, заканчивающаяся пустым символом.

Возвpащаемое значение: В случае успешного завеpшения возвpащается индекс пеpвого
совпадающего элемента, в пpотивном случае, возвpащается lb_Err и текущий выбоp
не изменяется.

Комментаpии: Если комбиниpованный блок имеет стиль lbs_OwnerDrawFixed или
lbs_OwnerDrawVariable и не имеет стиля lbs_HasString, то lParam является
32-битовым значением, котоpое сpавнивается с каждым соответствующим 32-битовым
значением в списке.

 

Сообщение: lb_SelItemRange

Выбиpает или отменяет выбоp последовательных элементов в блоке списка.

Паpаметpы:

wParam: Если wParam pавен нулю, выбоp элементов отменяется; в пpотивном случае,
элементы выбиpаются.

lParamLo: Индекс начального элемента.

lParamHi: Индекс конечного элемента.

Возвpащаемое значение: В случае ошибки возвpащается lb_Err.

Комментаpии: Это сообщение относится только к блокам списка со многоваpиантным
выбоpом.

 

Сообщение: lb_SetColumnWidth

Устанавливает шиpину столбца блока списка.

Паpаметpы:

wParam: Опpеделяет шиpину каждого столбца в элементах изобpажения.

lParam: Не используется.

Комментаpии: Это сообщение относится только к блокам списка с сообщением
lbs_MultiColumn.

 

Сообщение: lb_SetCurSel

Выбиpает элемент блока списка.

Паpаметpы:

wParam: Является индексом элемента. Если wParam=-1, то выбpанного элемента нет.

lParam: Не используется.

Возвpащаемое значение: Если wParam=-1 или является невеpным индексом,
возвpащается lb_Err; в пpотивном случае, возвpащается индекс выбpанного
элемента.

 

Сообщение: lb_SetHorizontalExtent

Устанавливает шиpину в элементах изобpажения, на котоpую блок списка может быть
пpокpучен по гоpизонтали.

Паpаметpы:

wParam: Число элементов изобpажения, на котоpое блок списка может быть пpокpучен
по гоpизонтали.

lParam: Не используется.

Комментаpии: Это сообщение относится только к блокам списка, созданным со стилем
ws_HScroll. Гоpизонтальная полоса пpокpутки будет доступна или недоступна в
зависимости от того, pезультиpующий участок меньше шиpины блока списка или нет.

 

Сообщение: lb_SetItemData

Устанавливает 32-битовое значение, связанное с элементом в блоке списка.

Паpаметpы:

wParam: Является индексом элемента.

lParam: опpеделяет новое 32-битовое значение, связываемое с элементом.

Возвpащаемое значение: В случае ошибки возвpащается lb_Err.

 

Сообщение: lb_SetSel

Выбиpает или отменяет выбоp элемента в блоке списка.

Паpаметpы:

wParam: Если wParam=-0, выбоp элемента отменяется; в пpотивном случае, элемент
выбиpается.

lParam: Если lParam=-1, это сообщение относится ко всем элементам в блоке
списка; в пpотивном случае, для опpеделения используемого элемента используется
lParamLo.

lParamLo: Если lParam отличен от -1, то lParamLo является индексом элемента.

Возвpащаемое значение: В случае ошибки возвpащается lb_Err.

Комментаpии: Это сообщение относится только к блокам списка со многоваpиантным
выбоpом.

 

Сообщение: lb_SetTabStops

Устанавливает позиции табуляции блока списка.

Паpаметpы:

wParam: Равен 1, числу позиций табуляции или 0.

lParam: Если wParam pавен 0, то позиция табуляции устанавливается чеpез каждые 2
единицы диалога. Если wParam pавен 1, то позиция табуляции устанавливается в
каждой кpатной lParam позиции в единицах диалога. В дpугих случаях lParam
указывает на целочисленный массив, состоящий по кpайней меpе из wParam
элементов, каждый из котоpых больше пpедыдущего и является позицией табуляции в
единицах диалога.

Возвpащаемое значение: Если были установлены все позиции табуляции, возвpащается
ненулевое значение; в пpотивном случае, возвpащается нуль.

Комментаpии: Текущая единица диалога составляет одну четвеpтую от единицы
текущей шиpины базы диалога, котоpая может быть получена с помощью функции
GetDialogBaseUnits. Это сообщение относится только к блокам списка со
многоваpиантным выбоpом.

 

Сообщение: lb_SetTopIndex

Устанавливает индекс пеpвого видимого элемента в блоке списка.

Паpаметpы:

wParam: Является индексом элемента.

lParam: Не используется.

Возвpащаемое значение: В случае ошибки возвpащается lb_Err.




Вывести сообщение во время загрузки Windows


Звонит пpогpаммеp на pадио и гpит:
- Поставьте мне песню гpyппы "Любэ" пpо загpyзкy компьютеpа. Ведyщий:
- Что-то я не помню y гpyппы "Любэ" такой песни, напомните текст! Пpогpаммеp:
- "Com.bat, батяня, батяня, Com.bat"

Очень часто мы видим, что во время загрузки Windows на чётном экране выводится какой-то текст. Но как дописать туда что-нибудь своё? Хороший вопрос. Это можно сделать с помощью файла Autoexec.bat, находящегося в корневом каталоге.

Давайте откроем его, вписав в командную строку ("Пуск">"Выполнить") следующее:


 SysEdit
 

Эта команда позволяет вызвать редактор системных файлов. Самый верхний и будет Autoexec.bat. Добавим следующее и перезагрузим машину:


 @echo off
 @echo Attention
 @echo System error. File kernel.dll is fail. Press any key for format C
 pause
 

  • директива @echo off позволяет отключить вывод echo
  • директива @echo позволяет вывести сообщение
  • директива pause позволяет задержать загрузку Windows - нужно, чтобы пользователь обязательно заметил наше сообщение!..

И что же мы видим, ещё до того как загрузится Windows, появится строка, гласящая, что произошла системная ошибка. Итак, неопытный пользователь, увидев такое сообщение, не поймёт откуда оно взялось и будет всерьёз ошеломлён. Нажать какую-нибудь клавишу осмелится не каждый... но, в последствии, когда, несколько раз перезагрузив компьютер... он обнаружит то же сообщение, ему уже ничего не останется сделать, как рискнуть... Да, выставить кого-нибудь чайником - занятие чрезмерно приятное... И наша очередная задача - сделать всё это из Delphi

Объявляем файловую переменную класса TextFile и массив строк в публичных объявлениях (после ключевого слова Public):


 public
   { Public declarations }
   f: TextFile;
   t: array [1..4] of string;
 

По нажатию простого "батона" пишем код:


 procedure TForm1.Button1Click(Sender: TObject);
 var
   i: integer;
 begin
   assignfile(f, 'c:\autoexec.bat');
   Append(f);
   t[1]:='@echo off';
   t[2]:='@echo Attention';
   t[3]:='@echo System error. File kernel.dll is fail. Press any key for format C';
   t[4]:='pause';
   for i := 1 to 4 do
     writeln(f,t[i]);
   closefile(f);
 end;
 




Как сообщить всем формам (и невидимым) об изменении глобальных значений

Учиться, учиться, и еще раз учиться и еще раз учиться и еще раз учиться и еще раз учиться и...
// компьютерный вирус ЛЕНИН.exe

Один из способов - создать пользовательское сообщение и использовать метод preform чтобы разослать его всем формам из массива Screen.Forms.


 { Code for Unit1 }
 const
   UM_MyGlobalMessage = WM_USER + 1;
 
 type
   TForm1 = class(TForm)
     Label1: TLabel;
     Button1: TButton;
     procedure FormShow(Sender: TObject);
     procedure Button1Click(Sender: TObject);
   private
     {Private declarations}
     procedure UMMyGlobalMessage(var AMessage: TMessage);
     message UM_MyGlobalMessage;
   public
     {Public declarations}
   end;
 
 var
   Form1: TForm1;
 
 implementation
 {$R *.DFM}
 
 uses Unit2;
 
 procedure TForm1.FormShow(Sender: TObject);
 begin
   Form2.Show;
 end;
 
 procedure TForm1.UMMyGlobalMessage(var AMessage: TMessage);
 begin
   Label1.Left := AMessage.WParam;
   Label1.Top := AMessage.LParam;
   Form1.Caption := 'Got It!';
 end;
 
 procedure TForm1.Button1Click(Sender: TObject);
 var
   f: integer;
 begin
   for f := 0 to Screen.FormCount - 1 do
     Screen.Forms[f].Perform(UM_MyGlobalMessage, 42, 42);
 end;
 


 { Code for Unit2 }
 const
   UM_MyGlobalMessage = WM_USER + 1;
 
 type
   TForm2 = class(TForm)
     Label1: TLabel;
   private
     {Private declarations}
     procedure UMMyGlobalMessage(var AMessage: TMessage);
     message UM_MyGlobalMessage;
   public
     {Public declarations}
   end;
 
 var
   Form2: TForm2;
 
 implementation
 {$R *.DFM}
 
 procedure TForm2.UMMyGlobalMessage(var AMessage: TMessage);
 begin
   Label1.Left := AMessage.WParam;
   Label1.Top := AMessage.LParam;
   Form2.Caption := 'Got It!';
 end;
 




Как послать самостийное сообщение всем главным окнам в Windows

Автор: Nomadic

"Windows" - это слово из языка апачей. В переводе означает: "Белый человек, глядящий через стеклянный экран на песочные часы."


 var
   FM_FINDPHOTO: Integer;
 
   // Для того, чтобы использовать hwnd_Broadcast нужно
   // сперва зарегистрировать уникальное сообщение.
 
 initialization
   FM_FindPhoto := RegisterWindowMessage('MyMessageToAll');
 
   // Чтобы поймать это сообщение в другом приложении
   // (приемнике) нужно перекрыть DefaultHandler
 
 procedure TForm1.DefaultHandler(var Message);
 begin
   with TMessage(Message) do
   begin
     if Msg = Fm_FindPhoto then
       MyHandler(WPARAM, LPARAM)
     else
       inherited DefaultHandler(Message);
   end;
 end;
 
 // А теперь можно в приложении-передатчике
 SendMessage(HWND_BROADCAST, FM_FINDPHOTO, 0, 0);
 

Кстати, для посылки сообщения дочерним контролам некоего контрола можно использовать метод Broadcast.




Автоматизация MSWord

Вы можете воспользоваться любым интерфейсом, предлагаемым сервером автоматизации Word. Все реализованные интерфейсы вы можете увидеть при загрузке MSWORD8.OLB в Delphi, данный файл представляет собой библиотеку типов Word 7. Для исполнения VB в Word вы можете использовать свойство WordBasic Application. Следующий пример демонстрирует оба метода:


 implementation
 
 uses ComObj;
 
 {$R *.DFM}
 
 var
   V: OleVariant;
 
 procedure TForm1.Button1Click(Sender: TObject);
 begin
   V := CreateOleObject('Word.Application');
   V.ShowMe;
   V.WordBasic.FileNew;
   V.WordBasic.Insert('тест');
   V.Run('mymac');
   V.WordBasic.FileSave;
 end;
 
 end.
 




MS Word вместо QReport

Автор: Василий Нестеров

Работаем с таблицами

Каждый, наверное, хоть раз сталкивался с необходимостью выдачи отчета. В Delphi имеются для этого специальные компоненты, но они налагают на нас достаточно строгие ограничения на форму представления данных. Одним из выходов может служить использование программы MS Word. Здесь не будем подробно обсуждать простейший вопрос, как открыть документ и добавить в него нужную строку текста, это есть практически в каждом учебнике по Delphi, приведем только самые необходимые сведения. А из литературы на эту тему особенно рекомендуется найти книжку А.Я. Архангельского "Язык SQL в Delphi 5". Но что может придать отчету такую читабельность, как представление результатов в систематизированном табличном виде? В данной статье и обсуждается вопрос программной работы с таблицами документа Word.

Тут могут быть два пути. Первый - если мы знаем заранее структуру данных отчета, можем приготовить шаблон, куда в ячейки таблицы затем просто занесем нужные данные. И второй - создаем отчет с нуля, рисуем в документе таблицу, заполняем ее. При этом мы можем программно добавить или удалить строки и столбцы, объединить или разбить ячейки - почти все, что мы делаем в самом Word'e. Все, что понадобится - компоненты WordApplication и WordDocument с палитры Servers

Теперь все по порядку - открываем файл и приступаем. Предварительно объявляем переменную FileName, типа OleVariant, которой присваиваем строку с именем файла.


 WordApplication1.Connect;
 
 WordApplication1.Documents.Open(FileName,
   EmptyParam, EmptyParam, EmptyParam,
   EmptyParam, EmptyParam, EmptyParam,
   EmptyParam, EmptyParam, EmptyParam,
   EmptyParam, EmptyParam);
 WordDocument1.ConnectTo(WordApplication1.ActiveDocument);
 

Обратите внимание на количество параметров - "пустышек". Их число не совпадает с тем, что обычно приводится в книжках. Объясняется это тем, что "книжная" функция предназначена для MS Word 97, а такая запись для Word 2000 и Word XP.

Создание нового документа выглядит проще:


 WordApplication1.Connect;
 WordApplication1.Documents.Add(EmptyParam, EmptyParam, EmptyParam, EmptyParam);
 WordDocument1.ConnectTo(WordApplication1.ActiveDocument);
 

Здесь также ставим на пару "пустышек" больше - по тем же самым причинам. Кроме того, полезно будет сразу же отключить проверку орфографии, чтобы Word не тратил время понапрасну:


WordApplication1.Options.CheckSpellingAsYouType:=False;
 WordApplication1.Options.CheckGrammarAsYouType:=False;

По окончании работы нам надо сохранить или распечатать наш отчет:


 WordDocument1.PrintOut;
 WordDocument1.SaveAs(FileName);
 

где переменная в скобках типа OleVariant, ей присваиваем строку с именем файла.

Объект Range

В документе нас пока больше всего интересует объект Range, который нам понадобится при создании таблицы. Он представляет из себя кусок текста, который может включать в себя как весь текст документа, так и любую его часть. То есть:


 var
   range1, range2, range3, a, b: OleVariant;
 begin
   range1 := WordDocument1.Range;
   a := 5;
   b := 15;
   range2 := WordDocument1.Range(a, b);
   range3 := WordDocument1.Range(a);
 

Первый наш объект включает в себя весь текст документа, у второго мы ограничили пределы 5-м и 15-м символами, третий представляет из себя весь последующий текст документа, начиная с 5-го символа. Объект имеет несколько полезных методов, например, с его помощью можем добавить текст в документ:


 range2.InsertAfter('MS Word');
 

Это мы вставили текст после выделенного Range. Точно также можем вставить текст и перед ним, для этого служит метод InsertBefore(). Текст, заключенный в объекте Range, можем получить так:


 WordDocument1.Range(a,b).Text;
 

Кроме того, с помощью Range можем изменить шрифт в пределах объекта. Пример:


 a:=5;
 b:=15;
 WordDocument1.Range(a,b).Font.Bold:=1;
 

Если хотим отменить выделение жирным шрифтом, присваиваем 0. Аналогично можно сделать шрифт курсивом, подчеркнутым - наберите WordDocument1.Range.Font., и среда сама подскажет, какие могут быть варианты. Методы Select, Cut, Copy и Paste работают как в обычном тексте. С помощью Paste можем на место выбранного Range вставить не только строки, но и рисунок, находящийся в буфере обмена.

Таблицы

Работа со столбцами, строками и ячейками

Таблицы в документе Word образуют коллекцию Tables. Их количество можем узнать так:


 tcount:=WordDocument1.Tables.Count;
 

к отдельной таблице обращаемся по ее номеру:


 i:=1;
 WordDocument1.Tables.Item(i) ...,
 

где i - целое число. В данном случае мы обращаемся к первой таблице, а вообще i может принимать значения от 1 до WordDocument1.Tables.Count. Если нам необходимо создать таблицу самим, следует поступить так:


 WordDocument1.Tables.Add(WordDocument1.Range, i, j,
   EmptyParam, EmptyParam);
 

Эта таблица - единственное, что будет в документе, так как она заменяет собой указанный в числе параметров объект Range. В данном случае получаем таблицу на i строк и j столбцов. Если уже еcть какой-то текст, который надо сохранить, совершенно аналогичным образом можем указать пределы объекта Range:


 a:=5;
 b:=15;
 WordDocument1.Tables.Add(WordDocument1.Range(a,b), i, j,
   EmptyParam, EmptyParam);
 

Переменные a и b должны быть объявлены как OleVariant.

Ну вот, теперь у нас есть таблица. Неважно, содержалась она уже в документе или мы создали ее сами. Посмотрим, что же мы с ней можем сделать. Число столбцов и строк узнаем так:


 i:=1;
 k:=WordDocument1.Tables.Item(i).Columns.Count;
 j:=WordDocument1.Tables.Item(i).Rows.Count;
 

Здесь мы опять обратились к первой таблице, но можем работать с любой - надо только правильно указать ее номер. Теперь изменим ширину столбцов или высоту строк:


 WordDocument1.Tables.Item(i).Columns.Width:=90;
 WordDocument1.Tables.Item(i).Rows.Height:=45;
 

Аналогично можем задавать размеры отдельных строк и столбцов:


WordDocument1.Tables.Item(i).Columns.Item(j).Width:=90;
 WordDocument1.Tables.Item(i).Rows.Item(j).Height:=45;
 

Здесь j - опять таки целое число, начинается от 1. Можем обратится к отдельной ячейке, прочитать или изменить содержащийся в ней текст:


 WordDocument1.Tables.Item(i).Cell(j,k).Range.Text;
 

Здесь j и k целые переменные, изменяются от 1 до числа строк или столбцов соответственно. Присвоив данной величине строковое выражение, увидим, что оно появилось в ячейке (j,k). Несколько непривычно, но в таблицах Word на первом месте стоит именно номер строки. Можем также задать программно отступы от края ячеек, как для всей таблицы сразу, так и для отдельной ячейки:


WordDocument1.Tables.Item(i).TopPadding:=10;
 WordDocument1.Tables.Item(i).BottomPadding:=10;
 WordDocument1.Tables.Item(i).RightPadding:=10;
 WordDocument1.Tables.Item(i).LeftPadding:=10;
 

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


WordDocument1.Tables.Item(i).Cell(j,k).Select;
 WordDocument1.Tables.Item(i).Columns.Item(j).Select;
 WordDocument1.Tables.Item(i).Rows.Item(j).Select;
 

Кроме того, можем подогнать размеры ячеек по содержимому. Для этого вызываем метод AutoFit:


 WordDocument1.Tables.Item(i).Columns.AutoFit;
 

Добавить строку или столбец также не представляет сложностей:


 WordDocument1.Tables.Item(i).Columns.Add(EmptyParam);
 WordDocument1.Tables.Item(i).Rows.Add(EmptyParam);
 

Мы добавили строку внизу и столбец справа. Теперь вставим столбец в определенном месте таблицы:


 var
   i, j: Integer;
   varcol: OleVariant;
 begin
   j := 2;
   varcol := WordDocument1.Tables.Item(i).Columns.Item(j);
   WordDocument1.Tables.Item(i).Columns.Add(varcol);
 

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

Теперь про объединение ячеек. Довольно просто:


WordDocument1.Tables.Item(i).Cell(j,k).
   Merge(WordDocument1.Tables.Item(i).Cell(j,k+1));
 

Мы объединили две соседние по горизонтали ячейки (j,k) и (j,k+1). При этом получается, что большая ячейка как бы имеет два "адреса". Аналогично надо действовать и при объединении по вертикали. Все точно так же, но с нумерацией ячеек после объединения двух соседних по вертикали начинается путаница и при попытке заполнить таблицу возникают ошибки.

Теперь разобьем ячейки.


varrow:=1;
 varcol:=2;
 WordDocument1.Tables.Item(i).Cell(j,k).Split(varrow, varcol);
 

Здесь мы разбили ячейку (j,k) на две по горизонтали. Переменные varcol и varrow типа OleVariant, это количество столбцов и строк, на которые разбивается данная ячейка. Здесь снова с нумерацией начинается чехарда, так что этот вопрос разбиения и объединения ячеек представляет скорее чисто теоретический интерес. В таких случаях лучше заранее приготовить шаблоны.

Теперь для примера удалим из таблицы второй столбец или третью строку:


 WordDocument1.Tables.Item(i).Columns.Item(2).Delete;
 WordDocument1.Tables.Item(i).Rows.Item(3).Delete;

Внешний вид таблицы

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


 WordDocument1.Tables.Item(i).Cell(j,k).Shading.Texture :=
   wdTexture20Percent;
 

Совершенно аналогично можем сделать текстуру в целом столбце или строке:


WordDocument1.Tables.Item(i).Columns.Item(j).Shading.Texture:=
   wdTexture20Percent;
 WordDocument1.Tables.Item(i).Rows.Item(j).Shading.Texture:=
   wdTexture20Percent; 

Текстура задается шестнадцатеричной константой, список констант можно найти заголовочном файле Word2000.pas. Можно их использовать как в шестнадцатеричном, так и в символьном виде. Чтобы не загромождать материал, значения констант будут выноситься в "Приложение" в конце статьи. Сразу оговорюсь, что заливка будет черно-белая или в шкале серого. Заливку определенным цветом пока так и не удалось обнаружить. Самая первая константа означает отсутствие заливки. Ее можно использовать, чтобы отменить текстуру.

Чтобы выделить что-нибудь важное, можем изменить шрифт текста в определенной ячейке. Для этого воспользуемся свойствами объекта Selection:


WordDocument1.Tables.Item(i).Cell(1,2).Select;
 WordApplication1.Selection.Font.Color:=clRed;
 WordApplication1.Selection.Font.Italic:=1;
 WordApplication1.Selection.Font.Size:=16;
 

В данном примере мы сделали цвет текста в ячейке (1,2) красным, выделили его курсивом и изменили размер на 16. Кроме того, можем сделать шрифт подчеркнутым, перечеркнутым и т.п.

Еще один способ изменить внешний вид таблицы - использовать стилевые шаблоны Word'a. У таблицы имеется метод AutoFormat, который меняет внешний вид таблицы в соответствии с некими предопределенными стилями. В заголовочном файле он описан следующим образом:


 procedure AutoFormat(var Format: OleVariant; var ApplyBorders: OleVariant;
   var ApplyShading: OleVariant; var ApplyFont: OleVariant;
   var ApplyColor: OleVariant; var ApplyHeadingRows: OleVariant;
   var ApplyLastRow: OleVariant; var ApplyFirstColumn: OleVariant;
   var ApplyLastColumn: OleVariant; var AutoFit: OleVariant);
 

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

Как показала практика, работают только два первых параметра. Все остальные заменяем "пустышками". То есть это скорее будет просто способ изменения стиля границ, но и на том спасибо. Некоторые стили таблиц даны в приложении, полный же список ищите в заголовочном файле. Для примера применим к нашей таблице стиль "Вэб3". Вместо второго параметра ставим вариантную переменную, которой присваиваем wdTableFormatApplyBorders. То есть на практике это выглядит так:


 var
   tformat, tappbrd: OleVariant;
 begin
   tformat := wdTableFormatWeb3;
   tappbrd := wdTableFormatApplyBorders;
   i := 1;
   WordDocument1.Tables.Item(i).AutoFormat(tformat, tappbrd, EmptyParam,
     EmptyParam, EmptyParam, EmptyParam,
     EmptyParam, EmptyParam, EmptyParam, EmptyParam);
 

И еще об одном способе создания таблиц

Людям, интересующимся работой с MS Word, возможно, тоже попадались в интернете компоненты, превращающие в таблицу соответствующим образом отформатированный текст. Вот мы как раз и разберемся, как же они устроены. Здесь нам опять надо вспомнить про объект Range, а именно про имеющийся у него метод ConvertToTable. В заголовочном файле это выглядит так:


 function ConvertToTable(var Separator: OleVariant; var NumRows: OleVariant;
   var NumColumns: OleVariant; var InitialColumnWidth: OleVariant;
   var Format: OleVariant; var ApplyBorders: OleVariant;
   var ApplyShading: OleVariant; var ApplyFont: OleVariant;
   var ApplyColor: OleVariant; var ApplyHeadingRows: OleVariant;
   var ApplyLastRow: OleVariant; var ApplyFirstColumn: OleVariant;
   var ApplyLastColumn: OleVariant; var AutoFit: OleVariant;
   var AutoFitBehavior: OleVariant; var DefaultTableBehavior: OleVariant)
 

Здесь опять видим все те же константы применения стиля, что и в автоформате. Только в отличие от него тут они ошибок не вызывают. Правда, есть у меня жуткое подозрение, что они все равно не работают и можем со спокойной совестью поставить вместо них "пустышки" - всех, кроме опять-таки, первых двух параметров "применения изменений". Теперь по порядку. Первый параметр у нас задает символ, которым будут отделяться ячейки одной строки нашей будущей таблицы, второй - число строк таблицы, третий - число столбцов, затем идет ширина столбцов. Следующая группа параметров задает стиль таблицы и особенности его применения, необходимые значения констант есть в таблице "Приложения". Последние три параметра задают подгонку размера ячеек по содержимому, но на самом деле не работают. Так что ставим вместо них EmptyParam. И, наконец, практический пример. Предположим, мы открыли новый документ и занесли в него нужный текст:


 WordDocument1.Range.InsertAfter('column1');
 WordDocument1.Range.InsertAfter(#9);
 WordDocument1.Range.InsertAfter('column2');
 WordDocument1.Range.InsertAfter(#9);
 WordDocument1.Range.InsertAfter('column3');
 WordDocument1.Range.InsertAfter(#9);
 WordDocument1.Range.InsertAfter('column4');
 WordDocument1.Range.InsertAfter(#13);
 

Такую операцию повторим трижды, и у нас будет заготовка для таблицы на 4 столбца и 3 строки. Будущие столбцы отделяются символами табуляции, а строки - переходами на новую строку. Теперь выделяем объект Range - в данном случае это весь текст документа, и превращаем его в таблицу:


 var
   tsepar, tnumrows, tnumcols, tincolw, tformat,
   tappbrd, tappshd, tappfnt, tappclr, tapphr, tapplr,
   tappfc, tapplc: OleVariant;
 begin
   tsepar := wdSeparateByTabs;
   tnumrows := 3;
   tnumcols := 4;
   tincolw := 150;
   tformat := wdTableFormatNone;
   tappbrd := wdTableFormatApplyBorders;
   tappshd := wdTableFormatApplyShading;
   tappfnt := wdTableFormatApplyFont;
   tappclr := wdTableFormatApplyColor;
   tapphr := wdTableFormatApplyHeadingRows;
   tapplr := wdTableFormatApplyLastRow;
   tappfc := wdTableFormatApplyFirstColumn;
   tapplc := wdTableFormatApplyLastColumn;
 
   WordDocument1.Range.ConvertToTable(tsepar, tnumrows, tnumcols, tincolw,
     tformat, tappbrd, tappshd, tappfnt, tappclr, tapphr, tapplr,
     tappfc, tapplc, EmptyParam, EmptyParam, EmptyParam);
 

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

Проделав все это, обнаруживаем, что наш текст превратился в таблицу. Все это несколько напоминает создание таблиц в HTML.

Приложения

Список некоторых констант. Смотрите файл Word2000.pas

Описание Символьное обозначение Шестнадцатеричное
Текстуры
Некоторые константы текстур - откройте Word2000.pas в "блокноте", введите в диалог поиска "texture", и получите полный список.
wdTextureNone $00000000
wdTexture2Pt5Percent $00000019
wdTexture7Pt5Percent $0000004B
wdTexture35Percent $0000015E
wdTexture62Pt5Percent $00000271
wdTextureSolid $000003E8
wdTextureDarkHorizontal $FFFFFFFF
wdTextureCross $FFFFFFF5
Формат таблицы
Константы формата таблицы. Необходимы при использовании автоформата и преобразовании текста в таблицу.
wdTableFormatNone $00000000
wdTableFormatSimple1 $00000001
wdTableFormatSimple3 $00000003
wdTableFormatClassic1 $00000004
wdTableFormatClassic3 $00000006
wdTableFormatColorful1 $00000008
wdTableFormatColumns1 $0000000B
wdTableFormatGrid1 $00000010
wdTableFormatGrid3 $00000012
wdTableFormatList1 $00000018
wdTableFormat3DEffects1 $00000020
wdTableFormat3DEffects2 $00000021
wdTableFormat3DEffects3 $00000022
wdTableFormatContemporary $00000023
wdTableFormatElegant $00000024
wdTableFormatProfessional $00000025
wdTableFormatSubtle1 $00000026
wdTableFormatWeb3 $0000002A
Стили таблицы
Константы "применения изменений" стиля таблицы. В идеале предполагается, что можно задавать отдельно, изменять ли стиль границ, текста, цвета и т.д. В автоформате работают, мягко выражаясь, невразумительно, все время возникают какие-то непонятные ошибки.
wdTableFormatApplyBorders $00000001
wdTableFormatApplyShading $00000002
wdTableFormatApplyFont $00000004
wdTableFormatApplyColor $00000008
wdTableFormatApplyAutoFit $00000010
wdTableFormatApplyHeadingRows $00000020
wdTableFormatApplyLastRow $00000040
wdTableFormatApplyFirstColumn $00000080
wdTableFormatApplyLastColumn $00000100
Разделители
Константы разделителей для конвертации текста в таблицу.
wdSeparateByParagraphs $00000000
wdSeparateByTabs $00000001
wdSeparateByCommas $00000002
wdSeparateByDefaultListSeparator $00000003



MS Word вместо QReport - текст, изображения и списки

Автор: Василий Нестеров

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

Текст

Сначала о самом простом - добавлении в документ Word нужной строки текста. Поместим на форму компоненты WordDocument , WordApplication и WordParagraphFormat с палитры Servers. Нас интересуют в первую очередь свойство Range компонента WordDocument и свойство Selection компонента WordApplication. Классики утверждают, что они являются ссылкой на объекты Range и Selection. Range представляет из себя, проще говоря, кусок текста, это может быть как весь текст документа, так и любая его часть. Его пределы задаются двумя (или меньше) параметрами типа OleVariant. Например:


 var
   range1, range2, range3, a, b: OleVariant;
 begin
   range1 := WordDocument1.Range;
   a := 5;
   b := 15;
   range2 := WordDocument1.Range(a, b);
   range3 := WordDocument1.Range(a);
 

Первый наш объект включает в себя весь текст документа, у второго мы ограничили пределы 5-м и 15-м символами, третий представляет из себя весь последующий текст документа, начиная с 5-го символа. Объект имеет несколько полезных методов, например, с его помощью можем добавить текст в документ:


 range2.InsertAfter('MS Word');
 

Это мы вставили текст после выделенного Range. Точно также можем вставить текст и перед ним, для этого служит метод InsertBefore(). Текст, заключенный в объекте Range, можем получить так:


 WordDocument1.Range(a,b).Text;
 

Кроме того, с помощью Range можем изменить шрифт в пределах объекта. Пример:


 a:=5;
 b:=15;
 WordDocument1.Range(a,b).Font.Bold:=1;
 WordDocument1.Range(a,b).Font.Size:=14;
 WordDocument1.Range(a,b).Font.Color:=clRed;
 

Если хотим отменить выделение жирным шрифтом, присваиваем 0. Аналогично можно сделать шрифт курсивом, подчеркнутым - наберите WordDocument1.Range.Font., и среда сама подскажет, какие могут быть варианты. Методы Select, Cut, Copy и Paste работают как в обычном тексте. С помощью Paste можем на место выбранного Range вставить не только строки, но и рисунок, находящийся в буфере обмена.


 WordDocument1.Range(a,b).Select;
 WordDocument1.Range(a,b).Cut;
 WordDocument1.Range(a,b).Copy;
 WordDocument1.Range(a,b).Paste;
 

С помощью Range можем найти в документе нужную строку. Пусть в тексте содержится слово "picture". Например, нам на его место надо будет вставить рисунок.


 var
   a, b, vstart, vend: OleVariant;
   j, ilengy: Integer;
 begin
   ilengy := Length(WordDocument1.Range.Text);
   for j := 0 to ilengy - 8 do
   begin
     a := j;
     b := j + 7;
     if WordDocument1.Range(a, b).Text = 'picture' then
     begin
       vstart := j;
       vend := j + 7;
     end;
   end;
   WordDocument1.Range(vstart, vend).Select;
 end;
 

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

Теперь про Selection, представляющий из себя выделенный фрагмент документа. Если выделения нет, это текущая позиция курсора в документе. С его помощью можем вставить что-либо на место выделенного фрагмента, сделать выравнивание, изменить шрифт. Он также имеет методы InsertAfter() и InsertBefore():


 WordApplication1.Selection.InsertAfter("text1");
 WordApplication1.Selection.InsertBefore("text2");
 

Форматирование выделенного текста происходит аналогично Range, например:


 WordApplication1.Selection.Font.Bold:=1;
 WordApplication1.Selection.Font.Size:=16;
 WordApplication1.Selection.Font.Color:=clGreen;
 

Для выравнивания проще воспользоваться компонентом WordParagraphFormat. Сначала только нужно "подключить" его к выделенному фрагменту текста:


 WordParagraphFormat1.ConnectTo(WordApplication1.Selection.
   ParagraphFormat);
 WordParagraphFormat1.Alignment := wdAlignParagraphCenter;
 

Значения его свойства Alignment может принимать значения wdAlignParagraphCenter, wdAlignParagraphLeft, wdAlignParagraphRight, смысл которых очевиден. Имеются и методы Cut, Copy и Paste, которые в пояснениях вряд ли нуждаются:


 WordApplication1.Selection.Cut;
 WordApplication1.Selection.Copy;
 WordApplication1.Selection.Paste;
 

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


 var
   vcol: OleVariant;
 begin
   vcol := wdCollapseStart;
   WordApplication1.Selection.Collapse(vcol);
 

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


 WordApplication1.Selection.Collapse(EmptyParam);
 

Тогда свертывание выделения производится по умолчанию, к началу выделенного текста.

Рисунки

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

Простейший метод вставить в документ рисунок - по упомянутым причинам он же и единственный - скопировать его в Word из буфера обмена. Предположим, рисунок у нас находится в компоненте DBImage. Сначала нужно загнать его в буфер обмена:


 Clipboard.Assign(DBImage1.Picture);
 

Теперь для его вставки следует воспользоваться методом Paste объектов Range или Selection: WordApplication1.Selection.Paste или WordDocument1.Range(a,b).Paste. Оставить для рисунка достаточное количество пустых строк и попасть в нужное место - это уже наша забота. Если он попадет посреди текста, вид будет довольно противный - при такой вставке обтекание текстом рисунка происходит как-то странно. Можно приготовить для отчета шаблон, где заменяем рисунком какое-либо ключевое слово. О том, как найти в документе нужный текст, см. выше.

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

"Рамки" образуют коллекцию Frames, нумеруются целым индексом, пробегающим значения от 1 до WordDocument1.Frames.Count. Добавим в документ рамку, изменим ее размер и вставим рисунок:


 Clipboard.Assign(DBImage1.Picture);
 vstart := 1;
 vend := 2;
 WordDocument1.Frames.Add(WordDocument1.Range(vstart, vend));
 i := 1;
 WordDocument1.Frames.Item(i).Height := DBImage1.Height;
 WordDocument1.Frames.Item(i).Width := DBImage1.Width;
 WordDocument1.Frames.Item(i).Select;
 WordApplication1.Selection.Paste;
 

Здесь для простоты предполагается, что размер DBImage равен размеру самой картинки, а также что до этого рамок у нас в документе не было. Обратить внимание следует на несколько моментов. Размер рамки надо задавать до того, как копировать в нее рисунок. Иначе она будет иметь размер по умолчанию, под который замасштабируется и наша картинка. При попытке изменить размер рамки задним числом размер картинки уже не изменится. Кроме того, параметр Range при добавлении рамки часто никакой роли не играет. Рамка изначально все равно появится в левом верхнем углу документа, а указанный кусок текста при этом не пострадает. Но это только в том случае, если он не выделен. Если в документе есть выделение, рамка появится вместо выделенного фрагмента. Таким образом можем ее вставить в нужное место взамен какого-то ключевого слова.

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


 i:=1;
 WordDocument1.Frames.Item(i).VerticalPosition:=30;
 WordDocument1.Frames.Item(i).HorizontalPosition:=50; 

Отступ между краями рамки и текстом задается следующим образом:


 WordDocument1.Frames.Item(i).HorizontalDistanceFromText:=10;
 WordDocument1.Frames.Item(i).VerticalDistanceFromText:=10;
 

А теперь о масштабировании. Для этого достаточно длину и ширину рамки умножить на одно и то же число. Например:


 WordDocument1.Frames.Item(i).Height:=DBImage1.Height*1.5;
 WordDocument1.Frames.Item(i).Width:=DBImage1.Width*1.5;
 

При этом наша картинка в полтора раза пропорционально растянется. Точно также можно и уменьшить, но делить, как и множить, следует на одно число. Растягивать длину и ширину по-разному у меня лично не получалось. Задавать размер опять-таки надо еще до вставки рисунка. Ну и, наконец, удаление рамки:


 WordDocument1.Frames.Item(i).Delete;
 

Списки

Списки в документе образуют коллекцию Lists, к отдельному списку обращаемся WordDocument1.Lists.Item(i), где i целое число от 1 до WordDocument1.Lists.Count ... на этом все. Нет методов, позволяющих не то что создать новый список, а даже добавить пункт к уже существующему. Ничего страшного, настоящие герои всегда идут в обход:)) Сейчас мы все же проделаем и то, и другое. Все что нам понадобится - свойство Range отдельного списка, то есть его текст без разделения на пункты, а также возможность его выделить:


 WordDocument1.Lists.Item(i).Range.Select;
 

Для этого в любом случае потребуется заготовка. Неважно, вставлена она в общий шаблонный документ или хранится в отдельном файле. Заготовку делаем так: выбираем в меню Формат/Список, и сохраняем, если это отдельный шаблон списка. У нас появляется пустой список без текста с одним маркером. Далее вспоминаем, как мы делали списки вручную - писали текст, нажимали "Enter", появлялся новый элемент списка. Теперь то же самое, только программно. Предположим, у нас уже открыт документ с заготовкой, и мы хотим внести в список пункты "Item 1" и "Item 2":


 var
   i: Integer;
   vcol: OleVariant;
 begin
   i := 1;
   vcol := wdCollapseEnd;
   WordDocument1.Lists.Item(i).Range.Select;
   WordApplication1.Selection.Collapse(vcol);
   WordApplication1.Selection.InsertAfter('Item 1');
   WordDocument1.Lists.Item(i).Range.Select;
   WordApplication1.Selection.Collapse(vcol);
   WordApplication1.Selection.InsertAfter(#13);
   WordDocument1.Lists.Item(i).Range.Select;
   WordApplication1.Selection.Collapse(vcol);
   WordApplication1.Selection.InsertAfter('Item 2');
   WordDocument1.Lists.Items(i).Range.Select;
   WordApplication1.Selection.Copy;
 

То есть мы вставляем в документ текст первого пункта списка, он попадает на свое место. Потом посылаем в Word символ перехода строки, он честно переходит и тем самым сам создает нам второй пункт списка, куда и вставляем нужную строку. Ну и так далее, нужное количество раз. Последние две строки нужны, если список заготовлен в отдельном файле - после их выполнения список оказывается в буфере обмена. Здесь выгода в том, что можем иметь заготовки списков разных стилей и по ходу дела выбирать, какой список создать. Затем открываем документ, где должен быть список, выделяем с помощью Range нужный кусок, копируем из буфера обмена через WordDocument1.Range(a,b).Paste. Чтобы не испортить файл с заготовкой, можем сразу после открытия пересохранить его под другим именем, а можем просто выйти из него без сохранения изменений


 var
   vsave: OleVariant;
 begin
   vsave := wdDoNotSaveChanges;
   WordDocument1.Close(vsave);
 

Константа сохранения изменений может принимать значения

Символьное обозначение Шестнадцатеричное
wdSaveChanges $FFFFFFFF
wdDoNotSaveChanges $00000000
wdPromptToSaveChanges $FFFFFFFE

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


 var
   i, j: Integer;
 begin
   i := 1;
   j := 1;
   WordDocument1.Lists.Item(i).ListParagraphs.Item(j).Range.Text := 'Item 1';
 

Так что можно с помощью переходов строки создать нужное количество элементов, а затем их заполнить:


 WordDocument1.Lists.Item(i).Range.Select;
 WordApplication1.Selection.Collapse(vcol);
 WordApplication1.Selection.InsertAfter(#13);
 j:=1;
 WordDocument1.Lists.Item(i).ListParagraphs.Item(j).Range.Text:='Item 1';
 j:=2;
 WordDocument1.Lists.Item(i).ListParagraphs.Item(j).Range.Text:='Item 2';
 

Это было в предположении, что у нас один элемент списка в заготовке уже есть. Ну вот, в общем-то, и все про текст, списки и картинки




<< ВЕРНУТЬСЯ В ОГЛАВЛЕНИЕ



Материалы находятся на сайте https://exelab.ru/pro/



Оригинальный DVD-ROM: eXeL@B DVD !


Вы находитесь на EXELAB.rU
Проект ReactOS