Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 2009.08.09;
Скачать: [xml.tar.bz2];

Вниз

Не могу понять замыкания   Найти похожие ветки 

 
тимохов ©   (2009-06-08 01:18) [0]

Товарищи и соратники!

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

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

Заранее спасибо. Особенно буду благодарен за хорошие статьи по теме.


 
тимохов ©   (2009-06-08 01:20) [1]

Собсно вопрос возник после чтения статьи http://habrahabr.ru/blogs/webdev/38642/

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


 
Игорь Шевченко ©   (2009-06-08 01:43) [2]

В Pascal-е издревне существуют вложенные функции, которые могут ссылаться на переменные/параметры внешней функции. В других языках не так (в С, например, их нет).


 
тимохов ©   (2009-06-08 01:47) [3]

2Игорь.

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


 
antonn ©   (2009-06-08 02:03) [4]

оффтоп :)
напомнило "...но шмель об этом не знает и летает только поэтому" :)
замыкания какие то... нет чтобы попроще - вложенные функции :)


 
тимохов ©   (2009-06-08 02:08) [5]


> замыкания какие то... нет чтобы попроще - вложенные функции
> :)

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


 
sniknik ©   (2009-06-08 02:17) [6]

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

зачем нужно? ну например один раз описав процедуру которая вешает событие на какой нибудь "div" я ее могу вызвать для нескольких, и с одной стороны не боятся, что переменные пересекутся, с другой уверен что используются локальные (глобальные немного "тормознее").

> Для меня вообще бред. Я не понимаю зачем все это, кроме как навредить создаваемому приложению.
просто нельзя рассматривать "фичу" одного языка в контексте другого.


 
Игорь Шевченко ©   (2009-06-08 02:21) [7]

Контекст может располагаться не только на стеке...


 
Alex Konshin ©   (2009-06-08 04:36) [8]


> Игорь Шевченко ©   (08.06.09 01:43) [2]
> В Pascal-е издревне существуют вложенные функции, которые
> могут ссылаться на переменные/параметры внешней функции.
>  В других языках не так (в С, например, их нет).

Игорь, ты прав, что их нет в C, но в GCC C++ они есть, хотя и немногие об этом знают. И вообще в GCC много чего есть, но нет нормальной документации.

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


 
Alex Konshin ©   (2009-06-08 04:38) [9]

По поводу расширений GCC http://linux.yaroslavl.ru/docs/prog/gcc/gcc1-4.html
Наверняка можно найти и первоисточник, но мне лень было искать и я привёл первую попавшуюся ссылку на русском языке.


 
Игорь Шевченко ©   (2009-06-08 10:12) [10]

Alex Konshin ©   (08.06.09 04:36) [8]

Я первый раз слово __closure увидел в C++ Builder, там этим модификатором обозначались обработчики событий.


 
oxffff ©   (2009-06-08 10:17) [11]

Дмитрий, приветствую.

Внимательно прочитай.
Замечательные примеры.

Is it a llama? Is it a lambada? No, it"s the lambda! - by Jarle Stabell
http://edn.embarcadero.com/article/33336


 
Тимохов_   (2009-06-08 11:05) [12]


> Alex Konshin ©   (08.06.09 04:36) [8]
>
> По поводу запоминания контекста. В Java это тоже так в аналогичной
> ситуации. Только там нет вложенных функций и даже нельзя
> передать указательна функцию. Приходится создавать объект
> с методом. Так вот, значения из текущего контекста, используемые
> методом, неявно сохраняются как константы в новом объекте.
>  Думаю, что в JavaScript точно такая же технология используется.


Спасибо, Alex. Я аналогию понял. Не понял сути. :(

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

Другой вопрос, контекст, сохраненный в рамках outer-функции. Тут я вообще не понимаю не фига. Например, такой псевдо-код:

proc Init();
var
  I;
begin
  I := 0;
  func Inner(A);
  begin
     I := I + A;
  end;
  RegisterCallback(Inner);
end;

var
  Global_Callback: TProc;

proc RegisterCallback(Callback: TProc);
begin
  Global_Callback := Callback;
end;

proc MainAlgorith();
begin
  что-то делается, результат передается в Global_Callback;
end;

begin
  Init();
  MainAlgorith();

  Вопрос - как достать результат работы  
  MainAlgorith(), сохраненный в локальной переменной
  функции Init();
end;


Вопрос в коде - как получить I из Init?

В твоем примере про объекты, методы и контексты - я бы просто обратился к члену объекта. А тут как? Где добыть I?


> oxffff ©   (08.06.09 10:17) [11]

Спасибо, вечером почитаю.


 
Alkid ©   (2009-06-08 11:15) [13]


> Тимохов_   (08.06.09 11:05) [12]

ЕМНИП, в Java есть inner-классы, которые содержат неявную ссылку на экземпляр внешнего класса, в чьём контексте были созданы, но не являются подлинными лексическими замыканиями, т.е. локальные переменные контекста, в котором были созданы, они не захватывают.


 
jack128_   (2009-06-08 13:08) [14]

Дим, попробуй Linq to objects в шарпе. C# тоже полноценный(возможно более полноценный, чем дельфи)  и ничего, не чурается замыканий. Собственно в том виде, в котором анонимные методы в дельфе сделаны - они применимы только в ограниченных случаях. Тот же Linq for objects на них не построишь. Точнее в принципе сделать можно - но использовать это будет ОЧЕНЬ неудобно.


 
Тимохов_   (2009-06-08 13:47) [15]

Жень. Возьми на себя евангелистсткую миссию - расскажи про замыкания и Linq! :) Объясни своими словами что-ли.

Я, например, уже C# не пользуюсь. Даже не стоит. Поэтому посмотреть не могу.


 
sniknik ©   (2009-06-08 13:55) [16]

> В твоем примере про объекты, методы и контексты - я бы просто обратился к члену объекта.
а в javascript все объекты, строки, числа, функции, все. т.е. например вызывая функцию fn() ты на самом деле вызываешь метод объекта - obj.fn(), у которого само собой есть ссылка на родительский. а те переменные, которые кроме того само собой тоже объекты, еще и его проперти.
т.е. если хочешь сделать также, то должен повторить модель, потому наверное и в его примере "про объекты, методы и контексты".

> А тут как? Где добыть I?
а никак, в паскале эта переменная определяется в стеке, выполнилась функция - все, забудь про нее.


 
Игорь Шевченко ©   (2009-06-08 13:58) [17]


> а никак, в паскале эта переменная определяется в стеке,
> выполнилась функция - все, забудь про нее.


локальную переменную необязательно в стеке объявлять. Например const она вовсе не в стеке.

{$WRITEABLECONST ON}
procedure TForm1.Button1Click(Sender: TObject);
const
 NCalls: Integer = 0;
begin
 Inc(NCalls);
 ShowMessageFmt ("you clicked me %d times", [NCalls]);
end;


 
Mystic ©   (2009-06-08 14:10) [18]

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

Например, есть некоторое событие. И надо передать в это событие дополнительный параметр. Это легко сделать при помощи замыкания.

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


 
sniknik ©   (2009-06-08 14:18) [19]

> локальную переменную необязательно в стеке объявлять. Например const она вовсе не в стеке.
потому что она глобальная, просто объявлена локально (предположительно нигде больше не используется, но верни ее адрес из функции и пользуйся вне ее... если есть желание делать через задницу)


 
Тимохов_   (2009-06-08 14:45) [20]


> sniknik ©   (08.06.09 13:55) [16]


Я понимаю, что JS сильно другой язык, нежели дельфи. Насколько я понимаю, он прототипо-ориентированный, а не объекто-ориентированный. Т.е. я как бы понимаю, что замыкания там могут играть роль инкапсуляторов - т.е. inner функция получает доступ к контексту, как бы к private переменным - имитируется инкапсуляция.

Ты можешь в дельфи привести пример?

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

Заранее благодарю.


 
jack128_   (2009-06-08 14:59) [21]


> Жень. Возьми на себя евангелистсткую миссию - расскажи про
> замыкания и Linq! :)

Косноязычен я к сожалению.

Можешь вот почитать: http://www.rsdn.ru/article/dotnet/LinqAsStapToFp.xml  Простым доступным языком написано. там кой какие заморочки шарпа описаны, ну судя по d2009 код жир тем же путем пойдет. Видимо хочет о каждую граблю лично лбом стукнуться, место того, чтоб учесть опыт MS C#


 
sniknik ©   (2009-06-08 15:09) [22]

> Ты можешь в дельфи привести пример?
могу попробовать. только зачем? неуклюже получится.

> чем отличается замыкание от локальных функций?
вот тебе аналогия
локальная(?) вернее просто функция в javascript это объект, с методом. чтобы использовать этот объект в функциональном прошу заметить языке, определяется функция с набором переменных, и возвращаемым значением - другая функция, вложенная, у которой есть доступ к этим переменным.
вызвав первую функцию, ты создаешь объект, но сохраняешь ссылку не на него а на возвращаемую внутреннюю функцию у которой эта ссылка определена по умолчанию. и любой последующий вызов этой "вернутой" функции использует созданный для нее объект внешней.
по моему все просто.
хочешь еще объект, еще раз вызываешь(создаешь) внешнюю и запоминаешь возвращаемую функцию для работы с переменными этого объекта.

т.е. то же самое объектное программирование, только "вывернутое наизнанку". доступ "изнутри", а не "сверху" объекта.


 
Mystic ©   (2009-06-08 15:11) [23]

> Ты можешь в дельфи привести пример?

Я в Delphi про замыкания не знаю, если замыкания из JavaScript, то... Например, TList.Sort. В этот метод надо передать функцию Compare. Эта функция принимает два указателя. Но может быть, что сортировка списка зависит от того, какие галочки пользователь выбрал на форме, т. е. зависеть от каких-то параметров a, b, c. При этом если комбинаторный взрыв мешает написать отдельно функцию на каждый возможный вариант сортировки. Получается примерно следующее:


procedure DoSort(List: TList; UkraineCompare: Boolean; CaseInsensitive: Boolean);

 function Compare(Item1, Item2: Pointer): Integer;
 begin
   if UkraineCompare then
     if CaseInsensitive then
   ...
  Result := 0;
 end;

begin
 List.Sort(@Compare);
end;


 
Тимохов_   (2009-06-08 15:13) [24]


> sniknik ©   (08.06.09 15:09) [22]


> "вывернутое наизнанку"


Вот ключ моего непонимания! Надо смотреть на все это с изнанки :)

Спасибо все, сегодня вечером посижу, почитаю и подумаю, т.к. разобраться с этими замыканиями все же хочу хорошо, а то чую себя каким-то ретроградом :)

Что не пойму, то спрошу здесь.


 
jack128_   (2009-06-08 15:17) [25]

Вот кста код, использующий способность захватывать контекст внешней функции даже после её(функции) завершения.

Можешь попробывать реализовать TMyComponent в традиционном стиле. Сравни сколько кода у тебя получится.

program Project5;

{$APPTYPE CONSOLE}

uses
 SysUtils, Classes;

type
 // Фактически - эта функция - это и есть енумератор.
 // должна вернуть false - если больше нет элементов,
 // иначе - true и сам элемент в параметре NextItem
 TEnumerateFunc<T> = reference to function (var NextItem: T): boolean;
 TEnumerator<T> = record
 strict private
   FFunc: TEnumerateFunc<T>;
   FCurrent: T;
 public
   constructor Create(const AEnumerateFunc: TEnumerateFunc<T>);
   property Current: T read FCurrent;
   function MoveNext: Boolean;
 end;
 TEnumeratorFactory<T> = record
 strict private
   FFunc: TEnumerateFunc<T>;
 public
   constructor Create(const AEnumerateFunc: TEnumerateFunc<T>);
   function GetEnumerator: TEnumerator<T>;
 end;

constructor TEnumeratorFactory<T>.Create(const AEnumerateFunc: TEnumerateFunc<T>);
begin
 FFunc := AEnumerateFunc;
end;

function TEnumeratorFactory<T>.GetEnumerator: TEnumerator<T>;
begin
 Result := TEnumerator<T>.Create(FFunc)
end;

constructor TEnumerator<T>.Create(const AEnumerateFunc: TEnumerateFunc<T>);
begin
 FFunc := AEnumerateFunc;
end;

function TEnumerator<T>.MoveNext: Boolean;
begin
 Result := FFunc(FCurrent)
end;

// Теперь пример.
// допустим мы хотим чтобы в зависимости от параметра получать вложенные компоненты в прямой или же обратной последовательности:
type
 TMyComponent = class(TComponent)
 public
   function GetComponents(AForward: boolean): TEnumeratorFactory<TComponent>;
 end;

function TMyComponent.GetComponents(AForward: boolean): TEnumeratorFactory<TComponent>;
var
 Index: Integer;
 Func: TEnumerateFunc<TComponent>;
begin
 if AForward then
 begin
   Index := -1;
   Func := function (var NextItem: TComponent): boolean
     begin
       Index := Index + 1; // переманная Index определена вне анонимного метода.  
       Result := Index < (ComponentCount - 1);
       if Result then
         NextItem := Components[Index]
     end;
 end
 else begin
   Index := ComponentCount;
   Func := function (var NextItem: TComponent): boolean
     begin
       Index := Index - 1;
       Result := Index >= 0;
       if Result then
         NextItem := Components[Index]
     end;
 end;
 Result := TEnumeratorFactory<TComponent>.Create(Func);
end;

ну и пример а теперь от мечтаний - к реалием. Все это не работает, потому что delphi2009 - глюкав как не знаю что.

var
 MyComp: TMyComponent;
 C: TComponent;
begin
 try
   MyComp := TMyComponent.Create(nil);
   try
     for C in MyComp.GetComponents(True) do; // ERROR!!!!!!!!!!!!!!!!!!! [DCC Error] Project5.dpr(89): E2010 Incompatible types: "TEnumerator<Classes.TComponent>" and "Pointer
   finally
     MyComp.Free
   end;
 except
   on E:Exception do
     Writeln(E.Classname, ": ", E.Message);
 end;
 ReadLn;
end.


 
jack128_   (2009-06-08 15:21) [26]

Кста, Дим, оффтоп небольшой. Что такое "Private Report"  Баг баг репорт по этому коду стал приватным. Насколько я понимаю его терь никто кроме меня неможет видить. Не знаешь что это за хрень??


 
sniknik ©   (2009-06-08 15:30) [27]

пример из ссылки
   function createCounter() {
      var numberOfCalls = 0;
      return function() {
         return ++numberOfCalls;
      }
   }
   var fn = createCounter();
   fn(); //1
   fn(); //2
   fn(); //3

на дельфи (ну, более менее, например т.к. в D7 лямда функций нет то пришлось обьявить. ну и не стал возвращать значение просто показываю)

unit Unit1;

interface

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

type
 Tinner = procedure of object;

 TForm1 = class(TForm)
   Button1: TButton;
   procedure FormCreate(Sender: TObject);
   procedure Button1Click(Sender: TObject);
 private
   inout: Tinner;
 end;

 TCounter = class
   Count: integer;
   function Init: Tinner;
   procedure Inner;
 end;

var
 Form1: TForm1;

implementation

{$R *.dfm}

function TCounter.Init: Tinner;
begin
 Count:= 0;
 result:= Inner;
end;

procedure TCounter.Inner;
begin
 Inc(Count);
 ShowMessage(IntToStr(Count))
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 inout:= TCounter.Create.Init();
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 inout;
end;

end.


 
Тимохов_   (2009-06-08 15:31) [28]


> jack128_   (08.06.09 15:17) [25]

Ну что сказать по твоему примеру - понять и идейно красиво, ничего не скажешь. Т.е. используя замыкание ты избегаешь того, что тебе нужно будет делать 2 класса, которые будут реализовывать итераторы - один для возрастания, другой для убывания. Да, ловко.

Интересно, конечно, как они в компиляторе реализовали управление памятью :)

Будет время поставлю Д2009 и посмотрю.


> jack128_   (08.06.09 15:21) [26]

Это значит, что ты попал - за тобой уже выехали!

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


 
jack128_   (2009-06-08 15:36) [29]


> Интересно, конечно, как они в компиляторе реализовали управление
> памятью :)

Тревиально.  

Вот это
type
 TIntFunc = reference to function: Integer;

эквивалентно:

type
 IntFunc = interface
    function Invoke: Integer;
 end;

каждая конкретная функция - преобразуется в класс, который реализует этот интерфейс.


 
Sergey Masloff   (2009-06-08 15:52) [30]

jack128_   (08.06.09 15:17) [25]

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


 
Игорь Шевченко ©   (2009-06-08 16:38) [31]

jack128_   (08.06.09 15:17) [25]

Был язык, как язык, а стал С++ какой-то. Мерзость


 
Тимохов_   (2009-06-08 16:51) [32]


> Игорь Шевченко ©   (08.06.09 16:38) [31]
>
> jack128_   (08.06.09 15:17) [25]
>
> Был язык, как язык, а стал С++ какой-то. Мерзость


В полку ворчунов прибыло: Игорь, теперь я с тобой!

:)

Маркетинг, гребаный - если лямбда-исчисление нынче модно, то нужно его и в Дельфи засунуть - авось будет что красивое показать на презентации. :(


 
Игорь Шевченко ©   (2009-06-08 17:10) [33]

Тимохов_   (08.06.09 16:51) [32]

Видишь ли, Дима, все хорошо в меру. Может быть, и templates хороши, но уже не для меня - после стольких лет на паскале я привык к вполне определенным конструкциям языка.
Может, оно для тех, кто сегодня увидел впервые паскаль в виде D2009 и станет привычным, а мне так глаз режет.


 
Тимохов_   (2009-06-08 17:27) [34]


> Игорь Шевченко ©   (08.06.09 17:10) [33]
>
> Тимохов_   (08.06.09 16:51) [32]
>
> Видишь ли, Дима, все хорошо в меру.


Ты меня, видимо, Игорь, не понял. Я нисколько не нападаю - мне тоже режет.

Я даже так скажу - меня раздражают ситуации, когда одно и то же можно сделать несколькими СИЛЬНО разными СИНТАКСИЧЕСКИМИ способами. Обязательно в команде будет, кто будет любить одну конструкцию, другой другую - и будет бардак: знакомые всем циклы будут реализоваться настолько через задницу, что надо становиться реальным гуру в конкретном синтаксисе, если хочешь пробежаться от первого до последнего символа. Мода - это зло для языков. И не ИМХО. Я до сих пор вычищаю тот синтаксический понос, который сам же и привнес с началом использования Д2006.

Вот Всеволод (это автор второго отчета о семинаре Кодгира 2 июня) спросил у Девида Интерсимоны - а знает ли тот пример какого-то идеального кода, на который все должны равняться. Хороший вопрос, если вдуматься. Они напридумывали кучу всего, а не догадались нанять евангелиста, чтобы тот написал:
  а) доступную (не по цене, а физически);
  б) хорошую
книгу о том, как надо писать сейчас в дельфи.
Если не читали отчет Всеволода, то ответ был такой - Дельфи есть инструмент, и дело организации разрабатывать свои стандарты его использования. Я уверен порядочный разработчик компиляторов должен следовать фразе - мы в ответе за тех кого приручили. Если ты придумал фичу и показываешь ее в качестве маркетингового преимущества, то ты просто обязан в деталях показать как этим зафигато пользоваться.

Вот по Java была хорошая книга - философия java. Почему такой нет по Delphi?

ЗЫ Прошу ветку не закрывать. Оффтоп прекращаю.


 
Игорь Шевченко ©   (2009-06-08 17:32) [35]

Тимохов_   (08.06.09 17:27) [34]

Да этот вовсе не оффтоп.

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


 
Тимохов_   (2009-06-08 17:38) [36]


> По Delphi примеры, как пользоваться, довольно неплохие,
> приводят Тейксейра с Пачеко, может, и Кэнту тоже.


У Тейкстеры есть про замыкания? Или ты имеешь в виду старый, добрый дельфи <= version 7?

У Кенту может быть и есть по новому дельфи. Не может быть а точно есть.
Он на каждую версию дельфи выпускает свой Hand Book. Почему его только не переводят на русский? Хорошая евангелистская книга было бы.


 
Alkid ©   (2009-06-08 17:46) [37]


> Тимохов_   (08.06.09 16:51) [32]
> Маркетинг, гребаный - если лямбда-исчисление нынче модно,
>  то нужно его и в Дельфи засунуть - авось будет что красивое
> показать на презентации. :(

Замечу в сторону, что к лямбда счислению лямбды в C# и Дельфи почти никак не относятся :) Лямбда-счисление - это Haskell, Curry, Clean и т.п. :)

А вообще, как сказал кто-то, по мере развития все языки становятся всё больше и больше похожи на Лисп :)


 
Игорь Шевченко ©   (2009-06-08 17:57) [38]

Тимохов_   (08.06.09 17:38) [36]


> У Тейкстеры есть про замыкания? Или ты имеешь в виду старый,
>  добрый дельфи <= version 7?


Старый добрый, разумеется.


> Почему его только не переводят на русский?


А почему Borland/Codegear/Embarcadero help не переводят на русский ?



Страницы: 1 вся ветка

Форум: "Прочее";
Текущий архив: 2009.08.09;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.59 MB
Время: 0.006 c
15-1244383233
Nic
2009-06-07 18:00
2009.08.09
Мозговой штурм 3


15-1244175479
SPeller
2009-06-05 08:17
2009.08.09
Проектирование интерфейса


15-1244511567
SPeller
2009-06-09 05:39
2009.08.09
Вопрос про bpl...


2-1244709711
a.a.j.
2009-06-11 12:41
2009.08.09
Место позиции курсора в поле html страницы


11-1205307227
zhirik
2008-03-12 10:33
2009.08.09
Как перетаскивать форму за ее поверхность





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский