感谢Yair Altman在post上出色的undocumentedmatlab.com,我尝试使用丰富的编辑框和底层的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
我有两个问题:
在需要大量记录消息(即&gt; 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));
如果我在pause(0.1)
之后添加toc
,则图表看起来像
这里发生了什么?
这会导致一个非常“华而不实”的日志面板。每次我写一条消息时,内容会在滚动到顶部然后再回到底部时闪烁。再一次,这个缺陷是由setText()
引起的,它迫使插入符号出现在文档的开头。
我正在寻找这些问题的解决方案,最好是两者兼而有之。
答案 0 :(得分:1)
当然,使用getText()
,String
操作和setText()
是一个瓶颈。您强制编辑器组件将其整个内容转换为HTML表示形式,并在更改后重新分析整个HTML表示。编辑器无法检测到您刚刚添加了一些文本。组件的内容越多,性能损失就越高。
如果您有一个Swing文本组件,并希望在末尾附加一些文本,则可以使用:
(简单的)纯文本:
textComp.setCaretPosition(textComp.getDocument().getLength());
textComp.replaceSelection("\nMore Text");
(并非如此困难),例如HTML:
Document doc = textComp.getDocument();
textComp.getEditorKit().read(
new StringReader("More <i>styled</i> text"), doc, doc.getLength());
在第二种情况下,如果要将插入符号移动到最后,则必须像第一种情况一样添加setCaretPosition
调用。