| BlastOff | 
   Отправлено: 26.05.2004, 13:14 | 
 
 
 | 
  
Ученик-кочегар 
 
Группа: Участник 
Сообщений: 8 
  
  
 | 
 Я в процессе работы программы создаю форму, т.е. динамически. На ней два RichEdit'a. В них — какой-то текст. Как мне сделать, чтобы при прокрутке одного ScrollBar другой тоже прокручивался? Или если один ScrollBar прокручивает одновременно оба текста (примерно как в ТоталКомандере — сравнение файлов, там ScrollBar только у одного Edit'a). 
Помимо этого, если поставить курсор в один RichEdit и им прокручивать текст, то содержимое другого тоже бы прокручивалось.
  
Смысл: сравнение содержимого RichEdit'ов. 
Надеюсь, понятно рассказал свою проблему.  | 
  | 
| Gedeon | 
| Отправлено: 26.05.2004, 13:52 | 
 
 
 | 
 
  
Ветеран 
 
Группа: Модератор 
Сообщений: 1742 
  
  
 | 
 Создать компонент наследник от TRichEdit в нем создать событие OnScroll, а потом в его обработчике отсылать второму RichEdit сообщение WM_VSCROLL, WM_HSCROLL
 | 
  | 
| AVC | 
| Отправлено: 26.05.2004, 14:21 | 
 
 
 | 
  
Ветеран 
 
Группа: Модератор 
Сообщений: 1583 
  
  
 | 
 Можно без наследника повесить на таймер (будет с некоторым опозданием) 
| CODE  |   
void __fastcall TForm1::Timer1Timer(TObject *Sender) 
{ 
int y0 = SendMessage(RichEdit1->Handle, EM_GETFIRSTVISIBLELINE, 0, 0); 
int y1 = SendMessage(RichEdit2->Handle, EM_GETFIRSTVISIBLELINE, 0, 0); 
if (y0 != y1) SendMessage(RichEdit2->Handle, EM_LINESCROLL, 0, y0-y1); 
 |     | 
  | 
| BlastOff | 
| Отправлено: 26.05.2004, 14:47 | 
 
 
 | 
  
Ученик-кочегар 
 
Группа: Участник 
Сообщений: 8 
  
  
 | 
 | QUOTE (Gedeon @ 26/05/2004, 14:54) |  | Создать компонент наследник от TRichEdit в нем создать событие OnScroll, а потом в его обработчике отсылать второму RichEdit сообщение WM_VSCROLL, WM_HSCROLL |  
 
  
Если можно, подробнее.  | 
  | 
| BlastOff | 
| Отправлено: 26.05.2004, 14:49 | 
 
 
 | 
  
Ученик-кочегар 
 
Группа: Участник 
Сообщений: 8 
  
  
 | 
 | QUOTE (AVC @ 26/05/2004, 15:23) |  Можно без наследника повесить на таймер (будет с некоторым опозданием) 
| CODE  |   
void __fastcall TForm1::Timer1Timer(TObject *Sender) 
{ 
int y0 = SendMessage(RichEdit1->Handle, EM_GETFIRSTVISIBLELINE, 0, 0); 
int y1 = SendMessage(RichEdit2->Handle, EM_GETFIRSTVISIBLELINE, 0, 0); 
if (y0 != y1) SendMessage(RichEdit2->Handle, EM_LINESCROLL, 0, y0-y1); 
 |  
  |  
  
Ну ладно, допустим. Тогда вопрос: как мне на этой динамической форме обработать таймер? У меня форма описывается и создаётся в подпрограмме. И если я пишу
  
| CODE  |   
void __fastcall TForm2::Timer1Timer(TObject *Sender) 
{ 
int y0 = SendMessage(RichEdit1->Handle, EM_GETFIRSTVISIBLELINE, 0, 0); 
int y1 = SendMessage(RichEdit2->Handle, EM_GETFIRSTVISIBLELINE, 0, 0); 
if (y0 != y1) SendMessage(RichEdit2->Handle, EM_LINESCROLL, 0, y0-y1); 
} 
 |  
 
  
то она не понимает что такое Form2.  | 
  | 
| AVC | 
| Отправлено: 26.05.2004, 15:10 | 
 
 
 | 
  
Ветеран 
 
Группа: Модератор 
Сообщений: 1583 
  
  
 | 
 Таймер можно иметь в любой форме (я обычно имею один таймер в приложении и создаю к нему очередь). Ваша проблема должна решаться следующим образом: 
| CODE  |   
int y0 = SendMessage(newForm->RichEdit1->Handle, EM_GETFIRSTVISIBLELINE, 0, 0); 
int y1 = SendMessage(newForm->RichEdit2->Handle, EM_GETFIRSTVISIBLELINE, 0, 0); 
if (y0 != y1) SendMessage(RichEdit2->Handle, EM_LINESCROLL, 0, y0-y1); 
 |  
  
где newForm указатель на динамически созданную форму а RichEdit1 и RichEdit2 объявлены в секции __published или pyblic 
| QUOTE  |  | как мне на этой динамической форме обработать таймер?  |  
  
Если вы создаете новый экземпляр формы из существующего класса то там уже все есть (создается на этапе проектирования), а если вы создаете форму полностью вручную, то добавляйте компонент TTimer и заполняйте все его свойства. OnTimer это не более чем свойство компонента TTimer  | 
  | 
| Gedeon | 
| Отправлено: 26.05.2004, 15:42 | 
 
 
 | 
 
  
Ветеран 
 
Группа: Модератор 
Сообщений: 1742 
  
  
 | 
 Вас еще интересует вариант с созданием компонента или остановились на таймере? Напишите, ато просто так не хочется возиться. Чтобы узнать как обрабатывать событие динамически созданного компонента воспользуйтесь поиском по форуму.
 | 
  | 
| BlastOff | 
| Отправлено: 26.05.2004, 15:58 | 
 
 
 | 
  
Ученик-кочегар 
 
Группа: Участник 
Сообщений: 8 
  
  
 | 
 А можно без таймера? 
Или вообще, как-нибудь попроще?
  
Остановлюсь на динамически созданных компонентах. Хорошо, поищу. 
Я ж не заставляю кого-то возиться.  
  
Отредактировано BlastOff — 26/05/2004, 17:02  | 
  | 
| AVC | 
| Отправлено: 26.05.2004, 16:03 | 
 
 
 | 
  
Ветеран 
 
Группа: Модератор 
Сообщений: 1583 
  
  
 | 
 Gedeon, не знаете как получить число видимых строк компонента Memo?  | 
  | 
| Gedeon | 
| Отправлено: 26.05.2004, 16:20 | 
 
 
 | 
 
  
Ветеран 
 
Группа: Модератор 
Сообщений: 1742 
  
  
 | 
| QUOTE (AVC @ 26/05/2004, 17:05) |  | Gedeon, не знаете как получить число видимых строк компонента Memo? |  
  
Уточните что значит видимых. 
Общее количество строк 
Memo1->Lines->Count; 
Если видимые имеется ввиду не пустые, то нужно найти количество строк в которых хоть один символ, кроме последнего != пробел.
 | 
  | 
| full_lamer | 
| Отправлено: 26.05.2004, 16:25 | 
 
 
 | 
  
Машинист паровоза 
 
Группа: Участник 
Сообщений: 225 
  
  
 | 
 Можно сделать вообще просто, по ламерски, если хочешь без наследований: перехвати просто все события — нажатия клавиш, клики мышей, изменение, и в каждом вызвай функцию которая будет синхронизировать скролы...  
 | 
  | 
| AVC | 
| Отправлено: 26.05.2004, 16:27 | 
 
 
 | 
  
Ветеран 
 
Группа: Модератор 
Сообщений: 1583 
  
  
 | 
 Видимых — означает видимых на экране. Проблема возникла кода понадобилось пронумеровать строки во внутреннем редакторе. Пришлось высоту окна делить на функцию от размера шрифта. Может можно проще а опять чего-то не вижу?  | 
  | 
| Gedeon | 
| Отправлено: 26.05.2004, 16:38 | 
 
 
 | 
 
  
Ветеран 
 
Группа: Модератор 
Сообщений: 1742 
  
  
 | 
 Делить и прийдется, высоту текста м. узнать так 
Canvas->TextHeight("A");
 | 
  | 
| AVC | 
| Отправлено: 26.05.2004, 16:45 | 
 
 
 | 
  
Ветеран 
 
Группа: Модератор 
Сообщений: 1583 
  
  
 | 
 Спасибо, а жаль.  | 
  | 
| olegenty | 
| Отправлено: 27.05.2004, 08:20 | 
 
 
 | 
  
Ветеран 
 
Группа: Модератор 
Сообщений: 2412 
  
  
 | 
 А вот и компонент, наследник от TRichEdit, с переопределённой WndProc и дополнительным полем Synchro, куда надо вписывать синхронизируемый RichEdit. Можно перекрёстно, одно ограничение — фокус должен быть у того RichEdit, скролл которого финхронизируется со вторым пассивным.
  
Протестировано, работает 
| CODE  |   
//---------------------------------------------------------------------------
  
#ifndef RichEditVScrollH 
#define RichEditVScrollH 
//--------------------------------------------------------------------------- 
#include <SysUtils.hpp> 
#include <Classes.hpp> 
#include <ComCtrls.hpp> 
#include <Controls.hpp> 
#include <StdCtrls.hpp> 
//--------------------------------------------------------------------------- 
class PACKAGE TRichEditVScroll : public TRichEdit 
{ 
private: 
   TRichEdit *m_pSynchro; 
protected: 
public: 
   __fastcall TRichEditVScroll(TComponent* Owner); 
__published: 
   __property TRichEdit *Synchro = {read = m_pSynchro, write = m_pSynchro}; 
protected: 
   virtual void __fastcall WndProc(Messages::TMessage &Message); 
}; 
//--------------------------------------------------------------------------- 
#endif 
 |  
  
| CODE  |   
//---------------------------------------------------------------------------
  
#include <vcl.h>
  
#pragma hdrstop
  
#include "RichEditVScroll.h" 
#pragma package(smart_init) 
//--------------------------------------------------------------------------- 
// ValidCtrCheck is used to assure that the components created do not have 
// any pure virtual functions. 
//
  
static inline void ValidCtrCheck(TRichEditVScroll *) 
{ 
   new TRichEditVScroll(NULL); 
} 
//--------------------------------------------------------------------------- 
__fastcall TRichEditVScroll::TRichEditVScroll(TComponent* Owner) 
   : TRichEdit(Owner) 
{ 
   m_pSynchro = NULL; 
}
  
void __fastcall TRichEditVScroll::WndProc(Messages::TMessage &Message) 
{ 
   if (Message.Msg == WM_VSCROLL) 
   { 
       if (m_pSynchro && 
           m_pSynchro->Handle != this->Handle && 
           !m_pSynchro->Focused()) 
       { 
           SendMessage(m_pSynchro->Handle, Message.Msg, Message.WParam, Message.LParam); 
       } 
   } 
   TRichEdit::WndProc(Message); 
} 
//--------------------------------------------------------------------------- 
namespace Richeditvscroll 
{ 
   void __fastcall PACKAGE Register() 
   { 
        TComponentClass classes[1] = {__classid(TRichEditVScroll)}; 
        RegisterComponents("Olegenty", classes, 0); 
   } 
} 
//---------------------------------------------------------------------------
  
 |   
 | 
  | 
| Gedeon | 
| Отправлено: 27.05.2004, 08:40 | 
 
 
 | 
 
  
Ветеран 
 
Группа: Модератор 
Сообщений: 1742 
  
  
 | 
 Неплохо бы еще добавить горизонтальный скроллинг, а вообще если для целей сравнения файлов, наверное удобно было бы не только скрол перемещать, но и курсор в самом контроле.
 | 
  | 
| olegenty | 
| Отправлено: 27.05.2004, 12:38 | 
 
 
 | 
  
Ветеран 
 
Группа: Модератор 
Сообщений: 2412 
  
  
 | 
 дома посмотрю, сейчас времени нет...   идея-то понятна, всё же просто  
 | 
  | 
| Gedeon | 
| Отправлено: 27.05.2004, 13:04 | 
 
 
 | 
 
  
Ветеран 
 
Группа: Модератор 
Сообщений: 1742 
  
  
 | 
| QUOTE (olegenty @ 27/05/2004, 13:40) |  дома посмотрю, сейчас времени нет...   идея-то понятна, всё же просто   |  
  
Согласен, задача простая, надо просто сесть и реализовать, я написал бы, но сейчас занят переходом на новую работу, тут сдать всего дофига надо.
 | 
  | 
| olegenty | 
| Отправлено: 27.05.2004, 14:39 | 
 
 
 | 
  
Ветеран 
 
Группа: Модератор 
Сообщений: 2412 
  
  
 | 
 Изменения: 
| CODE  |   
void __fastcall TRichEditVScroll::WndProc(Messages::TMessage &Message) 
{ 
   switch (Message.Msg) 
   { 
       case WM_VSCROLL: 
       case WM_HSCROLL: 
       case WM_MOUSEWHEEL: 
           if (m_pSynchro && 
               m_pSynchro->Handle != this->Handle && 
               !m_pSynchro->Focused()) 
           { 
               SendMessage(m_pSynchro->Handle, Message.Msg, Message.WParam, Message.LParam); 
           } 
           break; 
       case WM_KEYDOWN: 
       case WM_KEYUP: 
           switch (Message.WParam) 
           { 
               case VK_END  : 
               case VK_HOME : 
               case VK_LEFT : 
               case VK_UP   : 
               case VK_RIGHT: 
               case VK_DOWN : 
               case VK_PRIOR: 
               case VK_NEXT : 
                   if (m_pSynchro && 
                       m_pSynchro->Handle != this->Handle && 
                       !m_pSynchro->Focused()) 
                       { 
                           int y0 = SendMessage(this->Handle, EM_GETFIRSTVISIBLELINE, 0, 0); 
                           int y1 = SendMessage(m_pSynchro->Handle, EM_GETFIRSTVISIBLELINE, 0, 0); 
                           if (y0 != y1) SendMessage(m_pSynchro->Handle, EM_LINESCROLL, 0, y0-y1); 
                       } 
                   break; 
           } 
           break; 
   } 
   TRichEdit::WndProc(Message); 
} 
 |   
 | 
  | 
| olegenty | 
| Отправлено: 27.05.2004, 15:01 | 
 
 
 | 
  
Ветеран 
 
Группа: Модератор 
Сообщений: 2412 
  
  
 | 
 А лучше сделать это для SynEdit — там номера строк есть ещё и возможность подсветки: очень удобно...
 | 
  | 
| BlastOff | 
| Отправлено: 27.05.2004, 16:15 | 
 
 
 | 
  
Ученик-кочегар 
 
Группа: Участник 
Сообщений: 8 
  
  
 | 
 Теперь по порядку. Что я делаю неправильно? 
1. Component — New Component. Ancestor Type: TRichEdit. Class Name: TRichEditVScroll. Жму ОК. 
2. Копирую из примера (для *.h файла) в RichEditVScroll.h весь текст. 
3. Копирую подпрограммы из примера в текст основной программы. В обработчике нажатия на свою кнопку создаю TRichEdit3: | CODE  |  | TRichEditVScroll* RichEdit3=new TRichEditVScroll(this); |  
  
4. F9 — Undefined symbol 'TRichEditVScroll' 
5. Вопрос — почему?
  
Блин, а ведь хочется разобраться. ыыыыыыыыыыыыы.....  | 
  | 
| olegenty | 
| Отправлено: 28.05.2004, 06:48 | 
 
 
 | 
  
Ветеран 
 
Группа: Модератор 
Сообщений: 2412 
  
  
 | 
 1. New->Package 
2. Зацепи к нему мой компонент 
3. Наслаждайся
 | 
  | 
| olegenty | 
| Отправлено: 28.05.2004, 06:52 | 
 
 
 | 
  
Ветеран 
 
Группа: Модератор 
Сообщений: 2412 
  
  
 | 
 Вот тебе пакэдж. Просто установи у себя, и всё. (*.bpk)
  
  
 | 
  | 
| Gedeon | 
| Отправлено: 28.05.2004, 08:26 | 
 
 
 | 
 
  
Ветеран 
 
Группа: Модератор 
Сообщений: 1742 
  
  
 | 
 Установить компонент в принципе удобнее, но в вашем случае надо было просто сделать 
#include хидер компонента в ваш юнит. 
так я компоненты отлаживаю.
 | 
  | 
| olegenty | 
| Отправлено: 28.05.2004, 08:58 | 
 
 
 | 
  
Ветеран 
 
Группа: Модератор 
Сообщений: 2412 
  
  
 | 
 2Gedeon — горизонтальная синхронизация "мнимой каретки" у меня не получилась пока...
 | 
  | 
| BlastOff | 
| Отправлено: 29.05.2004, 15:14 | 
 
 
 | 
  
Ученик-кочегар 
 
Группа: Участник 
Сообщений: 8 
  
  
 | 
 Блин, ну вы круты! 
Особенно благодарен olegenty! Спасибо. Ладно, на пару строчек сглючивает, когда фокус стоит не там, где надо. Это фигня. Я исправлю!
  
Ещё раз спасибо. (но не думайте, что так легко от меня отделаетесь!    | 
  | 
| olegenty | 
| Отправлено: 30.05.2004, 06:45 | 
 
 
 | 
  
Ветеран 
 
Группа: Модератор 
Сообщений: 2412 
  
  
 | 
 ну хорошо, если помог...   
а глюк с фокусом — я просто не придумал, как избежать рекурсивного вызова обработчика события в случае перекрёстной ссылки, и фокус — как раз флаг, который спасает от зацикливания.
 | 
  |