【问题标题】:Improve Performance On GUI log提高 GUI 日志的性能
【发布时间】:2013-10-14 03:48:00
【问题描述】:

感谢 Yair Altman 在undocumentedmatlab.com 上出色的post,我尝试使用丰富的编辑框和底层的java 组件来实现一个GUI 日志程序。这是代码的简化版本:

首先是创建面板的代码

function jEditbox = logPanel()
    hFig = figure('color', 'w');
    hPanel = uipanel(hFig);

    % Prepare the log editbox
    hLogPanel = uicontrol('style', 'edit', 'max', 5, 'Parent', hPanel, ...
        'Units', 'normalized', 'Position', [0, 0.2, 1, 0.8], 'Background', 'w');

    % Get the underlying Java editbox, which is contained within a scroll-panel
    jScrollPanel = findjobj(hLogPanel);
    try
        jScrollPanel.setVerticalScrollBarPolicy(jScrollPanel.java.VERTICAL_SCROLLBAR_AS_NEEDED);
        jScrollPanel = jScrollPanel.getViewport();
    catch %#ok<CTCH>
        % may possibly already be the viewport, depending on release/platform etc.
    end
    jEditbox = handle(jScrollPanel.getView, 'CallbackProperties');

    % Prevent user editing in the log-panel
    jEditbox.setEditable(false);

    % Set-up a Matlab callback function to handle hyperlink clicks
    set(jEditbox,'HyperlinkUpdateCallback',@linkCallbackFcn);

    % Ensure we have an HTML-ready editbox
    HTMLclassname = 'javax.swing.text.html.HTMLEditorKit';
    if ~isa(jEditbox.getEditorKit, HTMLclassname)
        jEditbox.setContentType('text/html');
    end
end

然后是日志记录代码:

function logMessage(jEditbox, text)
    % newText = [iconTxt, msgTxt ' '];
    text = [text '<br/>'];

    % Place the HTML message segment at the bottom of the editbox
    currentHTML = char(jEditbox.getText);
    newHTML = strrep(currentHTML, '</body>', text);
    jEditbox.setText(newHTML);
    endPosition = jEditbox.getDocument.getLength;
    jEditbox.setCaretPosition(endPosition);
end

我有两个问题:

  1. 在需要大量记录消息(即 > 500 条)的应用程序中存在重大性能问题。使用分析器和以下代码(请注意,我已修改 why 以返回字符串而不是打印到命令行),我发现瓶颈在于 setText()。谁能解释图中的尖峰是什么?

    h = logPanel();
    
    n = 1e3;
    time = nan(n, 1);
    profile on
    for i = 1:n
        tic
        logMessage(h, why)
        time(i) = toc;
    end
    profile viewer
    avgTime = mean(time);
    figure('color', 'w')
    bar(time)
    hold on
    plot([0, n], avgTime*ones(1, 2), '-k', 'LineWidth', 2)
    hold off
    title(sprintf('Average Time = %f [s]', avgTime));
    

    如果我在toc 之后添加pause(0.1),则图表如下所示

    这是怎么回事?

  2. 这会导致非常“华丽”的日志面板。每次我写一条消息时,内容都会闪烁,因为它滚动到顶部然后又回到底部。同样,此缺陷是由于 setText() 造成的,它强制插入符号位于文档的开头。

我正在寻找这些问题中的任何一个的解决方案,最好同时解决。

【问题讨论】:

  • 在我的 OSX 10.8 和 R2012b 上,平均时间在 4 到 16 毫秒之间,没有pause(0.1)
  • 看来R2013b在这个部门的效率不如R2012b。我在 2012b 上试过这个,得到了和你相似的结果。尝试使用更大的n(例如,5000)运行基准测试。我的速度仍然很慢。
  • 我不知道getText() 有什么问题成为瓶颈,但我想在toc 之后或tic 之前放置一个drawnow 你会看到类似的变化。如果我的直觉是正确的,那么差异是因为事件队列(可能是图形对象)在jEditbox 方法之一(可能是getText)上被刷新。

标签: java matlab user-interface


【解决方案1】:

当然,使用getText()String 操作和setText() 是一个瓶颈。您强制编辑器组件将其全部内容转换为 HTML 表示,并在更改后重新解析整个 HTML 表示。编辑器无法检测到您刚刚添加了一些文本。你的组件的内容越多,性能损失就越大。

如果你有一个 Swing 文本组件并且想在末尾附加一些文本,你可以使用:

  1. (简单的)纯文本:

    textComp.setCaretPosition(textComp.getDocument().getLength());
    textComp.replaceSelection("\nMore Text");
    
  2. (没那么难)内容类型中的文本,例如HTML:

    Document doc = textComp.getDocument();
    textComp.getEditorKit().read(
      new StringReader("More <i>styled</i> text"), doc, doc.getLength());
    

在第二种情况下,如果您想将插入符号移到末尾,您必须像第一种情况一样添加setCaretPosition 调用。

【讨论】:

    猜你喜欢
    • 2016-05-13
    • 1970-01-01
    • 2016-07-19
    • 2017-02-23
    • 2010-12-05
    • 1970-01-01
    • 1970-01-01
    • 2012-07-07
    • 1970-01-01
    相关资源
    最近更新 更多