Your wish is my command

It’s a long journey

Wslib V2

wslib v2가 릴리스 되었습니다.

TwsListView에서 컬럼을 클릭하면 자동으로 정렬하는 옵션을 추가했네요. 리스트뷰 정렬에 이제 코딩이 하나도 필요없습니다.

덧) 버전을 r2에서 v2로 변경했습니다. Google code 위키에서 r2를 SubVersion revision으로 인식하고 바로 거기로 링크를 해버리네요.

Www/wordpress-themes Ports

개인적으로 사용하고 있던 wordpress-themes ports를 저는 이미 send-pr했었고 아직 approved가 안된 것으로 알고 있었습니다. 그런데 너무 오래걸린다 하고 혹시나하고 살펴보니 send-pr을 하지 않았더군요. 큭.. 이런 건망증인지..

방금 send-pr 했음

TPopupMenu의 기본 메뉴 실행하기

윈도우 탐색기의 팝업 메뉴를 보면 오른쪽 그림처럼 Open 메뉴 아이템은 굵은 폰트로 표시됩니다. 이건 해당 아이템을 더블클릭 또는 엔터키를 누르면 해당 메뉴를 실행하겠다는 Windows의 표현입니다.

당연히 TPopupMenu에서도 지원하지요. TMenuItem.Default 프러퍼티가 있으면 수행하면 됩니다.

그런데 이 기능을 구현하려면 여간 귀찮치요.

  1. 키보드 메시지 처리해서 VK_RETURN 메시지 처리하고
  2. 더블클릭했을때도 체크하고
  3. 또한 해당 컨트럴에 연결된 팝업 메뉴도 확인해서 기본 메뉴가 있는지 없는지 확인하고..
  4. 있으면 이벤트 실행하고..

컨트럴에 연결된 팝업 메뉴의 기본 액션을 수행하는 것만 보자면..

function TwsControlHelper.ExecuteDefaultPopupAction: Boolean;
// 팝업 메뉴의 디폴트로 설정된 메뉴 아이템에 설정된 이벤트를 실행한다
var
  Item, DefaultItem: TMenuItem;
begin
  Result := False;
  if not Assigned(PopupMenu) then Exit;

  DefaultItem := nil;
  for Item in PopupMenu.Items do
    if Item.Default then
    begin
      DefaultItem := Item;
      Break;
    end;

  if Assigned(DefaultItem) then
  begin
    if Assigned(DefaultItem.Action) then
      Result := DefaultItem.Action.Execute
    else if Assigned(DefaultItem.OnClick) then
    begin
      Result := True;
      DefaultItem.OnClick(DefaultItem);
    end;
  end
end;

TControl의 Helper로 작성했이니 어디서든 저렇게 쓰면 됩니다. 이것을 키보드나 마우스 이벤트 핸들러에 적용해보면..

procedure TwsListView.DblClick;
begin
  // 더블클릭에 아무런 이벤트도 연결되어 있지않으면 기본 팝업 액션을 수행
  if not Assigned(OnDblClick) and Assigned(PopupMenu) then
    ExecuteDefaultPopupAction else
    inherited;
end;

procedure TwsListView.KeyUp(var Key: Word; Shift: TShiftState);
begin
  case Key of
    VK_RETURN:
      if not FCaptionEditing then
      begin
        if not ExecuteDefaultPopupAction then
          inherited;
      end else
        inherited;
    else inherited;
  end;
end;

이렇게 됩니다.

TwsListView에 연결된 팝업메뉴에 기본 메뉴가 있으면, 이제 리스트 뷰에서 Enter를 누르거나 아이템을 더블클릭하면 해당 메뉴 이벤트가 자동으로 수행됩니다.

TListView의 Caption Editing와 VK_RETURN 키 이벤트

제목을 쓰기 거시기해서 위처럼 적었고.. 하여간 TListView에서 EditCaption 기능은 자주 사용되는 기능이죠.  그리고 리스트 뷰에서 Enter를 누르면 뭔가 실행하는 것도 자주 하는 것이고..

이 두가지를 하게 되면 뭔가 꼬입니다. TListView의 Key[Up|Down]에서 VK_RETURN일 때 뭔가 하려는데, 잘 되는것 처럼 보이는데, 캡션을 편집중일 떄(IsEditing=True)는 캡션 편집을 완료하고자 누르는 엔터에 반응을 하는 문제가 있습니다.

case Key of
  VK_RETURN:
      // Editing을 끝내는 Enter도 아래가  수행됩니다.
      DoSomething;

이걸 해결하고자 간단히 IsEditing을 사용하면..

case Key of
  VK_RETURN:
      // 이렇게해도 상황은 나아지지 않지요.
      if not IsEditing then
        DoSomething;

잘 될것 같은데, 안됩니다. 저 이벤트는 Inline Editor의 Enter이벤트를 넘기는 것이니깐, 저 함수가 실행될 때도 IsEditing=True가 됩니다. 이걸 해결하려면… 뭐 TListView의 Notify이벤트를 써야하니 TListView를 상속해서 하나 만들어야 하지요.

TMyListView = class(TListView)
private
  FItemCaptionEditing: Boolean;
protected
    procedure CNNotify(var Message: TWMNotify); message CN_NOTIFY;
    procedure KeyUp(var Key: Word; Shift: TShiftState); override;
end;

procedure TMyListView.CNNotify(var Message: TWMNotify);
begin
  inherited;

  with Message do
    case NMHdr^.code of
      LVN_BEGINLABELEDIT: FItemCaptionEditing := True;
      LVN_ENDLABELEDIT:  FItemCaptionEditing := False;
    end;
end;

procedure TMyListView.KeyUp(var Key: Word; Shift: TShiftState);
begin
  case Key of
    VK_RETURN:
      if not FItemCaptionEditing then
        DoSomething else
        inherited;
  end;
end;

해결되었군요. 근데 이게 델파이의 문제일까요? Windows의 문제일까요? Windows에 한표.. 근데 문제일까요? 아닐까요?… 흠흠.. 그건… 에매하네요.

TBitBtn.DoubleBuffered

TBitBtn을 폼에 올려놓으면 DoubleBuffered가  True로 설정된다. 근데 왜? 콤포넌트의 기본값은 DoubleBuffered=True로 설정해 놓지 않을걸까?

TValueListEditor OnValidate

TValueListEditor에서 입력한 값을 Validation하려고 봤더니 Validate에 뭔가 이상합니다. OnValidate 이벤트에 성공/ 실패가 있을줄 알았더니만 없네..

그래서 OnValidate에 아래처럼하고

procedure TValueListEditorForm.ValueListEditor1Validate(Sender: TObject; ACol,
  ARow: Integer; const KeyName, KeyValue: string);
begin
  if Trim(KeyValue) = " then
    FValidateFailed := True;
  end;

선택을 못하게.. ㅋㅋ

procedure TValueListEditorForm.ValueListEditor1SelectCell(Sender: TObject; ACol,
  ARow: Integer; var CanSelect: Boolean);
begin
  if FValidateFailed then
  begin
    CanSelect := False;
    FValidateFailed := False;
  end;
end;

Drag and Drop Component Suite를 이용한 탐색기에 파일 저장 그리고..

Drag and Drop Component Suite를 이용해 어제 오늘 놀고 있습니다. 이걸로

  1. ListView에 파일 목록이 있고 이를 탐색기로 Drag&Drop로 저장
  2. 파일의 데이터는 실제 파일이 아니고 Application에서 생성하는 데이터
  3. Drag&Drop으로 ListView안에서 위치 조절

와 같은 일을 하고자 합니다. 1, 2 번은 Drag&Drop Suite에서 제공해주는 TVirtualFileStreamDataFormat을 이용해서 하면 되는데, 마지막 리스트 안에서 위치조절하는 것은 복잡하네요.

Shell로 Drag&Drop이 없으면 간단히 델파이에서 제공하는 기능을 이용하면 되는데, Drag&Drop Suite와 같이 쓰면 이것이 안됩니다. 둘중에 하나만 사용해야하는 현상이 발생합니다(이것때문에 삽질좀 하고..).

결국은 TCustomDataFormat을 이용해서 2가지 데이터 형태를 같이 사용해서 해결했습니다. 자세한 내용은 코드확인!

[DragDropShellAndVCL][2]