Search code examples
c++winapic++buildervclrichedit

How to synchronize two RichEdit's scrolling position?


I add my program two RichEdit which the one displays binary contents and the another shows the index of the byte. I hope these two edit always anchor on the same position while/after scrolling.

image

A possible way is to handle the main RichEdit's WM_VSCROLL and WM_MOUSEWHEEL message and pass the message and parameters to the second RichEdit. I've tried this but I found that the two edits aligned not very well. And the other disadvantage is the both RichEdits' scroll bar needs to be enabled, if I only enable one, the another can't receive WM_MOUSEWHEEL message, but I hope one scroll bar displayed only.

image

The second way I've tried is using a timer and synchronize with LINESCROLL regularly by the time (< 10ms is better). This works well most of the time, but sometimes still have the unaligned issue.

Is there a better solution to handle this kind of demand?

//---------------------------------------------------------------------------
void __fastcall TBinaryEdit::Timer1Timer(TObject *Sender)
{
    int srcLine = 0;
    int trgLine = 0;

    if (Sender == Timer1) {
        srcLine = GetRichEditLineNo(MainEdit);
        trgLine = GetRichEditLineNo(IndexEdit);

        if (srcLine != trgLine) {
            SendMessage(IndexEdit->Handle, EM_LINESCROLL, 0, srcLine - trgLine);
        }
    }
}
//---------------------------------------------------------------------------
int TBinaryEdit::GetRichEditLineNo(TRichEdit* RE)
{
    int line;
    int wordpos;

    TRect rt;
    POINTL pt;

    SendMessage(RE->Handle, EM_GETRECT, 0, LPARAM(&rt));
    pt.x = RE->Left + rt.left;
    pt.y = RE->Top + rt.top;
    wordpos = SendMessage(RE->Handle, EM_CHARFROMPOS, 0, LPARAM(&pt));
    line = SendMessage(RE->Handle, EM_LINEFROMCHAR, wordpos, 0);

    return line;
}

Solution

  • Thanks for your help. I've found a simple solution for my short-term need.

    As I mentioned before, the second RichEdit's scroll bar should be enabled for receiving WM_MOUSEWHEEL message, but I don't like both edit have scroll bar displayed. For this reason, I use EM_LINESCROLL instead to replace the mouse wheel message. I write a sub class derive the TRichEdit and overwrite its WM_MOUSEWHEEL handler, then pass EM_LINESCROLL message with the mouse wheel's delta value to both RichEdits.

    int zDelta = GET_WHEEL_DELTA_WPARAM(Message.WParam);
    int scroll = zDelta == -120 ? 1 : -1;
    
    SendMessage(MainEdit->Handle, EM_LINESCROLL, 0, scroll);
    SendMessage(IndexEdit->Handle, EM_LINESCROLL, 0, scroll);
    

    This makes the text vertical offset in RichEdits be aligned. But I think there must be better solution, I will keep research for improvement.