TStringList에는 Sort기능이 있다 
이것은 프로그램에 매우 유용하게 쓰일수 있다. 

TStringList의  Sort기능  QuickSort로 구현되어있다. 
아래팁에 TStringList의 VCL소스를 참조하라 
http://cbuilder.borlandforum.com/impboard/impboard.dll?action=read&db=bcb_tip&no=733 

아래 샘플들은 TMemo 에 있는 내용을 TStringList를 Sorting하는 예제들이다. 

[방법1] 
;기본 Sort() 메소드를 이용 

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    TStringList *lst=new TStringList;
    lst->Assign(Memo1->Lines);
    lst->Sort();
    Memo1->Lines->Assign(lst);
    delete lst;
}



[방법2] 
;Sorted = true 기능 이용 
; 이 기능은 특별히 Sort함수를 호출하지 않아도 
; data가 add될때 알아서 Sort해준다. 

void __fastcall TForm1::Button2Click(TObject *Sender)
{
    TStringList *lst=new TStringList;
    lst->Sorted=true;
    lst->Assign(Memo1->Lines);
    Memo1->Lines->Assign(lst);
    delete lst;
}



[방법3] 
; 정렬하면서 중복되는 데이타 삭제 
; 방법2의 기능에서  list의 Duplicates=dupIgnore 로 해주면 중복되는 데이타는 삭제된다. 

void __fastcall TForm1::Button3Click(TObject *Sender)
{
    TStringList *lst=new TStringList;
    lst->Sorted=true;
    lst->Duplicates=dupIgnore;
    lst->Assign(Memo1->Lines);
    lst->Add("dfaf");
    Memo1->Lines->Assign(lst);
    delete lst;
}



Duplicates 옵션은 3가지가 있다. 
0- dupIgnore   : 중복되는 데이타 무시 
1 - dupError    : 중복인 경우 에러발생 
2 - dupAccept : 중복인경우에도 수용 


[방법4] 
; 그런데 StringList의 Sort기능은 기본적으로 string을 compare한다. 
   즉  1,2,3,14,23,31 이 있는경우 정렬하면  1,14,2,23,3,31 이런 순으로 정렬된다. 
   오름차순 순서대로 1,2,3,14,23,31 순으로 정렬하기 위해서는 CustomSort 기능을 이용하여 
   직접 Sort함수를 만들어서 쓰면된다. 

int __fastcall ListSortIntegerProc(TStringList *lst,int r1,int r2)
{
    if(StrToInt(lst->Strings[r1])>StrToInt(lst->Strings[r2]))return 1;
    else if(StrToInt(lst->Strings[r1])Strings[r2])) return -1;
    else return 0;
}
void __fastcall TForm1::Button5Click(TObject *Sender)
{
    TStringList *lst=new TStringList;
    lst->Assign(Memo1->Lines);
    lst->CustomSort(ListSortIntegerProc);
    Memo1->Lines->Assign(lst);
    delete lst;
}


//------------------------------------------ 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 델파이
 //오름차순 정렬
 
function ListSortIntegerProcAsc(lst:TStringList;r1,r2:Integer):Integer;
begin
    if(StrToInt(lst.Strings[r1])>StrToInt(lst.Strings[r2])) then Result:= 1
    else if(StrToInt(lst.Strings[r1])(LST.Strings[r2]))then  Result:=-1
    else Result:= 0;
end;
 
procedure TfrmWebHard.Button2Click(Sender: TObject);
var
  sLst: TStringList;
begin
  sLst:=TStringList.Create;
  sLst.Assign(Memo1.Lines);
  sLst.CustomSort(ListSortIntegerProcAsc);
  Memo1.Lines.Assign(sLst);
  sLst.Free;
end;



[방법5] 
; 방법4와 같은 방법인데 내림차순으로 정렬하고 싶으면 
; CustomSort로 넘겨주는 process만 수정하면된다. 

int __fastcall ListSortIntegerDescProc(TStringList *lst,int r1,int r2)
{
    if(StrToInt(lst->Strings[r1])Strings[r2]))return 1;
    else if(StrToInt(lst->Strings[r1])>StrToInt(lst->Strings[r2])) return -1;
    else return 0;
}
//----------------------------------------------------------------
void __fastcall TForm1::Button6Click(TObject *Sender)
{
    TStringList *lst=new TStringList;
    lst->Assign(Memo1->Lines);
    lst->CustomSort(ListSortIntegerDescProc);
    Memo1->Lines->Assign(lst);
    delete lst;
}




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//델파이
//내림차순 정렬
 
function ListSortIntegerProcDesc(lst:TStringList;r1,r2:Integer):Integer;
begin
    if(StrToInt(lst.Strings[r1])>StrToInt(lst.Strings[r2]))then Result:= -1
    else if(StrToInt(lst.Strings[r1])(LST.Strings[r2]))then  Result:= 1
    else Result:= 0;
end;
procedure TfrmWebHard.Button3Click(Sender: TObject);
var
  sLst: TStringList;
begin
  sLst:=TStringList.Create;
  sLst.Assign(Memo1.Lines);
  sLst.CustomSort(ListSortIntegerProcDesc); 
  Memo1.Lines.Assign(sLst);
  sLst.Free;
end;



[방법6] 
; 마지막으로 TStringList를 이용하여 Sort기능을 이용할때 
  sorting전에 순서는 기억하지 못한다. 
  sorting후에 sort전에 순서가 필요한 경우 다음과 같이 하면된다. 

void __fastcall TForm1::Button7Click(TObject *Sender)
{
    TStringList *lst=new TStringList;
    lst->Assign(Memo1->Lines);
    for(int i=0;iCount;i++)lst->Objects[i]=(TObject *)i;
    lst->CustomSort(ListSortIntegerProc);

    Memo1->Lines->Clear();
    for(int i=0;iCount;i++)
        Memo1->Lines->Add(lst->Strings[i]+"  orginal  order:"+IntToStr(int(lst->Objects[i])));

    delete lst;
}

원본링크 : http://www.borlandforum.com/impboard/impboard.dll?action=read&db=bcb_tip&no=735


두 함수의 기능

=> 메시지는 주로 사용자에 의해 발생되지만 프로그램 내부에서 윈도우간의 통신을
위해 의도적으로 다른 윈도우에게 메시지를 보낼 수도 있다. 이때는 다음 두 함수를 
사용한다.

BOOL PostMessage( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam );
LRESULT SendMessage( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam );

두 함수의 인수가 완전히 동일하다. 여기서 Post 라는 말은 우리말로 "붙인다"라고
번역하며 Send 라는 말은 "보낸다"라고 번역한다.




★ PostMessage 함수


PostMessage 함수는 Msg 인수로 지정된 메시지를 hWnd 윈도우의 메시지 큐에 집어넣어

윈도우 프로시저에서 이 메시지를 처리하도록 한다. 메시지를 메시지 큐에 넣어 놓기만

하고 곧바로 리턴하므로 메시지는 곧바로 처리되지 않는다. 큐에 붙여진 메시지는

GetMessage 에 의해 읽혀지고 DispatchMessage 에 의해 윈도우 프로시저로 보내져

처리될 것이다.



급하게 처리될 필요가 없거나 또는 지금 하고 있는 작업을 완전히 끝내야만 처리할

수 있는 메시지는 PostMessage 함수로 큐에 붙인다. 이 함수로 붙여진 메시지는

언제 처리될지 정확하게 예측하기 힘들다. 그래서 붙여지는 메시지의 wParam 과

lParam 에는 지역 포인터를 사용하지 않아야 한다. 메시지를 붙일 시점에는

포인터가 존재했더라도 메시지가 처리될 시점에는 포인터가 무효해질 수 있기

때문이다.


PostMessage 는 메시지를 큐에 붙인 후 성공하면 TRUE 를 리턴하며 실패하면

FALSE 를 리턴하는데 이 리턴값은 가급적이면 점검해보는 것이 좋다. 왜냐하면

메시지 큐는 크기가 한정되어 있기 때문에 고속으로 전송되는 모든 메시지를

다 수용하지 못할 수도 있기 때문이다.



PostMessage 의 첫번째 인수인 hWnd 는 이 메시지를 받을 윈도우의 핸들인데 이값은

아주 특수하게 NULL 일 수도 있다. 즉, 메시지를 받는 대상 윈도우가 없는 메시지를

큐에 붙일 수도 있는데 이런 메시지는 특정 윈도우에게 신호를 보내기 위한 것이

아니라 응용 프로그램 전반에 걸친 작업 지시를 보낼때 사용된다. 대상 윈도우가

없기 때문에 이 메시지는 윈도우 프로시저가 처리할 수 없으며 반드시 메시지 루프에서

직접 처리해주어야 한다.



while(GetMessage(&Message, 0, 0, 0) {
if (Message.message == WM_SOME ) {
// 직접 처리
} else {
TranslateMessage( &Message );
DispatchMessage( &Message );
}
}



GetMessage 로 메시지를 꺼낸 후 곧바로 메시지 ID 를 비교해보고 스레드를 위한

메시지인지 검사해본다. 만약 스레드를 위한 메시지라면 메시지 루프에서

직접 처리해야 하며 DispatchMessage 함수로 보내서는 안된다. 대상 윈도우가

지정되지 않은 메시지이기 때문에 이 메시지를 받아줄 윈도우 프로시저가 없기

때문이다. PostMessage 함수가 메시지를 붙여넣는 큐가 윈도우를 위한 큐가 아니라

스레드를 위한 큐이기 때문에 이런 기법이 가능하다. 다른 스레드의 메시지 큐에

메시지를 붙일 때는 다음 함수가 사용된다.



BOOL PostThreadMessage ( DWORD idThread, UINT Msg, WPARAM wParam, LPARAM lParam );



윈도우 핸들 대신 스레드의 ID를 첫 번째 인수로 지정해준다. 이때 이 메시지를 받을

스레드는 반드시 스레드 큐를 가지고 있어야 하는데 큐를 가지지 않는

작업 스레드(Worker Thread)는 메시지를 받지 못한다.






★ SendMessage 함수

메시지를 큐에 넣는 것이 아니라 곧바로 윈도우 프로시저로 보내 즉각 처리하도록

하며 메시지가 완전히 처리되기 전에는 리턴하지 않는다. 즉 블록시킨다. 그래서

SendMessage는 윈도우간, 특히 부모 윈도우와 차일드 컨트롤간의 통신에 자주 사용된다.






         PostMessage     SendMessage
        ↙            ↙
┏━┓    ┏━┓ 메시지루프    ↙
┃ ┃------→┃ ┃-------------→ WndProc
┃ ┃    ┃ ┃
┃ ┃    ┃ ┃
┗━┛    ┗━┛
시스템    스레드
메시지큐   메시지큐






질문2) 함수명앞의 LRESULT , BOOL 의 선언은 function 의 리턴예약어 Result 와 Boolean 명칭하는건가요?

=> BOOL 은 델파이에서의 Boolean 과 같습니다.


그러나, LRESULT 는 Result 와는 다릅니다.

LRESULT 는 Win32 API 에서 쓰이는 리턴값의 한 종류입니다.

Result 는 델파이에서 function 의 마지막에 사용되는 C언어로 따지자면 return 예약어와 같은 것입니다.


원본 링크 : http://blog.daum.net/magixtech/1906578




uses

  ComObj;

var

  ExcelApp: OleVariant;

implementation


procedure TForm1.Button1Click(Sender: TObject);

const

  // SheetType

  xlChart = -4109;

  xlWorksheet = -4167;

  // WBATemplate

  xlWBATWorksheet = -4167;

  xlWBATChart = -4109;

  // Page Setup

  xlPortrait = 1;

  xlLandscape = 2;

  xlPaperA4 = 9;

  // Format Cells

  xlBottom = -4107;

  xlLeft = -4131;

  xlRight = -4152;

  xlTop = -4160;

  // Text Alignment

  xlHAlignCenter = -4108;

  xlVAlignCenter = -4108;

  // Cell Borders

  xlThick = 4;

  xlThin = 2;

var

  ColumnRange: OleVariant;

  // Function to get the number of Rows in a Certain column

  function GetLastLine(AColumn: Integer): Integer;

  const

    xlUp = 3;

  begin

    Result := ExcelApp.Range[Char(96 + AColumn) + IntToStr(65536)].end[xlUp].Rows.Row;

  end;

begin

  { Start Excel }

  // By using GetActiveOleObject, you use an instance of Word that's already running,

  // if there is one.

  try

    ExcelApp := GetActiveOleObject('Excel.Application');

  except

    try

      ExcelApp := GetActiveOleObject('scalc.Application');

    except  

      try

        // If no instance of Word is running, try to Create a new Excel Object

        ExcelApp := CreateOleObject('Excel.Application');  

      except

        try

          // If no instance of Word is running, try to Create a new scalc Object

          ExcelApp := CreateOleObject('scalc.Application');  

        except

          ShowMessage('Cannot start Excel/Excel not installed ?');

          Exit;

        end;                

      end;    

    end;

  end;

  // Add a new Workbook, Neue Arbeitsmappe offnen

  ExcelApp.Workbooks.Add(xlWBatWorkSheet);

  // Open a Workbook, Arbeitsmappe offnen

  ExcelApp.Workbooks.Open('c:\YourFileName.xls');


  // Rename the active Sheet

  ExcelApp.ActiveSheet.Name := 'This is Sheet 1';

  // Rename

  ExcelApp.Workbooks[1].WorkSheets[1].Name := 'This is Sheet 1';

  // Insert some Text in some Cells[Row,Col]

  ExcelApp.Cells[1, 1].Value := 'SwissDelphiCenter.ch';

  ExcelApp.Cells[2, 1].Value := 'http://www.swissdelphicenter.ch';

  ExcelApp.Cells[3, 1].Value := FormatDateTime('dd-mmm-yyyy', Now);

  // Setting a row of data with one call

  ExcelApp.Range['A2', 'D2'].Value := VarArrayOf([1, 10, 100, 1000]);

  // Setting a formula

  ExcelApp.Range['A11', 'A11'].Formula := '=Sum(A1:A10)';

  // Change Cell Alignement

  ExcelApp.Cells[2, 1].HorizontalAlignment := xlright;

  // Change the Column Width.

  ColumnRange := ExcelApp.Workbooks[1].WorkSheets[1].Columns;

  ColumnRange.Columns[1].ColumnWidth := 20;

  ColumnRange.Columns[2].ColumnWidth := 40;

  // Change Rowheight / Zeilenhohe andern:

  ExcelApp.Rows[1].RowHeight := 15.75;

  // Merge cells, Zellen verbinden:

  ExcelApp.Range['B3:D3'].Mergecells := True;

  // Apply borders to cells, Zellen umrahmen:

  ExcelApp.Range['A14:M14'].Borders.Weight := xlThick; // Think line/ Dicke Linie

  ExcelApp.Range['A14:M14'].Borders.Weight := xlThin;  // Thin line Dunne Linie

  // Set Bold Font in cells, Fettdruck in den Zellen

  ExcelApp.Range['B16:M26'].Font.Bold := True;

  // Set Font Size, Schriftgroße setzen

  ExcelApp.Range['B16:M26'].Font.Size := 12;

  //right-aligned Text, rechtsbundige Textausrichtung

  ExcelApp.Cells[9, 6].HorizontalAlignment := xlright;

  // horizontal-aligned text, horizontale Zentrierung

  ExcelApp.Range['B14:M26'].HorizontalAlignment := xlHAlignCenter;

  // left-aligned Text, vertikale Zentrierung

  ExcelApp.Range['B14:M26'].VerticallyAlignment := xlVAlignCenter;


  { Page Setup }

  ExcelApp.ActiveSheet.PageSetup.Orientation := xlLandscape;

  // Left, Right Margin (Seitenrander)

  ExcelApp.ActiveSheet.PageSetup.LeftMargin  := 35;

  ExcelApp.ActiveSheet.PageSetup.RightMargin := -15;

  // Set Footer Margin

  ExcelApp.ActiveSheet.PageSetup.FooterMargin := ExcelApp.InchesToPoints(0);

  // Fit to X page(s) wide by Y tall

  ExcelApp.ActiveSheet.PageSetup.FitToPagesWide := 1;  // Y

  ExcelApp.ActiveSheet.PageSetup.FitToPagesTall := 3; // Y

  // Zoom

  ExcelApp.ActiveSheet.PageSetup.Zoom := 95;

  // Set Paper Size:

  ExcelApp.PageSetup.PaperSize := xlPaperA4;

  // Show/Hide Gridlines:

  ExcelApp.ActiveWindow.DisplayGridlines := False;

  // Set Black & White

  ExcelApp.ActiveSheet.PageSetup.BlackAndWhite := False;

  // footers

  ExcelApp.ActiveSheet.PageSetup.RightFooter := 'Right Footer / Rechte Fußzeile';

  ExcelApp.ActiveSheet.PageSetup.LeftFooter  := 'Left Footer / Linke Fußzeile';

  // Show Excel Version:

  ShowMessage(Format('Excel Version %s: ', [ExcelApp.Version]));

  // Show Excel:

  ExcelApp.Visible := True;

  // Save the Workbook

  ExcelApp.SaveAs('c:\filename.xls');

  // Save the active Workbook:

  ExcelApp.ActiveWorkBook.SaveAs('c:\filename.xls');

end;

procedure TForm1.FormDestroy(Sender: TObject);

begin

  // Quit Excel

  if not VarIsEmpty(ExcelApp) then

  begin

    ExcelApp.DisplayAlerts := False;  // Discard unsaved files....

    ExcelApp.Quit;

  end;

end;


원본 링크 : http://seniorkr.tistory.com/41


선그리기 참고 


procedure TForm1.Button1Click(Sender: TObject);
var
  Excel: OleVariant;
  WorkBook: OleVariant;
  WorkSheet: OleVariant;

  i : integer;

Const
  xlNone = -4142;
  xlDiagonalDown = 5;
  xlDiagonalUp = 6;
  xlEdgeLeft = 7;
  xlEdgeTop = 8;
  xlEdgeBottom = 9;
  xlEdgeRight = 10;
  xlContinuous = 1;

  xlThin = 2;
  xlThick = 4;

  xlAutomatic = -4105;

begin

  Excel := CreateOleObject('Excel.Application');
  Excel.Visible := True;

  // 워크북 추가
  Excel.WorkBooks.Add;
  WorkBook := Excel.ActiveWorkBook;

  // 워크시트 추가
  Workbook.sheets.add;

  // 작업할  워크시트 선택
  WorkSheet := WorkBook.WorkSheets[1];

  // 선그리기
  WorkSheet.Range['B5:E10'].Borders[xlDiagonalDown].LineStyle := xlNone;
  WorkSheet.Range['B5:E10'].Borders[xlDiagonalUp].LineStyle := xlNone;
  WorkSheet.Range['B5:E10'].Borders[xlEdgeLeft].LineStyle := xlContinuous;
  WorkSheet.Range['B5:E10'].Borders[xlEdgeTop].LineStyle := xlContinuous;
  WorkSheet.Range['B5:E10'].Borders[xlEdgeBottom].LineStyle := xlContinuous;
  WorkSheet.Range['B5:E10'].Borders[xlEdgeBottom].Weight := xlThick;
  WorkSheet.Range['B5:E10'].Borders[xlEdgeBottom].ColorIndex := xlAutomatic;
  WorkSheet.Range['B5:E10'].Borders[xlEdgeRight].LineStyle := xlContinuous;

end;


원본 : http://wwwi.tistory.com/174


참고

http://skql.tistory.com/11

http://www.nika-soft.com/nativeexcel2/doc/brd_pls.htm



실제 적용 소스


//엑셀파일로 저장하기

procedure TfN040070_1.Btn_SaveClick(Sender: TObject);

var

  vHandle : THandle;

  vExcel  : Variant;

  vSheet  : Variant;

  Range   : Variant;

  i       : integer;

Const

  xlCenter = -4108;

  xlRight = -4152;

  xlNone = -4142;

  xlDiagonalDown = 5;

  xlDiagonalUp = 6;

  xlEdgeLeft = 7;

  xlEdgeTop = 8;

  xlEdgeBottom = 9;

  xlEdgeRight = 10;

  xlContinuous = 1;


  xlThin = 2;

  xlThick = 4;


  xlAutomatic = -4105;


begin

  vHandle := FindWindow('XLMAIN',nil);

  if vHandle <> 0 then vExcel := GetActiveOLEObject('Excel.Application')

  else

  begin

    try

      vExcel := CreateOLEObject('Excel.Application');

    except

      Application.MessageBox('Excel을 열 수 없습니다.'+ char(13) +

                             'Excel이 설치되어 있는지 확인하세요!',

                             '정보', MB_OK);

    end;

  end;


  //엑셀객체 정의

  vExcel.Visible := True;                                      


  SetForegroundWindow(vHandle);

  vExcel.WorkBooks.Add;

  vExcel.WorkBooks[vExcel.WorkBooks.Count].WorkSheets[1].Name := Caption;

  vSheet := vExcel.WorkBooks[vExcel.WorkBooks.Count].WorkSheets[Caption];


  //컬럼, 로우 사이즈 변경

  vSheet.Columns[1].ColumnWidth := 35;

  vSheet.Columns[2].ColumnWidth := 20;

  vSheet.Columns[3].ColumnWidth := 10;

  vSheet.Columns[4].ColumnWidth := 25;


  vExcel.Rows[1].RowHeight := 8;

  vExcel.Rows[4].RowHeight := 8;


  //해더 설정

  vSheet.Cells[2,1].Value := 'TEST1'; vSheet.Cells[2,2].Value := Trim(B_1.Caption);

  vSheet.Cells[2,3].Value := 'TEST2'; vSheet.Cells[2,4].Value := Trim(B_2.Caption);

  vSheet.Range['A2:D2'].Borders.LineStyle := xlContinuous;


  vSheet.Cells[3,1].Value := 'TEST3'; vSheet.Cells[3,2].Value := Trim(B_3.Caption);

  vSheet.Cells[3,3].Value := 'TEST4;  vSheet.Cells[3,4].Value := Trim(B_4.Caption);

  vSheet.Range['A3:D3'].Borders.LineStyle := xlContinuous;


  //데이터 설정

  for i:= 0 to ed_contents.Lines.Count -1 do begin

    //데이터 치환_ 메모장에서 한줄씩 치환

    vSheet.Cells[5+i,1].Value := ed_contents.Lines.Strings[i];


    //테두리 라인 그리기

    vSheet.Range['A'+IntToStr(5+i)].Borders[xlEdgeLeft].LineStyle := xlContinuous; //왼쪽 라인 그리기

    vSheet.Range['D'+IntToStr(5+i)].Borders[xlEdgeRight].LineStyle:= xlContinuous; //오른쪽 라인 그리기


    if i = 0 then //첫번째줄

      vSheet.Range['A'+IntToStr(5+i), 'D'+IntToStr(5+i)].Borders[xlEdgeTop].LineStyle := xlContinuous //윗쪽 라인 그리기

    else if i = ed_contents.Lines.Count -1 then //마지막줄

      vSheet.Range['A'+IntToStr(5+i), 'D'+IntToStr(5+i)].Borders[xlEdgeBottom].LineStyle := xlContinuous; //아랫쪽 라인 그리기

  end;


  //눈금자 안보이게 설정

  vExcel.ActiveWindow.DisplayGridlines := False;

end;

+ Recent posts