CodeGear C++ Builder中是否有比TMemo更快的组件?

3
我正在使用CodeGear C++ Builder 2009,遇到了TMemo组件的问题。它运行得太慢了。我使用它来显示来自COM串口的ASCII文本。我需要在每个符号从COM串口传输时都能立即显示出来。问题是,如果COM串口传输了大量文本,TMemo上的旧文本会开始闪烁,并且文本越多,情况会变得越糟糕。当TMemo包含1000行文本时,刷新延迟是巨大的!
我将doubleBuffered属性设置为true,但这没有帮助。像SecureCRT这样的应用程序如何使刷新时间最短?新文本可以平滑添加,没有闪烁。哪个组件可以产生这样的结果?

他们很可能使用更接近操作系统功能的内容,而不是 Borland 类... - PlasmaHH
@Hitman_99:请展示你用来填充TMemo的实际代码。你很可能只是使用它的方式不对。 - Remy Lebeau
2个回答

1

与其实时将字符显示到TMemo中,不如先将它们保存到内存缓冲区中,然后使用短定时器定期将缓冲区复制到TMemory中,并在添加新文本时使用Lines->BeginUpdate()Lines->EndUpdate()方法。此外,1000行是很多的,您可能需要在一段时间后开始删除旧行,以便添加新行。我通常将我的控件限制为几百行。

更新:尝试像这样做:

TMemoryStream *Buffer;

// serial port callback
void BytesReceived(void *Data, int Length)
{
    Buffer->Position = Buffer->Size;
    Buffer->WriteBuffer(Data, Length);
}

__fastcall TForm1::TForm1(TComponent *Owner)
    : TForm(Owner)
{
    Buffer = new TMemoryStream;
}

__fastcall TForm1::~TForm1()
{
    delete Buffer;
}

void __fastcall TForm1::TimerElapsed(TObject *Sender)
{
    if (Buffer->Size > 0)
    {
        Memo1->Lines->BeginUpdate();
        Memo1->SelStart = Memo1->GetTextLen();
        Memo1->SelLength = 0;
        Memo1->SelText = AnsiString((char*)Buffer->Memory, Buffer->Size);
        Memo1->SelStart = Memo1->GetTextLen();
        Memo1->Perform(EM_SCROLLCARET, 0, 0);
        Memo1->Lines->EndUpdate();
        Buffer->Clear();
    }
}

我实现了BeginUpdate()和EndUpdate(),它们解决了一些问题。在将文本放入备忘录之前进行缓冲会更完美,但我不能这样做,因为我需要立即查看每个字节。例如:在将固件发送到连接到SerialCom端口的设备后,有一些进度,用点(.)表示,因此当我缓冲输入时,我无法看到此进度。我计划在今年晚些时候开始处理这个项目,所以如果我想出一个解决方案,我会在这里发布。 - Hitman_99
这就是为什么我建议使用短定时器定期刷新缓冲区,比如100-250毫秒。您仍然可以获得接近实时的UI更新,但是插入到Memo中的操作可以更有效率 - 较少的大型插入而不是更多的小型插入。此外,对于实际的插入操作,插入新文本的最有效方法是将SelStart属性设置为Memo的末尾,然后设置SelText属性,而不是使用Add()或Text属性。 - Remy Lebeau
使用您提出的技术,是否可以将滚动条保持在备忘录窗口底部?由于新条目不可见,您需要将滚动条拖到窗口底部。 - Hitman_99
在插入新文本后,通过设置 SelStart 属性将插入符号再次放置在文本末尾,并向 Memo 发送一个 EM_SCROLLCARET 消息。我已经更新了示例。 - Remy Lebeau
谢谢。但是如果在调用Memo1->Lines->EndUpdate()之前调用Memo->Perform(EM_SCROLLCARET, 0, 0),它将什么也不做,不会滚动文本。但是在调用Memo1->Lines->EndUpdate()之后调用它可以完美地工作。 - Hitman_99

0
对于Windows设备来说,最好的方法是使用线程事件而不是定时器事件。将串行等待事件放置在thread->execute()中(这是一个do while循环)。
串行等待事件在没有接收到任何内容之前不会执行任何操作。一旦接收到内容,它会存储在*buffer中,并检查缓冲区/字符串的长度。
然后将其放置在备忘录中。
memo->text=buffer;
or 
memo->lines-add(buffer);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接