Вопросы и ответы - Delphi - Общие вопросы - Библиотека программиста
Пользователь

Добро пожаловать,

Регистрация или входРегистрация или вход
Потеряли пароль?Потеряли пароль?

Ник:
Пароль:

Меню сайта




Ваше мнение
Как вы узнали о нашем сайте?

От друга, знакомого
Из печатных источников
Из поисковой машины
По ссылке с другого сайта
Случайно
Не знаю


Результаты
Другие опросы

Всего голосов: 966
Комментарии: 4


Наши партнеры



Статистика




Programming books  Download software  Documentation  Scripts  Content Managment Systems(CMS)  Templates  Icon Sets  Articles  Contacts  Voting  Site Search




Вопросы и ответы - Delphi - Общие вопросы

         
 
BEEP для дельфи, который работает, как в TP
Я применяю следующий код, однако он работает только под Win9x/me

(Под WinNT/2000/XP вы можете использовать Beep(Tone, Duration)

- задавать тон и продолжительность звучания).


Код
procedure Sound(Freq : Word);

var B : Byte;

begin

if Freq > 18 then

begin

Freq := Word(1193181 div LongInt(Freq));

B := Byte(GetPort($61));

if (B and 3) = 0 then

begin

SetPort($61, Word(B or 3));

SetPort($43, $B6);

end;

SetPort($42, Freq);

SetPort($42, Freq shr 8);

end;

end;



procedure NoSound;

var Value: Word;

begin

Value := GetPort($61) and $FC;

SetPort($61, Value);

end;



procedure SetPort(address, Value:Word);

var bValue: byte;

begin

bValue := trunc(Value and 255);

asm

mov dx, address

mov al, bValue

out dx, al

end;

end;



function GetPort(address:word):word;

var bValue: byte;

begin

asm

mov dx, address

in al, dx

mov bValue, al

end;

GetPort := bValue;

end;

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



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

Наблюдаются многочисленные глюки при прорисовке, сообщения системы об ошибках и перерасходе ресурсов без видимых причин, вплоть до убиения приложения системой или краха системы. Характерно для Windows линии 9X, у которых максимальное количество графических и оконных ресурсов (GDI и USER) сильно ограничено.

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

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



ТИПОВЫЕ РЕШЕНИЯ.



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

2. У динамически создаваемых компонентов устанавливать владельца и родителя. Подробности - в статье "Жизнь и смерть в режиме run-time".

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

Интерфейс MDI - хорошая концепция. Но всякое техническое решение имеет свою область применения. Это удобно, когда пользователю нужно работать с однотипными объектами в разных окнах и переходить от одного к другому, причем количество их заранее неизвестно, и допускается изменение размеров окна. Примеры - работа с документами (Word, Excel, etc.).

4. Как правило, многочисленные элементы управления не нужны пользователю одновременно (вспомните о правиле 7±2 - именно таково среднее количество объектов, за которыми человек может следить одновременно, не напрягаясь). Их можно разделить на группы и расположить на страницах компонента TPageControl. Таким способом можно скрыть видимую сложность очень большого интерфейса по вводу и редактированию данных.

Если группы компонентов однотипны (меняются только данные), то решение еще более упрощается, с одновременным снятием нагрузки на ресурсы системы. Компонент TTabControl, который внешне выглядит также, как и TPageControl, содержит только одну группу контролов, а программист по событию смены закладки OnChange имеет возможность сменить данные.

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

В случае, если нужно много TComboBox, применяют следующую хитрость. Для визуализации используют TStringGrid, а для редактирования в текущую ячейку вставляют TComboBox, устанавливая ему размеры и координаты по ячейке и набивая его программно (если набор элементов меняется). Один и тот же экземпляр редактирующего контрола используется во всех ячейках, поскольку он не нужен одновременно везде. Эта же техника используется и в VCL для редактирования ячеек TStringGrid, TDBGrid.

Есть масса компонентов типа TStringGrid сторонних разработчиков, которые расширяют возможности стандартного.

6. DB-aware визуальные компоненты - такие как TDBGrid - способны обрабатывать огромный объем данных, не требуя при этом пропорциональное количество ресурсов GDI/USER. В конце концов, если не хочется связываться с СУБД, можно загнать информацию в TClientDataSet и кормить из него DB-aware controls на форме. Одновременно получаешь все прелести сортировки и фильтрации данных.

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

7. Следует стремиться уменьшить количество компонентов - потомков TWinControl (например - TButton), заменяя их на потомки TGraphicControl (пример - TSpeedButton). Последние не используют объекты USER, поскольку не являются окнами в понятиях Windows.

8. Рекомендуется разрабатывать и эксплуатировать ресурсоемкие приложения в среде Windows NT и ее наследников (2000, XP).
Быстрый способ обмена значений в 2-х переменных
Код
procedure SwapVars1(var u, v; Size: Integer);

var

x: Pointer;

begin

GetMem(x, Size);

try

System.move(u, x^, Size);

System.move(v, u, Size);

System.move(x^, v, Size);

finally

FreeMem(x);

end;

end;


procedure SwapVars2(var Source, Dest; Size: Integer);

begin

asm

push edi

push esi

mov esi,Source

mov edi,Dest

mov ecx,Size

cld

@1:

mov al,[edi]

xchg [esi],al

inc si

stosb

loop @1

pop esi

pop edi

end;

end;



procedure TForm1.Button2Click(Sender: TObject);

begin

SwapVars1(X1, X2, SizeOf(Integer));

end;
Взять один символ из потока памяти
Код

unit MsFormR;



interface



uses

Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,

StdCtrls, ExtCtrls;



type

TForm1 = class(TForm)

OpenDialog1: TOpenDialog;

SaveDialog1: TSaveDialog;

Memo1: TMemo;

ListBox1: TListBox;

Panel1: TPanel;

Button1: TButton;

Button2: TButton;

Splitter1: TSplitter;

procedure FormCreate(Sender: TObject);

procedure Button1Click(Sender: TObject);

procedure Button2Click(Sender: TObject);

private

MemStr1: TMemoryStream;

public

procedure ShowMemStr;

end;



var

Form1: TForm1;



implementation



{$R *.DFM}



procedure TForm1.FormCreate(Sender: TObject);

begin

MemStr1 := TMemoryStream.Create;

end;



procedure TForm1.Button1Click(Sender: TObject);

var

Str1: TFileStream;

begin

OpenDialog1.Filter :=

'Any file (*.*)|*.*';

OpenDialog1.DefaultExt := '*';

if OpenDialog1.Execute then

begin

Str1 := TFileStream.Create (

OpenDialog1.Filename, fmOpenRead);

try

MemStr1.LoadFromStream (Str1);

ShowMemStr;

Button2.Enabled := true;

finally

Str1.Free;

end;

end;

end;



procedure TForm1.ShowMemStr;

begin

Memo1.Lines.LoadFromStream (MemStr1);

end;



procedure TForm1.Button2Click(Sender: TObject);

const

ndx: LongInt = 1;

var

pch: PChar;

tmpC: Char;

begin

pch := MemStr1.Memory;

tmpC := pch[ndx];

pch[ndx] := #0;

ListBox1.Items.SetText(MemStr1.Memory);

pch[ndx] := tmpC;



if ndx < MemStr1.Size then

Inc(ndx)

else

Button2.Enabled := False;

end;



end.

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


Код
function TestFunc1(d: Double): Integer;

begin

....

end;



function TestFunc2(d: Double): Integer;

begin

....

end;



exports

TestFunc1,

TestFunc2;



procedure TForm1.Button1Click(Sender: TObject);

var

Func: function (d: Double): Integer;

begin

@Func := GetProcAddress(hInstance, PChar(Edit1.Text));

if @Func = nil then

raise Exception.CreateFmt('Функция с именем "%s" не существует', [Edit1.Text]);

ShowMessage(IntToStr(Func(10.63)));

end;


Использование PosEx взамен Pos
В Delphi 7 в модуле StrUtils внесены некоторые изменения.

Есть новая функция: PosEx.



Обьявление этих функций:



Код
Function Pos(Substr: String; S: String): Integer;

Function PosEx(Const SubStr, S: String; Offset: Cardinal = 1): Integer;




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


Ниже приведена реализация функции в модуле StrUtils (если вы используете более старшую версию среди разработки вы сможете сами добавить этот код и использовать его вместо функции Pos):



Код
Function PosEx(Const SubStr, S: String; Offset: Cardinal = 1): Integer;

var

I,X: Integer;

Len, LenSubStr: Integer;

begin

If Offset = 1 Then

Result := Pos(SubStr, S)

Else

begin

I := Offset;

LenSubStr := Length(SubStr);

Len := Length(S) - LenSubStr + 1;

While I <= Len Do

begin

If S[I] = SubStr[1] Then

begin

X := 1;

While (X < LenSubStr) And (S[I + X] = SubStr[X + 1]) Do

Inc(X);

If (X = LenSubStr) Then

begin

Result := I;

Exit;

End;

End;

Inc(I);

End;

Result := 0;

End;

End;

Как использовать параметры командной строки?
Paramcount - показывает сколько параметров передано

Paramstr(0) - это имя с путем твоей программы

Paramstr(1) - имя первого параметра

Paramstr(2) - имя второго параметра и т.д.

Если ты запускаешь:

с:myprog.exe /a -b22 c:dev то Paramcount будет равен 3

Paramstr(0) будет равен с:myprog.exe

Paramstr(1) будет равен /a

Paramstr(2) будет равен -b22

Paramstr(3) будет равен c:dev



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


Например у тебя возможно 3 параметра:


Если параметр = "/v" то выдать сообщение, если параметр "/c" то покрасить форму в синий цвет, если параметр "/f" - поменять заголовок формы:


Код

if paramstr(1) = '/v' then

showmessage('Parameter "/v" was found!');

if paramstr(1) = '/c' then

color := clBlue;

if paramstr(1) = '/f' then

caption := 'Parameter "/f" was found';



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

Как использовать переменную для имени процедуры?
Каким образом можно использовать переменную типа String в качестве имени процедуры?



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


Код

type

TMacroProc = procedure(param: Integer);

//массив, сопоставляющий имена процедур их адресам во время выполнения приложения:

TMacroName = string[32];

TMacroLink = record

name: TMacroName;

proc: TMacroProc;

end;

TMacroList = array [1..MaxMacroIndex] of TMacroLink;



const

Macros: TMacroList = (

(name: 'Proc1'; proc: Proc1),

(name: 'Proc2'; proc: Proc2),

...

); //интерпретатор функций, типа:



procedure CallMacro(name: String; param: Integer);

var

i: Integer;

begin

for i := 1 to MaxMacroIndex do

if CompareText(name, Macros[i].name) = 0 then

begin

Macros[i].proc(param);

break;

end;

end;



{Макропроцедуры необходимо объявить в секции Interface модуля или с ключевым словом Far, например: }

procedure Proc1(n: Integer); far;

begin

...

end;



procedure Proc2(n: Integer); far;

begin

...

end;


Как сделать procedure/function с переменным количеством параметров?
Код
{ .... }



type

VA_FN = function(const par1, par2{, ...}: Pointer): Boolean;

cdecl varargs;



{ .... }



//

// varargs without "external" keyword

//

function fn(const par1, par2{, ...}: Pointer): Boolean; cdecl;

var

last_arg: Pointer absolute par2;

ptr_args: array[0..MAXLONG shr 2] of Pointer absolute last_arg;

dw_args: array[0..MAXLONG shr 2] of Cardinal absolute last_arg;

s_args: array[0..MAXLONG shr 2] of PChar absolute last_arg;

w_args: array[0..MAXLONG shr 2] of WideString absolute last_arg;

begin

// ptr_args[1] is first optional argument

Result := (ptr_args[1] {par3} = Pointer(1)) and

(dw_args[2] {par4} = 2) and

(string(ptr_args[3]) = 'CHAR') and

(w_args[4] = 'WCHAR');

end;



procedure test_fn;

begin

// VA_FN typecast

VA_FN(@fn)({par1}nil, {par2}nil, {par3}Pointer(1), {par4}2, {par5}'CHAR',

{par6}WideString('WCHAR'));

end;
Можно ли задать шаг в For?
Код
For i:=0 to Maximum do if i mod step = 0 then

begin

end;
О переносе проекта в другую папку
При нарушении правила «один проект — одна папка»: в некоторых проектах, вопреки означенному правилу, многие модули хранятся во вложенных папках, в результате delphi указывает длинные маршруты доступа к соответствующим файлам. Если такой проект скопировать на дискету, то эти маршруты останутся без изменения и компилятор не сможет найти нужные файлы. Еще хуже, если скопировать проект в другую папку на том же жестком диске. В этом случае начнутся неприятности: вы будете что-то изменять в новом проекте, но приложение на это никак не отреагирует, а если вы установите контрольную точку останова в каком-либо из модулей, то она окажется неработоспособной — компилятор будет по-прежнему использовать оригинальные файлы, а не копии.



Если вы захотите перенести проект в другую папку и при этом сохранить его работоспособность, вам нужно сначала с помощью опции file|save project as скопировать в эту папку файл проекта, а затем с помощью опции file|save as перенести туда все связанные с проектом модули: только тогда delphi сумеет внести необходимые коррекции в файл проекта. Но если все файлы хранятся в единственной папке, то в предложении uses не указываются маршруты доступа, и поэтому вы сможете безболезненно скопировать разом все файлы в другую папку.



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



Печать страницы
Печать страницы


Внимание! Если у вас не получилось найти нужную информацию, используйте рубрикатор или воспользуйтесь поиском


.



книги по программированию исходники компоненты шаблоны сайтов C++ PHP Delphi скачать