Q&A

  • 질문]Tmemo field 내용을 스크롤시킬때...
화면에 네게의 TMEMO field(Tmemo1,Tmemo2,Tmeom3,Tmemo4) 가 있고, 각각 vertical scroll bar가 있어서,
버티칼 스크롤바를 움직이면, 메모필드 속의 내용을 스크롤 시켜서 볼 수 있습니다.

만약 어느 하나의 스크롤바를 마우스로 클릭하고 하방으로 드래그 시킬때(그러면 메모필드의 텍스트들이 스크롤되어 보이겠죠) 나머지 세개의 스크롤바도 똑같이 움직이는 효과를 구현하려면,
어떻게 처리를 해야하는지요?

다시말씀드리면, 네게의 서로 다른 메모 필드의 버티컬스크롤바를 , 어느 한 필드의 버티컬스크롤바로
동시에 제어하는 방법입니다.
(제생각엔, 버티컬 스크롤바의 위치를 버티컬바에서 계산하여, 나머지에도 그 위치 값을 넣어주면
될것 같은데, 초보라 어찌할 바를 모르겠습니다.어떤 함수를 써야하는지도 모르겠구요^^)

감사합니다.

참고로...다음 프로시져는 여기서 확인한 내용임
procedure TForm1.ScrollBar1Scroll(Sender: TObject; ScrollCode: TScrollCode;
  var ScrollPos: Integer);
begin

         begin
          memo1.Perform(WM_VSCROLL,SB_LINEDOWN,0);
          memo2.Perform(WM_VSCROLL,SB_LINEDOWN,0);
         end;
end;

end.
이렇게하면 하나의 추가 수직스크롤바를 추가하여 이것을 스크롤시키면 따라서
두개의 메모필드가 거의 같은 속도로 하방으로만 스크롤 됩니다.
이 수직 스크롤바에 따라 같이 움직이도록 제어코드를 넣어주면 쉬울것 같긴합니다.
6  COMMENTS
  • Profile
    구창민 2009.08.15 02:41
    안녕하세요..

    우선 그 네개의 TMemo 콘트롤의 크기가 동일하다는 가정하에 아래 예제를 따라해보세요..

    저는 두개로만 구현해보았는데, Memo3, Memo4 를 DoSync 프로시저 안에 기술해 주시면 되겠지요..

    원리는 기준이 되는 Memo 콘트롤의 메시지를 가로채서 동일한 메시지를 다른 Memo 콘트롤에도 발생시키는 것입니다.

    이런것을 '서브클래싱'이라고 부릅니다.. 한번 따라해 보시면 이해 되실거예요..

    그럼 즐거운 프로그래밍 하시구요..


    unit Unit4;

    interface

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

    type
    TForm4 = class(TForm)
    Memo1: TMemo;
    Memo2: TMemo;
    Memo3: TMemo;
    procedure FormCreate(Sender: TObject);
    private
    { Private declarations }
    FOldMemoWndProc: TWndMethod;
    procedure NewMemoWndProc(var M: TMessage);
    procedure DoSync(Msg: Cardinal; wParam: Integer; lParam: Integer);
    public
    { Public declarations }
    end;

    var
    Form4: TForm4;
    OldWindowProc : Pointer;

    implementation

    {$R *.dfm}

    procedure TForm4.DoSync(Msg: Cardinal; wParam: Integer; lParam: Integer);
    begin
    Memo2.Perform(Msg, Wparam, Lparam);
    end;

    procedure TForm4.NewMemoWndProc(var M: TMessage);
    begin
    case M.Msg of
    WM_VSCROLL, WM_HSCROLL, WM_MOUSEWHEEL :
    DoSync(M.Msg, M.WParam, M.LParam);
    end;
    FOldMemoWndProc(M);
    end;

    procedure TForm4.FormCreate(Sender: TObject);
    begin
    FOldMemoWndProc := Memo1.WindowProc;
    Memo1.WindowProc := NewMemoWndProc;
    end;


    end.
  • Profile
    김동원 2009.08.15 22:27
    초보가 이해하긴 대단히 어려운 내용같습니다..

    하여간, 좋은 답변주신데 대해 , 저의 감사의 마음을 전합니다.

    고맙습니다.

    FOldMemWnProc(M) <---- 이건 내장 프로시져인가요?

    어떤 내용인지 확인하려면, 어디를 찾아봐야합니까?

    윈도우프로시져???
  • Profile
    구창민 2009.08.17 19:09
    조금 설명을 달아 보겠습니다..

    음.. FOldMemoWndProc 는 함수포인터라고 하는건데.. 일종의 변수라고 보면 됩니다.

    TWndMethod 를 따라가보시면 아래처럼 생겨먹었습니다.
    TWndMethod = procedure(var Message: TMessage) of object;

    TMemo 같은 콘트롤들은 메시지를 처리하는 프로시저를 가지고 있습니다..
    델파이에는 그것들을 프로퍼티화 시켜두었습니다.
    그것이 바로 WndProc 입니다.
    TControl 의 WndProc 를 보면 아래처럼 생겼습니다.
    아래 내용을 다 이해하실 필요는 없고요.. 그냥 이렇게 생겼구나..하고 넘어 가시면 됩니다.


    procedure TControl.WndProc(var Message: TMessage);
    var
    Form: TCustomForm;
    KeyState: TKeyboardState;
    WheelMsg: TCMMouseWheel;
    Panned: Boolean;
    {$IF DEFINED(CLR)}
    LMsg: TMessage;
    {$IFEND}
    begin
    if (csDesigning in ComponentState) then
    begin
    Form := GetParentForm(Self, False);
    if (Form <> nil) and (Form.Designer <> nil) and
    Form.Designer.IsDesignMsg(Self, Message) then Exit
    end;
    if (Message.Msg >= WM_KEYFIRST) and (Message.Msg <= WM_KEYLAST) then
    begin
    Form := GetParentForm(Self);
    if (Form <> nil) and Form.WantChildKey(Self, Message) then Exit;
    end
    else if (Message.Msg >= WM_MOUSEFIRST) and (Message.Msg <= WM_MOUSELAST) then
    begin
    if not (csDoubleClicks in ControlStyle) then
    case Message.Msg of
    WM_LBUTTONDBLCLK, WM_RBUTTONDBLCLK, WM_MBUTTONDBLCLK:
    Dec(Message.Msg, WM_LBUTTONDBLCLK - WM_LBUTTONDOWN);
    end;
    case Message.Msg of
    WM_MOUSEMOVE: Application.HintMouseMessage(Self, Message);
    WM_MBUTTONDOWN:
    begin
    if (csPannable in ControlStyle) and
    (ControlState * [csDestroyingHandle, csPanning] = []) and
    not Mouse.IsDragging then
    begin
    Mouse.CreatePanningWindow;
    Panned := False;
    if Assigned(Mouse.PanningWindow) then
    begin
    if Self is TWinControl then
    Panned := Mouse.PanningWindow.StartPanning(TWinControl(Self).Handle, Self)
    else if Parent <> nil then
    Panned := Mouse.PanningWindow.StartPanning(Parent.Handle, Self)
    else
    begin
    Form := GetParentForm(Self, False);
    if Form <> nil then
    Panned := Mouse.PanningWindow.StartPanning(Form.Handle, Self);
    end;
    end;
    if Panned then
    begin
    Message.Result := 1;
    Application.HideHint;
    end
    else if Assigned(Mouse.PanningWindow) then
    Mouse.PanningWindow := nil;
    end;
    end;
    WM_LBUTTONDOWN, WM_LBUTTONDBLCLK:
    begin
    if FDragMode = dmAutomatic then
    begin
    BeginAutoDrag;
    Exit;
    end;
    Include(FControlState, csLButtonDown);
    end;
    WM_LBUTTONUP:
    Exclude(FControlState, csLButtonDown);
    else
    with Mouse do
    if WheelPresent and (RegWheelMessage <> 0) and
    (Integer(Message.Msg) = Integer(RegWheelMessage)) then
    begin
    GetKeyboardState(KeyState);
    {$IF DEFINED(CLR)}
    WheelMsg := TCMMouseWheel.Create;
    {$IFEND}
    with WheelMsg do
    begin
    Msg := Message.Msg;
    ShiftState := KeyboardStateToShiftState(KeyState);
    WheelDelta := Message.WParam;
    Pos := SmallPoint(Message.LParam and $FFFF, Message.LParam shr 16);
    end;
    {$IF DEFINED(CLR)}
    LMsg := WheelMsg.OriginalMessage;
    MouseWheelHandler(LMsg);
    {$ELSE}
    MouseWheelHandler(TMessage(WheelMsg));
    {$IFEND}
    Exit;
    end;
    end;
    end
    else if Message.Msg = CM_VISIBLECHANGED then
    with Message do
    SendDockNotification(Msg, WParam, LParam);
    Dispatch(Message);
    end;


    Memo1.WindowProc 를 임시로 선언한 함수포인터 변수 FOldMemoWndProc 에 기억해두고,
    Memo1.WindowProc 는 NewMemoWndProc 로 대치시킵니다.

    그렇게 되면 Memo1 에서 발생하는 메시지는 이제 NewMemoWndProc 에서 처리할 수 있게 됩니다.
    또한 NewMemoWndProc 에서 메시지를 처리하고 나서 기존의 메시지도 처리하도록 FOldMemoWndProc(M) 을 호출도 해주는 것이지요..

    Memo 에서 스크롤이 발생할 수 있는경우가 크게 세가지가 있겠지요..

    WM_VSCROLL, WM_HSCROLL, WM_MOUSEWHEEL <-- 이 메시지들인데요..

    이 메시지들이 발생했을때.. 사용자 정의 함수인 DoSync()를 호출해서..

    발생한 메시지와 동일한 메시지들을 다른 Memo 컨트롤에서도 발생시켜 주는것입니다.

    그러면 다른 메모콘트롤들도 스크롤때 발생하는 동일한 동작을 하게 되겠지요..

    procedure TForm4.DoSync(Msg: Cardinal; wParam: Integer; lParam: Integer);
    begin
    Memo2.Perform(Msg, Wparam, Lparam);
    //이곳에 원하시는 Memo 컴포넌트들을 아래처럼 기술해 주시면 되겠지요..
    //Memo3.Perform(Msg, Wparam, Lparam);
    //Memo4.Perform(Msg, Wparam, Lparam);
    end;

    아..말주변이 없어 설명드리기 되게 힘드네요..

    아뭍든 핵심원리는 위와 같습니다..

    그럼.. 즐거운 프로그래밍하세요..
  • Profile
    김동원 2009.08.19 02:08
    어렴풋이 이해할수있게되었습니다. 정말 감사합니다.그런데
    실제로 코드를 입력해보니 아래와 같은 오류가 발생하는데,
    무엇이 잘못되었는지요?
    ]
    Dosync 를 호출하는 과정에서
    DBmemo3.Perform(Msg,Wparam,Lparam);

    여기서 '(' expected but ')' found 라는 오류 메시지가 뜹니다.
    어떻게 수정해야하는지요?
  • Profile
    구창민 2009.08.19 18:25
    동원님.. 위에러만 봐서는 상황을 알 수 없고요...
    에러나는 부분의 함수부분만이라도 떼서 올려보세요..
    혹은 전체코드를 올려도 좋고요..
  • Profile
    김동원 2009.08.21 01:03
    님께서 올려주신대로 새로 코드를 써서 만들었더니 잘 됩니다.
    그런데 문제는 다른데 있었던것 같습니다.

    Memo 컴포넌트에 대해서는 위에 올려주신 것이 잘 동작합니다
    그런데
    똑같은 상황을
    Memo 컴포넌트가 아닌 DBmemo 컴포넌트를 썼더니 안됩니다.

    어떻게 고쳐야할지요?

    Memo2.Perform(Msg, Wparam, Lparam);

    이부분에서 Memo2 를 DBmemo2.Perform 으로 바꿨더니 안됩니다.

    그냥 memo component에서 스크롤 되는 것을 인터셉트하는것과
    dbmemo component 에서 사용하는 함수가 다른가요??
    이해가 잘 안됩니다.(느낌으로는 같을것 같은데요..^^)
    =====================================================
    상세하고 지속적인 답변에 거듭 감사를 드립니다.

    꾸벅

    참고] 제가 만든 코드를 올리려고 해도, 너무 길어서
    올릴수가 없군요.(^_^)
    • 이성찬
    • 2009.08.24 03:47
    • 4 COMMENTS
    • /
    • 0 LIKES
    • 구창민
      2009.08.24 18:34
      안녕하세요.. 코드는 문제 없어보이는데.. 개발하시는 PC 의 OS 가 비스타가 아닌지요? 비스타의 경우...
    • 이성찬
      2009.08.26 06:22
      KDDG_MIN//답변 감사합니다. 하지만 윈도 xp sp3인걸요ㅠ
    • 구창민
      2009.08.26 22:19
      안녕하세요.. 제가 TurboDelphi 가 없어서 테스를 못해보았는데.. 정품으로 테스트시 Vista, XP 에서 ...
    • 이성찬
      2009.08.27 02:47
      KDDG_MIN//아, 여기서도 작동 잘 됩니다 ^^ 감사합니다. 아직 배우는중이라 이런면에서 좀 부족한듯 하네...
    • 박진수
    • 2009.08.21 23:54
    • 1 COMMENTS
    • /
    • 0 LIKES
    • 홍성락
      2009.08.23 09:22
      폴더에 대한 옵션이 많아서 그런가 봅니다. 비스타에선 기본적으로 폴더를 생성하면 [고급특성]에서 '...
    • 치꼬
      2009.08.22 02:51
      배우는 단계에서는 그닥 차이점은 중요하지 않을듯합니다.
    • 윤영훈
    • 2009.08.20 04:14
    • 5 COMMENTS
    • /
    • 0 LIKES
    • 최용일
      2009.08.20 20:31
      ShowMessage대신에 MessageBox나 MessageDlg함수를 쓰세요...
    • 장성호
      2009.08.21 00:49
      //다음과 같이 만들어서.. procedure ShowMessageEx(const sTitle:String;const sMsg:String); b...
    • 성더기
      2009.08.22 02:32
      위에 방법도 있구요 델파이 메뉴의 프로젝트 > 프로젝트 옵션 > 프로그램 타이틀을 다른 바꾸시면...
    • 장성호
      2009.08.22 10:00
      Application 타이틀을 바꿔서도 가능하네요 다음과 같이 Application.Title을 변경해서도 구현이 가능...
    • 윤영훈
      2009.08.25 20:13
      감사합니다~ 한번씩 다 확인해고 제일 맞는 걸로 사용해야겠네요. 도움 주신 분들 정말정말 감사해요~
    • 최용일
      2009.08.18 18:43
      상용이구요... 아래 홈페이지에서 구매하실 수 있습니다. http://www.devart.com/dac.html
    • 조상은
      2009.08.18 19:25
      최용일님 정말 감사합니다. 알려주신 사이트 들어가서 보니 SQL에 직접 붙일 때 사용하는 컴포넌트이...
    • 조상은
      2009.08.18 20:12
      위의 글을 작성하다보니 install package에서 runtime packages 에 정의된 목록이 의심이 가서 다른 정상...
    • 문병구
    • 2009.08.15 00:11
    • 3 COMMENTS
    • /
    • 0 LIKES
    • 백록화
      2009.08.15 09:16
      흠...보통 스캐너에서 바코드번호와 엔터값이 넘어옵니다. 따로 자릿수 처리를 할 필요가 없을껀데요.....
    • 아르스
      2009.08.18 00:15
      백록화 님의 말씀 처럼 OnKeyPress 나 OnKeyDown 이벤트에 if Key = #13 then begin ..... end; 또는 i...
    • 문병구
      2009.08.18 01:21
      맞네요..제가 착각을 했네요... 바코드 값이 읽어지는 것은 마치 키보드에 값을 넣고 모두 넣은 다음 엔...
    • 김동원
    • 2009.08.14 18:55
    • 6 COMMENTS
    • /
    • 0 LIKES
    • 구창민
      2009.08.15 02:41
      안녕하세요.. 우선 그 네개의 TMemo 콘트롤의 크기가 동일하다는 가정하에 아래 예제를 따라해보세요....
    • 김동원
      2009.08.15 22:27
      초보가 이해하긴 대단히 어려운 내용같습니다.. 하여간, 좋은 답변주신데 대해 , 저의 감사의 마음을 ...
    • 구창민
      2009.08.17 19:09
      조금 설명을 달아 보겠습니다.. 음.. FOldMemoWndProc 는 함수포인터라고 하는건데.. 일종의 변수라고...
    • 김동원
      2009.08.19 02:08
      어렴풋이 이해할수있게되었습니다. 정말 감사합니다.그런데 실제로 코드를 입력해보니 아래와 같은 오류...
    • 구창민
      2009.08.19 18:25
      동원님.. 위에러만 봐서는 상황을 알 수 없고요... 에러나는 부분의 함수부분만이라도 떼서 올려보세요....
    • 김동원
      2009.08.21 01:03
      님께서 올려주신대로 새로 코드를 써서 만들었더니 잘 됩니다. 그런데 문제는 다른데 있었던것 같습니다. ...
    • cdrd
    • 2009.08.13 20:15
    • 1 COMMENTS
    • /
    • 0 LIKES
    • 김동원
      2009.08.14 18:24
      위 질문중 1번에서 ADO,BDE 두가지만 말씀드릴수 있습니다. 제가 경험한 것이 이것 뿐이라서요.(저는 초...
    • 현실환
      2009.08.18 21:16
      Antialiased Drawing을 할려면 GDI가 아닌 GDI+ 함수를 이용해야 합니다. 컴포넌트 자체는 TImage를 그...
    • 오델로
    • 2009.08.12 19:50
    • 4 COMMENTS
    • /
    • 0 LIKES
    • 김병윤
      2009.08.12 21:28
      10분에 천원이면...한시간에 6천원...하루에 14만4천원? 뜨억 @.@;; ㅋㅋ 설마 이렇게 많이 받지는 않겠죠...
    • 오델로
      2009.08.12 22:54
      아 완전 깔끔한 한방이네요 ㅠ.ㅠ 완전 감솨*10000000000000000000 소중하게 보겠습니다... Edit6....
    • 김병윤
      2009.08.13 01:46
      Format에 관해서 따로 알아두시는게 좋으실텐데 여기다 다 설명드리기는 좀 그렇고 대략...설명하자면 ...
    • 오델로
      2009.08.19 18:24
      이제서야 답변봤네요^^ 유용한 답변 감사합니다...^^ 복사해서 따로 저장후에 써야겠네요 ㅋ즐거운 하루...
    • 이훈
    • 2009.08.12 08:47
    • 2 COMMENTS
    • /
    • 0 LIKES
    • 구창민
      2009.08.12 18:45
      코드를 올려보세요..
    • 김병윤
      2009.08.12 21:37
      폼.Hide 때문입니다. 번쩍하고 사라지지 않습니까? 폼.Show; 로 폼을 호출하면 그 아래 코드까지 일사...
    • 구창민
      2009.08.12 20:49
      아래 코드 한줄을 추가해 보세요.. Application.ProcessMessages; fmInfoProgress.Show; 즐거운 ...
    • 김병윤
      2009.08.12 22:15
      Application.ProcessMessages; 요놈이 루프 안에 있어야 원하시는 결과를 얻으실 수 있을 듯 합니다. ^^
    • Hyphen
      2009.08.12 22:56
      fmInfoProgress.Show; Application.ProcessMessages; 순서를 이렇게 하니까 보이는 군요.. 대단히 ...
    • 치꼬
      2009.08.12 06:21
      내용은 정확히 파악은 잘 안되지만요. 위의 문장이 안되는건.. 말그대로 edit2.text 가 '' 것이 아니라...
    • 구창민
      2009.08.12 19:15
      안녕하세요.. 아래와 같은 문자열을 날짜로 치환하는 문장으로 해결하실수 있을거 같네요.. if Str...
    • 오델로
      2009.08.12 19:38
      답변 무한감사드립니다^^;; 아직 완전 백지상태라서 무작정 삽들고 파대기 시작하는중이라 답답합니다...
    • 백록화
      2009.08.11 21:32
      리더기가 시리얼통신을 사용한다면 관련 시리얼통신 콤포넌트에 데이터읽기 이벤트에서 제어를 해주심돼...
    • KDDG_Apine
      2009.08.12 04:12
      밑에 같이 id 컴포넌트를 사용하면 됩니다. ^^ 제가 사용했던부분인데.. 될겁니다. var nDate,...
    • 김지호
      2009.08.24 18:27
      답변 감사합니다 ^^