C++ Builder
| Главная | Уроки | Статьи | FAQ | Форум | Downloads | Литература | Ссылки | RXLib | Диски |

 
одновременная прокрутка текста
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



А можно без таймера?
Или вообще, как-нибудь попроще?

Остановлюсь на динамически созданных компонентах. Хорошо, поищу.
Я ж не заставляю кого-то возиться. ohmy.gif

Отредактировано 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



Можно сделать вообще просто, по ламерски, если хочешь без наследований: перехвати просто все события — нажатия клавиш, клики мышей, изменение, и в каждом вызвай функцию которая будет синхронизировать скролы... cool.gif
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



дома посмотрю, сейчас времени нет... smile.gif идея-то понятна, всё же просто smile.gif
Gedeon
Отправлено: 27.05.2004, 13:04


Ветеран

Группа: Модератор
Сообщений: 1742



QUOTE (olegenty @ 27/05/2004, 13:40)
дома посмотрю, сейчас времени нет... smile.gif идея-то понятна, всё же просто smile.gif

Согласен, задача простая, надо просто сесть и реализовать, я написал бы, но сейчас занят переходом на новую работу, тут сдать всего дофига надо.
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)

User Attached Image Скачать файл
RichEditVScroll.zip


Gedeon
Отправлено: 28.05.2004, 08:26


Ветеран

Группа: Модератор
Сообщений: 1742



Установить компонент в принципе удобнее, но в вашем случае надо было просто сделать
#include хидер компонента в ваш юнит.
так я компоненты отлаживаю.
olegenty
Отправлено: 28.05.2004, 08:58


Ветеран

Группа: Модератор
Сообщений: 2412



2Gedeon — горизонтальная синхронизация "мнимой каретки" у меня не получилась пока...
BlastOff
Отправлено: 29.05.2004, 15:14


Ученик-кочегар

Группа: Участник
Сообщений: 8



Блин, ну вы круты!
Особенно благодарен olegenty! Спасибо. Ладно, на пару строчек сглючивает, когда фокус стоит не там, где надо. Это фигня. Я исправлю!

Ещё раз спасибо. (но не думайте, что так легко от меня отделаетесь! wink.gif
olegenty
Отправлено: 30.05.2004, 06:45


Ветеран

Группа: Модератор
Сообщений: 2412



ну хорошо, если помог... smile.gif
а глюк с фокусом — я просто не придумал, как избежать рекурсивного вызова обработчика события в случае перекрёстной ссылки, и фокус — как раз флаг, который спасает от зацикливания.

Вернуться в Вопросы программирования в C++Builder