Как я уже говорил ...
Здесь это лучшее решение (не окончательное) с точки зрения эффективности, чистого кода и двунаправленности ... изменение одного влияет на другое ...
Пожалуйста, прочитайте комментарии к коду, чтобы понять, что делает каждое предложение ... это довольно сложно ... но основная идея такая же, как была раньше ... установить другую горизонтальную полосу прокрутки TMemo, как на TMemo, где пользователь действует ... независимо от того, что пользователь делает, перемещайте мышь и выбирайте текст, нажмите левую, правую, домашнюю, клавиши завершения, используйте горизонтальное колесо мыши (не у всех есть), перетащите полосу прокрутки, нажмите на любую часть горизонтальной полосы прокрутки и т.д ...
Основная идея заключается в том, что ... объект необходимо перекрасить, поэтому поместите горизонтальную полосу прокрутки другого объекта, идентичную этой ...
Эта первая часть просто для добавления вещей в класс TMemo, это просто создание нового производного класса, но с тем же именем класса, но только для модуля внутри объявленного.
Добавьте это в раздел интерфейса перед объявлением TForm, чтобы ваша TForm увидела этот новый класс TMemo вместо обычного:
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;
Следующая часть является реализацией предыдущих объявлений этого нового класса TMemo.
Добавьте это в раздел реализации везде, где вы предпочитаете:
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;
Теперь последняя часть, расскажите каждому TMemo, что это за другая памятка, которая должна быть синхронизирована.
В разделе вашей реализации для события Form1 Create добавьте что-то вроде этого:
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;
Помните, что мы добавили члена SyncMemo в наш новый специальный класс TMemo, именно для этого и расскажем друг другу, какой из них другой.
Теперь небольшая конфигурация для обоих TMemo jsut, чтобы все работало идеально:
- Пусть обе полосы прокрутки TMemo будут видны
- Пусть WordWrap false на обоих Tmemo
- Положите много текста (одинаково для обоих), длинные строки и много строк
Запустите его и посмотрите, как синхронизируются обе горизонтальные полосы прокрутки ...
- Если вы переместите одну горизонтальную полосу прокрутки, другую горизонтальную полосу прокрутки
движется ...
- Если вы идете по тексту вправо или влево, начало строки или конец строки,
и т. д., независимо от того, где SelStart на другом ... горизонтальном
текстовая прокрутка синхронизирована.
Проблема, почему это не окончательная версия, заключается в том, что:
- Полосы прокрутки (в моем случае горизонтальная) не могут быть скрыты ... поскольку, если одна скрыта, при вызове GetScrollPos она возвращает ноль, поэтому она не синхронизируется.
Если кто-то знает, как эмулировать скрытый или заставить GetScrollPos не возвращать ноль, пожалуйста, прокомментируйте, это единственное, что мне нужно исправить в окончательной версии.
Примечания:
- Очевидно, то же самое можно сделать с вертикальной полосой прокрутки ... просто измените
WM_HSCROLL для WM_VSCROLL и SB_HORZ для SB_VERT
- Очевидно, что то же самое может быть сделано для обоих одновременно ... просто скопируйте строку SyncMemo.Perform дважды и на одной позвольте WM_HSCROLL и SB_HORZ, а на другой позвольте WM_VSCROLL и SB_VERT
Вот пример процедуры New_WindowProc для синхронизации обеих полос прокрутки одновременно, может быть, для ленивых людей, может быть для людей, таких как copy & paste:
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;
Надеюсь, что кто-то может решить проблему скрытой полосы прокрутки, а GetScrollPos вернет ноль !!!