Список вопросов
------------------------------
Если вы изменяете имя какого-либо субъекта, код, связанный с ним, также необходимо изменить. Delphi не может скомпилировать код, так как не может догадаться о ваших намерениях. Поэтому, взяв форму из репозитория, проверьте соответствие имен, используемых на форме с именами в вашем коде и наличие необходимых функций и обработчиков. Просто внимательно проверьте ваш код и сделайте соответствующие изменения.
Включите WinCRT в список используемых модулей и пользуйтесь на здоровье.
Вот пара методов:
var i: integer; r: real; begin r := 34.56; i := trunc(r); {i = 34} {Первый метод} i := round(r); {i = 35} {Второй метод} end; |
Вам необходимо перехватывать нажатие клавиши и устанавливать ваш собственный ответ на это. Попробуйте:
procedure TMainForm.FormCreate(Sender: TObject);
begin
keyPreview := true; {"Включаем" обработку.}
end;
procedure TMainForm.FormKeyPress(Sender: TObject; var Key: Char); begin if Key = #13 then begin Key := #0; PostMessage(Handle, WM_NEXTDLGCTL, 0, 0); end; end; |
Действие клавиши Tab происходит после возникновения события OnKeyDown, а клавиша Enter "действует" уже в OnKeyPress. Следовательно, клавиша Enter должна приниматься во внимание в обоих обработчиках для достижения желаемого эффекта. Попробуйте:
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift:
TShiftState);
begin
if Key = VK_RETURN then Key = VK_TAB;
end;
procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char); begin if Key = #13 then Key := #9; end; |
Пользуйтесь методами ParamCount и ParamString.
Используйте следующий код:
DBGrid1.SelectedField := Table1SomeField; DBGrid1.SetFocus; |
Установите в компоненте Table свойство ACTIVE в FALSE. Разместите следующий код в обработчике создания формы:
session.AddPassword('Мой секретный пароль'); table1.active := true; |
Вот некоторый код, показывающий как это можно сделать:
const
ScreenHeight: Integer = 800; {Я разрабатывал мою форму в режиме 800x600.}
ScreenWidth: Integer = 600;
procedure TForm1.FormCreate(Sender: TObject); var x, y: LongInt; {Целое не будет достаточной для этого величиной.} begin form1.scaled := true; x := getSystemMetrics(SM_CXSCREEN); y := getSystemMetrics(SM_CYSCREEN); if (x <> ScreenHeight) or (y <> ScreenWidth) then begin form1.height := form1.height * x DIV ScreenHeight; form1.width := form1.width * y DIV ScreenWidth; scaleBy(x, ScreenHeight); end; end; |
Примечание: вы можете расширить данный код с целью пропорционального изменения размеров шрифтов.
При работе с датами в вычисляемых полях важна гарантия того, что все применяемые значения имеют нужный тип. Метод double (не документирован) приводит величину к необходимому типу.
В приведенном ниже методе d1 и d2 (часть table1) могут быть или датой (date) или иметь тип dateTime, d3 - целочисленное поле.
procedure TForm1.Table1CalcFields(DataSet: TDataset); var t1, t2: tDateTime; begin table1d1.asDateTime := Date + 2; {или table1d1.value := date + 2;} table1d2.asDateTime := Date - 2; t1 := table1d1.asDateTime; t2 := table1d2.asDateTime; table1d3.asInteger := trunc(double(t1) - double(t2)); end; |
Для ExpXY(X, Y) (например, Y^X), попробуйте:
ExpXY := Exp(Y * Ln(X)) |
Для использования функции объявите формальные параметры и результат функции как Extended, преобразование фактических параметров и возвращаемого функцией результата происходит автоматически. (Примечание: Ln - натуральный логарифм числа).
В секции private класса формы поместите:
PROCEDURE WMQueryOpen(VAR Msg : TWMQueryOpen); message WM_QUERYOPEN; |
В секции implementation создайте реализацию метода:
PROCEDURE TForm1.WMQueryOpen(VAR Msg : TWMQueryOpen); begin Msg.Result := 0; end; |
Это все! Форма всегда будет в виде иконки. BTW, естественно, вы при этом вы должны установить свойство формы WindowState в wsMinimized.
К примеру, создадим независимое окно:
with TMyForm.create(self) do show; |
Теперь нам нужно управлять этим. Вот один из способов изменения заголовка каждой созданной формы. Осуществим это через массив компонентов формы. В качестве другой формы данный пример использует диалоговое окно "О программе" (с именем "box").
procedure TForm1.Button1Click(Sender: TObject);
begin with tBox.create(self) do show; {Необходимо ComponentCount-1 поскольку отсчет идет с нуля} (form1.Components[form1.ComponentCount-1] as tForm).caption := 'About Box # ' + intToStr(form1.ComponentCount-2); end; |
Используйте свойство PopupComponent компонента PopupMenu для определения компонента, на котором была нажата правая клавиша мыши.
procedure TForm1.PopupItem1Click(Sender: TObject); begin Label1.Caption := PopupMenu1.PopupComponent.ClassName; end; |
Можно использовать свойство формы ActiveControl, но компонент, вызвавший контекстное меню, не обязательно должен быть активным элементом управления.
Нижеследующий исходный код проекта демонстрирует способ получения системных сообщений перед тем, как будут вызваны оконные процедуры приложения. Необходимость в этом неочевидна, но иногда все же может возникнуть. В большинстве случаев для этой цели достаточно обработать сообщение Application.OnMessage.
program Project1;
uses Forms, messages, wintypes, winprocs, Unit1 in 'UNIT1.PAS' {Form1}; {$R *.RES} var OldWndProc: TFarProc; function NewWndProc(hWndAppl: HWnd; Msg, wParam: Word; lParam: Longint): Longint; export; begin result := 0; { Значение, возвращаемое WndProc по умолчанию } {*** Здесь дескриптор сообщения; Номер сообщения в Msg ***} result := CallWindowProc(OldWndProc, hWndAppl, Msg, wParam, lParam); end; begin Application.CreateForm(TForm1, Form1); OldWndProc := TFarProc(GetWindowLong(Application.Handle, GWL_WNDPROC)); SetWindowLong(Application.Handle, GWL_WNDPROC, longint(@NewWndProc)); Application.Run; end. |
Используйте свойство объекта TAG. Для группирования объектов по определенным признакам вы можете установить значение свойства tag каждого объекта. (Идеальным было бы использование констант, описывающих объект.)
Примечание: код подразумевает, что только tButton может вызвать эту процедуру.
case (sender as tButton).tag of 0: blah; 1: blah_blah; end; |
Прокрутка формы осуществляется с помощью изменения свойства Position свойства формы VertScrollbar или HorzScrollbar. Следующий код показывает как это можно сделать:
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); const PageDelta = 10; begin With VertScrollbar do if Key = vk_Next then Position := Position+PageDelta else if Key = vk_Prior then Position := Position-PageDelta; end; |
Вот пример:
procedure TForm1.Button1Click(Sender: TObject); var t: TTable; begin t := TTable.create(self); with t do begin DatabaseName := 'MyAlias'; {персональный псевдоним} TableName := 'MyTbl.db'; open; edit; insert; fieldByName('TheField').assign(memo1.lines); {Вот оно!} post; {требуется!!!} close; end; { Конец with-блока. } end; |
Можно так:
procedure TForm1.Button1Click(Sender: TObject);
var
t1, t2: tTable; {t1 = PW таблица; t2 = ASCII версия}
begin
t1 := tTable.create(self);
with t1 do
begin
DataBaseName := 'pw'; { Персональный псевдоним для каталога Paradox }
tableName := 'customer.db'; { Исходная таблица }
open;
end;
t2 := tTable.create(self);
with t2 do
begin
DataBaseName := 'pw'; { Персональный псевдоним для каталога Paradox }
tableName := 'asdf.txt';
TableType := ttASCII;
createTable; open; edit; BatchMove(t1, batCopy); close; end; t1.close; end; |
Дважды щелкните на компоненте Table. Выберите поле, которое вы хотите форматировать. Далее воспользуйтесь свойствами DisplayFormat и EditFormat. DisplayFormat работает когда поле не имеет фокуса. EditFormat работает когда поле имеет фокус. Пользуйтесь теми же командами, что и для первого параметра функции FormatFloat, только без кавычек.
Если вы не используете Delphi, попробуйте следующий код:
function FormatNumber(l: longint): string; var len, count: integer; s: string; begin str(l, s); len := length(s); for count := ((len - 1) div 3) downto 1 do begin insert(',', s, len - (count * 3) + 1); len := len + 1; end; FormatNumber := s; end; |
Если вы пользуетесь Delphi, то, естественно, существует более простое решение:
function FormatNumber(l: longint): string;
begin FormatNumber := FormatFloat('#,##0', StrToFloat(IntToStr(l))); end; |
Время от времени производите в вашем коде вызов процедуры Application.ProcessMessages.
Существуют встроенные методы hi() и lo(), но если вы хотите знать как это делается и попытаться сделать по-другому... (хотя вряд ли вы сможете увеличить быстродействие <G>). Функция для вставки в Delphi отсутствует.
Примечание: Функции ассемблера возвращают содержимое регистра AX.
function GetHiByte(w: word): byte; assembler;
asm
mov ax, w
shr ax, 8
end;
function GetLoByte(w: word): byte; assembler; asm mov ax, w end; function SetHiByte(b: byte; w: word): word; assembler; asm xor ax, ax mov ax, w mov ah, b end; function SetLoByte(b: byte; w: word): word; assembler; asm xor ax, ax mov ax, w mov al, b end; |
Другой путь сделать это (с примером использования):
Type
TWord2Byte = record
Lo,Hi: Byte;
end;
var W: Word; B: Byte; begin W := $1234; B := TWord2Byte(W).Hi; writeln(TWord2Byte(W).Hi); { возвращаем } TWord2Byte(W).Lo := $67; TWord2Byte(W).Hi := $98; { shl не нужен! } end. |
Вы не указали, должны ли возвращаться значения или нет (в Pascal это важно.)
Если нет, сделайте такое объявление:
Procedure TurnOn; External; Procedure TurnOff; External; |
Если возвращаемые значения присутствуют, объявление должно быть таким:
Function TurnOn: Integer; External; Function TurnOff: Integer; External; |
Замените Integer возвращаемым типом данных. В любом случае вам необходимо прилинковать ваш OBJ-файл:
{$L filename.obj} |
Смотрите также в электронной справке раздел "linking external assembler code".
Delphi использует смешанную модель памяти, но это очень близко к большой модели "C". Установки по умолчанию:
Данная схема используется в Borland Pascal уже долгое время. Я нахожу это гибким и эффективным.
Именно поэтому все public-процедуры, методы и указатели уже готовы к эксплуатации на 32-битных платформах, Delphi32 не должна в них ничего менять. Похоже, Delphi32 также переключится на 32-битную адресацию данных и сегментов стека, что также не должно повлиять на ваши программы. Все, что может повлиять - изменение разрядности целого с 16 на 32 бита.
Например, для того, чтобы ваш компонент реагировал на сообщение wm_size, добавьте следующую строку:
procedure WMPaint(var Message: TWMPaint); message WM_PAINT; |
В секции реализации все происходит примерно так:
procedure TWhateverComponent.WMPaint(var Message: TWMPaint); begin {Теперь заставьте ваш компонент реагировать на событие должным образом} end; |
Это работает для любого системного сообщения. Большинство компонентов реагируют на наиболее популярные сообщения, и вы можете изменить поведение компонента, перекрыв или расширив его обработчик.
Используйте API-вызов GetDOSEnvironment().
Вот простейшая реализация хранителя экрана:
var
f: tForm;
begin f := tForm.create(self); f.WindowState := wsMaximized; f.color := black; f.borderStyle := bsNone; f.show; end; |
Естественно, нужно сделать намного больше. Например, организовать обратную связь. Реально форма должна закрываться при щелчке на ней мыши. Также вам необходимо скрыть мышиный курсор. И. т.д., и т.п.. Но приведенный выше пример уже ответил на ваш вопрос.
Для определения высоты и ширины строки в пикселах могут применяться два метода - TextHeigh и TextWidth. Данные методы могут быть доступны в компонентах, имеющих свойство Canvas, например, TForm. Компонент TPanel не имеет доступа к свойству Canvas, т.к. по умолчанию оно защищено (protected).
Если компонент не имеет свойство Canvas, то следующая функция поможет возвратить вам ширину текста, основанного на определенном шрифте.
function GetTextWidth(CanvasOWner: TForm; Text : String; TextFont : TFont): Integer; var OldFont : TFont; begin OldFont := TFont.Create; try OldFont.Assign( CanvasOWner.Font ); CanvasOWner.Font.Assign( TextFont ); Result := CanvasOWner.Canvas.TextWidth(Text); CanvasOWner.Font.Assign( OldFont ); finally OldFont.Free; end; end; |
Наилучшее место для показа окна с логотипом - в исходном коде проекта после первого FormCreate и перед Run. Этим мы осуществляем создание формы на лету и показ ее до момента фактического запуска приложения.
program Project1;
uses Forms, Unit1 in 'UNIT1.PAS' {Form1}, Splash; {$R *.RES} var SplashScreen : TSplashScreen; {в модуле Splash} begin Application.CreateForm(TForm1, Form1); SplashScreen := TSplashScreen.Create(Application); try SplashScreen.Show; { осуществите остальные CreatForms или другие действия прежде чем приложение запустится } SplashScreen.Close; finally {Убедитесь что окно с логотипом освобождается} SplashScreen.Free; end; Application.Run; end. |
Для вызова функции вы должны знать ее точный синтакс и установленный тип. Например, для вызова при нажатии на кнопку функции CallMe, принимающей в качестве параметров два целых числа, возвращающей строку и находящейся в MyTest.Dll, вы могли бы использовать следующий код:
procedure TForm1.Button1Click(Sender: TObject);
type TCallMeDll = function(a,b: Integer): string; var CallMeDll: TCallMeDll; FuncPtr: TFarProc; hDll: THandle; result: string; begin hDll:=LoadLibrary('Mytestdll.dll'); FuncPtr:=GetProcAddress(hDLL,'CallMe'); @CallMeDll:=FuncPtr; if @CallMeDll <> nil then result:=CallMeDll(4,5); FuncPtr:=nil; FreeLibrary(hDll); end; |
Обратите внимание на порядок действий: сначала мы нагружаем dll в память, затем получаем указатель на функцию, и затем назначаем его CallMeDll. В этой точке необходимо проверить, если ProcAdderss равен Nil, то вызов GetProcAddress был неудачным.
Важно иметь в виду, что чаще всего удобнее загружать библиотеку в самом начале работы программы, освобождать при окончании работы и пользоваться ею в теле программы с помощью полученного на нее указателя.
Функция косвенного вызова (Callback function) - одна из наиболее полезных реализаций вызовов в Windows. Вы определяете функцию в приложении, выполняющую некоторые действия, и передаете ее адрес в другую функцию, которая и осуществляет вызов первой функции, передавая ей параметры, с которыми она должна работать. Сделайте объявление в секции интерфейса:
{ В интерфейсе программы }
type TCallBackFunction = function(s: string): integer; CallMe(s: string): integer; |
И в секции реализации:
{ Программная реализация }
procedure TestCallBack(CallBackFunction: TCallBackFunction); far; external 'Other'; { Имейте в виду, что 'other' - размещенная в Dll процедура с именем TestCallBack } function CallMe(s: PChar): integer; begin { сделайте что-нибудь } CallMe := 1; { сделайте что-нибудь } end; procedure TForm1.Button1Click(Sender: TObject); begin TestCallBack(CallMe); end; |
Имейте в виду, что в 'Other' вы должны также объявить и использовать функциональный тип, например так:
{ в интерфейсе библиотеки Other }
type TMainFunction = function(s: string): integer; TestCallBack(MainFunc: TMainFunction); { в реализации библиотеки Other } TestCallBack(MainFunc: TMainFunction); var result: integer; begin result:=MainFunc('тест'); end; |
[000583]