2021년 7월 22일 목요일

swift vs delphi: 01

Swift를 공부하면서 Delphi를 재정립하자.

Structure

//Swift
struct Resolution {
var width = 0;
var height = 0;
}
let hd = Resolution(width: 1920, height: 1080)
var someResolution = Resolution(width: 640, height: 480) 

//Delphi
type
  TResolution = record
    width: integer;
    height: integer;
  end;
const
  hd: TResolution = (width: 1920; height: 1080);
var
  someResolution: TResolution = (width: 640; height: 480);

//Swift
  1. @propertyWrapper
  2. struct TwelveOrLess {
  3. private var number = 0
  4. var wrappedValue: Int {
  5. get { return number }
  6. set { number = min(newValue, 12) }
  7. }
  8. }

  9. //Delphi
  10. type TResolution = record private number : integer; function getWappedValue: integer; procedure setWappedValue(const Value: integer); property wrapValue: integer read number write number; property wrappedValue: integer read getWappedValue write setWappedValue; end;

  11. function TResolution.getWappedValue: integer;
  12. begin
  13.   Result:= number;
  14.   // willSet
  15. end;
  16. procedure TResolution.setWappedValue(const Value: integer);
  17. begin
  18.   if Value > 0 then
  19.     number:= Value
  20. else Value := 0;
  21.   // didSet
  22. end;


2021년 7월 21일 수요일

델파이 인터페이스

 델파이 인터페이스를 전혀 이해를 못하다가 Swift의 Protocol을 공부하면서 이해가 되었습니다. 물론 정확한지는 모르지만 제가 이해하는 수준입니다. 

이론적 배경은 구글링을 하시면 어렵게 설명되어 있으니 시스템프로그램하시는 분은 그곳을 참고하시고 저는 사용하는 입장에서만... 

Interface 가 도입된 배경은 Windows 32 시스템에서 COM을 사용하기 위한 것이고 지금은 COM을 사용하는 경우가 별로 없으니 GUID(Shift+Ctrl+G)는 생성할 필요는 없습니다.

먼저 다음과 같이 선언해보십시요.

type
  iCalc = interface
    function calcAdd(adx, bdx: integer): integer;
    function calcMulti(adx, bdx: integer): integer;
  end;
  TiCalc = class(TInterfacedObject, iCalc)
    function calcAdd(adx, bdx: integer): integer;
    function calcMulti(adx, bdx: integer): integer;
  end;
  jCalc = interface
    function calcSub(adx, bdx: integer): integer;
    function calcDivide(adx, bdx: integer): integer;
  end;
  TjCalc = class(TiCalc, iCalc, jCalc)
    function calcSub(adx, bdx: integer): integer;
    function calcDivide(adx, bdx: integer): integer;
  end;

구현은 Interface에서 하지 않고 Class에서 합니다.

TJCalc 가 다중상속되었슴에 주의하시면 되겠습니다. 

사용은 아래그림 및 아래와 같이하고


procedure TForm1.Button1Click(Sender: TObject);
var adx: iCalc;
begin
  adx:= TiCalc.Create;
  Label1.Caption:= adx.calcAdd(2, 3).ToString;
  //adx.free   Not need
end;
procedure TForm1.Button2Click(Sender: TObject);
var adx: jCalc;
begin
  adx:= TjCalc.Create;
  Label1.Caption:= adx.calcDivide(40, 2).ToString;
  //adx.free   Not need
end;
procedure TForm1.Button3Click(Sender: TObject);
var adx: iCalc;
begin
  adx:= TiCalc.Create;
  Label1.Caption:= adx.calcAdd(40, 2).ToString;
  //adx.free   Not need
end;

Button3에서는  TjCalc에서 구현하지 않은 상속받은 calcAdd 메소드를 사용했습에 주의하십시요.

결국 스위시의 프로토콜처럼 어떤 객체에 반드시 구현되어야 할(앞으로 사용 할 것임을 알리는?) 메소드를 먼저 선언한게 아닐까? 사용시에는 이것(Interface)만 보면 되겠지요.

 

2021년 7월 2일 금요일

Xcode 에서 command Line 실행파일위치

알고나면 아무것도 아닌데...

Xcode 에서 command Line 실행파일위치는?

즉, Swift , C ,C++ 등으로 생성한 실행파일의 위치는 어디인가?

나중에 터미널들에서 찾아가 실행하기위해서...

아래그림과 같이 찾아가면 됩니다.




해당 실행파일을 더블크릭하면 실행이되고, 
터미널에서 실행 할때는 통상 디렉토리까지 지정해주어야 실행됩니다.
필요하면 이전에 생성된 DerivedData 영역을 지워주면 좋을 것 같음. 

2021년 4월 28일 수요일

Delphi 10.4.2 TControlList 이해를 돕기위한 초간단 예제

델파이에서 애플의 테이블뷰를 구현 할 수 있게 되었습니다.

새로운 폼을 하나 만들고 ControlList를 alClient 로 올려놓고

ControlList 의 Item (prototype) 영역에 Label을 하나 올려 놓습니다.

간단하게하기위해 자료 컨테이너는 iMemo: TStringList 로 지정하고

아래 소스처럼 초기값을 넣습니다.

ComtrolList1.ItemHeight := 22;

procedure TForm2.ControlList1BeforeDrawItem(AIndex: Integer; ACanvas: TCanvas;
  ARect: TRect; AState: TOwnerDrawState);
begin
  Label1.Caption:= iMemo[Aindex];
end;
procedure TForm2.FormActivate(Sender: TObject);
begin
  iMemo:= TStringList.Create;
  iMemo.CommaText:= 'Hello, World,1,2,3,4,5,6,7,8,9';
  ControlList1.ItemCount:= iMemo.Count;
end;
procedure TForm2.FormDeactivate(Sender: TObject);
begin
  iMemo.Free;
end;

결과화면



 


2021년 3월 31일 수요일

Delphi 10.4.2 TControlList 예제

RAD스튜디오 10.4.2는 새로운 VCL 컨트롤들을 선보입니다. 그 중 TControlList는 매우 긴 리스트를 효과적으로 제어할 수 있는 컨트롤입니다. 현대식 룩앤필로, 원한다면 UI를 얼마든지 마음대로 설정할 수 있습니다.

파이어몽키의 ListView Item Designer와 닮은 TControlList는 리스트의 각 항목들을 대체해서(가상으로) 나타나는 리스트뷰 아이템의 레이아웃을 원하는 대로 만들 수 있습니다. 

TControlList는 단일 컬럼과 멀티 컬럼 레이아웃이 있는데, 원하는 형태를 선택할 수 있습니다. 완벽하게 가상화되어 있기 때문에 수천 혹은 수백만 개에 달하는 항목들도 얼마든지 제어 가능하며, 굉장히 빠른 스크롤이 가능합니다. 화면에 맞는 항목들만 표시할 수도 있습니다. 

그리고 High-DPI 옵션과 VCL 스타일을 지원할 뿐만 아니라 라이브바인딩(LiveBindings)도 완벽 지원합니다.

2021년 2월 2일 화요일

JSON 사용해보기 (Parsing)

 JSON의 이론적인 배경이 없이 사용하는데 참고가 될만한 사항만 정리 해봅니다.

동행복권을 REST로 읽어 보면 아래와 같은 구조입니다.

{"totSellamnt":100519459000,"returnValue":"success","drwNoDate":"2021-01-30","firstWinamnt":2188548716,"drwtNo6":41,"drwtNo4":31,"firstPrzwnerCo":11,"drwtNo5":38,"bnusNo":5,"firstAccumamnt":24074035876,"drwNo":948,"drwtNo2":18,"drwtNo3":30,"drwtNo1":13}

{} TJSONObject 
[] TJSONArray

"...." : 10051.. TJSONElement(Array 형태에서)
"...." : 10051   TJSONPair(Element 와 햇갈리죠)

"...." TJSONString
10051 TJSONValue

동행복권의 API는 단순하여 TJSONArray 가 없는 형태이다.

TJSONstring : TJSONValue 가 TJSONPair 가되는데 TJSONValue 자리에 TJSONObject, TJSONArray 가 올 수 있다.

TJASONObject 는 TJSONValue 형태와 TJASONText 형태로 우리가 볼 수 있다.

위의 형태가 TJSONValue 형태이고, 아래 형태가 TJSONText 형태이다.

{
   "totSellamnt":100519459000,
   "returnValue":"success",
   ..............
}


DELPHI의 RESTResponce 에는 이 2가지형태를 전부 제공해줍니다.
Var
  iJsonObject: TJSONObject;
  iJsonValue: TJSONValue;
선언해주고
iJsonObject := TJSONObject(RESTResponse1.JSONValue); 이와 같이 하여 가져옵니다.
Edit1.Text:= iJsonObject.ToJSON; 하면 위와 같은 형식으로 볼 수 있고
Memo1.Lines.Add( iJsonObject.ToString); 하면 2번째 형태로 보여줍니다.

예를 들어 bnusNo 의 값을 읽어오려면
iJsonValue := iJsonObject.Get('bnusNo').JSONValue; 와 같이 하면 되는데
TJsonValue는 TJSONObject가 될 수도 있고, string, number, boolean 이 될 수도 있다.
TJSONObject, , JSONString, TJSONNumber, TJSONPair, TJSONBool, TJSONArray

이렇게 알고 있는 형태로 변환하면서 읽어오면 됩니다.

물론 각각은 .Size 가 있어서 for var idx:= 0 iJsonValue.size -1 형태로 여러개의 Pair를 읽어 올 수도 있습니다.

다음에 기회되면 조금 복잡한 형태의 JSON을 읽어 Parsing 해보겠습니다.

2021년 1월 10일 일요일

리스트박스 값으로 소팅하기(ListBox, Value, Sort)

 리스트박스에 key=value 형태로 저장이 되어있을 때 Value 기준으로 소팅하고 싶으면,

문자데이터가 아니고 숫자데이터 일때

procedure TForm2.Button2Click(Sender: TObject);
var
  idx: Integer;
begin
  for idx := 0 to 30 do
    ListBox1.Items.AddPair(idx.ToString, IntToStr(Random(100)));
end;


// function TForm2.TStringsSort(List: TStringList; L, R: integer): integer;
// 이 아님에 주의!
function TStringsSort(List: TStringList; L, R: integer): integer;
begin
  Result:= StrToint(List.ValueFromIndex[L])-StrToInt(List.ValueFromIndex[R]);
end;


procedure TForm2.Button3Click(Sender: TObject);
var
  istrings: TStringList;
begin
  istrings:= TStringList.Create;
  try
    istrings.Assign(Listbox1.Items);
    istrings.CustomSort(@TStringsSort);
    Listbox1.Items.Assign(iStrings);
  finally
    istrings.Free;
  end;

2021년 1월 8일 금요일

Record를 담은 TList를 소팅하는 방법

TArray에서와 같은 방법으로 소팅하면 됩니다.

tBoll = record
    count: integer;
    name: string;
end; 
jTempArr: Tarray<tBoll>;
iList: TList<tBoll>
jBoll: tBoll;
iList := TList<TBoll>.Create;
SetLength(jTempArr, 45);
for idx := 0 to 44 do begin
      jTempArr[idx].Count := 0;
      jTempArr[idx].Name := BollName[idx];
 end;
 for idx := 0 to 44 do begin
        jBoll := jTempArr[idx];
        iList.Add(jBoll);
 end;
 iList.Sort(TComparer<TBoll>.Construct(
        function(const Left, Right: TBoll): integer begin
             Result := Left.Count - Right.Count;
             // Result:= CompareText(Left, Right);
        end));

와 같은 방법으로 하면 됩니다. 그냥 iList.sort 하였더니  숫자의 자리수가 다르거나  음수가 있으면 잘 안되더군요. 0, -99, 99 이렇게 되어있을 경우 0 이 가장적은 수가되버립니다.

잊어먹지 않기위해 정리하였습니다.  참고로 List 소팅도 정리합니다. (XE)

uses
  SysUtils, Generics.Defaults, Generics.Collections;
procedure Sort;
var
  List: TList<String>;
  AComparer: IComparer<string>;
  I: integer;
begin
  Randomize;
  AComparer:= TDelegatedComparer<string>.create(
    function(const Left, Right: String): integer begin
      Result:= StrToInt(Left) - StrToInt(Right);
    end);
  List:= TList<string>.Create(AComparer);
  for i := 0 to 9 do
    List.Add(IntToStr(Random(1000)));
  List.Sort;
  //  List.Sort(TComparer<string>.Construct(function(const left,right: string):integer begin
  //     Result:= StrToInt(Left)-StrToInt(Right); 
  //  end));
  for I := 0 to List.Count-1 do Writeln((List[i]));
  List.Free;
end;

2021년 1월 5일 화요일

레코드 형태의 행렬에서 검색하는 방법(TArray.BinarySearch)

type
  TBoll = record
    count: integer;
    name: string;
  end;
var     iArrayBoll: TArray<TBoll>;
procedure TForm1.Button2Click(Sender: TObject);
begin
  SetLength(iArrayBoll, Memo1.Lines.count);
  for var idx := low(iArrayBoll) to high(iArrayBoll) do begin
    iArrayBoll[idx].count := 25;
    iArrayBoll[idx].name := Memo1.Lines[idx];
  end;
  TArray.Sort<TBoll>(iArrayBoll, TComparer<TBoll>.Construct(
    function(const a, b: TBoll): integer begin
      // Result := StrToint(a.name) - StrToint(b.name); //숫자크기우선 정렬
      Result:= CompareText(a.name, b.name); //스트링 정상 정렬
    end));
  for var idx := low(iArrayBoll) to High(iArrayBoll) do begin
    Memo2.Lines.Add(iArrayBoll[idx].name + '=' + iArrayBoll[idx].count.ToString);
  end;
end;


procedure TForm1.Button4Click(Sender: TObject);
var
  idx: integer;
  iBoll: TBoll;
  Found: boolean;
begin
  if rbLineair.Checked then begin
    for idx := 0 to High(iArrayBoll) do
      if Edit1.Text = iArrayBoll[idx].name then begin
        Caption := intToStr(idx);
        Exit;
      end;
  end else begin
    iBoll.name := Edit1.Text;
    iBoll.count := 250;
    Found := TArray.BinarySearch<TBoll>(iArrayBoll, iBoll, idx, TDelegatedComparer<TBoll>.Construct(
      function(const a, b: TBoll): integer begin
        Result := CompareText(a.name, b.name);
      end));
    if Found then Caption := intToStr(idx) else Caption := 'No';
  end;
end;

사전에 정상 정렬되어 있지 않은 경우 아래처럼 오류가 나온다. BinarySearch 전에 스트링의 경우 정상 정렬(숫자크기우선 정렬이면 안됨)이되어 있어야 한다. 이것 때문에 두어시간 해메었었네요.

레코드 형태의 행렬을 소팅하는 방법(별거아닌데 예제가 귀해서...)

 TArray<integer>나, Tarray<string> 으로 되어 있느 배열은 Tarray.sort<integer>(iArray) 과 같은 방법으로 할수 있습니다.

procedure TForm1.Button1Click(Sender: TObject);
var     iArray: TArray<string>;
begin
  SetLength(iArray, Memo1.Lines.count);
  iArray := Memo1.Lines.ToStringArray;
  TArray.Sort<string>(iArray);
  Memo2.Lines.AddStrings(iArray);
end;

유사한 방법으로 레코드 형태의 배열이며 특정 필드로 소팅한다면

  TBoll = record
    count: integer;
    name: string;
  end;
procedure TForm1.Button2Click(Sender: TObject);
var     iArrayBoll: TArray<TBoll>;
begin
  SetLength(iArrayBoll, Memo1.Lines.count);
  for var idx := low(iArrayBoll) to high(iArrayBoll) do begin
    iArrayBoll[idx].count := 0;
    iArrayBoll[idx].name := Memo1.Lines[idx];
  end;
  TArray.Sort<TBoll>(iArrayBoll, TComparer<TBoll>.Construct(
    function(const a, b: TBoll): integer
    begin
      Result := StrToint(a.name)- StrToInt(b.name); 
     //string 의 경우에는 Result:= CompareText(a.name, b.name);
    end));
  for var idx := low(iArrayBoll) to High(iArrayBoll) do begin
    Memo2.Lines.Add(iArrayBoll[idx].name);
  end;
end;

검색은

procedure TForm1.Button3Click(Sender: TObject);

var
  iStr: string;
  idx: integer;
begin
  iStr := Edit1.Text;
  if Tarray.BinarySearch<string>(iArray, iStr, idx) then Button3.Caption:= intToStr(idx);
end;

델파이의 부활(Antigravity와의 만남)?

 델파이 프로그램을 사용하여 개인적으로 필요한 프로그램을 생성해 왔는데, 얼마전부터 파이썬으로 옮겨갔다.  그런데 Google 의 Antigravity를 만나고 나서 델파이에 대한 미련을 버리지 못해  제미나이가 Delphi이에 대한 학습도 엄청 했을...