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