2010-07-21 16 views
5

Próbuję zsynchronizować przewijanie dwóch komponentów TDBGrid w aplikacji VCL Forms, mam problemy z przechwytywaniem WndProc każdego komponentu siatki bez problemów z stosami. Próbowałem wysyłać wiadomości WM_VSCROLL pod przewijanymi zdarzeniami, ale nadal powoduje to nieprawidłowe działanie. Musi działać, aby kliknąć pasek przewijania, a także podświetlić komórkę lub przycisk myszy w górę lub w dół. Cała idea polega na tym, aby dwie siatki obok siebie wyświetlały rodzaj pasującego okna dialogowego.Zsynchronizowane składniki przewijania Delphi

Tried

SendMessage(gridX.Handle, WM_VSCROLL, SB_LINEDOWN, 0); 

także

procedure TForm1.GridXCustomWndProc(var Msg: TMessage); 
begin 
Msg.Result := CallWindowProc(POldWndProc, gridX.Handle, Msg.Msg, Msg.wParam, Msg.lParam); 

    if (Msg.Msg = WM_VSCROLL) then 
    begin 
     gridY.SetActiveRow(gridX.GetActiveRow); 
     gridY.Perform(Msg.Msg, Msg.wParam, Msg.lParam); 
     SetScrollPos(gridY.Handle, SB_VERT, HIWORD(Msg.wParam), True); 
    end; 
end; 

I

procedure TForm1.GridxCustomWndProc(var Msg: TMessage); 
begin 
    if (Msg.Msg = WM_VSCROLL) then 
    begin 
     gridY.SetActiveRow(gridX.GetActiveRow); 
     gridY.Perform(Msg.Msg, Msg.wParam, Msg.lParam); 
     SetScrollPos(gridY.Handle, SB_VERT, HIWORD(Msg.wParam), True); 
    end; 
    inherited WndProc(Msg); 
end; 

Pierwsza jest tylko rozwiązaniem tymczasowym, druga powoduje nieprawidłowe odczytanie pamięci, a trzecia powoduje przepełnienie stosu. Dlatego żadne z tych rozwiązań nie działa dla mnie. Chciałbym trochę informacji na temat tego, jak wykonać to zadanie! Z góry dziękuję.

AKTUALIZACJA: Rozwiązanie

private 
    [...] 
    GridXWndProc, GridXSaveWndProc: Pointer; 
    GridYWndProc, GridYSaveWndProc: Pointer; 
    procedure GridXCustomWndProc(var Msg: TMessage); 
    procedure GridYCustomWndProc(var Msg: TMessage); 

procedure TForm1.FormCreate(Sender: TObject); 
begin 
    GridXWndProc := classes.MakeObjectInstance(GridXCustomWndProc); 
    GridXSaveWndProc := Pointer(GetWindowLong(GridX.Handle, GWL_WNDPROC)); 
    SetWindowLong(GridX.Handle, GWL_WNDPROC, LongInt(GridXWndProc)); 

    GridYWndProc := classes.MakeObjectInstance(GridYCustomWndProc); 
    GridYSaveWndProc := Pointer(GetWindowLong(GridY.Handle, GWL_WNDPROC)); 
    SetWindowLong(GridY.Handle, GWL_WNDPROC, LongInt(GridYWndProc)); 
end; 

procedure TForm1.GridXCustomWndProc(var Msg: TMessage); 
begin 
    Msg.Result := CallWindowProc(GridXSaveWndProc, GridX.Handle, Msg.Msg, Msg.WParam, Msg.LParam); 
    case Msg.Msg of 
     WM_KEYDOWN: 
     begin 
     case TWMKey(Msg).CharCode of VK_UP, VK_DOWN, VK_PRIOR, VK_NEXT: 
      GridY.Perform(Msg.Msg, Msg.WParam, Msg.LParam); 
     end; 
     end; 
     WM_VSCROLL: 
     GridY.Perform(Msg.Msg, Msg.WParam, Msg.LParam); 
     WM_HSCROLL: 
     GridY.Perform(Msg.Msg, Msg.WParam, Msg.LParam); 
     WM_MOUSEWHEEL: 
     begin 
     ActiveControl := GridY; 
     GridY.Perform(Msg.Msg, Msg.WParam, Msg.LParam); 
     end; 
     WM_DESTROY: 
     begin 
     SetWindowLong(GridX.Handle, GWL_WNDPROC, Longint(GridXSaveWndProc)); 
     Classes.FreeObjectInstance(GridXWndProc); 
     end; 
    end; 
end; 

procedure TForm1.GridXMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); 
begin 
    GridY.SetActiveRow(GridX.GetActiveRow); 
end; 

procedure TForm1.GridYCustomWndProc(var Msg: TMessage); 
begin 
    Msg.Result := CallWindowProc(GridYSaveWndProc, GridY.Handle, Msg.Msg, Msg.WParam, Msg.LParam); 
    case Msg.Msg of 
     WM_KEYDOWN: 
     begin 
     case TWMKey(Msg).CharCode of VK_UP, VK_DOWN, VK_PRIOR, VK_NEXT: 
      GridX.Perform(Msg.Msg, Msg.WParam, Msg.LParam); 
     end; 
     end; 
     WM_VSCROLL: 
     GridX.Perform(Msg.Msg, Msg.WParam, Msg.LParam); 
     WM_HSCROLL: 
     GridX.Perform(Msg.Msg, Msg.WParam, Msg.LParam); 
     WM_MOUSEWHEEL: 
     begin 
     ActiveControl := GridX; 
     GridX.Perform(Msg.Msg, Msg.WParam, Msg.LParam); 
     end; 
     WM_DESTROY: 
     begin 
     SetWindowLong(GridY.Handle, GWL_WNDPROC, Longint(GridYSaveWndProc)); 
     Classes.FreeObjectInstance(GridYWndProc); 
     end; 
    end; 
end; 

procedure TForm1.GridYMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); 
begin 
    GridX.SetActiveRow(GridY.GetActiveRow); 
end; 

Dzięki - Sertac Akyuz do rozwiązania. Po zintegrowaniu z aplikacjami formularzy VCL za pomocą siatek, będą się wzajemnie zwijać podczas przewijania i zaznaczania wybranego rekordu.

Odpowiedz

3

Prawdopodobnie implementujesz zastąpienie komunikatu dla obu sieci. GridX przewija GridY, który z kolei przewija GridX, który z kolei ... SO. Możesz chronić powierzchniowy kod przewijania, otaczając blok flagami.

type 
    TForm1 = class(TForm) 
    [..] 
    private 
    FNoScrollGridX, FNoScrollGridY: Boolean; 
    [..] 

procedure TForm1.GridXCustomWndProc(var Msg: TMessage); 
begin 
    Msg.Result := CallWindowProc(POldWndProc, gridX.Handle, Msg.Msg, Msg.wParam, Msg.lParam); 

    if (Msg.Msg = WM_VSCROLL) then 
    begin 
    if not FNoScrollGridX then 
    begin 
     FNoScrollGridX := True 
     gridY.SetActiveRow(gridX.GetActiveRow); 
     gridY.Perform(Msg.Msg, Msg.wParam, Msg.lParam); 
//  SetScrollPos(gridY.Handle, SB_VERT, HIWORD(Msg.wParam), True); 
    end; 
    FNoScrollGridX := False; 
    end; 
end; 

Kod podobny do GridY. BTW, nie potrzebujesz SetScrollPos.


edit:

TForm1 = class(TForm) 
    [..] 
private 
    GridXWndProc, GridXSaveWndProc: Pointer; 
    GridYWndProc, GridYSaveWndProc: Pointer; 
    procedure GridXCustomWndProc(var Msg: TMessage); 
    procedure GridYCustomWndProc(var Msg: TMessage); 
    [..] 

procedure TForm1.FormCreate(Sender: TObject); 
begin 
    [..] 

    GridXWndProc := classes.MakeObjectInstance(GridXCustomWndProc); 
    GridXSaveWndProc := Pointer(GetWindowLong(GridX.Handle, GWL_WNDPROC)); 
    SetWindowLong(GridX.Handle, GWL_WNDPROC, LongInt(GridXWndProc)); 

    GridYWndProc := classes.MakeObjectInstance(GridYCustomWndProc); 
    GridYSaveWndProc := Pointer(GetWindowLong(GridY.Handle, GWL_WNDPROC)); 
    SetWindowLong(GridY.Handle, GWL_WNDPROC, LongInt(GridYWndProc)); 
end; 

procedure TForm1.GridXCustomWndProc(var Msg: TMessage); 
begin 
    Msg.Result := CallWindowProc(GridXSaveWndProc, GridX.Handle, 
     Msg.Msg, Msg.WParam, Msg.LParam); 

    case Msg.Msg of 
    WM_KEYDOWN: 
     begin 
     case TWMKey(Msg).CharCode of 
      VK_UP, VK_DOWN, VK_PRIOR, VK_NEXT: 
      GridY.Perform(Msg.Msg, Msg.WParam, Msg.LParam); 
     end; 
     end; 
    WM_VSCROLL: GridY.Perform(Msg.Msg, Msg.WParam, Msg.LParam); 
    WM_MOUSEWHEEL: 
     begin 
     ActiveControl := GridY; 
     GridY.Perform(Msg.Msg, Msg.WParam, Msg.LParam); 
     end; 
    WM_DESTROY: 
     begin 
     SetWindowLong(GridX.Handle, GWL_WNDPROC, Longint(GridXSaveWndProc)); 
     Classes.FreeObjectInstance(GridXWndProc); 
     end; 
    end; 
end; 

procedure TForm1.GridYCustomWndProc(var Msg: TMessage); 
begin 
    Msg.Result := CallWindowProc(GridYSaveWndProc, GridY.Handle, 
     Msg.Msg, Msg.WParam, Msg.LParam); 

    case Msg.Msg of 
    WM_KEYDOWN: 
     begin 
     case TWMKey(Msg).CharCode of 
      VK_UP, VK_DOWN, VK_PRIOR, VK_NEXT: 
      GridX.Perform(Msg.Msg, Msg.WParam, Msg.LParam); 
     end; 
     end; 
    WM_VSCROLL: GridX.Perform(Msg.Msg, Msg.WParam, Msg.LParam); 
    WM_MOUSEWHEEL: 
     begin 
     ActiveControl := GridX; 
     GridY.Perform(Msg.Msg, Msg.WParam, Msg.LParam); 
     end; 
    WM_DESTROY: 
     begin 
     SetWindowLong(GridY.Handle, GWL_WNDPROC, Longint(GridYSaveWndProc)); 
     Classes.FreeObjectInstance(GridYWndProc); 
     end; 
    end; 
end; 
+0

Otrzymuję błędy przepełnienia stosu podczas próby użycia 'odziedziczonego WndProc (Msg)' Również gdy mam kod, jak pokazano, otrzymuję niepoprawne odczyty pamięci i innych błędów środowiska wykonawczego. Nie jesteś pewien, czy to jedyny sposób na wykonanie tego zadania? – wfoster

+0

Co to jest "odziedziczony WndProc'?", Podałeś część kodu, która zastępuje 'WindowProc' siatki. Gdzie zastępujesz "WndProc"? Edytuj pytanie, aby wyświetlić odpowiedni kod. –

+0

Moje przeprosiny, zobacz zmiany – wfoster

3

mam częściową, ale teraz pełną roztwór roboczy (przynajmniej dla dwóch TMemo) ...

Znaczy częściowy, bo słuchać tylko do zmian na jeden TMemo ale nie na inny ...

znaczy pełną obróbkę, ponieważ nie zależy od tego, co jest zrobione ...

to jest tak proste, jak umieścić samym horyzoncie Tal wartość przewijania na jednym Memo, jak to jest z drugiej ...

To nic nie jest związane z wiadomościami, ale ponieważ starałem się uzyskać działające rozwiązanie przez zalewkowanie wiadomości WM_HSCROLL, itp ... zostawiłem kod, ponieważ to działa ... postaram się go poprawić później ... na przykład uwięzienie tylko WM_PAINT, lub w inny sposób ... ale na razie, umieściłem to tak, jak mam to od kiedy to działa ... i zrobiłem to nigdzie nie znajdziesz czegoś jeszcze lepszego ...

Oto kod, który działa:

// On private section of TForm1 
Memo_OldWndProc:TWndMethod; // Just to save and call original handler 
procedure Memo_NewWndProc(var TheMessage:TMessage); // New handler 

// On implementation section of TForm1  
procedure TForm1.FormCreate(Sender: TObject); 
begin 
    Memo_OldWndProc:=Memo1.WindowProc; // Save the handler 
    Memo1.WindowProc:=Memo_NewWndProc; // Put the new handler, so we can do extra things 
end; 

procedure TForm1.Memo_NewWndProc(var TheMessage:TMessage); 
begin 
    Memo_OldWndProc(TheMessage); // Let the scrollbar to move to final position 
    Memo2.Perform(WM_HSCROLL 
        ,SB_THUMBPOSITION+65536*GetScrollPos(Memo1.Handle,SB_HORZ) 
        ,0 
       ); // Put the horizontal scroll of Memo2 at same position as Memo1 
end; 

procedure TForm1.FormDestroy(Sender: TObject); 
begin 
    Memo1.WindowProc:=Memo_OldWndProc; // Restore the old handler 
end; 

To działa dla wszystkich sposobów, aby przewijać do zmiany ...

Uwagi:

  • Wiem, że to straszne pułapkę wszystkie wiadomości, ale przynajmniej działa ...
  • To jest moja pierwsza udana próba posiadania dwóch TMemos z zsynchronizowanym poziomym przewijaniem ar ...
  • Tak więc, jeśli ktoś może trochę poprawić (nie przechwytuje wszystkich wiadomości), proszę zrób to i opublikuj.
  • To tylko sprawia Memo1 być na poziomej synchronizacji z barem Memo2, ale nie Memo2 być w synchronizacji z Memo1
  • Naciśnij klawisze w górę, w dół, w lewo, w prawo, rolki myszki, itp ... co tylko chcesz, ale na Memo2 aby zobaczyć go w akcji

postaram się ją poprawić przez: robiąc coś na Memo2, Memo1 przewijania nadal być na synchronizację ...

Myślę, że może pracować dla allmost jakiejkolwiek kontroli, które ma ScrollBar, nie tylko TMemo ...

2

Jak powiedziałem ...

Tu jest lepszym rozwiązaniem (nie ostateczny jeden) pod względem wydajności, czystego kodu i dwukierunkowy ... zmianę na jednego oddziałuje na inne ...

Proszę przeczytać komentarze na temat kodu, aby zrozumieć, co robi każde zdanie ... jest to dość skomplikowane ... ale główna idea jest taka sama jak wcześniej ... Ustaw drugi poziomy pasek przewijania TMemo, tak jak to jest na TMemo, gdzie użytkownik działa ... bez względu na to, co robi użytkownik, porusz myszą i wybierz tekst, naciśnij lewy, prawy, dom, koniec klawiszy, użyj poziomego koła myszy (nie wszystkie mają), przeciągnij pasek nawigacyjny, naciśnij dowolną część poziomy pasek przewijania, itp ...

Ma w idei jest ... obiekt musi zostać ponownie pomalowany, a następnie umieść poziome poziomy pasek przewijania identyczny do tego ...

Ta pierwsza część służy tylko dodaniu rzeczy do klasy TMemo, po prostu tworzy nowa klasa pochodna, ale o tej samej nazwie klasy, ale tylko dla zadeklarowanej jednostki.

Dodaj ten interfejs sekcji, przed deklaracją TForm, więc TForm będzie zobaczyć tę nową klasę TMemo zamiast normalnego One:

type 
    TMemo=class(StdCtrls.TMemo) // Just to add things to TMemo class only for this unit 
    private 
     BusyUpdating:Boolean; // To avoid circular stack overflow 
     SyncMemo:TMemo; // To remember the TMemo to be sync 
     Old_WindowProc:TWndMethod; // To remember old handler 
     procedure New_WindowProc(var Mensaje:TMessage); // The new handler 
    public 
     constructor Create(AOwner:TComponent);override; // The new constructor 
     destructor Destroy;override; // The new destructor 
    end; 

to następna część jest wdrożenie do wcześniejszych deklaracji tej nowej klasy TMemo .

Dodaj to do sekcji realizacji gdziekolwiek preffer:

constructor TMemo.Create(AOwner:TComponent); // The new constructor 
begin 
    inherited Create(AOwner); // Call real constructor 
    BusyUpdating:=False; // Initialize as not being in use, to let enter 
    Old_WindowProc:=WindowProc; // Remember old handler 
    WindowProc:=New_WindowProc; // Replace handler with new one 
end; 

destructor TMemo.Destroy; // The new destructor 
begin 
    WindowProc:=Old_WindowProc; // Restore the original handler 
    inherited Destroy; // Call the real destructor 
end; 

procedure TMemo.New_WindowProc(var Mensaje:TMessage); 
begin 
    Old_WindowProc(Mensaje); // Call the real handle before doing anything 
    if BusyUpdating // To avoid circular stack overflow 
     or 
     (not Assigned(SyncMemo)) // If not yet set (see TForm1.FormCreate bwlow) 
     or 
     (WM_PAINT<>Mensaje.Msg) // If not when need to be repainted to improve speed 
    then Exit; // Do no more and exit the procedure 
    BusyUpdating:=True; // Set that object is busy in our special action 
    SyncMemo.Perform(WM_HSCROLL,SB_THUMBPOSITION+65536*GetScrollPos(Handle,SB_HORZ),0); // Send to the other TMemo a message to set its horizontal scroll as it is on this TMemo 
    BusyUpdating:=False; // Set that the object is no more busy in our special action 
end; 

Teraz ostatnia część, każdy TMemo powiedzieć co jest inne Memo, który ma być na synchronizacji.

W sekcji realizacji, dla Form1 Utwórz zdarzenie dodać coś takiego:

procedure TForm1.FormCreate(Sender: TObject); 
begin 
    Memo1.SyncMemo:=Memo2; // Tell Memo1 what TMemo must sync (Memo2) 
    Memo2.SyncMemo:=Memo1; // Tell Memo2 what TMemo must sync (Memo1) 
end; 

Pamiętaj dodaliśmy element SyncMemo naszej specjalnej nowej klasy TMemo, to było po prostu za to, powiedzieć sobie nawzajem, co jeden jest drugi.

Teraz trochę konfiguracja zarówno TMemo jsut niech ta praca doskonale:

  • Niech oba paski przewijania TMemo być widoczny
  • Niech WordWrap fałszywe zarówno Tmemo
  • włożył wiele tekstów (takie same dla obu), długie kolejki i wiele linii

uruchomić go i zobaczyć, jak obie poziome paski przewijania są zawsze dobrze na synchronizację ...

  • Jeśli przesuniesz jeden pasek przewijania poziomego, drugi pasek przewijania poziomego przesuwa ...
  • Jeśli pójdziesz na tekst do prawej lub lewej strony, linia początku lub na końcu linii, itd ..., bez względu na to, gdzie jest SelStart na drugim ... poziomym przewijaniu tekstu jest zsynchronizowany.

Problem, dlaczego nie jest to ostateczna wersja jest taka, że:

  • pasków przewijania (poziomo jeden w moim przypadku) nie może być ukryte ... ponieważ jeśli jeden jest ukryty, gdy dzwoni GetScrollPos zwraca zero, więc uniemożliwia synchronizację.

Jeśli ktoś wie, jak naśladować ukryte lub sprawić, aby GetScrollPos nie zwracał zera, proszę o komentarz, to jedyna rzecz, którą muszę naprawić dla ostatecznej wersji.

Uwagi:

  • Oczywiście to samo można zrobić z pionowym pasku przewijania ... wystarczy zmienić WM_HSCROLL do WM_VSCROLL i SB_HORZ do SB_VERT
  • Oczywiście to samo można zrobić zarówno w tym samym czasie. .. po prostu skopiować linię SyncMemo.Perform dwa razy i na jednej let WM_HSCROLL i SB_HORZ a na drugim niech WM_VSCROLL i SB_VERT

Oto przykład procedury New_WindowProc do synchronizacji oba paski przewijania w tym samym czasie, mA ybe dla leniwych, może dla ludzi takich jak kopiowania & pasty:

procedure TMemo.New_WindowProc(var Mensaje:TMessage); 
begin 
    Old_WindowProc(Mensaje); // Call the real handle before doing anything 
    if BusyUpdating // To avoid circular stack overflow 
     or 
     (not Assigned(SyncMemo)) // If not yet set (see TForm1.FormCreate bwlow) 
     or 
     (WM_PAINT<>Mensaje.Msg) // If not when need to be repainted to improve speed 
    then Exit; // Do no more and exit the procedure 
    BusyUpdating:=True; // Set that object is busy in our special action 
    SyncMemo.Perform(WM_HSCROLL,SB_THUMBPOSITION+65536*GetScrollPos(Handle,SB_HORZ),0); // Send to the other TMemo a message to set its horizontal scroll as it is on this TMemo 
    SyncMemo.Perform(WM_VSCROLL,SB_THUMBPOSITION+65536*GetScrollPos(Handle,SB_VERT),0); // Send to the other TMemo a message to set its vertical scroll as it is on this TMemo 
    BusyUpdating:=False; // Set that the object is no more busy in our special action 
end; 

nadzieję, że ktoś może rozwiązać problem ukryty jeden pasek przewijania i GetScrollPos powrocie do zera !!!

2

znalazłem rozwiązanie ... wiem, że to jest dość trudne ... ale przynajmniej jest w pełni funkcjonalny ...

Zamiast próbować ukryć poziomego paska przewijania ... i uczynić go być widocznym poza widocznym obszarem, aby użytkownik nie mógł go zobaczyć ...

Najtrudniejsze:

  • Umieść TPanel gdzie TMemo jest i umieścić TMemo wewnątrz TPanel
  • Ukryj granice TPanel umieścić BorderWith jako 0, a wszystkie kantach do bvNone/bkNone
  • Skonfiguruj TMemo Dopasuj do alTop, a nie do alClient, itp ...
  • Obetnij TPanel.OnResize, aby ustawić TMemo.Height na większy niż TPanel.Height tak wysoko, jak wysokość poziomego paska przewijania (do momentu użycia stałej wartości 20 pikseli, ale chciałbym wiedzieć, jak uzyskać prawdziwą wartość)

To wszystko ... gotowe !!! Poziomy pasek przewijania znajduje się poza widocznym obszarem ... możesz umieścić tam, gdzie chcesz, aby był TPanel, nadaj mu żądany rozmiar ... poziomy pasek przewijania nie będzie widoczny dla użytkownika i nie będzie ukryty, więc GetScrollPos będzie działał poprawnie ... Trudne, wiem, ale w pełni funkcjonalne.

Oto pełny kod do archiwum to:

w sekcji interfejsu, przed deklaracją TForm, więc TForm będzie zobaczyć tę nową klasę TMemo zamiast normalnego One:

type 
    TMemo=class(StdCtrls.TMemo) // Just to add things to TMemo class only for this unit 
    private 
     BusyUpdating:Boolean; // To avoid circular stack overflow 
     SyncMemo:TMemo; // To remember the TMemo to be sync 
     Old_WindowProc:TWndMethod; // To remember old handler 
     procedure New_WindowProc(var Mensaje:TMessage); // The new handler 
    public 
     constructor Create(AOwner:TComponent);override; // The new constructor 
     destructor Destroy;override; // The new destructor 
    end; 

w sekcji realizacji gdziekolwiek preffer:

constructor TMemo.Create(AOwner:TComponent); // The new constructor 
begin 
    inherited Create(AOwner); // Call real constructor 
    BusyUpdating:=False; // Initialize as not being in use, to let enter 
    Old_WindowProc:=WindowProc; // Remember old handler 
    WindowProc:=New_WindowProc; // Replace handler with new one 
end; 

destructor TMemo.Destroy; // The new destructor 
begin 
    WindowProc:=Old_WindowProc; // Restore the original handler 
    inherited Destroy; // Call the real destructor 
end; 

procedure TMemo.New_WindowProc(var Mensaje:TMessage); 
begin 
    Old_WindowProc(Mensaje); // Call the real handle before doing anything 
    if (WM_PAINT<>Mensaje.Msg) // If not when need to be repainted to improve speed 
     or 
     BusyUpdating // To avoid circular stack overflow 
     or 
     (not Assigned(SyncMemo)) // If not yet set (see TForm1.FormCreate bwlow) 
    then Exit; // Do no more and exit the procedure 
    BusyUpdating:=True; // Set that object is busy in our special action 
    SyncMemo.Perform(WM_HSCROLL,SB_THUMBPOSITION+65536*GetScrollPos(Handle,SB_HORZ),0); // Send to the other TMemo a message to set its horizontal scroll as it is on this TMemo 
    BusyUpdating:=False; // Set that the object is no more busy in our special action 
end; 

również w sekcji realizacji gdziekolwiek preffer:

procedure TForm1.FormCreate(Sender: TObject); 
begin 
    Memo1.SyncMemo:=Memo2; // Tell Memo1 what TMemo must sync (Memo2) 
    Memo2.SyncMemo:=Memo1; // Tell Memo2 what TMemo must sync (Memo1) 
end; 

procedure TForm1.pnlMemo2Resize(Sender: TObject); 
begin 
    Memo2.Height:=pnlMemo2.Height+20; // Make height enough big to cause horizontal scroll bar be out of TPanel visible area, so it will not be seen by the user 
end; 

To wszystko ludzie! Wiem, że to dość trudne, ale w pełni funkcjonalne.

Należy pamiętać, że zmieniłem na New_WindowProc kolejność oceny warunków OR ... służy tylko poprawie szybkości dla wszystkich innych wiadomości, więc opóźnij jak najdokładniej wszystkie leczenie wiadomości.

Mam nadzieję, że kiedyś będę wiedział, jak zastąpić takie 20 przez rzeczywistą (obliczoną lub odczytaną) wysokość poziomego paska przewijania TMemo.

+0

Możesz uzyskać domyślną wysokość paska przewijania za pomocą 'GetSystemMetrics', użyj' SM_CYHSCROLL' jako * nIndex * .. Zamiast zadawania tego pytania jako notatnika do rozwiązywania problemu, dlaczego nie chcesz zadać nowego pytania? –

1

Dzięki za GetSystemMetrics i SM_CYHSCROLL, ale to nie wystarczy ... wystarczy wystarczających 3 piksele więcej ...

więc po prostu użyć: GetSystemMetrics(SM_CYHSCROLL)+3

Uwaga: Dwa z tych pikseli może być spowodowane z panelem nadrzędnym z BevelWidth o wartości 1, ale mam BevelInner i BevelOuter o wartości bvNone, więc nie może; ale dodatkowy piksel nie wiem dlaczego.

Wielkie dzięki.

Jeśli wolisz, po prostu dołącz do jednego dużego posta, ale myślę, że lepiej nie mieszać ich.

W odpowiedzi na „Sertac Akyuz” (przepraszam to zrobić tutaj, ale nie wiem jak umieszczać je obok swoje pytanie):

  • kładę tutaj rozwiązania znalazłem jak je znaleźć ... moim zamiarem było nie używać go jako podkładki ...Rozwiązałem jsut sekund przed pisaniem postów
  • Myślę, że lepiej jest widzieć stare posty, a nie edytować wielokrotnie razy tylko ten sam wpis ... nie pozwoli to również, aby inni znali dokładne rozwiązanie, niech wiedzą, jak osiągnąć takie rozwiązanie.
  • Preferuję robienie rzeczy w taki sposób, jak "uczę łowić ryby, a nie dajesz rybę" ".
  • Nie otwierać nowe pytanie tylko dlatego, że tytuł ten jest tak dokładna, co starałem się zrobić

Ważne: odkrywam, że to idealne rozwiązanie nie może być wykonana przez wiadomość przechwytywania ponieważ jest przypadek, który powoduje przewijanie, ale nie ma komunikatu WM_VSCROLL, WM_HSCROLL (tylko WM_PAINT) ... jest związany z zaznaczaniem tekstu za pomocą myszy ... pozwól mi wyjaśnić, jak widzę to w akcji ... Po prostu zacznij pod koniec ostatniego linia wizualna i przesuń mysz lekko w dół, następnie zatrzymaj ruch myszy i pozwól przyciskowi myszy przycisnąć ... bez robienia czegokolwiek (mysz się nie rusza, nie ma klawisza, nie ma keydown, nie ma zmiany przycisku myszy, itd ...) TMemo jest przewijanie dow n till osiąga koniec tekstu ... to samo dzieje się w przypadku poziomych zwojów, gdy mysz znajduje się w pobliżu prawego końca linii wizualnej i przesunięta w prawo ... również w przeciwnych kierunkach ... takie zwoje nie są przesyłane tylko przez komunikaty WM_VSCROLLWM_HSCROLLWM_PAINT (przynajmniej na moim komputerze) ... to samo dzieje się na siatkach.