Delphi - база знаний

  35790931     

Реляционные базы данных?


Реляционные базы данных?



Итак, Реляционная база данных упрощённо является набором таблиц. Таблица же есть основной строительный кирпичик базы данных. Расмотрим структуру таблицы. Для начала представте себе таблицу, например в Word...
Что в ней есть?

Во-первых есть строки и колонки (raw and columns). В базах данных, в отличие от Word есть строгие ограничения на их содержимое, да и терминология немного другая:
1) Колонка называется тоже columns, но чаще употребляется понятие "поле" (field). Колонка всегда имеет имя (по которому ее можно найти) и обязана хранить данные только одного какого-либо типа - например целые числа, строки, дату/время и т.п. Создавая таблицу вы обязаны указать какой тип имеет каждое поле, другими словами, вы заранее должны определится, какого сорта данные будут хранится в колонке. Например, вот примерно так может выглядеть структура таблицы для хранения данных об участнике этого форума:

·Ник - строка (25 символов)  
·ФИО - строка (250 символов)  
·Дата регистрации - Дата/время  
·Количество постингов - Целое  
·Показывать email - True/False  

Обратите внимание что для строк я указал конкретную длину, а для остальных ничего не указывал. Зачем? Ответ прост - каждая строка должна занимать строго одинаковое место (об исключениях потом), и это сделано для быстроты поиска. Действительно , если бы каждая строка имела разную длину, то чтобы найти например 1000 строку, надо было бы перечитать все 999 предыдущих строк, но если известно, что каждая строка занимает например 1Кб, то чтобы прочитать 1000 строку достаточно прочитать 1 Кб с 999Кб... Другая сторона этого - например мне надо сравнить даты в приведенной выше таблице - сделать это просто - я точно знаю что первую дату можно прочитать с 276 байта, и так же точно я знаю точные координаты каждой даты. Именно в этом и лежит одна из сторон высокой скорости работы баз данных (другие способы ускорения работы рассмотрим позже).

2) Строка - в базах данных имеет специфическое название - запись (Record) - к Дельфийскому типу Record этот термин не имеет никакого отношения. Хотя большинство БД дают возможность перейти и прочитать например 10 запись, надо с самого начала попытаться никогда этим не пользоваться. Почему? Да просто потому что БД практически всегда подразумевают совместный доступ нескольких пользователей к одним и тем же данным, и если Вы хотите перейти на 10 запись, а другой пользователь в это время удалит запись номер 5, то вы перейдёте вовсе не на ту запись что ожидалось. А как же быть? У вас есть 2 способа - либо вы находите нужную запись по значению поля - например для нашей таблицы это будет выглядеть примерно так:



"Найти пользователя [Вася] в первой колонке"

В результате вы получите доступ ко всем полям записи для "Васи". Либо вы берёте все записи и перебираете их в цикле пока не найдёте нужный - это гораздо худший способ, так как работает на 2-3 порядка медленнее и имеет другие неприятные последствия (об этом позже), но он возможен и иногда применяется.




Репортинг, работа с принтером


Репортинг, работа с принтером


Cодержание раздела:


·
·  
·  
·  


·

(

раздел)

·

(

раздел)

·

(

раздел)

·

(

раздел)  







См. также статьи в других разделах:





Режим замены


Режим замены




Элементы управления Windows TEdit и TMemo не имеют режима замены. Однако этот режим можно эмулировать установив свойство SelLength edit'а или memo в 1 при обработке события KeyPress. Это заставит его перезаписывать символ в текущей позиции курсора. В примере этот способ используется для TMemo. Режим вставка/замена переключается клавишей "Insert".

Пример:

type
TForm1 = class(TForm)
        Memo1: TMemo;
        procedure Memo1KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
        procedure Memo1KeyPress(Sender: TObject; var Key: Char);
private
    {Private declarations}
        InsertOn : bool;
public
    {Public declarations}
end;

var
   Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Memo1KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
    if (Key = VK_INSERT) and (Shift = []) then
        InsertOn := not InsertOn;
end;

procedure TForm1.Memo1KeyPress(Sender: TObject; var Key: Char);
begin
    if ((Memo1.SelLength = 0) and (not InsertOn)) then
        Memo1.SelLength := 1;
end;

Автор:

Song

Взято из






RGB --> CMYK


RGB --> CMYK



procedure RGBTOCMYK(R : byte;
                    G : byte;
                    B : byte;
                    var C : byte;
                    var M : byte;
                    var Y : byte;
                    var K : byte);
begin
  C := 255 - R;
  M := 255 - G;
  Y := 255 - B;
  if C  0 then 
    begin
      c := c - k;
      m := m - k;
      y := y - k;
    end;
end;



RGB --> Gray


RGB --> Gray



function RgbToGray(RGBColor: TColor): TColor;
var
  Gray: byte;
begin
  Gray := Round((0.30 * GetRValue(RGBColor)) +
    (0.59 * GetGValue(RGBColor)) +
    (0.11 * GetBValue(RGBColor)));
  Result := RGB(Gray, Gray, Gray);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Shape1.Brush.Color := RGB(255, 64, 64);
  Shape2.Brush.Color := RgbToGray(Shape1.Brush.Color);
end;



Рисование без мерцания


Рисование без мерцания




Автор: Mike Scott

...вот я и удивляюсь - почему я получаю мерцание, если я вызываю Repaint или Refresh, а не метод OnPaint напрямую? Или это просто "вариация на тему"?

Имеются две фазы обновления окна. В первой фазе, при выводе окна, Windows посылает ему сообщение WM_ERASEBKGND, сообщающее о необходимости стирания фона перед процедурой рисования. Затем посылается сообщение WM_PAINT, служащее сигналом для закрашивания "переднего плана".

Тем не менее, вы можете пропустить первую фазу, которая вызывает мерцание, одним из двух способов: первый способ заключается в том, что вы форсируете обновление сами, с помощью вызова функции Windows API InvalidateRect. На входе он получает дескриптор окна, указатель на закрашиваемую область - передаем NIL, если вы хотите отрисовать всю область окна - и третий параметр, сообщающий о необходимости очистки фона. Вот как раз последний параметр и должен содержать значение FALSE, если вы сами будете в методе Paint полностью отрисовывать всю область:



InvalidateRect(Handle, NIL, FALSE ) ;




Handle должен быть дескриптором формы или элемента управления.

Описав первый способ, я скажу, что существует другое подходящее решение - использовать функциональность VCL. Вы можете указать VCL не стирать фон, добавляя [ csOpaque ] к значению свойства ControlStyle, как показано ниже:



ControlStyle := ControlStyle + [ csOpaque ] ;




Это ограничивает заполнение заднего фона, но вы все еще можете видеть процесс "наполнения" области изображением, т.е. процесс рисования. В этом случае вы можете отделаться от эффекта мельтешения, рисуя на TBitmap и выводя его затем на экран командой CopyRect.

Если вы хотите углубиться в тему дальше, то я отошлю вас к моей статье "Optimizing Display Updates in Delphi" (Оптимизация обновления экрана в Delphi), опубликованной в первом выпуске журнала "Delphi magazine".

Взято из





Рисование фрактальных графов


Рисование фрактальных графов




Автор: Михаил Марковский

...Очередная нетленка, которую я предлагаю Вам, написана мной самостоятельно (идею и примеры, реализованные в программе, я нашел в апрельском номере журнала "Химия и жизнь" за 1995 год). Теоретически она производит трансляцию L-систем с выводом образовавшихся фрактальных графов, а практически рисует кусты и деревья. Вроде бесполезно, но очень красиво. Эта программа написана для TP7, хотя легко переносится на Delphi (как то я уже переводил ее, но модуль бесследно исчез). Буду надеяться, что она придется Вам по душе.



usesgraph, crt;

const
  GrafType = 1; {1..3}

type
  PointPtr = ^Point;
  Point = record
    X, Y: Word;
    Angle: Real;
    Next: PointPtr
  end;
  GrfLine = array[0..5000] of
    Byte;
  ChangeType = array[1..30] of
    record
    Mean: Char;
    NewString: string
  end;

var
  K, T, Dx, Dy, StepLength, GrafLength: Word;
  grDriver, Xt: Integer;
  grMode: Integer;
  ErrCode: Integer;
  CurPosition: Point;
  Descript: GrfLine;
  StartLine: string absolute Descript;
  ChangeNumber, Generation: Byte;
  Changes: ChangeType;
  AngleStep: Real;
  Mem: Pointer;

procedure Replace(var Stroka: GrfLine;
  OldChar: Char;
  Repl: string);
var
  I, J: Word;
begin
  if (GrafLength = 0) or (Length(Repl) = 0) then
    Exit;
  I := 1;
  while I <= GrafLength do
  begin
    if Chr(Stroka[I]) = OldChar then
    begin
      for J := GrafLength downto I + 1 do
        Stroka[J + Length(Repl) - 1] := Stroka[J];
      for J := 1 to Length(Repl) do
        Stroka[I + J - 1] := Ord(Repl[J]);
      I := I + J;
      GrafLength := GrafLength + Length(Repl) - 1;
      continue
    end;
    I := I + 1
  end
end;

procedure PushCoord(var Ptr: PointPtr;

  C: Point);
var

  P: PointPtr;
begin

  New(P);
  P^.X := C.X;
  P^.Y := C.Y;
  P^.Angle := C.Angle;
  P^.Next := Ptr;
  Ptr := P
end;

procedure PopCoord(var Ptr: PointPtr;

  var Res: Point);
begin

  if Ptr <> nil then
  begin
    Res.X := Ptr^.X;
    Res.Y := Ptr^.Y;
    Res.Angle := Ptr^.Angle;
    Ptr := Ptr^.Next
  end
end;

procedure FindGrafCoord(var Dx, Dy: Word;

  Angle: Real;
  StepLength: Word);
begin

  Dx := Round(Sin(Angle) * StepLength * GetMaxX / GetMaxY);
  Dy := Round(-Cos(Angle) * StepLength);
end;

procedure NewAngle(Way: ShortInt;

  var Angle: Real;
  AngleStep: Real);
begin

  if Way >= 0 then
    Angle := Angle + AngleStep
  else
    Angle := Angle - AngleStep;
  if Angle >= 4 * Pi then
    Angle := Angle - 4 * Pi;
  if Angle < 0 then
    Angle := 4 * Pi + Angle
end;

procedure Rost(var Descr: GrfLine;

  Cn: Byte;
  Ch: ChangeType);
var
  I: Byte;
begin

  for I := 1 to Cn do
    Replace(Descr, Ch[I].Mean, Ch[I].NewString);
end;

procedure Init1;
begin

  AngleStep := Pi / 8;
  StepLength := 7;
  Generation := 4;
  ChangeNumber := 1;
  CurPosition.Next := nil;
  StartLine := 'F';
  GrafLength := Length(StartLine);
  with Changes[1] do
  begin
    Mean := 'F';
    NewString := 'FF+[+F-F-F]-[-F+F+F]'
  end;
end;

procedure Init2;
begin

  AngleStep := Pi / 4;
  StepLength := 3;
  Generation := 5;
  ChangeNumber := 2;
  CurPosition.Next := nil;
  StartLine := 'G';
  GrafLength := Length(StartLine);
  with Changes[1] do
  begin
    Mean := 'G';
    NewString := 'GFX[+G][-G]'
  end;
  with Changes[2] do
  begin
    Mean := 'X';
    NewString := 'X[-FFF][+FFF]FX'
  end;
end;

procedure Init3;
begin

  AngleStep := Pi / 10;
  StepLength := 9;
  Generation := 5;
  ChangeNumber := 5;
  CurPosition.Next := nil;
  StartLine := 'SLFF';
  GrafLength := Length(StartLine);
  with Changes[1] do
  begin
    Mean := 'S';
    NewString := '[+++G][---G]TS'
  end;
  with Changes[2] do
  begin
    Mean := 'G';
    NewString := '+H[-G]L'
  end;
  with Changes[3] do
  begin
    Mean := 'H';
    NewString := '-G[+H]L'
  end;
  with Changes[4] do
  begin
    Mean := 'T';
    NewString := 'TL'
  end;
  with Changes[5] do
  begin
    Mean := 'L';
    NewString := '[-FFF][+FFF]F'
  end;
end;

begin

  case GrafType of
    1: Init1;
    2: Init2;
    3: Init3;
  else
  end;
  grDriver := detect;
  InitGraph(grDriver, grMode, '');
  ErrCode := GraphResult;
  if ErrCode <> grOk then
  begin
    WriteLn('Graphics error:', GraphErrorMsg(ErrCode));
    Halt(1)
  end;
  with CurPosition do
  begin
    X := GetMaxX div 2;
    Y := GetMaxY;
    Angle := 0;
    MoveTo(X, Y)
  end;
  SetColor(white);
  for K := 1 to Generation do
  begin
    Rost(Descript, ChangeNumber, Changes);
    Mark(Mem);
    for T := 1 to GrafLength do
    begin
      case Chr(Descript[T]) of
        'F':
          begin
            FindGrafCoord(Dx, Dy, CurPosition.Angle, StepLength);
            with CurPosition do
            begin
              Xt := X + Dx;
              if Xt < 0 then
                X := 0
              else
                X := Xt;
              if X > GetMaxX then
                X := GetMaxX;
              Xt := Y + Dy;
              if Xt < 0 then
                Y := 0
              else
                Y := Xt;
              if Y > GetMaxY then
                Y := GetMaxY;
              LineTo(X, Y)
            end
          end;
        'f':
          begin
            FindGrafCoord(Dx, Dy, CurPosition.Angle, StepLength);
            with CurPosition do
            begin
              Xt := X + Dx;
              if Xt < 0 then
                X := 0
              else
                X := Xt;
              if X > GetMaxX then
                X := GetMaxX;
              Xt := Y + Dy;
              if Xt < 0 then
                Y := 0
              else
                Y := Xt;
              if Y > GetMaxY then
                Y := GetMaxY;
              MoveTo(X, Y)
            end
          end;
        '+': NewAngle(1, CurPosition.Angle, AngleStep);
        '-': NewAngle(-1, CurPosition.Angle, AngleStep);
        'I': NewAngle(1, CurPosition.Angle, 2 * Pi);
        '[': PushCoord(CurPosition.Next, CurPosition);
        ']':
          begin
            PopCoord(CurPosition.Next, CurPosition);
            with CurPosition do
              MoveTo(X, Y)
          end
      end
    end;
    Dispose(Mem);
    Delay(1000)
  end;
  repeat
  until KeyPressed;
  CloseGraph
end.



Взято из





Рисование графов


Рисование графов




...вы могли бы использовать объект TCanvas, чем рисовать самому. В вашем случае сгодится компонент TImage, он имеет bitmap и свойство canvas, на котором очень удобно рисовать.

Пример: (Создайте новую форму, добавьте к ней Image и Button. Добавьте следующий код к обработчику события нажатия кнопки)



var
x, l: Integer;
  y, a: Double;
begin
  Image1.Picture.Bitmap := TBitmap.Create;
  Image1.Picture.Bitmap.Width := Image1.Width;
  Image1.Picture.Bitmap.Height := Image1.Height; {Эти три строчки могут быть
  размещены в обработчике Form1.Create}
  l := Image1.Picture.Bitmap.Width;
  for x := 0 to l do
  begin
    a := (x / l) * 2 * Pi; {Преобразуем позицию по оси X к углу между 0 & 2Pi}
    y := Sin(a); {Ваша функция должна находиться здесь}
    y := y * (Image1.Picture.Bitmap.Height / 2); {Масштабируем по оси Y}
    y := y * -1; {Инвертируем Y, верх экрана это 0 !}
    y := y + (Image1.Picture.Bitmap.Height / 2);
      {Добавляем компенсацию для среднего 0}
    Image1.Picture.Bitmap.Canvas.Pixels[Trunc(x), Trunc(y)] := clBlack;
  end;
end;




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

Взято из





Рисование КРИВЫХ в Delphi


Рисование КРИВЫХ в Delphi




Автор: Dmitry Streblechenko

У кого-нибудь есть исходный код или какая-либо информация для рисования кривых Безье? Я должен использовать их в своем компоненте.

Я делал это недавно; мне было лениво разбираться с тем, как рисовать кривые Безье с помощью Win API, поэтому я использовал функцию Polyline().

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



PBezierPoint= ^TBezierPoint;
TBezierPoint = record
  X, Y: double;   // основной узел
  Xl, Yl: double; // левая контрольная точка
  Xr, Yr: double; // правая контрольная точка
end;

// P1 и P2 - две точки TBezierPoint, расположенные между 0 и 1:
// когда t=0 X=P1.X, Y=P1.Y; когда t=1 X=P2.X, Y=P2.Y;

procedure BezierValue(P1, P2: TBezierPoint; t: double; var X, Y: double);
var
  t_sq, t_cb, r1, r2, r3, r4: double;
begin
  t_sq := t * t;
  t_cb := t * t_sq;
  r1 := (1 - 3 * t + 3 * t_sq - t_cb) * P1.X;
  r2 := (3 * t - 6 * t_sq + 3 * t_cb) * P1.Xr;
  r3 := (3 * t_sq - 3 * t_cb) * P2.Xl;
  r4 := (t_cb) * P2.X;
  X := r1 + r2 + r3 + r4;
  r1 := (1 - 3 * t + 3 * t_sq - t_cb) * P1.Y;
  r2 := (3 * t - 6 * t_sq + 3 * t_cb) * P1.Yr;
  r3 := (3 * t_sq - 3 * t_cb) * P2.Yl;
  r4 := (t_cb) * P2.Y;
  Y := r1 + r2 + r3 + r4;
end;




Для рисования кривой Безье разделяем интервал между P1 и P2 на несколько отрезков (их количество влияет на точность воспроизведения кривой, 3 - 4 точки вполне достаточно), затем в цикле создаем массив точек, используем описанную выше процедуру с параметром t от 0 до 1 и рисуем данный массив точек, используя функцию polyline().

Взято из





Рисование в разных местах, захват изображения


Рисование в разных местах, захват изображения



Cодержание раздела:










Рождение, жизнь и гибель формы.


Рождение, жизнь и гибель формы.



(Перевод одноимённой статьи с сайта delphi.about.com )

В Windows основной элемент пользовательского интерфейса - форма. В Delphi каждый проект имеет по крайней мере одно окно - главное окно приложения. Все окна в Delphi основаны на объекте TForm. В данной статье мы рассмотрим основные события учавствующие в "жизни формы".

Форма
Формы имеют свои свойства, события и методы, при помощи которых Вы можете управлять видом и поведением формы. Форма, это обычный компонент Delphi, но в отличие от других, её нет на панели компонентов. Обычно форма создаётся при создании нового проекта (File | New Application). Вновь созданная форма будет главной формой приложения.

Дополнительные формы в проекте создаются через File | New Form. Так же существуют и другие способы создания форм, но здесь мы не будем рассматривать их...

Как и любой другой компонент (объект) форма имеет свои методы и реагирует на события. Давайте рассмотрим некоторые из этих событий...

Рождение


OnCreate -> OnShow -> OnActivate-> OnPaint -> OnResize -> OnPaint ...


OnCreate
Событие OnCreate возникает при создании TForm и только один раз. При создании формы (у каторой свойство Visible установлено в True), события произойдут в следующем порядке: OnCreate, OnShow, OnActivate, OnPaint.
В обработчике события OnCreate можно сделать какие-либо инициализационные действия, однако, любые объекты созданные в OnCreate будут уничтожены в событии OnDestroy.

OnShow
Это событие генерируется, когда форма станет видимой. OnShow вызывается сразу перед тем, как форма станет видимой. Это событие случается, если установить свойство формы Visible в True, либо при вызове методов Show или ShowModal.

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

OnPaint, OnResize
Эти события вызываются каждый раз, когда форма изначально создаётся. При этом OnPaint вызывается каждый раз, когда какому-нибудь элементу формы необходимо перерисоваться (это событие можно использовать, если необходимо при этом рисовать на форме что-то особенное).

Жизнь
Когда форма создана и все её элементы ждут своих событий, чтобы обрабатывать их, жизнь формы продолжается до тех пор, пока кто-нибудь не нажмёт крестик в верхнем правом углу формы!

Уничтожение
При уничтожении формы, события генерируются в следующем порядке:



... OnCloseQuery -> OnClose-> OnDeactivate -> OnHide -> OnDestroy






OnCloseQuery
Если мы попытаемся закрыть форму при помощи метода Close либо другим доступным способом (Alt+F4 либо через системное меню), то сгенерируется событие OnCloseQuery. Таким образом, это событие можно использовать, чтобы предотвратить закрытие формы. Обычно, событие OnCloseQuery используется для того, чтобы спросить пользователя - уверен ли он (возможно в приложении остались несохранённые данные).


procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
 if MessageDlg('Really close this window?', mtConfirmation, [mbOk, mbCancel], 0) = mrCancel then
   CanClose := False;
end;


Обработчик события OnCloseQuery содержит переменную CanClose, которая определяет, можно ли форме закрыться. Изначальное значение этой переменной True. Однако в обработчике OnCloseQuery можно установить возвращаемое значение CloseQuery в False, чтобы прервать выполнение метода Close.

OnClose
Если OnCloseQuery вернул CanClose=True (что указывает на то, что форма должна быть закрыта), то будет будет сгенерировано событие OnClose.
Событие OnClose даёт последний шанс, чтобы предотвратить закрытие формы. Обработчик OnClose имеет параметр Action со следующими четырьмя возможными значениями:
caNone. Форме не разрешено закрыться. Всё равно, что мы установим CanClose в False в OnCloseQuery.
caHide. Вместо закрытия, форма будет скрыта.
caFree. Форма будет закрыта, и занятые ей ресурсы будут освобождены.
caMinimize. Вместо закрытия, форма будет минимизирована. Это значение устанавливается поумолчанию у дочерних форм MDI.

Замечание: Когда пользователь шутдаунит Windows, то будет вызвано OnCloseQuery, а не OnClose. Если Вы не хотите, чтобы Windows завершила свою работу, то поместите свой код в обработчик события OnCloseQuery, хотя CanClose=False не сделает, того, что надо здесь.

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


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



Взято с Исходников.ru








RTF-->HTML


RTF-->HTML




Приведу программу, которую я использую для преобразования содержимого RichEdit в SGML-код. Она не формирует полный HTML-аналог, но вы сами можете добавить необходимый RTF-код и его интерпретацию в HTML-тэги.

Код содержит интуитивно понятные комментарии и строки на шведском языке, нецелесообразные для перевода.

functionrtf2sgml(text: string): string;
{Funktion for att konvertera en RTF-rad till SGML-text.}
var
  temptext: string;
  start: integer;
begin
  text := stringreplaceall(text, '&', '##amp;');
  text := stringreplaceall(text, '##amp', '&amp');
  text := stringreplaceall(text, '\' + chr(39) + 'e5', '&aring;');
  text := stringreplaceall(text, '\' + chr(39) + 'c5', '&Aring;');
  text := stringreplaceall(text, '\' + chr(39) + 'e4', '&auml;');
  text := stringreplaceall(text, '\' + chr(39) + 'c4', '&Auml;');
  text := stringreplaceall(text, '\' + chr(39) + 'f6', '&ouml;');
  text := stringreplaceall(text, '\' + chr(39) + 'd6', '&Ouml;');
  text := stringreplaceall(text, '\' + chr(39) + 'e9', '&eacute;');
  text := stringreplaceall(text, '\' + chr(39) + 'c9', '&Eacute;');
  text := stringreplaceall(text, '\' + chr(39) + 'e1', '&aacute;');
  text := stringreplaceall(text, '\' + chr(39) + 'c1', '&Aacute;');
  text := stringreplaceall(text, '\' + chr(39) + 'e0', '&agrave;');
  text := stringreplaceall(text, '\' + chr(39) + 'c0', '&Agrave;');
  text := stringreplaceall(text, '\' + chr(39) + 'f2', '&ograve;');
  text := stringreplaceall(text, '\' + chr(39) + 'd2', '&Ograve;');
  text := stringreplaceall(text, '\' + chr(39) + 'fc', '&uuml;');
  text := stringreplaceall(text, '\' + chr(39) + 'dc', '&Uuml;');
  text := stringreplaceall(text, '\' + chr(39) + 'a3', '&#163;');
  text := stringreplaceall(text, '\}', '#]#');
  text := stringreplaceall(text, '\{', '#[#');
  text := stringreplaceall(text, '{\rtf1\ansi\deff0\deftab720', ''); {Skall alltid tas bort}
  text := stringreplaceall(text, '{\fonttbl', ''); {Skall alltid tas bort}
  text := stringreplaceall(text, '{\f0\fnil MS Sans Serif;}', ''); {Skall alltid tas bort}
  text := stringreplaceall(text, '{\f1\fnil\fcharset2 Symbol;}', ''); {Skall alltid tas bort}
  text := stringreplaceall(text, '{\f2\fswiss\fprq2 System;}}', ''); {Skall alltid tas bort}
  text := stringreplaceall(text, '{\colortbl\red0\green0\blue0;}', ''); {Skall alltid tas bort}
{I version 2.01 av Delphi finns inte \cf0 med i RTF-rutan. Tog darfor bort
det efter \fs16 och la istallet en egen tvatt av \cf0.}
//temptext := hamtastreng (text,'{\rtf1','\deflang');
//text := stringreplace (text,temptext,''); {Hamta och radera allt fran start till deflang}
  text := stringreplaceall(text, '\cf0', '');
  temptext := hamtastreng(text, '\deflang', '\pard'); {Plocka fran deflang till pard for att fa }
  text := stringreplace(text, temptext, ''); {oavsett vilken lang det ar. Norska o svenska ar olika}
{Har skall vi plocka bort fs och flera olika siffror beroende pa vilka alternativ vi godkanner.}
//text := stringreplaceall (text,'\fs16','');{8 punkter}
//text := stringreplaceall (text,'\fs20','');{10 punkter}
{Nu stadar vi istallet bort alla tvasiffriga fontsize.}
  while pos('\fs', text) > 0 do

    begin
      application.processmessages;
      start := pos('\fs', text);
      Delete(text, start, 5);
    end;
  text := stringreplaceall(text, '\pard\plain\f0 ', '<P>');
  text := stringreplaceall(text, '\par \plain\f0\b\ul ', '</P><MELLIS>');
  text := stringreplaceall(text, '\plain\f0\b\ul ', '</P><MELLIS>');
  text := stringreplaceall(text, '\plain\f0', '</MELLIS>');
  text := stringreplaceall(text, '\par }', '</P>');
  text := stringreplaceall(text, '\par ', '</P><P>');
  text := stringreplaceall(text, '#]#', '}');
  text := stringreplaceall(text, '#[#', '{');
  text := stringreplaceall(text, '\\', '\');
  result := text;
end;

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


utfilnamn := mditted.exepath + stringreplace(stringreplace(extractfilename(pathname), '.TTT', ''), '.ttt', '') + 'ut.RTF';
brodtext.lines.savetofile(utfilnamn);
temptext := '';
assignfile(tempF, utfilnamn);
reset(tempF);
try
  while not eof(tempF) do
    begin
      readln(tempF, temptext2);
      temptext2 := stringreplaceall(temptext2, '\' + chr(39) + 'b6', '');
      temptext2 := rtf2sgml(temptext2);
      if temptext2 <> '' then temptext := temptext + temptext2;
      application.processmessages;
    end;
finally
  closefile(tempF);
end;
deletefile(utfilnamn);
temptext := stringreplaceall(temptext, '</MELLIS> ', '</MELLIS>');
temptext := stringreplaceall(temptext, '</P> ', '</P>');
temptext := stringreplaceall(temptext, '</P>' + chr(0), '</P>');
temptext := stringreplaceall(temptext, '</MELLIS></P>', '</MELLIS>');
temptext := stringreplaceall(temptext, '<P></P>', '');
temptext := stringreplaceall(temptext, '</P><P></MELLIS>', '</MELLIS><P>');
temptext := stringreplaceall(temptext, '</MELLIS>', '<#MELLIS><P>');
temptext := stringreplaceall(temptext, '<#MELLIS>', '</MELLIS>');
temptext := stringreplaceall(temptext, '<P><P>', '<P>');
temptext := stringreplaceall(temptext, '<P> ', '<P>');
temptext := stringreplaceall(temptext, '<P>-', '<P>_');
temptext := stringreplaceall(temptext, '<P>_', '<CITAT>_');
while pos('<CITAT>_', temptext) > 0 do
  begin
    application.processmessages;
    temptext2 := hamtastreng(temptext, '<CITAT>_', '</P>');
    temptext := stringreplace(temptext, temptext2 + '</P>', temptext2 + '</CITAT>');
    temptext := stringreplace(temptext, '<CITAT>_', '<CITAT>-');
  end;
writeln(F, '<BRODTEXT>' + temptext + '</BRODTEXT>');

Взято из

Советов по Delphi от


Сборник Kuliba





RTL Delphi (краткий справочник)


RTL Delphi (краткий справочник)



Cодержание раздела:






См. также статьи в других разделах:




RTTI и другие трюки с информацией о классах, модулях и т.п.


RTTI и другие трюки с информацией о классах, модулях и т.п.



Cодержание раздела:
























См. также другие разделы:







Runtime error 230 when running Kylix application outside of the IDE


Runtime error 230 when running Kylix application outside of the IDE



Why am I getting runtime error 230 when running my application outside of the Kylix IDE?


This error generally means your application cannot find a needed library.
Tunning the command source \kylix\bin\kylixpath in Linux should fix this. See the file deploy.txt that comes with Kylix.





Русификация Kylix


Русификация Kylix





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

Для Kylix желательно использовать кодовую страницу KOI-8r, которая является практически стандартом русского языка в Linux. Для того, чтобы Kylix мог понимать русские шрифты, нужно сделать следующее:

1. Открыть файл /etc/sysconfig/i18n и добавить в него следующие недостающие строки:

LANG=ru
LANGUAGE=ru_RU.KOI8-R:ru #опционально
LC_CTYPE=ru_RU.KOI8-R
LC_NUMERIC=ru_RU.KOI8-R
LC_TIME=ru_RU.KOI8-R
LC_COLLATE=ru_RU.KOI8-R
LC_MONETARY=ru_RU.KOI8-R
LC_MESSAGES=ru_RU.KOI8-R
LC_ALL=ru_RU.KOI8-R
SYSFONT=UniCyr_8x16
SYSFONTACM=koi8-r

Если какие-то из этих строк уже есть в файле, то нужно отредактировать существующие.

В системе уже должны быть установлены русские шрифты. В последних дистрибутивах почти всегда идут шрифты Cronyx Cyrillic, которых достаточно для нормальной работы Kylix.

И последнее, что надо сделать - настрокить переключение клавиатуры в файле /etc/X11/XF86Config. Там нужно отредактировать следующие строки:

Option "XkbLayout" "ru(winkeys)"
Option "XkbOptions" "grp:ctrl_shift_toggle"

Последняя строка показывает как будет переключатся раскладка. В данном случае будет использоваться сочетание клавишь Ctrl+Shift.

Вот и всё!!! Желательно ещё и перегрузить Linux, чтобы он заговорил по русски.



Взято с сайта





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


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) 
S97 Позднее время соединения - снятия трубки (V.32 Late Connecting Handshake Timing) 
S105 Размер кадра (Frame Size) 
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) 

Взято из

Советов по Delphi от


Сборник Kuliba






Самый быстрый способ узнать количество записей в таблице


Самый быстрый способ узнать количество записей в таблице





When using the standard dataset.recordcount in my client-server (win nt against sqlserver7 db, targettable has 500.000 records) i can go for lunch and stil be waiting (:-

Answer:

For those of you who don't know why u should not use the standard dataset.recordcount when developing client server database applications.
This article is especialy for those cs db apps against a sqlserver 7 db.

since the standard dataset.recordcount iterates from begin of the table through the end of the table to result in the recordcount. This is a crime when developing cs db apps (against sqlserver7).

simply use another way of obtaining the number of records. I use a sql for obtaining the number of records in a sqlserver table.

drop a tquery on the form

provide this tquery with the follow SQL:

SQL:

selectdistinct max(itbl.rows) 
from sysindexes as itbl 
inner join sysobjects as otbl on (itbl.id = otbl.id) 
where (otbl.type = 'U') and (otbl.name = :parTableName) 

notice the parameter: parTableName type string

use this tquery to find out how many rows in the table

TIP: try to make your own tYourSqlServerCountQuery and thus override the recordcount property.
ByTheWay: use this only for sqlserver

for other cs db apps simply use a count sql (coming upnext time...)


Взято с

Delphi Knowledge Base




Сценарии комбинаций потоковых моделей


Сценарии комбинаций потоковых моделей




Сценарий #1: Клиент STA и однопотоковый сервер

Внутренний сервер.

Клиентский поток STA, создающий объект в однопотоковом сервере, принимает прямое подключение к объекту, если этот поток живет в главном STA клиента. В противном случае COM создает объект в главном STA клиента и получает прокси (заместителя) к требуемому потоку. Почему COM поступает так? Ответ простой: однопотоковый сервер сообщил COM, что он может обслуживать поступающие вызовы к своим объектам только в одном потоке. COM заметит это и несомненно выполнит этот однопотоковый запрос, не "потревожив" сервер. Следовательно, любой многопотоковый клиент, желающий сообщить что-либо этому серверу, будет способен сделать это только потому, что COM заставить выполнить этот запрос в одном потоке STA. Для клиента STA COM выберет главный STA в качестве единственного потока STA.

Внешний сервер.
Все клиентские потоки STA будут пользоваться заместителями, маршалируемыми и обслуживаемыми главным (единственным) STA внешнего сервера.

Сценарий #2: Клиент STA и сервер MTA



Внутренний сервер.

Клиентский поток STA, создающий объект из сервера MTA, получит прокси (заместителя) к этому объекту, маршалированного из созданного COM MTA в клиентском приложении. На первый взгляд это кажется странным, так как по определению объект MTA должен иметь возможность прямого доступа вне зависимости от того, какой поток создан, или откуда к нему производится доступ. Другими словами, почему бы COM не создавать объект непосредственно в STA запрашивающего клиента? Давайте попробуем понять, что произойдет, если COM создаст экземпляр объекта непосредственно в клиентском STA. Если COM создает объект MTA непосредственно в клиенте STA, то с точки зрения клиента, объект живет в этом STA, но с точки зрения сервера объект в действительности живет в MTA, т.е. он выглядит так, как будто он может осуществлять все вызовы из любого потока в любое время. Теперь, если клиент пытается передать интерфейс обратного вызова методу этого объекта MTA (очевидно, что этот интерфейс нужен объекту, расположенному в клиенте, а этот объект поддерживает только STA, так как клиент работает в модели STA) и сервер пытается осуществить обратный вызов через этот интерфейс, то у сервера нет способа узнать, что этот интерфейс не в состоянии обслуживать одновременные вызовы из нескольких потоков сервера (который размещается в MTA). Другими словами клиентский объект, реализующий интерфейс обратного вызова может "задохнуться", если сервер начнет производить одновременные вызовы из разных потоков. Следовательно, создавая объект всозданном COM MTA и передавая прокси (заместителя) обратно к затребовавшему его STA, любые обратные вызовы, исходящие от сервера, будут производиться этим MTA и выстраиваться последовательно через прокси в STA, который содержит объект, обслуживающий обратный вызов.

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

Сценарий #3: Клиент MTA и однопотоковый сервер



Внутренний сервер.

Клиентский поток MTA, создающий объект из однопотокового сервера, будет принимать прокси к этому объекту, маршалированный созданным COM главным STA в клиенте (полагая, что клиент еще не создан главным STA). Очевидно, COM не может допускать прямого создания объектов однопотокового сервера в MTA, так как он не сможет пережить одновременные вызовы из потоков MTA.

Внешний сервер.
Все клиентские потоки MTA будут пользоваться прокси (заместителями), маршалированными и обслуживаемыми главным (единственным) STA внешнего сервера.

Сценарий #4: Клиент MTA и сервер STA

Внутренний сервер.

Клиентский поток MTA, создающий объект из сервера STA, получит прокси (заместителя) к этому объекту, маршалированного, созданным COM STA в клиентском приложении. Только это имеет смысл, так как сервер сказал COM, что он может поддерживать только STA и поэтому нет способа, чтобы COM прямо создавал объект в MTA, в котором другие потоки MTA преспокойно "завалят" его! Таким образом, если он живет в STA, любые вызовы, производимые потоками MTA, будут выстраиваться последовательно к STA, который, по соглашению, как раз и является тем, с чем может работать сервер.
Внешний сервер.


Все клиентские потоки MTA будут пользоваться прокси, маршалированными и обслуживаемыми в каждом соответствующем STA внешнего сервера.

Сценарий #5: Однопотоковый клиент и сервер STA

Внутренний сервер.

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

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

Сценарий #6: Однопотоковый клиент и сервер MTA

Внутренний вервер.

Этот сценарий является недоделанным вариантом сценария #2, в котором имеется только один STA в клиенте, главный STA. Таким образом, по тем же причинам, что и при сценарии #2, COM будет создавать объект в созданном COM MTA и возвращать прокси к главному потоку STA. Внешний сервер. Клиентский главный поток будет пользоваться прокси, маршалируемым и обслуживаемым в MTA внешнего сервера.
Ну вот мы и рассмотрели все возможные несовместимые комбинации потоковых моделей клиентов и серверов. Мы увидели, как COM предоставляет возможность этим клиентам и серверам работать совместно. Теперь я бы хотел рассказать о необычайно интересном вопросе смешанного использования потоковых моделей. С появлением STA и MTA иногда стала появляться необходимость взаимодействия клиентов и серверов с потоками STA в одних местах и с потоками MTA в других местах внутри одного приложения. Обычно такая потребность появляется по бизнес-причинам, появляющимся при тщательном изучении того, как Ваши клиентское и серверное приложения будут взаимодействовать друг с другом. Например, Ваш сервер может нуждаться в использовании некоторых объектов для решения задач реального времени, в то время как другие не должны (или не могут) работать в режиме "производительности реального времени". В этом случае логично иметь объекты "реального времени", создаваемые в MTA, где они могут реализовать максимальную производительность, и, в то же время, иметь остальные объекты, обслуживаемые в одном или многих STA. То, что я должен описать здесь, называется Смешанная потоковая модель (Mixed Threading Model), обозначая тем самым, что Ваше приложение пользуется комбинацией (смесью) различных потоковых моделей для своих объектов.
В действительности в смешанной модели нет ничего нового. Клиентское приложение может, например, создавать целый букет рабочих потоков, живущих в MTA, в то время как другая группа потоков STA обслуживает какие-то другие потребности.
Серверное приложение также может работать аналогично, т.е. организовывать гроздь объектов в MTA для получения максимальной производительности и, в то же время, порождать кучу потоков STA для других объектов. Мне нет никакой необходимости демонстрировать, как клиент или сервер собирается создавать STA и MTA в рамках единственного процесса, так как Вы уже знакомы с технологией как это делается. Необходимо только создать букет потоков, каждый из которых входит либо в STA, либо в MTA и, бум!, Вы получили смешанную потоковую модель, работающую в Вашем приложении. Об этой смешанной модели важно знать то, что она существует и может оказаться очень удобной для решения каких-то проблем, которые могут встретиться Вам при создании Вами клиентских и серверных приложений. Поддержка смешанной потоковой модели для внешних серверов заключается просто в создании букета потоков и явным указанием для каждого потока его STA или MTA.
Для внутренних серверов, однако, мы можем ожидать, что COM полагается на строковый параметр ThreadingModel, как и в случае однопотокового STA. Сервером объектов может быть использован строковый параметр "ThreadingModel=Both" для указания, что COM может свободно создавать этот объект в STA или в MTA, т.е. он поддерживает как STA, так и MTA.
Но как COM узнает, должен он создавать объект в STA или в MTA? Как я уже говорил ранее, внутренний сервер обычно рассчитывает, что клиентское приложение явно создает потоки STA и MTA, содержащие серверные объекты. В случае, когда "ThreadingModel=Both", подразделение клиентского потока прямо определяет, где COM будет создавать этот объект. Другими словами, если клиентский поток STA создает объект - COM явно создает его в STA. Если клиентский поток MTA создает объект - COM однозначно создаст его в MTA.




ScreenMate


ScreenMate




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

p.s К сожалению вам надо позаботиться о кадрах анимации этого персонажа самим т.к рисунки я послать немогу...



{*******************************************************}
{ }
                           { Delphi VCL Extensions (RX) }
                                                      { }
                    { Copyright (c) 1995, 1996 AO ROSNO }
                 { Copyright (c) 1997, 1998 Master-Bank }
                                                      { }
{*******************************************************}

unit Animate;

interface

{$I RX.INC}

uses Messages, {$IFDEF WIN32}Windows, {$ELSE}WinTypes, WinProcs,
{$ENDIF}
  SysUtils, Classes, Graphics, Controls, Forms, StdCtrls, Menus,
  ExtCtrls;

type
  TGlyphOrientation = (goHorizontal, goVertical);

  { TRxImageControl }

  TRxImageControl = class(TGraphicControl)
  private
    FDrawing: Boolean;
  protected
    FGraphic: TGraphic;
    function DoPaletteChange: Boolean;
    procedure DoPaintImage; virtual; abstract;
    procedure PaintDesignRect;
    procedure PaintImage;
    procedure PictureChanged;
  public
    constructor Create(AOwner: TComponent); override;
  end;

  { TAnimatedImage }

  TAnimatedImage = class(TRxImageControl)
  private
    { Private declarations }
    FActive: Boolean;
    FAutoSize: Boolean;
    FGlyph: TBitmap;
    FImageWidth: Integer;
    FImageHeight: Integer;
    FInactiveGlyph: Integer;
    FOrientation: TGlyphOrientation;
    FTimer: TTimer;
    FNumGlyphs: Integer;
    FGlyphNum: Integer;
    FStretch: Boolean;
    FTransparentColor: TColor;
    FOpaque: Boolean;
    FTimerRepaint: Boolean;
    FOnFrameChanged: TNotifyEvent;
    FOnStart: TNotifyEvent;
    FOnStop: TNotifyEvent;
    procedure DefineBitmapSize;
    procedure ResetImageBounds;
    procedure AdjustBounds;
    function GetInterval: Cardinal;
    procedure SetAutoSize(Value: Boolean);
    procedure SetInterval(Value: Cardinal);
    procedure SetActive(Value: Boolean);
    procedure SetOrientation(Value: TGlyphOrientation);
    procedure SetGlyph(Value: TBitmap);
    procedure SetGlyphNum(Value: Integer);
    procedure SetInactiveGlyph(Value: Integer);
    procedure SetNumGlyphs(Value: Integer);
    procedure SetStretch(Value: Boolean);
    procedure SetTransparentColor(Value: TColor);
    procedure SetOpaque(Value: Boolean);
    procedure ImageChanged(Sender: TObject);
    procedure UpdateInactive;
    procedure TimerExpired(Sender: TObject);
    function TransparentStored: Boolean;
    procedure WMSize(var Message: TWMSize); message WM_SIZE;
  protected
    { Protected declarations }
    function GetPalette: HPALETTE; override;
    procedure Loaded; override;
    procedure Paint; override;
    procedure DoPaintImage; override;
    procedure FrameChanged; dynamic;
    procedure Start; dynamic;
    procedure Stop; dynamic;
  public
    { Public declarations }
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure DoPaintImageOn(Mycanvas: Tcanvas; x, y: integer);
      virtual;
  published
    { Published declarations }
    property Active: Boolean read FActive write SetActive default
      False;
    property Align;
    property AutoSize: Boolean read FAutoSize write SetAutoSize
      default True;
    property Orientation: TGlyphOrientation read FOrientation write
      SetOrientation
      default goHorizontal;
    property Glyph: TBitmap read FGlyph write SetGlyph;
    property GlyphNum: Integer read FGlyphNum write SetGlyphNum
      default 0;
    property Interval: Cardinal read GetInterval write SetInterval
      default 100;
    property NumGlyphs: Integer read FNumGlyphs write SetNumGlyphs
      default 1;
    property InactiveGlyph: Integer read FInactiveGlyph write
      SetInactiveGlyph default -1;
    property TransparentColor: TColor read FTransparentColor write
      SetTransparentColor
      stored TransparentStored;
    property Opaque: Boolean read FOpaque write SetOpaque default
      False;
    property Color;
    property Cursor;
    property DragCursor;
    property DragMode;
    property ParentColor default True;
    property ParentShowHint;
    property PopupMenu;
    property ShowHint;
    property Stretch: Boolean read FStretch write SetStretch default
      True;
    property Visible;
    property OnClick;
    property OnDblClick;
    property OnMouseMove;
    property OnMouseDown;
    property OnMouseUp;
    property OnDragOver;
    property OnDragDrop;
    property OnEndDrag;
{$IFDEF WIN32}
    property OnStartDrag;
{$ENDIF}
    property OnFrameChanged: TNotifyEvent read FOnFrameChanged write
      FOnFrameChanged;
    property OnStart: TNotifyEvent read FOnStart write FOnStart;
    property OnStop: TNotifyEvent read FOnStop write FOnStop;
  end;

implementation

uses RxConst, VCLUtils;

{ TRxImageControl }

constructor TRxImageControl.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  ControlStyle := [csClickEvents, csCaptureMouse, csOpaque,
{$IFDEF WIN32}csReplicatable, {$ENDIF}csDoubleClicks];
  Height := 105;
  Width := 105;
  ParentColor := True;
end;

procedure TRxImageControl.PaintImage;
var
  Save: Boolean;
begin
  Save := FDrawing;
  FDrawing := True;
  try
    DoPaintImage;
  finally
    FDrawing := Save;
  end;
end;

procedure TRxImageControl.PaintDesignRect;
begin
  if csDesigning in ComponentState then
    with Canvas do
    begin
      Pen.Style := psDash;
      Brush.Style := bsClear;
      Rectangle(0, 0, Width, Height);
    end;
end;

function TRxImageControl.DoPaletteChange: Boolean;
var
  ParentForm: TCustomForm;
  Tmp: TGraphic;
begin
  Result := False;
  Tmp := FGraphic;
  if Visible and (not (csLoading in ComponentState)) and (Tmp <>
    nil)
{$IFDEF RX_D3} and (Tmp.PaletteModified){$ENDIF} then
  begin
    if (GetPalette <> 0) then
    begin
      ParentForm := GetParentForm(Self);
      if Assigned(ParentForm) and ParentForm.Active and
        Parentform.HandleAllocated then
      begin
        if FDrawing then
          ParentForm.Perform(WM_QUERYNEWPALETTE, 0, 0)
        else
          PostMessage(ParentForm.Handle, WM_QUERYNEWPALETTE, 0, 0);
        Result := True;
{$IFDEF RX_D3}
        Tmp.PaletteModified := False;
{$ENDIF}
      end;
    end
{$IFDEF RX_D3}
    else
    begin
      Tmp.PaletteModified := False;
    end;
{$ENDIF}
  end;
end;

procedure TRxImageControl.PictureChanged;
begin
  if (FGraphic <> nil) then
    if DoPaletteChange and FDrawing then
      Update;
  if not FDrawing then
    Invalidate;
end;

{ TAnimatedImage }

constructor TAnimatedImage.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FTimer := TTimer.Create(Self);
  Interval := 100;
  FGlyph := TBitmap.Create;
  FGraphic := FGlyph;
  FGlyph.OnChange := ImageChanged;
  FGlyphNum := 0;
  FNumGlyphs := 1;
  FInactiveGlyph := -1;
  FTransparentColor := clNone;
  FOrientation := goHorizontal;
  FAutoSize := True;
  FStretch := True;
  Width := 32;
  Height := 32;
end;

destructor TAnimatedImage.Destroy;
begin
  FOnFrameChanged := nil;
  FOnStart := nil;
  FOnStop := nil;
  FGlyph.OnChange := nil;
  Active := False;
  FGlyph.Free;
  inherited Destroy;
end;

procedure TAnimatedImage.Loaded;
begin
  inherited Loaded;
  ResetImageBounds;
  UpdateInactive;
end;

function TAnimatedImage.GetPalette: HPALETTE;
begin
  Result := 0;
  if not FGlyph.Empty then
    Result := FGlyph.Palette;
end;

procedure TAnimatedImage.ImageChanged(Sender: TObject);
begin
  FTransparentColor := FGlyph.TransparentColor and not PaletteMask;
  DefineBitmapSize;
  AdjustBounds;
  PictureChanged;
end;

procedure TAnimatedImage.UpdateInactive;
begin
  if (not Active) and (FInactiveGlyph >= 0) and
    (FInactiveGlyph < FNumGlyphs) and (FGlyphNum <> FInactiveGlyph) then
  begin
    FGlyphNum := FInactiveGlyph;
  end;
end;

function TAnimatedImage.TransparentStored: Boolean;
begin
  Result := (FGlyph.Empty and (FTransparentColor <> clNone)) or
    ((FGlyph.TransparentColor and not PaletteMask) <>
    FTransparentColor);
end;

procedure TAnimatedImage.SetOpaque(Value: Boolean);
begin
  if Value <> FOpaque then
  begin
    FOpaque := Value;
    PictureChanged;
  end;
end;

procedure TAnimatedImage.SetTransparentColor(Value: TColor);
begin
  if Value <> TransparentColor then
  begin
    FTransparentColor := Value;
    PictureChanged;
  end;
end;

procedure TAnimatedImage.SetOrientation(Value: TGlyphOrientation);
begin
  if FOrientation <> Value then
  begin
    FOrientation := Value;
    DefineBitmapSize;
    AdjustBounds;
    Invalidate;
  end;
end;

procedure TAnimatedImage.SetGlyph(Value: TBitmap);
begin
  FGlyph.Assign(Value);
end;

procedure TAnimatedImage.SetStretch(Value: Boolean);
begin
  if Value <> FStretch then
  begin
    FStretch := Value;
    PictureChanged;
    if Active then
      Repaint;
  end;
end;

procedure TAnimatedImage.SetGlyphNum(Value: Integer);
begin
  if Value <> FGlyphNum then
  begin
    if (Value < FNumGlyphs) and (Value >= 0) then
    begin
      FGlyphNum := Value;
      UpdateInactive;
      FrameChanged;
      PictureChanged;
    end;
  end;
end;

procedure TAnimatedImage.SetInactiveGlyph(Value: Integer);
begin
  if Value < 0 then
    Value := -1;
  if Value <> FInactiveGlyph then
  begin
    if (Value < FNumGlyphs) or (csLoading in ComponentState) then
    begin
      FInactiveGlyph := Value;
      UpdateInactive;
      FrameChanged;
      PictureChanged;
    end;
  end;
end;

procedure TAnimatedImage.SetNumGlyphs(Value: Integer);
begin
  FNumGlyphs := Value;
  if FInactiveGlyph >= FNumGlyphs then
  begin
    FInactiveGlyph := -1;
    FGlyphNum := 0;
  end
  else
    UpdateInactive;
  FrameChanged;
  ResetImageBounds;
  AdjustBounds;
  PictureChanged;
end;

procedure TAnimatedImage.DefineBitmapSize;
begin
  FNumGlyphs := 1;
  FGlyphNum := 0;
  FImageWidth := 0;
  FImageHeight := 0;
  if (FOrientation = goHorizontal) and (FGlyph.Height > 0) and
    (FGlyph.Width mod FGlyph.Height = 0) then
    FNumGlyphs := FGlyph.Width div FGlyph.Height
  else if (FOrientation = goVertical) and (FGlyph.Width > 0) and
    (FGlyph.Height mod FGlyph.Width = 0) then
    FNumGlyphs := FGlyph.Height div FGlyph.Width;
  ResetImageBounds;
end;

procedure TAnimatedImage.ResetImageBounds;
begin
  if FNumGlyphs < 1 then
    FNumGlyphs := 1;
  if FOrientation = goHorizontal then
  begin
    FImageHeight := FGlyph.Height;
    FImageWidth := FGlyph.Width div FNumGlyphs;
  end
  else {if Orientation = goVertical then}
  begin
    FImageWidth := FGlyph.Width;
    FImageHeight := FGlyph.Height div FNumGlyphs;
  end;
end;

procedure TAnimatedImage.AdjustBounds;
begin
  if not (csReading in ComponentState) then
  begin
    if FAutoSize and (FImageWidth > 0) and (FImageHeight > 0) then
      SetBounds(Left, Top, FImageWidth, FImageHeight);
  end;
end;

type
  TParentControl = class(TWinControl);



Взято из





Sending a file via DCOM


Sending a file via DCOM



I would like to send a file through DCOM however I can only send standard types. How can I send bytes across to a client?

You need to use a variant array (VarArrayLock should be useful as well).




Sending an image to the printer


Sending an image to the printer



Sending a bitmap based on the screen to the printer is an
invalid operation that will usually fail, unless the print
driver has been designed to detect this error condition and
compensate for the error. This means you should use the VCL
canvas methods Draw, StretchDraw,CopyRect, BrushCopy, and
the like to transfer a bitmap to the printer, since the
underlying bitmap is based on the screen, and is device
dependent. The only way to reliably print an image is to
use DIBs (Device Independent Bitmaps). Getting a valid DIB can
be difficult, as there are many Windows API functions that must
be used correctly. Further, many video drivers incorrectly fill
in the DIB structure in regards to the color table in the DIB.

The following example demonstrates an attempt to overcome
some of these problems and limitations. The example should
compile successfully under all versions of Delphi/C++ Builder.

The core function in the example, BltTBitmapAsDib(), accepts
a handle to a device to image to, the x and y coordinates you
wish the bitmap to be imaged at, the width and height you wish
the image to be (stretching and shrinking is acceptable), and
the TBitmap you wish to image.


uses Printers;

type
  PPalEntriesArray = ^TPalEntriesArray; {for palette re-construction}
  TPalEntriesArray = array[0..0] of TPaletteEntry;

procedure BltTBitmapAsDib(DestDc : hdc;   {Handle of where to blt}
                          x : word;       {Bit at x}
                          y : word;       {Blt at y}
                          Width : word;   {Width to stretch}
                          Height : word;  {Height to stretch}
                          bm : TBitmap);  {the TBitmap to Blt}
var
  OriginalWidth :LongInt;               {width of BM}
  dc : hdc;                             {screen dc}
  IsPaletteDevice : bool;               {if the device uses palettes}
  IsDestPaletteDevice : bool;           {if the device uses palettes}
  BitmapInfoSize : integer;             {sizeof the bitmapinfoheader}
  lpBitmapInfo : PBitmapInfo;           {the bitmap info header}
  hBm : hBitmap;                        {handle to the bitmap}
  hPal : hPalette;                      {handle to the palette}
  OldPal : hPalette;                    {temp palette}
  hBits : THandle;                      {handle to the DIB bits}
  pBits : pointer;                      {pointer to the DIB bits}
  lPPalEntriesArray : PPalEntriesArray; {palette entry array}
  NumPalEntries : integer;              {number of palette entries}
  i : integer;                          {looping variable}
begin
{If range checking is on - lets turn it off for now}
{we will remember if range checking was on by defining}
{a define called CKRANGE if range checking is on.}
{We do this to access array members past the arrays}
{defined index range without causing a range check}
{error at runtime. To satisfy the compiler, we must}
{also access the indexes with a variable. ie: if we}
{have an array defined as a: array[0..0] of byte,}
{and an integer i, we can now access a[3] by setting}
{i := 3; and then accessing a[i] without error}
{$IFOPT R+}
  {$DEFINE CKRANGE}
  {$R-}
{$ENDIF}

 {Save the original width of the bitmap}
  OriginalWidth := bm.Width;

 {Get the screen's dc to use since memory dc's are not reliable}
  dc := GetDc(0);
 {Are we a palette device?}
  IsPaletteDevice :=
    GetDeviceCaps(dc, RASTERCAPS) and RC_PALETTE = RC_PALETTE;
 {Give back the screen dc}
  dc := ReleaseDc(0, dc);

 {Allocate the BitmapInfo structure}
  if IsPaletteDevice then
    BitmapInfoSize := sizeof(TBitmapInfo) + (sizeof(TRGBQUAD) * 255)
  else
    BitmapInfoSize := sizeof(TBitmapInfo);
  GetMem(lpBitmapInfo, BitmapInfoSize);

 {Zero out the BitmapInfo structure}
  FillChar(lpBitmapInfo^, BitmapInfoSize, #0);

 {Fill in the BitmapInfo structure}
  lpBitmapInfo^.bmiHeader.biSize := sizeof(TBitmapInfoHeader);
  lpBitmapInfo^.bmiHeader.biWidth := OriginalWidth;
  lpBitmapInfo^.bmiHeader.biHeight := bm.Height;
  lpBitmapInfo^.bmiHeader.biPlanes := 1;
  if IsPaletteDevice then
    lpBitmapInfo^.bmiHeader.biBitCount := 8
  else
    lpBitmapInfo^.bmiHeader.biBitCount := 24;
  lpBitmapInfo^.bmiHeader.biCompression := BI_RGB;
  lpBitmapInfo^.bmiHeader.biSizeImage :=
    ((lpBitmapInfo^.bmiHeader.biWidth *
      longint(lpBitmapInfo^.bmiHeader.biBitCount)) div 8) *
      lpBitmapInfo^.bmiHeader.biHeight;
  lpBitmapInfo^.bmiHeader.biXPelsPerMeter := 0;
  lpBitmapInfo^.bmiHeader.biYPelsPerMeter := 0;
  if IsPaletteDevice then begin
    lpBitmapInfo^.bmiHeader.biClrUsed := 256;
    lpBitmapInfo^.bmiHeader.biClrImportant := 256;
  end else begin
    lpBitmapInfo^.bmiHeader.biClrUsed := 0;
    lpBitmapInfo^.bmiHeader.biClrImportant := 0;
  end;

 {Take ownership of the bitmap handle and palette}
  hBm := bm.ReleaseHandle;
  hPal := bm.ReleasePalette;

 {Get the screen's dc to use since memory dc's are not reliable}
  dc := GetDc(0);

  if IsPaletteDevice then begin
   {If we are using a palette, it must be}
   {selected into the dc during the conversion}
    OldPal := SelectPalette(dc, hPal, TRUE);
   {Realize the palette}
    RealizePalette(dc);
  end;
 {Tell GetDiBits to fill in the rest of the bitmap info structure}
  GetDiBits(dc,
            hBm,
            0,
            lpBitmapInfo^.bmiHeader.biHeight,
            nil,
            TBitmapInfo(lpBitmapInfo^),
            DIB_RGB_COLORS);

 {Allocate memory for the Bits}
  hBits := GlobalAlloc(GMEM_MOVEABLE,
                       lpBitmapInfo^.bmiHeader.biSizeImage);
  pBits := GlobalLock(hBits);
 {Get the bits}
  GetDiBits(dc,
            hBm,
            0,
            lpBitmapInfo^.bmiHeader.biHeight,
            pBits,
            TBitmapInfo(lpBitmapInfo^),
            DIB_RGB_COLORS);


  if IsPaletteDevice then begin
   {Lets fix up the color table for buggy video drivers}
    GetMem(lPPalEntriesArray, sizeof(TPaletteEntry) * 256);
   {$IFDEF VER100}
      NumPalEntries := GetPaletteEntries(hPal,
                                         0,
                                         256,
                                         lPPalEntriesArray^);
   {$ELSE}
      NumPalEntries := GetSystemPaletteEntries(dc,
                                               0,
                                               256,
                                               lPPalEntriesArray^);
   {$ENDIF}
    for i := 0 to (NumPalEntries - 1) do begin
      lpBitmapInfo^.bmiColors[i].rgbRed :=
        lPPalEntriesArray^[i].peRed;
      lpBitmapInfo^.bmiColors[i].rgbGreen :=
        lPPalEntriesArray^[i].peGreen;
      lpBitmapInfo^.bmiColors[i].rgbBlue :=
        lPPalEntriesArray^[i].peBlue;
    end;
    FreeMem(lPPalEntriesArray, sizeof(TPaletteEntry) * 256);
  end;

  if IsPaletteDevice then begin
   {Select the old palette back in}
    SelectPalette(dc, OldPal, TRUE);
   {Realize the old palette}
    RealizePalette(dc);
  end;

 {Give back the screen dc}
  dc := ReleaseDc(0, dc);

 {Is the Dest dc a palette device?}
  IsDestPaletteDevice :=
    GetDeviceCaps(DestDc, RASTERCAPS) and RC_PALETTE = RC_PALETTE;


  if IsPaletteDevice then begin
   {If we are using a palette, it must be}
   {selected into the dc during the conversion}
    OldPal := SelectPalette(DestDc, hPal, TRUE);
   {Realize the palette}
    RealizePalette(DestDc);
  end;

 {Do the blt}
  StretchDiBits(DestDc,
                x,
                y,
                Width,
                Height,
                0,
                0,
                OriginalWidth,
                lpBitmapInfo^.bmiHeader.biHeight,
                pBits,
                lpBitmapInfo^,
                DIB_RGB_COLORS,
                SrcCopy);

  if IsDestPaletteDevice then begin
   {Select the old palette back in}
    SelectPalette(DestDc, OldPal, TRUE);
   {Realize the old palette}
    RealizePalette(DestDc);
  end;

 {De-Allocate the Dib Bits}
  GlobalUnLock(hBits);
  GlobalFree(hBits);

 {De-Allocate the BitmapInfo}
  FreeMem(lpBitmapInfo, BitmapInfoSize);

 {Set the ownership of the bimap handles back to the bitmap}
  bm.Handle := hBm;
  bm.Palette := hPal;

  {Turn range checking back on if it was on when we started}
{$IFDEF CKRANGE}
  {$UNDEF CKRANGE}
  {$R+}
{$ENDIF}
end;


procedure TForm1.Button1Click(Sender: TObject);
begin
  if PrintDialog1.Execute then begin
    Printer.BeginDoc;
    BltTBitmapAsDib(Printer.Canvas.Handle,
                    0,
                    0,
                    Image1.Picture.Bitmap.Width,
                    Image1.Picture.Bitmap.Height,
                    Image1.Picture.Bitmap);
    Printer.EndDoc;
  end;
end;



Сервисы NT


Сервисы NT



Cодержание раздела:







Шаблоны в Object Pascal


Шаблоны в Object Pascal



Шаблоны в Object Pascal
( перевод одноимённой статьи с сайта community.borland.com )

Наверное каждый Delphi программист хоть раз общался с программистом C++ и объяснял насколько
Delphi мощнее и удобнее. Но в некоторый момент, программист C++ заявляет примерно следующее
"OK, но Delphi использует Pascal, а значит не поддерживает множественное наследование и шаблоны,
поэтому он не так хорош как C++."

Насчёт множественного наследования можно легко заявить, что Delphi имеет интерфейсы, которые
прекрасно справляются со своей задачей, но вот насчёт шаблонов Вам прийдётся согласится, так как
Object Pascal не поддерживает их.

Давайте посмотрим на эту проблему по-внимательней
Шаблоны позволяют делать универсальные контейнеры такие как списки, стеки, очереди, и т.д.
Если Вы хотите осуществить что-то подобное в Delphi, то у Вас есть два пути:

Использовать контейнер TList, который содержит указатели. В этом случае Вам прийдётся всё
время делать явное приведение типов.
Сделать подкласс контейнера TCollection или TObjectList, и убрать все методы, зависящие от типов
каждый раз, когда Вы захотите использовать новый тип данных.
Третий вариант, это сделать модуль с универсальным классом контейнера, и каждый раз, когда нужно
использовать новый тип данных, нам прийдётся в редакторе искать и вносить исправления. Было бы
здорово, если всю эту работу за Вас делал компилятор.... вот этим мы сейчас и займёмся!

Например, возьмём классы TCollection и TCollectionItem. Когда Вы объявляете нового потомка TCollectionItem
, то так же Вы наследуете новый класс от TOwnedCollection и переопределяете большинство методов, чтобы
их можно было вызывать с новыми типами.

Давайте посмотрим, как создать универсальную коллекцию шаблонов класса:

Шаг 1: Создайте новый текстовый файл (не юнитовский) с именем TemplateCollectionInterface.pas:

_COLLECTION_ = class (TOwnedCollection)
protected
 function  GetItem (const aIndex : Integer) : _COLLECTION_ITEM_;
 procedure SetItem (const aIndex : Integer;
                    const aValue : _COLLECTION_ITEM_);
public
 constructor Create (const aOwner : TComponent);

 function Add                                 : _COLLECTION_ITEM_;
 function FindItemID (const aID    : Integer) : _COLLECTION_ITEM_;
 function Insert     (const aIndex : Integer) : _COLLECTION_ITEM_;
 property Items      [const aIndex : Integer] : _COLLECTION_ITEM_ read GetItem write SetItem;
end;

Обратите внимание, что нет никаких uses или interface clauses, только универсальное объявление
типа, в котором _COLLECTION_ это имя универсальной коллекции класса, а _COLLECTION_ITEM_
это имя методов, содержащихся в нашем шаблоне.

Шаг 2: Создайте второй текстовый файл и сохраните его как TemplateCollectionImplementation.pas:

constructor _COLLECTION_.Create (const aOwner : TComponent);
begin
 inherited Create (aOwner, _COLLECTION_ITEM_);
end;

function _COLLECTION_.Add : _COLLECTION_ITEM_;
begin
 Result := _COLLECTION_ITEM_ (inherited Add);
end;

function _COLLECTION_.FindItemID (const aID : Integer) : _COLLECTION_ITEM_;
begin
 Result := _COLLECTION_ITEM_ (inherited FindItemID (aID));
end;

function _COLLECTION_.GetItem (const aIndex : Integer) : _COLLECTION_ITEM_;
begin
 Result := _COLLECTION_ITEM_ (inherited GetItem (aIndex));
end;

function _COLLECTION_.Insert (const aIndex : Integer) : _COLLECTION_ITEM_;
begin
 Result := _COLLECTION_ITEM_ (inherited Insert (aIndex));
end;

procedure _COLLECTION_.SetItem (const aIndex : Integer;
                                const aValue : _COLLECTION_ITEM_);
begin
 inherited SetItem (aIndex, aValue);
end;

Снова нет никаких uses или interface clauses , а только код универсального типа.

Шаг 3: Создайте новый unit-файл с именем MyCollectionUnit.pas:

unit MyCollectionUnit;

interface

uses Classes;

type TMyCollectionItem = class (TCollectionItem)
     private
      FMyStringData  : String;
      FMyIntegerData : Integer;
     public
      procedure Assign (aSource : TPersistent); override;
     published
      property MyStringData  : String  read FMyStringData  write FMyStringData;
      property MyIntegerData : Integer read FMyIntegerData write FMyIntegerData;
     end;

     // !!! Указываем универсальному классу на реальный тип
     
     _COLLECTION_ITEM_ = TMyCollectionItem; 
     
     // !!! директива добавления интерфейса универсального класса

     {$INCLUDE TemplateCollectionInterface} 

     // !!! переименовываем универсальный класс

     TMyCollection = _COLLECTION_;          

implementation

uses SysUtils;

// !!! препроцессорная директива добавления универсального класса

{$INCLUDE TemplateCollectionImplementation} 

procedure TMyCollectionItem.Assign (aSource : TPersistent);
begin
 if aSource is TMyCollectionItem then
 begin
  FMyStringData  := TMyCollectionItem(aSource).FMyStringData;
  FMyIntegerData := TMyCollectionItem(aSource).FMyIntegerData;
 end
 else inherited;
end;

end.

Вот и всё! Теперь компилятор будет делать всю работу за Вас! Если Вы измените интерфейс
универсального класса, то изменения автоматически распространятся на все модули, которые
он использует.

Второй пример
Давайте создадим универсальный класс для динамических массивов.

Шаг 1: Создайте текстовый файл с именем TemplateVectorInterface.pas:

_VECTOR_INTERFACE_ = nterface
 function  GetLength : Integer;
 procedure SetLength (const aLength : Integer);

 function  GetItems (const aIndex : Integer) : _VECTOR_DATA_TYPE_;
 procedure SetItems (const aIndex : Integer;
                     const aValue : _VECTOR_DATA_TYPE_);

 function  GetFirst : _VECTOR_DATA_TYPE_;
 procedure SetFirst (const aValue : _VECTOR_DATA_TYPE_);

 function  GetLast  : _VECTOR_DATA_TYPE_;
 procedure SetLast  (const aValue : _VECTOR_DATA_TYPE_);

 function  High  : Integer;
 function  Low   : Integer;

 function  Clear                              : _VECTOR_INTERFACE_;
 function  Extend   (const aDelta : Word = 1) : _VECTOR_INTERFACE_;
 function  Contract (const aDelta : Word = 1) : _VECTOR_INTERFACE_; 

 property  Length                         : Integer             read GetLength write SetLength;
 property  Items [const aIndex : Integer] : _VECTOR_DATA_TYPE_  read GetItems  write SetItems; default;
 property  First                          : _VECTOR_DATA_TYPE_  read GetFirst  write SetFirst;
 property  Last                           : _VECTOR_DATA_TYPE_  read GetLast   write SetLast;
end;

_VECTOR_CLASS_ = class (TInterfacedObject, _VECTOR_INTERFACE_)
private
 FArray : array of _VECTOR_DATA_TYPE_;
protected
 function  GetLength : Integer;
 procedure SetLength (const aLength : Integer);

 function  GetItems (const aIndex : Integer) : _VECTOR_DATA_TYPE_;
 procedure SetItems (const aIndex : Integer;
                     const aValue : _VECTOR_DATA_TYPE_);

 function  GetFirst : _VECTOR_DATA_TYPE_;
 procedure SetFirst (const aValue : _VECTOR_DATA_TYPE_);

 function  GetLast  : _VECTOR_DATA_TYPE_;
 procedure SetLast  (const aValue : _VECTOR_DATA_TYPE_);
public
 function  High  : Integer;
 function  Low   : Integer;

 function  Clear                              : _VECTOR_INTERFACE_;
 function  Extend   (const aDelta : Word = 1) : _VECTOR_INTERFACE_;
 function  Contract (const aDelta : Word = 1) : _VECTOR_INTERFACE_; 

 constructor Create (const aLength : Integer);
end;

Шаг 2: Создайте текстовый файл и сохраните его как TemplateVectorImplementation.pas:

constructor _VECTOR_CLASS_.Create (const aLength : Integer);
begin
 inherited Create;

 SetLength (aLength);
end;

function _VECTOR_CLASS_.GetLength : Integer;
begin
 Result := System.Length (FArray);
end;

procedure _VECTOR_CLASS_.SetLength (const aLength : Integer);
begin
 System.SetLength (FArray, aLength);
end;

function _VECTOR_CLASS_.GetItems (const aIndex : Integer) : _VECTOR_DATA_TYPE_;
begin
 Result := FArray [aIndex];
end;

procedure _VECTOR_CLASS_.SetItems (const aIndex : Integer;
                                   const aValue : _VECTOR_DATA_TYPE_);
begin
 FArray [aIndex] := aValue;
end;

function _VECTOR_CLASS_.High : Integer;
begin
 Result := System.High (FArray);
end;

function _VECTOR_CLASS_.Low : Integer;
begin
 Result := System.Low (FArray);
end;

function _VECTOR_CLASS_.GetFirst : _VECTOR_DATA_TYPE_;
begin
 Result := FArray [System.Low (FArray)];
end;

procedure _VECTOR_CLASS_.SetFirst (const aValue : _VECTOR_DATA_TYPE_);
begin
 FArray [System.Low (FArray)] := aValue;
end;

function _VECTOR_CLASS_.GetLast : _VECTOR_DATA_TYPE_;
begin
 Result := FArray [System.High (FArray)];
end;

procedure _VECTOR_CLASS_.SetLast (const aValue : _VECTOR_DATA_TYPE_);
begin
 FArray [System.High (FArray)] := aValue;
end;

function _VECTOR_CLASS_.Clear : _VECTOR_INTERFACE_;
begin
 FArray := Nil;

 Result := Self;
end;

function _VECTOR_CLASS_.Extend (const aDelta : Word) : _VECTOR_INTERFACE_;
begin
 System.SetLength (FArray, System.Length (FArray) + aDelta);

 Result := Self;
end;

function _VECTOR_CLASS_.Contract (const aDelta : Word) : _VECTOR_INTERFACE_;
begin
 System.SetLength (FArray, System.Length (FArray) - aDelta);

 Result := Self;
end;
Шаг 3: Создайте unit файл с именем FloatVectorUnit.pas:

unit FloatVectorUnit;

interface

uses Classes;                           // !!! Модуль "Classes" содержит объявление класса TInterfacedObject

type _VECTOR_DATA_TYPE_ = Double;       // !!! тип данных для класса массива Double

     {$INCLUDE TemplateVectorInterface}

     IFloatVector = _VECTOR_INTERFACE_; // !!! give the interface a meanigful name
     TFloatVector = _VECTOR_CLASS_;     // !!! give the class a meanigful name

function CreateFloatVector (const aLength : Integer = 0) : IFloatVector; // !!! дополнительная функция 

implementation

{$INCLUDE TemplateVectorImplementation}

function CreateFloatVector (const aLength : Integer = 0) : IFloatVector;     
begin
 Result := TFloatVector.Create (aLength);
end;

end.

Естевственно, можно дополнить универсальный класс дополнительными
функциями. Всё зависит от Вашей фантазии!

Использование шаблонов
Вот пример использования нового векторного интерфейса:

procedure TestFloatVector;
 var aFloatVector : IFloatVector;
     aIndex       : Integer;
begin
 aFloatVector := CreateFloatVector;

 aFloatVector.Extend.Last := 1;
 aFloatVector.Extend.Last := 2;

 for aIndex := aFloatVector.Low to aFloatVector.High do
 begin
  WriteLn (FloatToStr (aFloatVector [aIndex]));
 end;
end.

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

Комментарии и вопросы присылайте по адресу rossen_assenov@yahoo.com!

Взято с Исходников.ru



Схемы и возможности


Схемы и возможности



Each function listed below returns information about capabilities or the schema.



DbiOpenCfgInfoList:
Returns a handle to an in-memory table listing all the nodes in the configuration file accessible by
the specified path.

DbiOpenDatabaseList:
Creates an in-memory table containing a list of accessible databases and their descriptions.

DbiOpenDriverList:
Creates an in-memory table containing a list of driver names available to the client application.

DbiOpenFamilyList:
Creates an in-memory table listing the family members associated with a specified table.

DbiOpenFieldList:
Creates an in-memory table listing the fields in a specified table and their descriptions.

DbiOpenFieldTypesList:
Creates an in-memory table containing a list of field types supported by the table type for the driver type.

DbiOpenFunctionArgList:
Returns a list of arguments to a data source function.

DbiOpenFunctionList:
Returns a description of a data source function.

DbiOpenIndexList:
Opens a cursor on an in-memory table listing the indexes on a specified table, along with
their descriptions.

DbiOpenIndexTypesList:
Creates an in-memory table containing a list of all supported index types for the driver type.

DbiOpenLockList:
Creates an in-memory table containing a list of locks acquired on the table.

DbiOpenRintList :
Creates an in-memory table listing the referential integrity links for a specified table, along with
their descriptions.

DbiOpenSecurityList:
Creates an in-memory table listing record-level security information about a specified table.

DbiOpenTableList:
Creates an in-memory table with information about all the tables accessible to the client application.

DbiOpenTableTypesList:
Creates an in-memory table listing table type names for the given driver.

DbiOpenVchkList:
Creates an in-memory table containing records with information about validity checks for fields
within the specified table.


Взято с

Delphi Knowledge Base




Should I install Kylix as root or a regular user?


Should I install Kylix as root or a regular user?



Installing Kylix as root has the advantage of allowing all users to access the Kylix installation, provided you install it into a "shared" location. I reccomend installing Kylix as root into the directory /usr/local/kylix. However, if you are going to be the only user using Kylix, you may want to install it as that user into your home directory.

To install as root, type su from the command prompt and enter the super user password. Then, run the Kylix installer.

Примечание от Vit: обычно при установке от имени root возникает ошибка -10



Симфония на клавиатуре(статья)


Симфония на клавиатуре(статья)



( Перевод одноимённой статьи с сайта delphi.about.com )
Начиная с самого рассвета компьютерной промышленности, клавиатура была первичным устройством ввода информации, и вероятнее всего сохранит свою позицию ещё долгое время.
События клавиатуры, наряду с событиями мыши, являются основными элементами взаимодействия пользователя с программой. В данной статье пойдёт речь о трёх событиях, которые позволяют отлавливать нажатия клавиш в приложении Delphi: OnKeyDown, OnKeyUp и OnKeyPress.
Для получения ввода с клавиатуры, приложения Delphi могут использовать два метода. Самый простой способ, это воспользоваться одним из компонентов, автоматически реагирущем на нажатия клавиш, таким как Edit. Второй способ заключается в создании процедур в форме, которые будут обрабатывать нажатия и отпускания клавиш. Эти обработчики могут обрабатывать как нажатия одиночных клавиш, так и комбинаций. Итак, вот эти события:
OnKeyDown - вызывается, когда на клавиатуре нажимается любая клавиша. OnKeyUp - вызывается, когда любая клавиша на клавиатуре отпускается. OnKeyPress - вызывается, когда нажимается клавиша, отвечающая за определённый ASCII символ.
Теперь самое время посмотреть, как выглядят в программе заголовки обработчиков:

procedure TForm1.FormKeyDown
(Sender: TObject; var Key: Word; Shift: TShiftState);
...
procedure TForm1.FormKeyUp
(Sender: TObject; var Key: Word; Shift: TShiftState);
...
procedure TForm1.FormKeyPress
(Sender: TObject; var Key: Char);

Все события имеют один общий параметр, обычно называемый Key. Этот параметр используется для передачи кода нажатой клавиши. Параметр Shift (в процедурах OnKeyDown и OnKeyUp), указывает на то, была ли нажата клавиша в сочетании с Shift, Alt, и Ctrl.
Фокус
Фокус, это способность получать пользовательский ввод через мышь или клавиатуру. Получать события от клавиатуры могут только те объекты, которые имеют фокус. На форме активного приложения в один момент времени может быть активным (иметь фокус) только один компонент.
Некоторые компоненты, такие как TImage, TPaintBox, TPanel и TLabel не могут получать фокус, другими словами, это компоненты, наследованные от TGraphicControl. Так же не могут получать фокус невидимые компоненты, такие как TTimer.
OnKeyDown, OnKeyUp
События OnKeyDown и OnKeyUp обеспечивают самый низкий уровень ответа клавиатуры. Обработчики OnKeyDown и OnKeyUp могут реагировать на все клавиши клавиатуры, включая функциональные и комбинации с клавишами Shift, Alt, и Ctrl.
События клавиатуры - не взаимоисключающие. Когда пользователь нажимает клавишу, то генерируются два события OnKeyDown и OnKeyPress, а когда отпускает, то только одно: OnKeyUp. Если пользователь нажмёт одну из клавиш, которую OnKeyPress не сможет определить, то будет сгенерировано только одно событие OnKeyDown, а при отпускании OnKeyUp.
OnKeyPress
OnKeyPress возвращает различные значения ASCII для 'g' и 'G,'. Однако, OnKeyDown и OnKeyUp не делают различия между верхним и нижним регистром.
Параметры Key и Shift
Параметр Key можно изменять, чтобы приложение получило другой код нажатой клавиши. Таким образом можно ограничивать набор различных символов, которые пользователь может ввести с клавиатуры. Например разрешить вводить только цифры. Для этого добавьте в обработчик события OnKeyPress следующий код и установите KeyPreview в True (см. ниже).

if Key in ['a'..'z'] + ['A'..'Z'] then Key:=#0

Это выражение проверяет, содержит ли параметр Key символы нижнего регистра ('a'..'z') и символы верхнего регистра ('A'..'Z'). Если так, то в параметр заносится значение нуля, чтобы предотвратить ввод в компонент Edit (например).
В Windows определены специальные константы для каждой клавиши. Например, VK_RIGHT соответствует коду клавиши для правой стрелки.
Чтобы получить состояния специальных клавиш, таких как TAB или PageUp можно воспользоваться API функцией GetKeyState. Клавиши состояния могут находиться в трёх состояниях: отпущена, нажата, и включена. Если старший бит равен 1, то клавиша нажата, иначе отпущена. Для проверки этого бита можно воспользоваться API функцией HiWord. Если младший бит равен 1, то клавиша включена. Вот пример получения сосотояния специальной клавиши:

if HiWord(GetKeyState(vk_PageUp)) <> 0 then
  ShowMessage('PageUp - DOWN')
else
  ShowMessage('PageUp - UP');

В событиях OnKeyDown и OnKeyUp, Key является беззнаковым двухбайтовым (Word) значением, которое представляет виртуальную клавишу Windows. Для получания значения символа можно воспользоваться функцией Chr. В событии OnKeyPress параметр Key является значением Char, которое представляет символ ASCII.
События OnKeyDown и OnKeyUp имеют параметр Shift с типом TShiftState. В Delphi тип TShiftState определён как набор флагов, определяющих состояние Alt, Ctrl, и Shift при нажатии клавиши.
Например, следующий код (из обработчика OnKeyUp) соединяет строку 'Ctrl +' с нажатой клавишей и отображает результат в заголовке формы:

if ssCtrl in Shift then
  Form1.Caption:= 'Ctrl +' + Chr(Key);

Если нажать Ctrl + A, то будут сгенерированы следующие события:

KeyDown (Ctrl) // ssCtrl
KeyDown (Ctrl+A) //ssCtrl + 'A'
KeyPress (A) 
KeyUp (Ctrl+A)

Переадресация событий клавиатуры в форму
Клавиатурный обработчик может работать на двух уровнях: на уровне компонентов и на уровне формы. Свойство формы KeyPreview определяет, будут ли клавиатурные события формы вызываться перед клавиатурными событиями компонентов, так как форма может получать все нажатия клавиш, предназначенные для компонента имеющего в данный момент фокус.
Чтобы перехватить нажатия клавиш на уровне формы, до того как они будут переданы компонентам на форме, необходимо установить свойство KeyPreview в True. После этого компонент как и раньше будет получать события, однако сперва они будут попадать в форму, чтобы дать возможность программе разрешить или запретить ввод различных символов.
Допустим, У Вас на форме есть несколько компонентов Edit и процедура Form.OnKeyPress выглядит следующим образом:

procedure TForm1.FormKeyPress
(Sender: TObject; var Key: Char);
begin
 if Key in ['0'..'9'] then Key := #0
end;

Если один из компонентов Edit имеет фокус и свойство KeyPreview установлено в False, то этот код не будет выполнен - другими словами, если пользователь нажмёт клавишу '5', то в компоненте Edit, имеющем фокус, появится символ "5".
Однако, если KeyPreview установлено в True, то событие формы OnKeyPress будет выполнено до того, как компонент Edit увидит нажатую клавишу. Поэтому, если пользователь нажмёт клавишу '5', то в Key будет подставлено нулевое значение, предотвращая тем самым попадание числовых символов в Edit.

ПРИЛОЖЕНИЕ: Таблица кодов виртуальных клавиш.

Symbolic
constant name Value
(hexadecimal) Keyboard (or mouse) equivalent VK_LBUTTON 01 Left mouse button VK_RBUTTON 02 Right mouse button VK_CANCEL 03 Control-break processing VK_MBUTTON 04 Middle mouse button (three-button mouse) VK_BACK 08 BACKSPACE key VK_TAB 09 TAB key VK_CLEAR 0C CLEAR key VK_RETURN 0D ENTER key VK_SHIFT 10 SHIFT key VK_CONTROL 11 CTRL key VK_MENU 12 ALT key VK_PAUSE 13 PAUSE key VK_CAPITAL 14 CAPS LOCK key VK_ESCAPE 1B ESC key VK_SPACE 20 SPACEBAR VK_PRIOR 21 PAGE UP key VK_NEXT 22 PAGE DOWN key VK_END 23 END key VK_HOME 24 HOME key VK_LEFT 25 LEFT ARROW key VK_UP 26 UP ARROW key VK_RIGHT 27 RIGHT ARROW key VK_DOWN 28 DOWN ARROW key VK_SELECT 29 SELECT key VK_PRINT 2A PRINT key VK_EXECUTE 2B EXECUTE key VK_SNAPSHOT 2C PRINT SCREEN key VK_INSERT 2D INS key VK_DELETE 2E DEL key VK_HELP 2F HELP key   30 0 key   31 1 key   32 2 key   33 3 key   34 4 key   35 5 key   36 6 key   37 7 key   38 8 key   39 9 key   41 A key   42 B key   43 C key   44 D key   45 E key   46 F key   47 G key   48 H key   49 I key   4A J key   4B K key   4C L key   4D M key   4E N key   4F O key   50 P key   51 Q key   52 R key   53 S key   54 T key   55 U key   56 V key   57 W key   58 X key   59 Y key   5A Z key VK_NUMPAD0 60 Numeric keypad 0 key VK_NUMPAD1 61 Numeric keypad 1 key VK_NUMPAD2 62 Numeric keypad 2 key VK_NUMPAD3 63 Numeric keypad 3 key VK_NUMPAD4 64 Numeric keypad 4 key VK_NUMPAD5 65 Numeric keypad 5 key VK_NUMPAD6 66 Numeric keypad 6 key VK_NUMPAD7 67 Numeric keypad 7 key VK_NUMPAD8 68 Numeric keypad 8 key VK_NUMPAD9 69 Numeric keypad 9 key VK_SEPARATOR 6C Separator key VK_SUBTRACT 6D Subtract key VK_DECIMAL 6E Decimal key VK_DIVIDE 6F Divide key VK_F1 70 F1 key VK_F2 71 F2 key VK_F3 72 F3 key VK_F4 73 F4 key VK_F5 74 F5 key VK_F6 75 F6 key VK_F7 76 F7 key VK_F8 77 F8 key VK_F9 78 F9 key VK_F10 79 F10 key VK_F11 7A F11 key VK_F12 7B F12 key VK_F13 7C F13 key VK_F14 7D F14 key VK_F15 7E F15 key VK_F16 7F F16 key VK_F17 80H F17 key VK_F18 81H F18 key VK_F19 82H F19 key VK_F20 83H F20 key VK_F21 84H F21 key VK_F22 85H F22 key VK_F23 86H F23 key VK_F24 87H F24 key VK_NUMLOCK 90 NUM LOCK key VK_SCROLL 91 SCROLL LOCK key VK_LSHIFT A0 Left SHIFT key VK_RSHIFT A1 Right SHIFT key VK_LCONTROL A2 Left CONTROL key VK_RCONTROL A3 Right CONTROL key VK_LMENU A4 Left MENU key VK_RMENU A5 Right MENU key VK_PLAY FA Play key VK_ZOOM FB Zoom key
Взято с Исходников.ru



Символы разного цвета в StringGrid


Символы разного цвета в StringGrid



Ниже представлен юнит, который позволяет поместить текст в String Grid с символами различного цвета:

unit Strgr;

interface

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

type
  TForm1 = class(TForm)
    StringGrid1: TStringGrid;
    procedure StringGrid1DrawCell(Sender: TObject; Col, Row: Longint;
      Rect: TRect; State: TGridDrawState);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.StringGrid1DrawCell(Sender: TObject; Col, Row: Longint;
  Rect: TRect; State: TGridDrawState);
const
  CharOffset = 3;
begin
  with StringGrid1.canvas do
  begin
    font.color := clMaroon;
    textout(rect.left + CharOffset, rect.top + CharOffset, 'L');
      font.color := clNavy;
    textout(rect.left + CharOffset + TextWidth('L'),
      rect.top + CharOffset, 'loyd');
  end;
end;

end.

Взято с Исходников.ru



Синхронизация двух компонентов ScrollBox


Синхронизация двух компонентов ScrollBox




Решить задачу помогут обработчики событий OnScroll (в данном примере два компонента ScrollBox (ScrollBar1 и ScrollBar2) расположены на форме TMainForm):



procedureTMainForm.ScrollBar1Scroll(Sender: TObject;
ScrollCode: TScrollCode; var ScrollPos: Integer);
begin
  ScrollBar2.Position:=ScrollPos;
end;

procedure TMainForm.ScrollBar2Scroll(Sender: TObject;
ScrollCode: TScrollCode; var ScrollPos: Integer);
begin
  ScrollBar1.Position := ScrollPos;
end;




Взято с





Синтаксис SQL-функции Substring


Синтаксис SQL-функции Substring





SUBSTRING('DelphiWorld - это супер!!!' from 1 to 6)


Взято из





Системная дата и время


Системная дата и время


Cодержание раздела:







См. также статьи в других разделах:





Системные функции и WinAPI


Системные функции и WinAPI


Cодержание раздела:


·

(раздел)

·

(раздел)

·

(раздел)

·

(раздел)

·

(раздел)

·

(раздел)

·

(раздел)

·

(раздел)

·

(раздел)

·

(раздел)

·

(раздел)



·

(раздел)

·

(раздел)

·

(раздел)

·

(раздел)

·

(раздел)

·

(раздел)

·

(раздел)

·

(раздел)

·

(раздел)

·

(раздел)

·

(раздел)

·

(раздел)

·

(раздел)

·

(раздел)

·

(раздел)

·

(раздел)

·

(раздел)

·

(раздел)

·

(раздел)

·

(раздел)

·

(раздел)

·

(раздел)

·

(раздел)

·

(раздел)

·

(раздел)

·

(раздел)

·

(раздел)

·

(раздел)

·

(раздел)

·

(раздел)

·

(раздел)





Системные папки, имя компьютера


Системные папки, имя компьютера



Cодержание раздела:









См. также статьи в других разделах:






Системные сообщения (сокращения)


Системные сообщения (сокращения)




BM  - ButtonMode
BN  - Button
BS  - ButtonStyle
CB  - ComboBox
CBN - Combo Box Notifications
CBS - ComboBoxStyle
EM  - EditMessage
ES  - EditStyle
FM  - FileManager
LB  - ListBox
LBN - ListBox Notifications
LBS - ListBoxStyle
MB  - MessageButton (Typen)
PS  - PenStyle
SB  - ScrollBar
SBS - ScrollBarStyle
SM  - SystemMetrics
SPI - SystemParametersInfo
WM  - WindowMessage
WS  - WindowStyle




Сканирование доменов локальной сети


Сканирование доменов локальной сети





Переменная List заполняется списком доменов. Функция возвращает код ошибки обращения к сети.

Function FillNetLevel(xxx: PNetResource; list: TStrings) : Word;
Type
    PNRArr = ^TNRArr;
    TNRArr = array[0..59] of TNetResource;
Var
   x: PNRArr;
   tnr: TNetResource;
   I : integer;
   EntrReq,
   SizeReq,
   twx: Integer;
   WSName: string;
begin
     Result := WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_ANY,
                                RESOURCEUSAGE_CONTAINER, xxx, twx);
     If Result = ERROR_NO_NETWORK Then Exit;
     if Result = NO_ERROR then
     begin
            New(x);
            EntrReq := 1;
            SizeReq := SizeOf(TNetResource)*59;
            while (twx <> 0) and 
                  (WNetEnumResource(twx, EntrReq, x, SizeReq) <> ERROR_NO_MORE_ITEMS) do
            begin
                  For i := 0 To EntrReq - 1 do
                  begin
                   Move(x^[i], tnr, SizeOf(tnr));
                   case tnr.dwDisplayType of
                    RESOURCEDISPLAYTYPE_DOMAIN:
                    begin
                       if tnr.lpRemoteName <> '' then
                           WSName:= tnr.lpRemoteName
                           else WSName:= tnr.lpComment;
                       list.Add(WSName);
                    end;
                    else FillNetLevel(@tnr, list);
                   end;
                  end;
            end;
            Dispose(x);
            WNetCloseEnum(twx);
     end;
end;

Источник: 



Сколько открыто дочерних окон?


Сколько открыто дочерних окон?





Form1.MDIChildCount


Закрыть все окна:

withForm1 do 
  for I := 0 to MDIChildCount-1 
    do MDIChildren[I].Close;


Взято с





Скорость работы процессора, точный таймер


Скорость работы процессора, точный таймер



Данная тема уже обсуждалась, но у меня есть своя реализация сабжа. Начиная с Pentium MMX, Intel ввели в процессор счетчик тактов на 64 бита (Присутствует точно и в К6). Для того чтобы посмотреть на его содержание, была введена команда "rdtsc" (подробное описание в интеловской мануале). Эту возможность можно использовать для реализации сабжа.
Поскольку Дельфи не в курсе насчет rdtsc, то пришлось юзать опкод (0F31).
Привожу простенький примерчик юзания, Вы уж извините - немножко кривоват получился, да и ошибка компилятора какая-то вылезла :( (V4 Bld5.104 Upd 2). Кому интересно, поделитесь своими соображениями по этому поводу. Особенно интересует работа в режиме когда меняется частота процессора (Duty Cycle, Standby).


// (C) 1999 ISV
unit Unit1;interfaceuses  Windows, Messages, SysUtils, Classes, Graphics,
 Controls, Forms,Dialogs,  StdCtrls, Buttons, ExtCtrls;
type  TForm1 = class(TForm)
    Label1: TLabel;
    Timer1: TTimer;
    Label2: TLabel;
    Label3: TLabel;
    Button1: TButton;
    Button2: TButton;
    Label4: TLabel;
    procedure Timer1Timer(Sender: TObject);
    procedure FormActivate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private    
{ Private declarations }
  public    
{ Public declarations }
    Counter:integer;
      //Счетчик срабатывания таймера    
Start:int64;              
//Начало роботы    
Previous:int64;        
//Предыдущее значение    
PStart,PStop:int64;
 //Для примера выч. времени   
 CurRate:integer;
     //Текущая частота проца    
function GetCPUClick:int64;    
function GetTime(Start,Stop:int64):double;
 end;
var  Form1: TForm1;implementation{$R *.DFM}
// Функция работает на пнях ММХ или выше а
// также проверялась на К6
function TForm1.GetCPUClick:int64;
begin
  asm    db  0fh,31h   
// Опкод для команды rdtsc    mov dword ptr result,eax    mov dword ptr result[4],edx  
end;
// Не смешно :(. Без ?той штуки
// Компайлер выдает Internal error C1079  
Result:=Result;
end;
// Время в секундах между старт и стоп
function TForm1.GetTime(Start,Stop:int64):double;
begin
  try    result:=(Stop-Start)/CurRate  except    result:=0;
 end;
end;
// Обработчик таймера считает текущую частоту, выводит ее, а также
// усредненную частоту, текущий такт с момента старта процессора.
// При постоянной частоте процессора желательно интервал братьпобольше
// 1-5с для точного прощета частоты процессора.
procedure TForm1.Timer1Timer(Sender: TObject);
  var    i:int64;
begin
  i:=GetCPUClick;
  if Counter=0    then Start:=i    else 
begin
      Label2.Caption:=Format('Частота общая:%2f',[(i-Start)/(Counter*Timer1.Interval*1000)]);
      Label3.Caption:=Format('Частота текущая:%2f',[(i-Previous)/(Timer1.Interval*1000)]);
      CurRate:=Round(((i-Previous)*1000)/(Timer1.Interval));
    end;
  Label1.Cap примера
procedure TForm1.Button1Click(Sender: TObject);
begin
  PStart:=GetCPUClick;
end;
// Останавливаем отсчет времени и показуем соко
// прошло секунд
procedure TForm1.Button2Click(Sender: TObject);
begin
  PStop:=GetCPUClick;
  Label4.Caption:=Format!
('Время между нажатиями:%gсек',[GetTime(PStart,PStop)])
end;
end.

Взято с сайта



Скрытые настройки Дельфи


Скрытые настройки Дельфи





Some undocumented registry settings of Delphi 5 (which -slightly adapted- might also work with Delphi 4 and below) modify the behavior of the Delphi component palette in a manner you may like!
Most values are stored as strings, and boolean values are represented as "1" for true and "0" for false. All values are stored in

HKEY_CURRENT_USER

As always, use of this information is at your own risk... ;-)

Software\Borland\Delphi\5.0\Extras\AutoPaletteSelect

will cause a tab on the component palette to be automatically selected when the mouse is hovering over it. If the mouse is in the top two- thirds (2/3) of the tab, the palette for that tab will automatically be displayed.

Software\Borland\Delphi\5.0\Extras\AutoPaletteScroll

will make you scroll left and right automatically whenever the mouse is positioned over the relevant arrow.

Software\Borland\Delphi\5.0\Editor\Options\NoCtrlAltKeys

Disables menu item Ctrl+Alt key sequences for international keyboards

Software\Borland\Delphi\5.0\Form Design\AlwaysEnableMiddleEast

Forces Right-to-Left text in the form designer (?)

Software\Borland\Delphi\5.0\Extras\FontNamePropertyDisplayFontNames

Display the fonts in the object inspector dropdown in the font's actual style (slow with many fonts installed). See also DsgnIntf.FontNamePropertyDisplayFontNames in D5.

Software\Borland\Delphi\5.0\Compiling\ShowCodeInsiteErrors

Show compilation errors found by CodeInsite in the message view window

Software\Borland\Delphi\5.0\Globals\PropValueColor

Fill in with a string like "clGreen" to change the color of the right half (properties) of the Object Inspector.

Software\Borland\Delphi\5.0\Disabled Packages

This is the place you put Delphi Direct :)

Software\Borland\Delphi\5.0\Globals\TwoDigitYearCenturyWindow

Default value for TwoDigitYearCenturyWindow (see the help file)

Software\Borland\Delphi\5.0\Component Templates\CCLibDir

Alternative component templates directory (shared/network)

Software\Borland\Delphi\5.0\FormDesign\DefaultFont="Arial,8" [D4] or "Arial,8,Bold" [D5]

The default for new forms (you might prefer using the repository's default form checkbox instead)

Software\Borland\Delphi\5.0\Wizards

Alternate key to store Expert/Wizard DLLs to load at startup

Software\Borland\Delphi\5.0\Debugging\DontPromptForJITDebugger

Don't ask to change the current JIT debugger (?)

Software\Borland\Delphi\5.0\Version Control\VCSManager

The DLL used for the version control interface in the IDE.

Software\Borland\Delphi\5.0\Globals\PrivateDir

A way to specify an alternative directory for the location for the Delphi configuration files when running the application from a network drive or the CD-ROM.

Software\Borland\Delphi\5.0\Main Window\Palette Visible
Software\Borland\Delphi\5.0\Main Window\Speedbar Visible
Software\Borland\Delphi\5.0\Main Window\Palette Hints
Software\Borland\Delphi\5.0\Main Window\Speedbar Hints
Software\Borland\Delphi\5.0\Main Window\Split Position

These seem to have no effect at runtime, but are read by the IDE. The actually used values come from

HKEY_CURRENT_USER\Software\Borland\Delphi\5.0\Toolbars

Software\Borland\Delphi\5.0\ProjectManager\Dockable
Software\Borland\Delphi\5.0\PropertyInspector\Dockable
Software\Borland\Delphi\5.0\CallStackWindow\Dockable
Software\Borland\Delphi\5.0\ModuleWindow\Dockable

Read but unused settings. Used values come from DSK files.

There are lots of other interesting registry keys that aren't modifiable in the IDE, but they all have values written by default, so you can find and play with them much easier.

Взято с

Delphi Knowledge Base






Смена свойств приложения, открываемого, по умолчанию в среде при её запуске


Смена свойств приложения, открываемого, по умолчанию в среде при её запуске



Большинство стандартных темплейтов зашиты в delphide70.bpl (70 - версия), остальные - в каталоге Objrepos. Описаны же последние в файле bin\delphi32.dro. Т.о:
1. Добавляем в "delphi32.dro" строки:

[C:\ProgramFiles\Lang\Delphi7\ObjRepos\MyApp\MyApp]
Type=ProjectTemplate
Page=Projects
Name=My Application
Description=This is my application template
Author=Eugene
Icon=C:\Program Files\Lang\Delphi7\ObjRepos\MyApp\MyApp.ico
DefaultProject=1
Designer=dfm

(для темплейтов формы Type=FormTemplate, DefaultMainForm=0/1, DefaultNewForm=0/1)
2. Размещаем нашу темплейт-прогу в каталоге "C:\Program Files\Lang\Delphi7\ObjRepos\MyApp\" и называем её "MyApp.dpr".
3. Жмём "File/New/Application" (т.к. у нас DefaultProject=1), либо заходим во вкладку "Projects", а затем кликаем два раза по "My Application".
4. Радуемся!

Автор:

Jin X   

Взято из





Смешиваем два цвета.


Смешиваем два цвета.



Самый простой способ смешать два цвета c1 и c2, это вычислить средние значения rgb-значений. Данный пример не отличается особой быстротой, поэтому если Вам нужно быстро смешивать цвета, то прийдётся пошевелить мозгами...

function GetMixColor (c1, c2: TColor): TColor;
begin
  // вычисляем средние значения Красного, Синего и Зелёного значений
  // цветов c1 и c2:
  Result := RGB (
                  (GetRValue (c1) + GetRValue (c2)) div 2,
                  (GetGValue (c1) + GetGValue (c2)) div 2,
                  (GetBValue (c1) + GetBValue (c2)) div 2
                );
end;

Взято с Исходников.ru



Собираем тестовый пример


Собираем тестовый пример



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

В начале код dll c объектом.

library CalcDll;

uses
  SysUtils,
  Classes;

type

 HResult=Longint;

 ICalcBase=interface                      //чисто абстрактный интерфейс
   procedure SetOperands(x,y:integer);
   procedure Release;
 end;

 ICalc=interface(ICalcBase)
   ['{149D0FC0-43FE-11D6-A1F0-444553540000}']
   function Sum:integer;
   function Diff:integer;
 end;

 ICalc2=interface(ICalcBase)
   ['{D79C6DC0-44B9-11D6-A1F0-444553540000}']
   function Mult:integer;
   function Divide:integer;
 end;

 MyCalc=class(TObject,ICalc,ICalc2)  //два интерфейса
   fx,fy:integer;
 public
   procedure SetOperands(x,y:integer);
   function Sum:integer;
   function Diff:integer;
   function Divide:integer;
   function Mult:integer;
   procedure Release;
   function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
   function _AddRef:Longint; stdcall;
   function _Release:Longint; stdcall;
 end;

const
 S_OK = 0;
 E_NOINTERFACE = HRESULT($80004002);

procedure MyCalc.SetOperands(x,y:integer);
begin
 fx:=x; fy:=y;
end;

function MyCalc.Sum:integer;
begin
  result:=fx+fy;
end;

function MyCalc.Diff:integer;
begin
  result:=fx-fy;
end;

function MyCalc.Divide:integer;
begin
  result:=fx div fy;
end;

function MyCalc.Mult:integer;
begin
  result:=fx*fy;
end;

procedure MyCalc.Release;
begin
 Free;
end;

function MyCalc.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
  if GetInterface(IID, Obj) then
    Result := S_OK
  else
    Result := E_NOINTERFACE;
end;

function MyCalc._AddRef;
begin
end;

function MyCalc._Release;
begin
end;

procedure CreateObject(const IID: TGUID; var ACalc);
var
 Calc:MyCalc;
begin
 Calc:=MyCalc.Create;
 if not Calc.GetInterface(IID,ACalc) then
  Calc.Free;
end;

exports
 CreateObject;

begin
end.

А теперь тестер.

unit tstcl;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls,ComObj;

type

 //обратите внимание! Используем один унифицированный интерфейс
  IUniCalc=interface   
    procedure SetOperands(x,y:integer);
    procedure Release;
    function Sum:integer;
    function Diff:integer;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  end;

var
  Form1: TForm1;
  _Mod:Integer;  //хэндл модуля
  СreateObject:procedure (IID:TGUID; out Obj); //процедура из dll.

  Calc:IUniCalc;        //это указатель на интерфейс котрый мы будем получать
  ICalcGUID:TGUID;   
  ICalc2GUID:TGUID; 
  flag:boolean;         // какой интерфейс активный.

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
  _Mod:=LoadLibrary(PChar('C:\Kir\COM\SymplDll\CalcDll.dll'));

  //Эти GUID я просто скопировал из исходника CalcDll.dll
  ICalcGUID:=StringToGUID('{149D0FC0-43FE-11D6-A1F0-444553540000}');
  ICalc2GUID:=StringToGUID('{D79C6DC0-44B9-11D6-A1F0-444553540000}');
  flag:=true;

  СreateObject:=GetProcAddress(_Mod,'CreateObject');

  СreateObject(ICalcGUID,Calc);
  if Calc<>nil then
    Calc.SetOperands(10,5);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  if Calc<>nil then
   Calc.Release;
  FreeLibrary(_Mod);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
   ShowMessage(IntToStr(Calc.diff));
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
   ShowMessage(IntToStr(Calc.Sum));
end;

procedure TForm1.Button3Click(Sender: TObject);
var
   tmpCalc:IUniCalc;
begin
   if flag then
     Calc.QueryInterface(ICalc2GUID,tmpCalc)
   else
     Calc.QueryInterface(ICalcGUID,tmpCalc);
   flag:=not flag;  
   Calc:=tmpCalc;
end;

end.

Обратите вснимание, что происходит при нажатии на кнопку3. Мы используем ту же самую переменную, для работы со вторым интерфейсом! Этот пример показывает, что получая указатель на интерфейс, его методы мы получаем за счет смещения, от адреса который этот указатель содержит. Короче, мы получаем адрес таблицы методов.
Потыкайте, посмотрите что происходит.




События, происходящие в приложениях Delphi при завершении работы Windows


События, происходящие в приложениях Delphi при завершении работы Windows



Я провел небольшое исследование, и вот что я выяснил:
При закрытии приложения (используя системное меню или вызывая метод закрытия формы), возникают следующие события:
FormCloseQuery - действие по умолчанию, устанавливает переменную CanClose в значание TRUE и продолжает закрытие формы.  
FormClose  
FormDestroy  
Если приложение активно и вы пытаетесь завершить работу Windows (Shut Down), происходят следующие события (с соблюдением последовательности):
FormCloseQuery  
FormDestroy  
Мы видим, что метод FormClose в этом случае не вызывается.
Теперь воспроизведем всю последовательность событий, происходящую при попытке завершить работу Windows:
Windows посылает сообщение WM_QUERYENDSESSION всем приложениям и ожидает ответ.  
Каждое приложение получает сообщение и возвращает одну из величин: не равную нулю - приложение готово завершить свою работу, 0 - приложение не может завершить свою работу.  
Если одно из приложений возвращает 0, Windows не завершает свою работу, а снова рассылает всем окнам сообщение, на этот раз WM_ENDSESSION.  
Каждое приложение должно снова подтвердить свою готовность завершить работу, поэтому операционная система ожидает ответа TRUE, резонно предполагая, что оставшиеся приложения с момента предыдущего сообщения закрыли свои сессии и готовы завершить работу. Теперь посмотрим, как на это реагирует Delphi-приложение: приложение возвращает значение TRUE и немедленно вызывает метод FormDestroy, игнорируя при этом метод FormClose. Налицо проблема.  
Завершение работы Windows.  
Первое решение проблемы: приложение Delphi на сообщение WM_QUERYENDSESSION должно возвратить 0, не дав при этом Windows завершить свою работу. При этом бессмысленно пытаться воспользоваться методом FormCloseQuery, поскольку нет возможности определить виновника завершения работы приложения (это может являться как результатом сообщения WM_QUERYENDSESSION, так и просто действием пользователя при попытке закрыть приложение).
Другое решение состоит в том, чтобы при получении сообщения WM_QUERYENDSESSION самим выполнить необходимые действия, вызвав метод FormClose.

unit Unit1;
interface
uses
  SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls, Forms,
  Dialogs;
type
  TForm1 = class(TForm)
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
{--------------------------------------------------------}
{ Объявляем свой обработчик сообщения WM_QUERYENDSESSION }
{--------------------------------------------------------}
    procedure WMQueryEndSession(
      var Message: TWMQueryEndSession); message WM_QUERYENDSESSION;
  public
{ Public declarations }
  end;
var
  Form1: TForm1;

implementation
{$R *.DFM}

{--------------------------------------------------------------}
{ Создаем процедуру обработки сообщения WM_QUERYENDSESSION. }
{ Приложение получит только это сообщение при попытке Windows }
{ завершить работу }
{--------------------------------------------------------------}

procedure TForm1.WMQueryEndSession(var Message: TWMQueryEndSession);
begin
  inherited; { сначала сообщание должен обработать наследуемый метод }
{--------------------------------------------------------------------}
{ в этой точке вы также можете сообщить Windows о неготовности }
{ приложения завершить работу... }
{ Message.Result:=0; }
{-------------------------------------------или----------------------}
{ вызов процедуры освобождения ресурсов, предусмотренной в FormClose }
{ MyCleanUpProcedure; }
{--------------------------------------------------------------------}
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  MyCleanUpProcedure;
end;

end.

Взято с Исходников.ru



Соединение с интернетом


Соединение с интернетом



Cодержание раздела:






См. также другие разделы:





Сохранение и чтение файлов в BLOB-полях


Сохранение и чтение файлов в BLOB-полях




//Сохраняем
procedure TForm1.Button1Click(Sender: TObject); 
var 
  blob: TBlobStream; 
begin 
  blob := yourDataset.CreateBlobStream(yourDataset.FieldByName('YOUR_BLOB'), bmWrite); 
  try 
    blob.Seek(0, soFromBeginning); 
    fs := TFileStream.Create('c:\your_name.doc', fmOpenRead or 
      fmShareDenyWrite); 
    try 
      blob.CopyFrom(fs, fs.Size) 
    finally 
      fs.Free 
    end; 
  finally 
    blob.Free 
  end; 
end;

// Загружаем
procedure TForm1.Button1Click(Sender: TObject); 
var 
  blob: TBlobStream; 
begin 
  blob := yourDataset.CreateBlobStream(yourDataset.FieldByName('YOUR_BLOB'), bmRead); 
  try 
    blob.Seek(0, soFromBeginning); 

    with TFileStream.Create('c:\your_name.doc', fmCreate) do 
      try 
        CopyFrom(blob, blob.Size) 
      finally 
        Free 
      end; 
  finally 
    blob.Free 
  end; 
end;


Взято из





Сохранение и выдёргивание ресурсов в DLL или EXE?


Сохранение и выдёргивание ресурсов в DLL или EXE?



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

Далее рассмотрим, как создать файл ресурсов, содержащий корию какого-либо файла. После создания такого файла его можно легко прицепить к Вашему проекту директивой {$R}. Файл ресурсов, который мы будем создавать имеет следующий формат:

+ заголовок
+ заголовок для нашего RCDATA ресурса
+ собственно данные - RCDATA ресурс

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

Заголовок ресурса выглядит следующим образом:

TResHeader = record 
  DataSize: DWORD;        // размер данных       
  HeaderSize: DWORD;      // размер этой записи 
  ResType: DWORD;         // нижнее слово = $FFFF => ordinal 
  ResId: DWORD;           // нижнее слово = $FFFF => ordinal 
  DataVersion: DWORD;     // * 
  MemoryFlags: WORD; 
  LanguageId: WORD;       // * 
  Version: DWORD;         // * 
  Characteristics: DWORD; // * 
end; 

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

Приведённый код создаёт файл ресурсов и копирует его в данный файл:

procedure CreateResourceFile( 
  DataFile, ResFile: string;  // имена файлов 
  ResID: Integer              // id ресурсов 
); 
var 
  FS, RS: TFileStream; 
  FileHeader, ResHeader: TResHeader; 
  Padding: array[0..SizeOf(DWORD)-1] of Byte; 
begin 

  { Open input file and create resource file } 
  FS := TFileStream.Create(  // для чтения данных из файла
    DataFile, fmOpenRead); 
  RS := TFileStream.Create(  // для записи файла ресурсов 
    ResFile, fmCreate); 

  { Создаём заголовок файла ресурсов - все нули, за исключением 
    HeaderSize, ResType и ResID } 
  FillChar(FileHeader, SizeOf(FileHeader), #0); 
  FileHeader.HeaderSize := SizeOf(FileHeader); 
  FileHeader.ResId := $0000FFFF; 
  FileHeader.ResType := $0000FFFF; 

  { Создаём заголовок данных для RC_DATA файла 
    Внимание: для создания более одного ресурса необходимо 
    повторить следующий процесс, используя каждый раз различные 
    ID ресурсов } 
  FillChar(ResHeader, SizeOf(ResHeader), #0); 
  ResHeader.HeaderSize := SizeOf(ResHeader); 
  // id ресурса - FFFF означает "не строка!" 
  ResHeader.ResId := $0000FFFF or (ResId shl 16); 
  // тип ресурса - RT_RCDATA (from Windows unit) 
  ResHeader.ResType := $0000FFFF 
    or (WORD(RT_RCDATA) shl 16); 
  // размер данных - есть размер файла 
  ResHeader.DataSize := FS.Size; 
  // Устанавливаем необходимые флаги памяти 
  ResHeader.MemoryFlags := $0030; 

  { Записываем заголовки в файл ресурсов } 
  RS.WriteBuffer(FileHeader, sizeof(FileHeader)); 
  RS.WriteBuffer(ResHeader, sizeof(ResHeader)); 

  { Копируем файл в ресурс } 
  RS.CopyFrom(FS, FS.Size); 

  { Pad data out to DWORD boundary - any old 
    rubbish will do!} 
  if FS.Size mod SizeOf(DWORD) <> 0 then 
    RS.WriteBuffer(Padding, SizeOf(DWORD) - 
      FS.Size mod SizeOf(DWORD)); 

  { закрываем файлы } 
  FS.Free; 
  RS.Free; 
end; 

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



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

Вся процедура заключается в создании потока ресурса, создании файлового потока и копировании из потока ресурса в поток файла.

procedure ExtractToFile(Instance:THandle; ResID:Integer; ResType, FileName:String); 
var 
  ResStream: TResourceStream; 
  FileStream: TFileStream; 
begin 
  try 
    ResStream := TResourceStream.CreateFromID(Instance, ResID, pChar(ResType)); 
    try 
      //if FileExists(FileName) then 
        //DeleteFile(pChar(FileName)); 
      FileStream := TFileStream.Create(FileName, fmCreate); 
      try 
        FileStream.CopyFrom(ResStream, 0); 
      finally 
        FileStream.Free; 
      end; 
    finally 
      ResStream.Free; 
    end; 
  except 
    on E:Exception do 
    begin 
      DeleteFile(FileName); 
      raise; 
    end; 
  end; 
end; 

Всё, что требуется, это получить Instance exe-шника или dll (у Вашего приложения это Application.Instance или Application.Handle, для dll Вам прийдётся получить его самостоятельно :)

ResID тот же самый ID , который был присвоен ресурсу

ResType WAVEFILE, BITMAP, CURSOR, CUSTOM - это типы ресурсов, с которыми возможно работать, но у меня получилось успешно проделать процедуру только с CUSTOM

FileName - это имя файла, который мы хотим создать из ресурса


Взято с Исходников.ru




Сохранение параметров шрифта в INI-файле


Сохранение параметров шрифта в INI-файле




functionFontToStr(font: TFont): string;
  procedure yes(var str: string);
  begin

    str := str + 'y';
  end;
  procedure no(var str: string);
  begin

    str := str + 'n';
  end;
begin

  {кодируем все атрибуты TFont в строку}
  Result := '';
  Result := Result + IntToStr(font.Color) + '|';
  Result := Result + IntToStr(font.Height) + '|';
  Result := Result + font.Name + '|';
  Result := Result + IntToStr(Ord(font.Pitch)) + '|';
  Result := Result + IntToStr(font.PixelsPerInch) + '|';
  Result := Result + IntToStr(font.size) + '|';
  if fsBold in font.style then
    yes(Result)
  else
    no(Result);
  if fsItalic in font.style then
    yes(Result)
  else
    no(Result);
  if fsUnderline in font.style then
    yes(Result)
  else
    no(Result);
  if fsStrikeout in font.style then
    yes(Result)
  else
    no(Result);
end;

procedure StrToFont(str: string; font: TFont);
begin

  if str = '' then
    Exit;
  font.Color := StrToInt(tok('|', str));
  font.Height := StrToInt(tok('|', str));
  font.Name := tok('|', str);
  font.Pitch := TFontPitch(StrToInt(tok('|', str)));
  font.PixelsPerInch := StrToInt(tok('|', str));
  font.Size := StrToInt(tok('|', str));
  font.Style := [];
  if str[0] = 'y' then
    font.Style := font.Style + [fsBold];
  if str[1] = 'y' then
    font.Style := font.Style + [fsItalic];
  if str[2] = 'y' then
    font.Style := font.Style + [fsUnderline];
  if str[3] = 'y' then
    font.Style := font.Style + [fsStrikeout];
end;

function tok(sep: string; var s: string): string;

  function isoneof(c, s: string): Boolean;
  var
    iTmp: integer;
  begin
    Result := False;
    for iTmp := 1 to Length(s) do
    begin
      if c = Copy(s, iTmp, 1) then
      begin
        Result := True;
        Exit;
      end;
    end;
  end;
var

  c, t: string;
begin

  if s = '' then
  begin
    Result := s;
    Exit;
  end;
  c := Copy(s, 1, 1);
  while isoneof(c, sep) do
  begin
    s := Copy(s, 2, Length(s) - 1);
    c := Copy(s, 1, 1);
  end;
  t := '';
  while (not isoneof(c, sep)) and (s <> '') do
  begin
    t := t + c;
    s := Copy(s, 2, length(s) - 1);
    c := Copy(s, 1, 1);
  end;
  Result := t;
end;


Взято из





Сохранение TForm и ее свойств в BLOB-поле


Сохранение TForm и ее свойств в BLOB-поле




procedureSaveToField(FField: TBlobField; Form: TComponent);
var
  Stream: TBlobStream;
  FormName: string;
begin
  FormName := Copy(Form.ClassName, 2, 99);
  Stream := TBlobStream.Create(FField, bmWrite);
  try
    Stream.WriteComponentRes(FormName, Form);
  finally
    Stream.Free;
  end;
end;

procedure LoadFromField(FField: TBlobField; Form: TComponent);
var
  Stream: TBlobStream;
  I: integer;
begin
  try
    Stream := TBlobStream.Create(FField, bmRead);
    try
      {удаляем все компоненты}
      for I := Form.ComponentCount - 1 downto 0 do
        Form.Components[I].Free;
      Stream.ReadComponentRes(Form);
    finally
      Stream.Free;
    end;
  except
    on EFOpenError do
      {ничего};
  end;
end;

Взято из





Сохранение точных размеров при печати


Сохранение точных размеров при печати




Приведенный ниже модуль демонстрирует принцип использования GetDeviceCaps для получения исчерпывающей информации о вашем принтере, включая HORZRES и VERTRES (горизонтальное и вертикальное разрешение в пикселах) на дюйм бумаги. Используя значения LOGPIXELSX и LOGPIXELSY, вы можете откалибровать принтер для точного задания количества точек на дюйм в горизонтальном и вертикальном направлениях.

В дополнение к информации о принтере, приведенный модуль демонстрирует способ печати, при котором изображение выводится на принтер "естественного" размера; также показана возможность размещения изображения на бумаге в определенной позиции и определенного размера (т.е. с применением масштабирования). Я думаю это должно вам помочь в деле управления принтером.

Пример также демонстрирует вывод на печать синусной кривой в конкретной позиции печати с заданными в дюймах размерами. Я думаю вы без труда разберетесь как перейти на метрическую систему размеров.


unitTstpr2fm;

{Пример использования объекта Printer из модуля TPrinter.

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

Демонстрация величин, возвращаемых функцией Windows API GetDeviceCaps.

interface

uses

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

type

TForm1 = class(TForm)
Print: TButton;
Image1: TImage;
procedure PrintClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var

  Form1: TForm1;

implementation

uses
  Printers;

{Константы WINAPI GetDeviceCaps получены из C++ windows.h и wingdi.h}

{Отдельные константы здесь приведены только для информации о их наличии}
const
  DRIVERVERSION = 0;
  TECHNOLOGY = 2; {Смотри windows.h для значения маски}
  HORZSIZE = 4;
  VERTSIZE = 6;
  HORZRES = 8;
  VERTRES = 10;
  BITSPIXEL = 12;
  PLANES = 14;
  NUMBRUSHES = 16;
  NUMPENS = 18;
  NUMMARKERS = 20;
  NUMFONTS = 22;
  NUMCOLORS = 24;
  PDEVICESIZE = 26;
  CURVECAPS = 28; {Смотри windows.h для значения маски}
  LINECAPS = 30; {Смотри windows.h для значения маски}
  POLYGONALCAPS = 32; {Смотри windows.h для значения маски}
  TEXTCAPS = 34; {Смотри windows.h для значения маски}
  CLIPCAPS = 36; {Смотри windows.h для значения маски}
  RASTERCAPS = 38; {Смотри windows.h для значения маски}
  ASPECTX = 40;
  ASPECTY = 42;
  ASPECTXY = 44;

  LOGPIXELSX = 88;
  LOGPIXELSY = 90;

  SIZEPALETTE = 104;
  NUMRESERVED = 106;
  COLORRES = 108;

  PHYSICALWIDTH = 110; {Смотри определение в windows.h}
  PHYSICALHEIGHT = 111; {Смотри определение в windows.h}
  PHYSICALOFFSETX = 112; {Смотри определение в windows.h}
  PHYSICALOFFSETY = 113; {Смотри определение в windows.h}
  SCALINGFACTORX = 114; {Смотри определение в windows.h}
  SCALINGFACTORY = 115; {Смотри определение в windows.h}

  DeviceCapsString: array[1..34] of string =
  ('DRIVERVERSION', 'TECHNOLOGY', 'HORZSIZE',
    'VERTSIZE', 'HORZRES', 'VERTRES',
    'BITSPIXEL', 'PLANES', 'NUMBRUSHES',
    'NUMPENS', 'NUMMARKERS', 'NUMFONTS',
    'NUMCOLORS', 'PDEVICESIZE', 'CURVECAPS',
    'LINECAPS', 'POLYGONALCAPS', 'TEXTCAPS',
    'CLIPCAPS', 'RASTERCAPS', 'ASPECTX',
    'ASPECTY', 'ASPECTXY', 'LOGPIXELSX',
    'LOGPIXELSY', 'SIZEPALETTE', 'NUMRESERVED',
    'COLORRES', 'PHYSICALWIDTH', 'PHYSICALHEIGHT',
    'PHYSICALOFFSETX', 'PHYSICALOFFSETY', 'SCALINGFACTORX',
    'SCALINGFACTORY');

  DeviceCapsIndex: array[1..34] of INTEGER =
  (0, 2, 4, 6, 8, 10, 12, 14, 16, 18,
    20, 22, 24, 26, 28, 30, 32, 34, 36, 38,
    40, 42, 44, 88, 90, 104, 106, 108, 110, 111,
    112, 113, 114, 115);

{$R *.DFM}

function iPosition(const i: INTEGER): INTEGER;
begin

  RESULT := Integer(i * LongInt(Printer.PageWidth) div 1000)
end {iPosition};

function jPosition(const j: INTEGER): INTEGER;
begin

  RESULT := Integer(j * LongInt(Printer.PageHeight) div 1000)
end {jPosition};

procedure TForm1.PrintClick(Sender: TObject);

var
  DestinationRectangle: TRect;
  GraphicAspectRatio: DOUBLE;
  i: INTEGER;
  j: INTEGER;
  iBase: INTEGER;
  iPixelsPerInch: WORD;
  jBase: INTEGER;
  jDelta: INTEGER;
  jPixelsPerInch: WORD;
  OffScreen: TBitMap;
  PixelAspectRatio: DOUBLE;
  SourceRectangle: TRect;
  TargetRectangle: TRect;
  value: INTEGER;
  x: DOUBLE;
  y: DOUBLE;
begin

  Printer.Orientation := poLandscape;
  Printer.BeginDoc;

{Делаем прямоугольник для показа полей}
  Printer.Canvas.Rectangle(0, 0, Printer.PageWidth, Printer.PageHeight);

{Свойства принтера и страницы}
  Printer.Canvas.Font.Name := 'Times New Roman';
  Printer.Canvas.Font.Size := 12;
  Printer.Canvas.Font.Style := [fsBold];
  Printer.Canvas.TextOut(iPosition(50), jPosition(40), 'Свойства принтера и страницы');

  Printer.Canvas.Font.Style := [];
  Printer.Canvas.Font.Size := 10;
  iBase := iPosition(50);
  jBase := 60;
  jDelta := 18;
  Printer.Canvas.TextOut(iPosition(50), jPosition(jBase),
    Printer.Printers.Strings[Printer.PrinterIndex]);
  INC(jBase, jDelta);

  Printer.Canvas.TextOut(iBase, jPosition(jBase),
    'Пикселей:  ' + IntToStr(Printer.PageWidth) + ' X ' +
    IntToStr(Printer.PageHeight));
  INC(jBase, jDelta);

  Printer.Canvas.TextOut(iBase, jPosition(jBase),
    'Дюймов:  ' + FormatFloat('0.000',
    Printer.PageWidth / Printer.Canvas.Font.PixelsPerInch) + ' X ' +
    FormatFloat('0.000',
    Printer.PageHeight / Printer.Canvas.Font.PixelsPerInch));
  INC(jBase, 2 * jDelta);

  Printer.Canvas.TextOut(iBase, jPosition(jBase),
    'Шрифт:  ' + Printer.Canvas.Font.Name + '   Размер:  ' +
    IntToStr(Printer.Canvas.Font.Size));
  INC(jBase, jDelta);

  Printer.Canvas.TextOut(iBase, jPosition(jBase),
    'Пикселей в дюйме:  ' + IntToStr(Printer.Canvas.Font.PixelsPerInch));
  INC(jBase, jDelta);

  Printer.Canvas.TextOut(iBase, jPosition(jBase),
    '''ТЕКСТ'':  ' + IntToStr(Printer.Canvas.TextWidth('ТЕКСТ')) + ' X ' +
    IntToStr(Printer.Canvas.TextHeight('ТЕКСТ')) + '
    пикселей');

{Значения GetDeviceCaps}
    INC(jBase, 2 * jDelta);
    Printer.Canvas.Font.Size := 12;
    Printer.Canvas.Font.Style := [fsBold];
    Printer.Canvas.TextOut(iBase, jPosition(jBase), 'GetDeviceCaps');
    INC(jBase, jDelta);

    Printer.Canvas.Font.Size := 10;
    Printer.Canvas.Font.Style := [];

    for j := LOW(DeviceCapsIndex) to HIGH(DeviceCapsIndex) do
      begin
        value := GetDeviceCaps(Printer.Handle, DeviceCapsIndex[j]);
        Printer.Canvas.TextOut(iBase, jPosition(jBase), DeviceCapsString[j]);

        if (DeviceCapsIndex[j] < 28) or (DeviceCapsIndex[j] > 38) then
          Printer.Canvas.TextOut(iPosition(250), jPosition(jBase), Format('%-8d', [value]))
        else
          Printer.Canvas.TextOut(iPosition(250), jPosition(jBase), Format('%.4x', [value]));

        INC(jBase, jDelta);

      end;

{Помещаем изображение в левый нижний угол}
    Printer.Canvas.Draw(iPosition(300), jPosition(100),
    Form1.Image1.Picture.Graphic);

{Помещаем то же изображение, имеющее ширину 1" и пропорциональную
высоту в позиции 4"-правее и 1"-ниже верхнего левого угла}
    GraphicAspectRatio := Form1.Image1.Picture.Height /
    Form1.Image1.Picture.Width;

    iPixelsPerInch := GetDeviceCaps(Printer.Handle, LOGPIXELSX);
    jPixelsPerInch := GetDeviceCaps(Printer.Handle, LOGPIXELSY);
    PixelAspectRatio := jPixelsPerInch / iPixelsPerInch;

    TargetRectangle := Rect(4 * iPixelsPerInch, {4"}
    jPixelsPerInch, {1"}
    6 * iPixelsPerInch, {6" -- 2" ширина}
    jPixelsPerInch +
    TRUNC(2 * iPixelsPerInch * GraphicAspectRatio *
    PixelAspectRatio));

    Printer.Canvas.TextOut(4 * iPixelsPerInch, jPixelsPerInch -
    Printer.Canvas.TextHeight('X'),
    '2" ширина от (4", 1")');
    Printer.Canvas.StretchDraw(TargetRectangle, Form1.Image1.Picture.Graphic);

{Создаем изображение в памяти и затем копируем его на холст принтера}
    SourceRectangle := Rect(0, 0, 3 * iPixelsPerInch - 1, 2 * jPixelsPerInch - 1);

{Это не должно работать!  Rectangle = Left, Top, Right, Bottom
Top и Bottom считаются зарезервированными?}
    DestinationRectangle := Rect(4 * iPixelsPerInch, 6 * jPixelsPerInch,
    7 * iPixelsPerInch - 1, 4 * jPixelsPerinch - 1);

    Printer.Canvas.TextOut(4 * iPixelsPerInch, 4 * jPixelsPerInch -
    Printer.Canvas.TextHeight('X'),
    IntToStr(3 * iPixelsPerInch) + ' пикселей на ' +
    IntToStr(2 * jPixelsPerInch) + ' пикселей -- ' +
    '3"-на-2" в (4",4")');

    OffScreen := TBitMap.Create;
    try
      OffScreen.Width := SourceRectangle.Right + 1;
      OffScreen.Height := SourceRectangle.Bottom + 1;
      with OffScreen.Canvas do
        begin
          Pen.Color := clBlack;
          Brush.Color := clWhite;
          Rectangle(0, 0, 3 * iPixelsPerInch - 1, 2 * jPixelsPerInch - 1);
          Brush.Color := clRed;
          MoveTo(0, 0);
          LineTo(3 * iPixelsPerInch - 1, 2 * jPixelsPerInch - 1);

          Brush.Color := clBlue;
          MoveTo(0, 0);
          for i := 0 to 3 * iPixelsPerInch - 1 do
            begin
              x := 12 * PI * (i / (3 * iPixelsPerInch - 1));
              y := jPixelsPerInch + jPixelsPerInch * SIN(x);
              LineTo(i, TRUNC(y));
            end

        end;

      Printer.Canvas.CopyRect(DestinationRectangle, OffScreen.Canvas,
        SourceRectangle);
    finally
      OffScreen.Free
    end;

{Список шрифтов для данного принтера}
    iBase := iPosition(750);
    Printer.Canvas.Font.Name := 'Times New Roman';
    Printer.Canvas.Font.Size := 12;
    Printer.Canvas.Font.Style := [fsBold];
    Printer.Canvas.TextOut(iBase, jPosition(40), 'Шрифты');

    Printer.Canvas.Font.Style := [];
    Printer.Canvas.Font.Size := 10;
    jDelta := 16;
    for j := 0 to Printer.Fonts.Count - 1 do
      begin
        Printer.Canvas.TextOut(iBase, jPosition(60 + jDelta * j), Printer.Fonts.Strings[j])
      end;

    Printer.EndDoc;

end;

end.

Взято из

Советов по Delphi от


Сборник Kuliba






Сохранение всего содержимого буфера обмена в файл


Сохранение всего содержимого буфера обмена в файл



Из рассылки "Мастера DELPHI. Новости мира компонент,..."

var FS:TFileStream;
procedure TForm1.bClearClick(Sender: TObject);
begin
OpenClipBoard(0);  
EmptyClipboard;  
CloseClipBoard;  
end;

procedure TForm1.BSaveClick(Sender: TObject);
var CBF:Cardinal;
CBFList:TList;  
i:Integer;  
h:THandle;  
p:Pointer;  
CBBlockLength,Temp:Cardinal;  
FS:TFileStream;  
begin
if OpenClipBoard(0)then begin  
CBFList:=TList.Create;  
CBF:=0;  
repeat  
CBF:=EnumClipboardFormats(CBF);  
if CBF<>0 then  
CBFList.Add(pointer(CBF));  
until CBF=0;  
edit1.text:=IntToStr(CBFList.Count);  
if CBFList.Count>0 then begin  
FS:=TFileStream.Create('e:\cp.dat',fmCreate);  
Temp:=CBFList.Count;  
FS.Write(Temp,SizeOf(Integer));  
for i:=0 to CBFList.Count-1 do begin  
h:=GetClipboardData(Cardinal(CBFList[i]));  
if h>0 then begin  
CBBlockLength:=GlobalSize(h);  
if h>0 then begin  
p:=GlobalLock(h);  
if p <> nil then begin  
Temp:=Cardinal(CBFList[i]);  
FS.Write(Temp,SizeOf(Cardinal));  
FS.Write(CBBlockLength,SizeOf(Cardinal));  
FS.Write(p^,CBBlockLength);  
end;  
GlobalUnlock(h);  
end;  
end;  
end;  
FS.Free;  
end;  
CBFList.Free;  
CloseClipBoard;  
  end;
end;

procedure TForm1.bLoadClick(Sender: TObject);
var h:THandle;
p:Pointer;  
CBF:Cardin!  
al;  
CBBlockLength:Cardinal;  
i,CBCount:Integer;  
FS:TFileStream;  
begin
if OpenClipBoard(0)then begin  
FS:=TFileStream.Create('e:\cp.dat',fmOpenRead);  
if FS.Size=0 then Exit;  
FS.Read(CBCount,sizeOf(Integer));  
if CBCount=0 then Exit;  
for i:=1 to CBCount do begin  
FS.Read(CBF,SizeOf(Cardinal));  
FS.Read(CBBlockLength,SizeOf(Cardinal));  
h:=GlobalAlloc(GMEM_MOVEABLE or GMEM_SHARE or GMEM_ZEROINIT,CBBlockLength);  
if h>0 then begin  
p:=GlobalLock(h);  
if p=nil then  
GlobalFree(h)  
else begin  
FS.Read(p^,CBBlockLength);  
GlobalUnlock(h);  
SetClipboardData(CBF,h);  
end;  
end;  
end;  
FS.Free;  
CloseClipBoard;  
end;  
end;

Взято с Vingrad.ru



Сохранить строку в памяти?+пример работы с атомами


Сохранить строку в памяти?+пример работы с атомами



Например через атомы:

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


const UniqueSignature='GI7324hjbHGHJKdhgn90jshUH*hjsjshjdj';

Procedure CleanAtoms;
var P:PChar;
  i:Word;
begin
GetMem(p, 256);  
For i:=0 to $FFFF do  
begin  
  GlobalGetAtomName(i, p, 255);  
  if StrPos(p, PChar(UniqueSignature))<>nil then GlobalDeleteAtom(i);  
end;  
FreeMem(p);  
end;

Procedure WriteAtom(Str:string);
begin
CleanAtoms;  
GlobalAddAtom(PChar(UniqueSignature+Str));  
end;

Function ReadAtom:string;
var P:PChar;
  i:Word;
begin
GetMem(p, 256);  
For i:=0 to $FFFF do  
begin  
GlobalGetAtomName(i, p, 255);  
if StrPos(p, PChar(UniqueSignature))<>nil then break;  
end;  
result:=StrPas(p+length(UniqueSignature));  
FreeMem(p);  
end;

procedure TReadFromAtom.Button1Click(Sender: TObject);
begin
WriteAtom(Edit1.text);  
end;

procedure TReadFromAtom.Button2Click(Sender: TObject);
begin
Showmessage(ReadAtom);  
end;

Примечание: константа "UniqueSignature" должна быть достаточно длинной, чтобы однозначно идентифицировать атом, в тоже время длина хранимой строки вместе с UniqueSignature не должна превышать 255 символов. Данная конструкция может хранить только 1 значение. Для хранения нескольких значений надо назначить несколько разных UniqueSignature и использовать сходные процедуры.

Автор ответа: Vit
Взято с Vingrad.ru