Spring4D 소개 - 델파이 개발을 한수준 높이기 (Introduction to Spring4D - Taking Delphi Development to the Next Level) 를 요약했습니다. (이 요약 번역은 원본 비디오와 내용이 일부 다르거나, Q&A등 일부 생략되었을 수 있습니다.)

 

이 스프링4D는 델파이 개발을 더 쉽고 더 견고하게 할 수 있도록 미리 구성된 라이브러리입니다. 많은 개발자들에게 필요했던 타입과 확장 기능이 구현되어 있습니다. 예를 들어, 스마트 포인터를 사용하면 메모리 누수 걱정없이 오브젝트를 만들어 쓸 수 있습니다. Spring4D의 컬렉션은 컬렉션이나 리스트 관리가 매우 간편합니다. (이런 라이브러리 또는 프레임워크를 사용하면) 코드는 더 짧아지고, 일관성과 품질은 더 높아집니다. 

  • Spring4D란?
  • Spring4D를 받는 방법
  • Spring4D의 기본 구성
  • Spring4D 구성 요소: Spring.Base
  • Nullable<T>
  • Event<T>
  • 스마트 포인터 (Shared<T> 와 Weak<T>)
  • Collections
  • Collections 인터페이스
  • 읽기전용 vs 불변
  • IEnumberable<T>
  • 스트리밍과 지연 실행
  • ICollection<T>
  • IList<T>
  • IMap, IDictionary, IMultiMap
  • ISet, IMultiSet

  • 더 많은 내용

발표자 (Stefan Glienke)는 델파이 경력 20년이 넘은 개발자이며, Spring4D 오픈소소의 개발 책임자입니다. (웹페이지: https://delphisorcery.blogspot.com )

 

원본 비디오 시청: https://delphicon.embarcadero.com/talks/introduction-to-spring4d-taking-delphi-development-to-the-next-level/

 

Spring4D 란

  • 델파이 오픈소스 라이브러리 (2010년에 출시된 XE와 그 이후 버전에서 사용 가능)
    • 상업용 무료 사용 (아파치 2.0 오픈 소스 라이선스)
    • 델파이 RTL 확장
    • 제네릭스(Generics)와 RTTI를 적극 활용
    • 계속 발전하는 중이고 상업용 소프트웨어 개발에 활용되고 있음
  • 원칙: “골라 쓰기” - 원하는 것만 골라서 사용할 수 있다. 강제하지 않는다.
  • 버전: 2020년 12월 현재 1.2.4 - 곧 2.0 발표 예정

Spring4D를 받는 방법

  • Git에서 내려받기 https://bitbucket.org/sglienke/spring4d.git (버전콘트롤을 사용하지 않는다면 전체 파일 다운로드)
  • Build.exe 를 실행하여 간편하게 설치/설정 가능 (또는 전체 파일을 직접 컴파일 하여 사용하기)
  • 코드를 모두 받아서 컴파일하여 사용할 수 있지만, 미리 컴파일된 .dcu를 사용하는 것이 편함 (단 몇초지만 매번 컴파일하는 시간도 아끼자)

Spring4D의 기본 구성

  • Base: RTL 확장, 컬렉션
  • Core: 의존성 주입(DI, Dependency Injection) 컨테이너, 인터셉션/목킹(Mocking)
  • Data: ObjectDataSet을 이용해 (TDBGrid 등) 데이터를 인식하는 UI 콘트롤에 연결
  • Persistence: ORM
  • Extensions: 암호화 및 기타 유틸리티 (암호화는 다른 암호화 전문 라이브러리보다 약함)

Spring4D 구성 요소: Spring.Base

  • Nullable<T>
  • Event<T> 멀티 캐스트 이벤트
  • 스마트 포인터 (Shared<T> 와 Weak<T>)
  • Collections: 가장 많이 활용되는 라이브러리
  • IEnumerable<T>
  • 리스트, 딕셔너리, 멀티맵, 세트, 큐

Nullable<T>

  • 특정 타입을 지키는 데이터 타입(Type safe date type) 이면서도 Null값을 가질 수 있다.
  • Null (값이 없음)을 넣기 위해 아래와 같이 억지로 만든 값을 사용할 필요가 없다.
    • 날짜 타입에 “날짜가 주어지지 않음”을 넣기 위해 -40000 이라는 가상의 값 넣기
    • Boolean에 “참인지 거짓인지 모름”을 넣기 위해 True/False/FileNotFound로 Inum을 직접 만들기
  • Variant 타입과는 다름
    • Variant는 호환 가능한 타입 변환을 암시적으로 수행하므로 언제든 다른 타입으로 변환될 여지가 있지만 Nullable<T>는 타입을 지키므로 정해진 타입 이외에는 담을 수 없다.(type safe)
    • 예를 들어 Variant에는 숫자 3과 문자열 ‘3’을 모두 넣을 수 있고, 상황에 따라 사용되지만, Nullable<Integer>에는 정수 3만 넣을 수 있고 문자열 3을 넣을 수는 없다.

//// Nullable<T> 예문

uses

  Spring;

procedure …

var

  n, n2: Nullable<TDateTime>; // uses Spring (Spring 유닛 사용) 필요

  d: TDateTime;

begin

  d := now;

  Log.Lines.Add(n.HasValue.ToString);

  Log.Lines.Add(n.ToString); // DataTime을 문자열로 출력할 때는 지역 설정 등 RTL에서 적용된 형식으로 출력

  Log.Lines.AddParagraph;

 

  n := d;

 

  Log.Lines.Add(n.HasValue.ToString); // 로컬 변수로 사용된 Nullable<T>은 할당을 하지 않고 바로 사용 가능

  Log.Lines.Add(n.ToString);

  Log.Lines.AddParagraph;

 

  n := nil; //n에 들어있는 값을 없앤다

 

  Log.Lines.Add(n.HasValue.ToString);

  Log.Lines.Add(n.GetValueOrDefault().ToString); // GetValueOrDefault() 값이 있으면 그 값을, 없으면 기본값을 출력

  Log.Lines.AddParagraph;

 

  Log.Lines.Add((n=n2).ToString);

  n := d;

  Log.Lines.Add((n=n2).ToString);

  n2 := d;

  Log.Lines.Add((n=n2).ToString);

end;

 

////결과 (및 해설)

False // 기본값이 적용되면, Nullable.HasValue의 결과는 False

Null // 기본값이 적용되면, Nullable.ToString의 결과는 ‘Null’(값없음)

 

True // 특정 시간을 넣으면, Nullable.HasValue의 결과는 True

19.11.2020 18:11:51 //독일 기준 날짜 형식 (발표자의 시간대가 독일로 되어 있음)

 

False // nil을 넣으면, Nullable.HasValue의 결과는 False

30.12.1899 // Nullable.GetValueOrDefault().ToString의 결과는 값없는 경우에 출력할 날짜 기본값

 

True // n과 n2는 둘다 값이 없으므로, n과 n2를 비교하면 ‘같음’이 된다

False // n에만 d를 넣고, n과 n2를 비교하면 ‘다름’이 된다

True // n과 n2는 둘다 d와 같은 값을 가지므로, n과 n2를 비교하면 ‘같음’이 된다.

 

Event<T>

  • (필요한 타입을 따로 만들 필요없어서 사용이 쉬운) Observer 패턴과 유사하다.
  • publish와 Subscribe를 구현하기 간단하다. 델파이에서 일반 이벤트 사용하는 것과 방식이 같다.
  • 제네릭 타입을 사용하므로 파라미터와 리턴 타입이 유연하다
    • <T>에 (TNotifyEvent 등) 원하는 타입을 지정하면 된다.
  • 빠르고 쓰레드에 안전하다

//// Event<T> 멀티 캐스트 이벤트 예문

uses

  Spring;

 

private fOnMouseMove: Event<TMouseMoveEvent>; // 델파이 기본 이벤트에서 마우스 상태값을 받아온다

 

// Event<TMouseMoveEvent>를 구독(subscribe)하는 함수

procedure …

var

  subscriber: TEventSubscriber; //구독자 변수

begin

  subscriber := TEventSubscriber.Create(Self); //구독자 생성

  fOnMouseMove.Add(subscriber.HandleMouseMove); //구독자가 잡은 마우스 이동 이벤트를 넣는다 (fOnMouseMove는 실제로 이벤트핸들러들의 목록이므로 Add 메소드를 가지도록 되어있다. 그 결과 한번 작동하면 목록에 있는 모든 이벤트핸들러가 작동한다.)

  subscriber.OnUpdate.Add(ChangeCaption); //구독자의 OnUpdate이벤트 발생시 실행할 이벤트핸들러 지정 (좌표값을 폼의 캡션에 찍도록 함)

  subscriber.OnUpdate.Add(ChangeColor); // (마우스 Y좌표가 300이상이면 빨강으로 바꾸고 아니면, 일반 윈도우 색을 유지하도록 함)

  Log.OnMouseMove := fOnMouseMove; //TMomo인 Log의 OnMouseMove 이벤트에 Event<TMouseMoveEvent>를 연결하여 포함된 이벤트핸들러가 모두 실행되도록 한다.

  fOnMouseMove.OnChange := NotifyEventChange; //Event<T>에 이벤트핸들러가 추가/삭제 되면 공지한다. (예를 들어 이 예문에서 폼을 종료하면, 이 이벤트가 작동된다. 그 이유는 TEventSubscriber.Create(Self)로 생성되었고, Self는 MainForm였다. 따라서 TEventSubscriber의 owner 역시 메인폼이 된다. 메인 폼이 제거되면, 이 구독자 역시 제거되고 등록된 이벤트핸들러 역시 제거된다.)

end;

스마트 포인터 (Shared<T> 와 Weak<T>)

  • 오브젝트와 기타 리소스의 생명주기가 관리 능력 추가
  • try finally 를 사용하여 명시적으로 오브젝트를 제거하지 않아도 된다. 이점은 여러 리소스 간에 오브젝트를 주고 받는 것 역시 간편하게 해준다.(어느 곳에서 제거해야 하는지를 걱정할 필요가 없다)
  • Weak<T>에서는 순환 참조 문제가 없다 (심지어 델파이에 [Weak] 속성이 추가되기 전부터 있었다)
  • 보너스: Weak<T>로 만든 오브젝트는 모든 플랫폼에서 작동한다. 또한 오브젝트가 제거될 때 알림을 받을 수 있다

//// 스마트 포인터 (Shared<T> 와 Weak<T>) 예문

// Shared<T>: 레코드 타입으로 사용할 때

procedure …

var

  sl: Shared<TStringList>;

begin

  sl := TStringList.Create; // operator overloading

  sl.Value.Add(‘델파이콘’); // 멤버에 직접 액세스하지 못하고 Value 속성을 사용하여 액세스한다

  Log.Lines.AddStrings(sl); //<T>에서 지정한 타입을 그냥 전달하는 것과 같은 방식으로 전달될 수 있다.

end;

 

// IShared<T>: 인터페이스 타입으로 사용할 때

procedure …

var

  sl: IShared<TStringList>; // 인터페이스 타입으로 사용할 때

begin

  sl := Shared.Make<TStringList>(TStringList.Create); // 직접 생성하지 않고 인터페이스에 맞추어야 한다.

  sl.Add(‘델파이콘’); // (이 인터페이스는 익명메소드처럼 지정된 타입을 반환하기 때문에) 멤버에 직접 액세스할 수 있다.

  Log.Lines.AddStrings(sl); //<T>에서 지정한 타입을 그냥 전달하는 것과 같은 방식으로 전달될 수 있다.

end;

 

// IShared<T>로 생성된 오브젝트를 직접 제거하고 싶으면, 파라미터로 익명메소드를 넣는다.

procedure …

var

  sl: IShared<TStrings>;

begin

  sl := Shared.Make<TStrings>(TStringList.Create,

    procedure(const s: TStrings)

    begin

      Log.Lines.AddStrings(sl); //TMemo인 Log에 ‘델파이콘’을 출력하고

      s.Free; //생성된 TStrings를 제거

    end);

  sl.Add(‘델파이콘’);

end;

 

// 스마트 포인터로 만든 오브젝트는 오브젝트 제거 코드를 쓰지 않아도. 자동 제거되므로 메모리 누수를 염려하지 않아도 된다.

// ReportMemoryLeakOnShutdown := True; //델파이 프로젝트에서 메모리 누수를 확인하는 코드

 

// Weak<T>

procedure …

var

  sl: TStringList; //Share<T>가 아닌 일반 TStringList

  weakRef: Weak<TStrings>; //문자열을 Weak 참조하기로 한다.

begin

  sl := TStringList.Create;

  weakRef := sl; // operator overloading

  sl.Add(‘델파이콘’);

 

  Log.Lines.Add(weakRef.IsAlive.ToString);

  Log.Lines.AddStrings(weakRef); // operator overloading

  Log.Lines.AddParagraph;

 

  sl.Free; //Share<T> 가 아니므로 직접 Free 했다. 그러면, Weak 참조하고 있는 곳에 모두 공지된다.

 

  // Weak<T>는 모든 플랫폼에서 작동된다.

  Log.Lines.Add(weakRef.IsAlive.ToString);

  Log.Lines.Add(Assigned(weakRef.Target).ToString); //Weak<T>.Target은 Shared<T>.Value와 같은 역할

  Log.Lines.Add(weakRef <> nil).ToString;

end;

 

////결과 (및 해설)

True // 참조 타겟이 살아있다

델파이콘 // 참조 타겟의 값

False // ‘참조 타겟이 제거되었음’을 알고 있음

False // ‘참조 타겟이 Assigned 되지 않았음’을 알고 있음

False // ‘참조 타겟이 nil 임’을 알고 있음

 

Collections

  • 인터페이스 기반이다.
    • 메모리 관리가 매우 쉽다
    • Collection를 함수에서 반환하고, 어느 곳에서든 사용하기만 하면 된다. 사용이 끝나면 자동 제거 된다.
  • IEnumberable<T>를 사용하여 API가 확장되었다.
    • 명확하게 표현되는 코드를 사용하도록 메소드가 제공된다.
    • 성가시게 루프를 사용할 필요가 적어진다.
  • Systems.Generics.Collections 대체한다.
    • 100%는 아니지만 왠만한 건 다 있고 델파이 컬렛션을 Spring.Collections로 마이그래이션도 쉽다.
  • TCollections와 IEnumberable에서 항상 팩토리 메소드를 사용한다.
    • (델파이 컬렉션과 달리) 클래스를 직접 사용하면 안된다. 제공되는 팩토리 메소드를 사용해야 한다.
    • Spring.Collection.* 유닛을 uses에 추가하면 해당 컬렉션을 사용할 수 있다.

Collections 인터페이스

  • IEnumberable<T>
    • (정렬되지 않은) 항목들의 나열을 제공하는 기반 타입
  • ICollection<T>, IReadOnlyCollection<T>
    • (인덱스 번호가 지정되지 않은) 항목들의 컬렉션, List의 기반 타입
  • IList<T>, IReadOnlyList<T>
    • (인덱스 기반의 메소드가 제공되는) 리스트
  • IMap<TKey, TValue>, IReadOnlyMap<TKey, TValue>
    • Dictionary와 MultiMap의 기반 타입
  • IDictionary<TKey, TValue>, IReadOnlyDictionary<TKey, TValue>
  • IMultiMap<TKey, TValue>, IReadOnlyMultiMap<TKey, TValue>
  • ISet<T>
    • MultiSet의 기반 타입
  • IMultiSet<T>, IReadOnlyMultiSet<T>

읽기전용 vs 불변

  • Spring4D에는 불변 컬렉션이 없다. (추가/변경/삭제가 해당 컬렉션 안에서 발생한다)
  • 하지만, 모든 타입은 ReadOnly 버전이 제공된다. (AsReadOnly 메소드 사용), 멀티쓰레드에 안전하지 않지만, 컬렉션을 사용하는 곳에서 추가/변경/삭제를 할 수 없다.
  • 컬렉션을 읽기 전용 목적으로 전달할 때에는 IEnumberable<T> 또는 알맞은 ReadOnly 컬렉션을 사용하자.

IEnumberable<T>

  • (정렬되지 않고) (실현되지 않은, not materialized) 항목들의 나열을 제공하는 기반 타입
  • 모든 컬렉션 타입의 기반
  • 사용할 수 있는 메소드가 매우 많음
  • ‘(실현되지 않은, not materialized)’ 이란?
    • 쿼리문 이라고 생각하면 됨 (Where절에 명시한 조건에 따라 가져올 항목이 결정되는 SQL구문과 유사)
    • SQL문이 실행되어야 해당 데이터 집합이 생기는 것과 같은 방식 (실행 전에는 해당 조건에 해당하는 데이터 컬렉션이 없다)
    • 물론 어딘가에는 전체 데이터가 있다. 하지만, 내가 원하는 컬렉션 세트는 조건이 실행되어야 생긴다.

//// IEnumberable<T>예문 (주문 총액이 9,000 이상인 고객 목록)

customers.Where (


  function (const c : TCustomer): Boolean


  begin


    Result := c.OrderTotal > 9000; 


  end);

 

스트리밍과 지연 실행

  • IEnumberable<T>의 작동은 최대한 늦게 실행된다
    • 예를 들어, 
customer.Where(조건).Take(10);
에서 조건은, 항목 10개를 만들기 위해 필요한 만큼만 작동한다.
  • 즉, 작동이 되고 나서야 컬렉션이 만들어진다.

ICollection<T>

  • 정렬되지 않은 항목들의 (변경 가능한) 컬렉션
    • Add / Remove / Extract 메소드 제공
  • IEnumberable<T>와 달리 항상 항목을 가지고 있는 컬렉션
  • OnChange 이벤트가 제공되어서 어떠한 변경도 공지할 수 있음

IList<T>

  • 정렬된 항목들의 (변경 가능한) 리스트
  • 인덱스를 통해 각 항목에 접근 가능
  • 정렬 기반 작동 기능 제공 (Insert, Delete, IndexOf, Sort,…)

//// IEnumberable<T> 예문

procedure …

var

  numbers: IEnumberable<Integer>;

  i: Integer; 

  oddNumbers: IEnumberable<Integer>;

begin

  numbers := TEnumberable.Range(1,10);

  for i in numbers do

    Log.Lines.Add(i.ToString); // 1˜10까지 숫자 출력

    Log.Lines.AddParagraph;

 

  oddNumbers := numbers.Where(

    function(const n: Integer): Boolean

    begin

      Result := Odd(n);

    end);

  for i in oddNumbers do

    Log.Lines.Add(i.ToString); // 1~10 중 홀수만 출력

    Log.Lines.AddParagraph;

    Log.Lines.Add(oddNumbers.Last.ToString); // 9 출력

end;

 

//// IList<T> 예문

// IList<T>에는 인덱스 위치에 삽입이 가능하다.

procedure …

var

  list: IList<Integer>;

  i: Integer;

  oddNumbers: IEnumberable<Integer>;

begin

  list := TCollection.CreateList<Integer>([4,5,6]);

  list.AddRange([7,8,9]);

  list.InsertRange(0, [1,2,3]);

 

  for i in list do

    Log.Lines.Add(i.ToString); // 1˜9까지 순서대로 숫자가 출력

    Log.Lines.AddParagraph;

 

  oddNumbers := list.Where(

    function(const n: Integer): Boolean

    begin

      Result := Odd(n);

    end);

 

  Log.Lines.Add(’숫자 11까지’);

  list.Add(11); // 뒤늦게 숫자 11을 List에 추가

  for i in oddNumbers do // oddNumbers는 정의된 조건에 맞는 컬렉션을 이 시점에서 다시 제공

    Log.Lines.Add(i.ToString); // 1~11까지 중 홀수만 출력 (11도 포함된다)

    Log.Lines.AddParagraph;

end;

 

IMap, IDictionary, IMultiMap

  • IMap은 딕셔너리와 멀티맵의 기반 타입이다
    • Add, Remove, ContainKey 등등의 메소드가 제공된다.
  • IDictionary는 ‘키-값’으로 구성된 쌍들이 모여있는 컬렉션 (키는 고유해야 함)
  • IMultiMap는 일종의 딕셔너리이며 각 값에 리스트가 들어간다 (즉, 키 하나에 여러 항목이 들어갈 수 있다)
    • 값에 들어 있는 컬렉션을 다룰 수 있도록 여러 가지가 제공된다.

//// IMultiMap<TKey, TValue> 예문

// IMultiMap<TKey, TValue> 에는 키 하나에 여러 값이 들어갈 수 있다.

procedure …

var

  words: IMultiMap<Integer, string>;

  s: string;

  i: Integer;

  oddNumbers: IEnumberable<Integer>;

begin

  words := TCollection.CreateMap<Integer, string>;

 

  for s in LorenIpsum do // LorenIpsum은 저자가 만든 무작위 글자 생성기

    words.Add(s.Length, s); //키에는 단어 수를, 값에는 해당 단어를 넣어 추가한다.

 

  for i in words.Keys.Ordered do

  begin

    Log.Lines.Add(‘글자 길이가 %d자인 단어:’, [i]);

    for s in words[i] do

      Log.Lines.Add(s);

  end;

end;

 

////결과 (및 해설)

// 키(글자 수)는 정렬되었지만

// 값(해당 글자)는 정렬되지 않고, 중복되기도 한다.

글자 길이가 2자인 단어:

ut

et

At

et

et

글자 길이가 3자인 단어:

sit

sed

sed

eos

글자 길이가 … …

 

// words := TCollection.CreateMap<Integer, string>; 대신

// words := TCollection.CreateHashMap<Integer, string>;을 사용하면

// 값(해당 글자)의 중복이 제거된다.

//중복된 값은 받지 않기 때문이다.

글자 길이가 2자인 단어:

ut

et

At

글자 길이가 3자인 단어:

sit

sed

eos

글자 길이가 …

 

// 이 때, 값을 출력하는 루프에서 값도 정렬하고 싶다면,

// for s in words[i] do를

// for s in words[i].Ordered do로 변경하면 된다 

// 다른 방법으로는 (더 간단하고 성능이 좋은 방법으로는),

// words := TCollection.CreateTreeMap<Integer, string>;을 사용하면

// Ordered 없이도 값(해당 글자)의 중복이 제거될 뿐만 아니라 값도 정렬된다.

글자 길이가 2자인 단어:

At

ea

et

no

ut

글자 길이가 3자인 단어:

duo

eos

est

sea

sed

sit

글자 길이가 …

 

ISet, IMultiSet

  • Enum 세트와 유사하다. 하지만 enum 이외의 어떤 타입도 가능하다
  • 고유한 항목들로만 구성된 컬렉션이다 (마치 딕셔너리에서 값이 없는 키들의 집합과 같다.)
    • 내부적으로 hashtable 또는 tree를 통해 구현된다.
      • HashTable은 델파이 해시테이블과 달리 순서에 맞게 삽입한다.
      • Tree는 비교 기준에 맞추어 알맞은 순서로 저장한다.
  • IMultiSet은 Dictionary<T, Integer>이며 숫자 즉 갯수는 추가/삭제에 따라 증가/감소한다.
    • 갯수 파악이 매우 쉽다.

//// IMultiSet 예문

procedure …

var

  wordCounts: IMultiSet<string>;

begin

  wordCounts := TCollection.CreateMultiSet<string>(LorenIpsum); //LorenIpsum은 문자열 배열을 반환

 

  for var entry s in wordCounts.Entries do

    Log.Lines.Add(‘%s %d, [entry.Item, entry.Count]);

  end;

end;

////결과 (및 해설)

// 각 항목 별 갯수가 표시된다

Lorem 4

ipsum 4

elitr 2

sed 4

labore 2

et 8

// 만약 글자수 순으로 정렬되도록 하려면

// for var entry s in wordCounts.Entries do를

// for var entry s in wordCounts.OrderedByCount.Entries do 로 바꾸면 된다.

et 8

Lorem 4

ipsum 4

dolor 4

sit 4

amet 4

consetetur 2

sadipscing 2 …

 

더 많은 내용

 


 

번호 제목 글쓴이 날짜 조회 수
공지 [DelphiCon 요약] 코드사이트 로깅 실전 활용 기법 (Real-world CodeSite Logging Techniques) 관리자 2021.01.19 15411
공지 [UX Summit 요약] 오른쪽 클릭은 옳다 (Right Click is Right) 관리자 2020.11.16 13959
공지 [10.4 시드니] What's NEW! 신기능 자세히 보기 관리자 2020.05.27 16495
공지 RAD스튜디오(델파이,C++빌더) - 고객 사례 목록 관리자 2018.10.23 22047
공지 [데브기어 컨설팅] 모바일 앱 & 업그레이드 마이그레이션 [1] 관리자 2017.02.06 23266
공지 [전체 목록] 이 달의 기술자료 & 기술레터 관리자 2017.02.06 18920
공지 RAD스튜디오(델파이, C++빌더) - 시작하기 [1] 관리자 2015.06.30 39243
공지 RAD스튜디오(델파이,C++빌더) - 모바일 앱 개발 사례 (2020년 11월 업데이트 됨) 험프리 2014.01.16 174694
70 [Delphi week 2015] 윈도우 3.11에서 델파이1.0 사용하기 관리자 2015.02.13 1138
69 Thalmic Labs의 MYO Armband Delphi SDK Beta7입니다. 쭈니아빠 2015.04.18 1135
68 [DelphiCon 요약] 델파이로 웹 다루기 (Powering the Web with Delphi) file 관리자 2021.02.16 1116
67 [10.4] 커스텀 매니지드 레코드(Custom Managed Records) 험프리 2020.05.14 1116
66 델파이로 빅데이터 데이터베이스 연동하기(Cassandra, Couchbase, MongoDB) 험프리 2017.10.30 1116
65 20150204 VCL 개발자를 위한 Speed UP! RAD스튜디오 관리자 2015.02.05 1104
64 [추가된 문법] DLL 정적 호출 시 지연 호출(Delayed)-델파이 2010 추가 김원경 2016.12.27 1096
63 [VCL] TaskDialog 컴포넌트 소개 Humphery 2015.02.25 1092
62 [따라하기] 인공지능 오목게임(6) - 흑백 바둑알 놓고 위치저장 file 대화마을 2017.10.01 1057
61 델파이 웹 개발: TMS WEB CORE VS. UNIGUI VS. INTRAWEB 관리자 2020.12.10 1037
60 [무료 온라인 세미나] Delphi Week 2015 file 관리자 2015.02.07 1014
59 [팁] VLC 플레이어(ActiveX Import 해) 사용하기 file 험프리 2020.09.22 989
58 데브기어 컴포넌트 컨버터 원리와 구조 설명 험프리 2019.10.11 982
57 수원과학대 학생이 델파이로 개발한 '축구 리그 앱' 관리자 2017.11.24 982
56 파스칼(PASCAL) 언어 50년과 델파이(DELPHI) 관리자 2021.03.31 968
55 [따라하기] 인공지능 오목게임(5) - 바둑알 놓기 [2] file 대화마을 2017.09.22 961
54 윈도우10에서 활용 가능한 델파이만의 5가지 기능들 관리자 2020.02.04 958
53 [VCL] TaskDialog 컴포넌트 소개 Humphery 2015.02.03 926
52 [DelphiCon 요약] 델파이 고성능 구현 (High Performance Delphi) 관리자 2020.12.27 898
51 델파이에서 파이썬 표현식 활용하기 (PYTHON4DELPHI 샘플 앱) 관리자 2020.11.03 876