Второй параметр в вызове — ширина прокрутки в точках.
Поиск строки в ListBox
Есть функция API Windows, что заставляет искать строку в ListBox с указанной позиции.
Например, поиск строки, что начинается на '1.' От текущей позиции курсора в ListBox. Т.о., нажимая на кнопку Button1, будут перебраны все строки начинающиеся на '1.'
procedure TForm1.Button1Click(Sender: TObject);
var S : string;
begin
S:='1.';
with ListBox1 do ItemIndex := Perform(LB_SELECTSTRING, ItemIndex, LongInt(S));
end;
Более подробную информацию о работе команды LB_SELECTSTRING можно узнать из Help-а Win32.
Пример получения позиции курсора из компоненты TMemo.
procedure TForm1.Memo1KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
Как определить работает ли уже данное приложение или это первая его копия?
Для Delphi 1. Каждый экземпляр программы имеет ссылку на свою предыдущую копию — hPrevInst: hWnd. Ее можно проверить перед созданием приложения и при необходимости отреагировать соответствующим образом. Если запущена только одна копия, то эта ссылка равна нулю.
Пример:
procedure TForm1.FormCreate(Sender: TObject);
begin
{Проверяем есть ли указатель на предыдущую копию приложения}
IF hPrevInst lt;gt; 0 THEN BEGIN
{Если есть, то выдаем сообщение и выходим}
MessageDlg('Программа уже запущена!', mtError, [mbOk], 0);
Halt;
END;
{Иначе - ничего не делаем (не мешаем созданию формы)}
end;
P.S. Для выхода необходимо использовать Halt, а не Close, как хотелось бы, так как форма еще не создана и закрывать нечего.
Есть и другой способ — по списку загруженных приложений
procedure TForm1.FormCreate(Sender: TObject);
VAR
Wnd : hWnd;
buff : ARRAY[0.. 127] OF Char;
Begin
Wnd := GetWindow(Handle, gw_HWndFirst);
WHILE Wnd lt;gt; 0 DO BEGIN
IF (Wnd lt;gt; Application.Handle) AND (GetWindow(Wnd, gw_Owner) = 0)
THEN BEGIN
GetWindowText (Wnd, buff, sizeof (buff ));
IF StrPas (buff) = Application.Title THEN
BEGIN
MessageDlg('Приложение уже загружено', mtWarning, [mbOk], 0);
Halt;
END;
END;
Wnd := GetWindow (Wnd, gw_hWndNext);
END;
End;
Еще один интересный способ для Win32. Дело в том, что можно в памяти создавать временные файлы. При перезагрузке они теряются, а так существуют. Кстати, этот метод можно использовать и для обмена информацией между вашими приложениями.
Пример:
program Project1;
uses
Windows, // Обязательно
Forms,
Unit1 in 'Unit1.pas' {Form1};
{$R *.RES}
Const
MemFileSize = 1024;
MemFileName = 'one_inst_demo_memfile';
Var
MemHnd : HWND;
begin
{ Попытаемся создать файл в памяти }
MemHnd := CreateFileMapping(HWND($FFFFFFFF),
nil,
PAGE_READWRITE,
0,
MemFileSize,
MemFileName);
{ Если файл не существовал запускаем приложение }
if GetLastErrorlt;gt;ERROR_ALREADY_EXISTS then
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end;
CloseHandle(MemHnd);
end.
Часто при работе у пользователя может быть открыто 5–20 окон и сообщение о том, что программа уже запущено приводит к тому, что он вынужден полчаса искать ранее запущенную копию. Выход из положения — найдя копию программы активировать ее, для чего в последнем примере перед HALT необходимо добавить строку :
Внутри приложения это выполняется достаточно просто с помощью вызова функции Windows API SendMessage() (можно воспользоваться и методом Perform того объекта (или формы), кому посылается сообщение о нажатой клавише).
Код
Memo1.Perform(WM_CHAR, Ord('A'), 0);
или
SendMessage(Memo1.Handle, WM_CHAR, Ord('A'), 0);
приведет к печати символа "A" в объекте Memo1.
II. Перехват нажатий клавиши внутри приложения.
Задача решается очень просто. Можно у формы установить свойство KeyPreview в True и обрабатывать событие OnKeyPress. Второй способ — перехватывать событие OnMessage для объекта Application.
III. Перехват нажатия клавиши в Windows.
Существуют приложения, которым необходимо перехватывать все нажатия клавиш в Windows, даже если в данный момент активно другое приложение. Это может быть, например, программа, переключающая раскладку клавиатуры, резидентный словарь или программа, выполняющая иные действия по нажатию "горячей" комбинации клавиш. Перехват всех событий в Windows (в том числе и событий от клавиатуры) выполняется с помощью вызова функции SetWindowsHook(). Данная функция регистрирует в системе Windows ловушку (hook) для определенного типа событий/сообщений. Ловушка — это пользовательская процедура, которая будет обрабатывать указанное событие. Основное здесь то, что эта процедура должна всегда присутствовать в памяти Windows. Поэтому ловушку помещают в DLL и загружают эту DLL из программы. Пока хоть одна программа использует DLL, та не может быть выгружена из памяти. Приведем пример такой DLL и программы, ее использующей. В примере ловушка перехватывает нажатие клавиш на клавиатуре, проверяет их и, если это клавиши "+" или "-", посылает соответствующее сообщение в конкретное приложение (окно). Окно ищется по имени его класса ("TForm1") и заголовку (caption, "XXX").
{текст библиотеки}
library SendKey;
uses
WinTypes, WinProcs, Messages;
const
{пользовательские сообщения}
wm_NextShow_Event = wm_User + 133;
wm_PrevShow_Event = wm_User + 134;
{handle для ловушки}
HookHandle: hHook = 0;
var
SaveExitProc : Pointer;
{собственно ловушка}
function Key_Hook(Code: integer; wParam: word; lParam: Longint): Longint; export;
var
H: HWND;
begin
{если Codegt;=0, то ловушка может обработать событие}
if Code gt;= 0 then
begin
{это те клавиши?}
if ((wParam = VK_ADD)or(wParam = VK_SUBTRACT)) and
(lParam and $40000000 = 0)
then begin
{ищем окно по имени класса и по заголовку}
H := FindWindow('TForm1', 'XXX');
{посылаем сообщение}
if wParam = VK_ADD then
SendMessage(H, wm_NextShow_Event, 0, 0)
else
SendMessage(H, wm_PrevShow_Event, 0, 0);
end;
{если 0, то система должна дальше обработать это событие}
{если 1 - нет}
Result:=0;
end
else
{если Codelt;0, то нужно вызвать следующую ловушку}
Result := CallNextHookEx(HookHandle,Code, wParam, lParam);
procedure WM_NextMSG (Var M : TMessage); message wm_NextShow_Event;
procedure WM_PrevMSG (Var M : TMessage); message wm_PrevShow_Event;
end;
var
Form1: TForm1;
P : Pointer;
implementation
{$R *.DFM}
{загрузка DLL}
function Key_Hook : Longint; far; external 'SendKey';
procedure TForm1.WM_NextMSG (Var M : TMessage);
begin
Label1.Caption:='Next message';
end;
procedure TForm1.WM_PrevMSG (Var M : TMessage);
begin
Label1.Caption:='Previous message';
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
{если не использовать вызов процедуры из DLL в программе,
то компилятор удалит загрузку DLL из программы}
P:=@Key_Hook;
end;
end.
Конечно, свойство Caption в этой форме должно быть установлено в "XXX".
Как сделать так, что при нажатии на Enter происходил переход к следующему элементу формы
Ставите у формы KeyPreview = true и создаете событие KeyPress следующего вида:
procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
if (Key = #13) then begin
Key:=#0;
Perform(WM_NEXTDLGCTL,0,0);
end;
end;
Вставка и удаление компонент в форму в design-time
Вопрос:
Каким образом можно отследить вставку и удаление компонент в форму в design-time? Такая информация могла бы пригодится, если моя компонента имеет ссылки на другие компоненты (например, как в связке TDateSource,TTable и др.)
класса TComponent. Перекрыв его в своей компоненты Вы можете произвести необходимые действия, в зависимости от значения параметра Operation типа
TOperation = (opInsert, opRemove);
объявленного в модуле Classes. Параметр AComponent — компонента, соответственно вставлемая или удаляемая, в зависимости от Operation.
Создание отчета в MS Word
(Пример для Delphi 1.0 поскольку в Delphi 2-3 лучше использовать:
var MsWord : variant;
MsWord := CreateOleObject('Word.Basic');
Для Delphi 3, пример ниже)
Создавать отчет в программе Word удобно если отчет имеет сложную структуру (тогда его быстрее создать в Word, чем в Qreport от Delphi, кроме того, этот QReport имеет "глюки"), либо, если после создания отчета его нужно будет изменять. Итак, первым делом в Word создается шаблон будущего отчета, это самый обыкновенный не заполненный отчет. А в места куда будет записываться информация нужно поставить метки. Например (для наглядности метки показаны синим цветом, реально они конечно не видны):
Далее в форму, откуда будут выводиться данные, вставляете компоненту DdeClientConv из палитры System. Назовем ее DDE1. Эта компонента позволяет передавать информацию между программами методом DDE. Свойства:
ConnectMode : ddeManual — связь устанавливаем вручную
DdeService : (winword) — с кем устанавливается связь
ServiceApplication : C:\MSOffice\Winword\WINWORD.EXE — полный путь доступа к программе. (Вот здесь можно наступить на грабли. Ведь Word может лежать в любой папке! Поэтому путь доступа к нему лучше взять из реестра, а еще лучше использовать OLE см.начало раздела)
Теперь пишем процедуру передачи данных:
{ Печать накладной }
procedure Form1.PrintN;
Var
S : string;
i : integer;
Sum : double; {итоговая сумма, кстати,совет: не пользуйтесь типом real!}
Tv, Ss : PChar;
begin
S:=GetCurrentDir+'\Накладная.doc'; { имя открываемого документа }
DDE1.OpenLink; { устанавливаем связь }
Tv:=StrAlloc(20000); Ss:=StrAlloc(300); { выделяем память }
{ даем команду открыть документ и установить курсор в начало документа }
{ Говорим Windows, что на нас можно бросать файлы }
DragAcceptFiles(Handle, True);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
{ Закрываем за собой дверь золотым ключиком}
DragAcceptFiles(Handle, False);
end;
end.
Привлечение внимания к окну
Часто возникает проблема — в многооконном приложении необходимо обратить внимание пользователя на то, что какое-то из окон требует внимания (например, к нему пришло сообщение по DDE, в нем завершился какой-либо процесс, произошла ошибка...). Это легко сделать, используя команду API FlashWindow:
procedure TForm1.Timer1Timer(Sender: TObject);
begin FlashWindow(Handle,true);
end;
В данном примере FlashWindow вызывается по таймеру ежесекундно, что приводит к миганию заголовка окна.
Заставка для программы
Сведения о программе, авторские права и т.д., лучше оформить в виде отдельной формы и показывать ее при запуске программы (как это сделано в Word).
Сделать это не сложно:
1. Создаете форму (например SplashForm).
2. Объявляете ее свободной (availableForms).
3. В Progect Source вставляете следующее (например):
program Splashin;
uses Forms, Main in 'MAIN.PAS', Splash in 'SPLASH.PAS'
{$R *.RES}
begin
try
SplashForm := TSplashForm.Create(Application);
SplashForm.Show;
SplashForm.Update;
Application.CreateForm(TMainForm, MainForm);
SplashForm.Hide;
finally
SplashForm.Free;
end;
Application.Run;
end.
И форма SplashForm держится на экране пока выполняется Create в главной форме. Но иногда она появляется и пропадает очень быстро, поэтому нужно сделать задержку:
ShowMessage('You hit the button on the caption bar');
end;
procedure TForm1.FormResize(Sender: TObject);
begin
//Force a redraw of caption bar if form is resized
Perform(WM_NCACTIVATE, Word(Active), 0);
end;
end.
Преобразование текста OEM в Ansi
Эта версия работает под любым Delphi.
(Начиная с Delphi 2, это можно записать короче с использованием AnsiToOem и OemToAnsi.)
Здесь все просто.
function ConvertAnsiToOem(const S : string) : string;
{ ConvertAnsiToOem translates a string into the OEM-defined character set }
{$IFNDEF WIN32}
var
Source, Dest : array[0..255] of Char;
{$ENDIF}
begin
{$IFDEF WIN32}
SetLength(Result, Length(S));
if Length(Result) gt; 0 then
AnsiToOem(PChar(S), PChar(Result));
{$ELSE}
if Length(Result) gt; 0 then
begin
AnsiToOem(StrPCopy(Source, S), Dest);
Result := StrPas(Dest);
end;
{$ENDIF}
end; { ConvertAnsiToOem }
function ConvertOemToAnsi(const S : string) : string;
{ ConvertOemToAnsi translates a string from the OEM-defined
character set into either an ANSI or a wide-character string }
{$IFNDEF WIN32}
var
Source, Dest : array[0..255] of Char;
{$ENDIF}
begin
{$IFDEF WIN32}
SetLength(Result, Length(S));
if Length(Result) gt; 0 then
OemToAnsi(PChar(S), PChar(Result));
{$ELSE}
if Length(Result) gt; 0 then
begin
OemToAnsi(StrPCopy(Source, S), Dest);
Result := StrPas(Dest);
end;
{$ENDIF}
end; { ConvertOemToAnsi }
Состояние кнопки insert (Insert/Overwrite)
{------------------------------------------}
{ Returns the status of the Insert key. }
{------------------------------------------}
function InsertOn: Boolean;
begin
if LowOrderBitSet(GetKeyState(VK_INSERT)) then InsertOn := true
else InsertOn := false
end;
Сводка функций модуля Math
Здесь я привожу полный список всех функций и процедур модуля Math. При переходе от Delphi 2 к Delphi 3 модуль Math почти не изменился, фирма Borland ввела в него только три новые функции: MaxIntValue, MInIntValue и Sumint. Эти функции отличаются от своих прототипов (MaxValue, MInValue и Sum) лишь тем, что работают исключительно с целыми числами, не принимая и не возвращая величин с плавающей точкой. Что касается остальных функций, то большинство из них вполне очевидно. Если вам покажется иначе — что ж, садитесь за исследования. И не надейтесь, что все тайны Delphi достанутся вам на блюдечке в виде help-файла!
Тригонометрические функции и процедуры
ArcCos — Арккосинус
ArcCosh — Пиперболический арккосинус
ArcSIn — Арксинус
ArcSInh — Гиперболический арксинус
ArcTahn — Гиперболический арктангенс
ArcTan2 — Арктангенс с учетом квадранта (функция ArcTan, не учитывающая квадрант, находится в модуле System)
Cosh — Гиперболический косинус
Cotan — Котангенс
CycleToRad — Преобразование циклов в радианы
DegToRad — Преобразование градусов в радианы
GradToRad — Преобразование градов в радианы
Hypot — Вычисление гипотенузы прямоугольного треугольника по длинам катетов
RadToCycle — Преобразование радианов в циклы
RadToDeg — Преобразование радианов в градусы
RacIToGrad — Преобразование радианов в грады
SinCos — Вычисление синуса и косинуса угла. Как и в случае SumAndSquares и MeanAndStdDev, одновременная генерация обеих величин происходит быстрее
Sinh — Гиперболический синус
Tan — Тангенс
Tanh — Гиперболический тангенс
Арифметические функции и процедуры
Cell — Округление вверх
Floor — Округление вниз
Frexp — Вычисление мантиссы и порядка заданной величины
IntPower — Возведение числа в целую степень. Если вы не собираетесь пользоваться экспонентами с плавающей точкой, желательно использовать эту функцию из-за ее скорости
Ldexp — Умножение Х на 2 в заданной степени
LnXPI — Вычисление натурального логарифма Х+1. Рекомендуется для X, близких к нулю
LogN — Вычисление логарифма Х по основанию N
LogIO — Вычисление десятичного логарифмах
Log2 — Вычисление двоичного логарифмах
Power — Возведение числа в степень. Работает медленнее IntPower, но для операций с плавающей точкой вполне приемлемо
Финансовые функции и процедуры
DoubleDecliningBalance — Вычисление амортизации методом двойного баланса
FutureValue — Будущее значение вложения
InterestPayment — Вычисление процентов по ссуде
InterestRate — Норма прибыли, необходимая для получения заданной суммы
InternalRateOfReturn — Вычисление внутренней скорости оборота вложения для ряда последовательных выплат
NetPresentValue — Вычисление чистой текущей стоимости вложения для ряда последовательных выплат с учетом процентной ставки
NumberOf Periods — Количество периодов, за которое вложение достигнет заданной величины
Payment — Размер периодической выплаты, необходимой для погашения ссуды, при заданном числе периодов, процентной ставке, а также текущем и будущем значениях ссуды
PerlodPayment — Платежи по процентам за заданный период
PresentValue — Текущее значение вложения
SLNDepreclatlon — Вычисление амортизации методом постоянной нормы
SYDepreclatlon — Вычисление амортизации методом весовых коэффициентов
Статистические функции и процедуры
MaxIntValue — Максимальное значение в наборе целых чисел. Функция появилась в Delphi 3. ее не существует в Delphi 2
MaxValue — Максимальное значение в наборе чисел. В Delphi 2 функция возвращает минималъное значение
Mean — Среднее арифметическое для набора чисел
MeanAndStdDev — Одновременное вычисление среднего арифметического и стандартного отклонения для набора чисел. Вычисляется быстрее, чем обе величины по отдельности
MinIntValLie — Минимальное значение в наборе целых чисел. Функция появилась в Delphi 3, ее не существует в Delphi 2
MInValue — Минимальное значение в наборе чисел. В Delphi 2 функция возвращает максимальное значение
MoiiientSkewKurtosIs — Статистические моменты порядков с первого по четвертый, а также асимметрия (skew) и эксцесс (kurtosis) для набора чисел
Norm — Норма для набора данных (квадратный корень из суммы квадратов)
PopnStdDev — Выборочное стандартное отклонение. Отличается от обычного стандартного отклонения тем, что при вычислениях используется выборочное значение дисперсии, PopnVarlance (см. ниже)
PopnVarlance — Выборочная дисперсия. Использует "смещенную" формулу TotalVanance/n
RandG — Генерация нормально распределенных случайных чисел с заданным средним значением и среднеквадратическим отклонением
StdDev — Среднеквадратическое отклонение для набора чисел
Sum — Сумма набора чисел
SLimsAndSquares — Одновременное вычисление суммы и суммы квадратов для набора чисел. Как и в других функциях модуля Math, обе величины вычисляются быстрее, чем по отдельности
Sumint — Сумма набора целых чисел. Функция появилась в Delphi 3, ее не существует в Delphi 2
SLimOfSquares — Сумма квадратов набора чисел
Total Variance — "Полная дисперсия" для набора чисел. Это сумма квадратов расстояний всех величин от их среднего арифметического
Variance — Выборочная дисперсия для набора чисел. Функция использует "несмещенную" формулу TotalVanапсе/ (n – 1)
Внутри конструктора Create компонента создаю другой компонент, но Delphi помещает запись о втором компоненте в dfm-файл!
У меня такая проблема: я пишу компонент, который внутри себя создаёт другой компонент. Конструктор первого компонента выглядит примерно так:
constructor TFirstComp.Create(AOwner:TComponent);
begin
inherited Create(AOwner);
SecondComp:=TSecondComp.Create(Owner)
end;
Проблема заключается в том, что при помещении первого компонента на форму в dfm-файл записывается информация и о втором компоненте тоже. А в pas-файл — только о первом. Это приводит к конфликтам. Для меня принципиально, чтобы хозяин у второго компонента был тот же, что и у первого. Как не дать Delphi поместить запись о TSecondComp в dfm-файл?
Попробуйте сделать так:
constructor TFirstComp.Create(AOwner:TComponent);
begin
inherited Create(AOwner);
SecondComp:=TSecondComp.Create(SELF);
end;
Т.е. дочернему компоненту в качастве владельца передавайте его непосредственного хозяина.
Как вставить иконку (или bitmap) в TRichEdit, причем так, чтобы пользователь мог ее удалить нажатием клавиши Del (как это сделано в Microsoft Word)?