2013-10-07 3 views
2

Благодаря превосходному post Яир Альтману на undocumentedmatlab.com, я попытался внедрить программу ведения графического интерфейса с использованием богатого editbox и базовых компонентов 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)); 
    

    benchmark

    Если добавить pause(0.1) после toc, то граф выглядит

    benchmark_pause

    Что здесь происходит?

  2. В результате получается очень «блестящая» панель журнала. Каждый раз, когда я пишу сообщение, содержимое мерцает при прокрутке вверх, а затем назад. Еще раз этот дефект вызван setText(), который заставляет каретку начинаться с документа.

Я ищу решения любой из этих проблем, желательно и то, и другое.

+0

Среднее время между 4 и 16 миллисекундами на моих OSX 10.8 и R2012b, без 'pause (0.1) ' – marsei

+0

Кажется, что R2013b менее эффективен в этом отделе, чем R2012b. Я пробовал это на 2012b и получил аналогичные результаты, как вы. Попробуйте запустить тест с большим значением 'n' (например, 5000). Я все еще сильно замедляюсь. – hoogamaphone

+0

Я не знаю, что случилось с 'getText()', чтобы быть узким местом, но я бы поставил себе представление о том, что после «toc» или перед 'tic' вы будете сбрасывать' tic', вы увидите подобное изменение. Если моя интуиция правильная, то несоответствие происходит из-за очереди событий (возможно, графических объектов), которая сбрасывается по одному из методов 'jEditbox' (вероятно,' getText'). – chappjc

ответ

1

Конечно, использование getText(), String манипуляции и setText() является узким местом. Вы вынуждаете компонент редактора преобразовывать все содержимое в представление HTML и повторно просматривать все представление HTML после изменения. Редактор не может обнаружить, что вы просто добавили немного текста. Чем больше содержимое вашего компонента, тем выше потеря производительности.

Если у вас есть свинг компонент текста и хотите добавить некоторый текст в конце концов, вы можете использовать:

  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 вызов, как и в первом случае.

+0

Спасибо! Это прекрасно работает! – hoogamaphone

Смежные вопросы