Можно ли убедить Swing кэшировать изображения, загруженные с помощью тега <img>в ячейку jTable, вместо повторной загрузки изображения при каждом перерисовке? - PullRequest
0 голосов
/ 22 февраля 2019

Как видно из заголовка, я заметил, что удаленно размещенные изображения, загруженные с использованием тегов <img> внутри содержимого ячейки jTable, перезагружаются каждый раз, когда компонент перерисовывается.Содержимое ячейки будет выглядеть примерно так: <html><img src="http://www.example.com/image.png"></html>

Обычно это не является большой проблемой, хотя с достаточно большими изображениями и компонентами, которые перекрашиваются достаточно часто, они могут стать проблемой производительности приложения.(поскольку он будет зависать при повторной загрузке образа каждый раз, когда компонент перекрашивается), и, возможно, проблема спама / полосы пропускания для любого плохого файлового сервера, на котором размещается образ.

Можно ли убедить Swingзагрузить изображение только в первый раз, когда оно необходимо, а затем повторно использовать кэшированную копию при перерисовке вместо повторной загрузки его каждый раз?

И чтобы уточнить, как я заметил это поведение, было:

  1. Обратите внимание на резкое снижение производительности при быстрой перерисовке ячейки jTable во время визуализации большого изображения на ней.
  2. Размещение указанного файла образа на файловом сервере Netty и просмотрвывод консоли выглядит следующим образом: Страницы и страницы этого, и более появляютсябыстро, как компонент перекрашивается

Редактировать, добавив MCVE к вопросу:

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;

public class Main {

    public static void main(String[] argv) {

        JFrame demoFrame = new JFrame("Table");

        JTable jTable = new JTable();

        demoFrame.getContentPane().add(new JScrollPane(jTable));

        DefaultTableModel dtm = new DefaultTableModel(new Object[]{"cache test"}, 5);

        jTable.setModel(dtm);

        jTable.setValueAt("<html><img src=\"https://i.imgur.com/zfa0mEn.png\"></html>", 2, 0);

        demoFrame.pack();
        demoFrame.setVisible(true);
    }

}

Было бы немного утомительно и излишне бросать вкакой-то файловый сервер, чтобы отслеживать запросы файлов здесь, так что я решил против этого.

1 Ответ

0 голосов
/ 23 февраля 2019

Я нашел способ решения проблемы, возможно, не самый красивый, но он решил и проблему с производительностью, и ненужный запрос спама для одного и того же изображения.

Следующий код содержит обаMCVE и реализация TableModelListener, которая будет автоматически определять, когда теги изображения помещаются в содержимое любой из ячеек jTable, локально загружать изображение в папку, созданную в рабочем каталоге приложения, а затем заменять атрибут src тега навместо этого укажите на этот кешированный файл.

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;

public class Main {

    public static void main(String[] argv) {

        JFrame demoFrame = new JFrame("Table");

        JTable jTable = new JTable();

        demoFrame.getContentPane().add(new JScrollPane(jTable));

        DefaultTableModel dtm = new DefaultTableModel(new Object[]{"cache test"}, 5);

        jTable.setModel(dtm);

        jTable.getModel().addTableModelListener(new ImageCachingTableModelListener());

        jTable.setValueAt("<html><img src=\"https://i.imgur.com/zfa0mEn.png\"></html>", 2, 0);

        demoFrame.pack();
        demoFrame.setVisible(true);
    }

    private static class ImageCachingTableModelListener implements TableModelListener {

        String regex = "<html>(?:[\\s\\S]*)<img(?:[\\s\\S]*)src=\"((?:[\\S]+)\\/([\\S]+\\.[A-Za-z0-9_-]+)(?:[\\s\\S]*))\"(?:[\\s\\S]*)?>(?:[\\s\\S]*)<\\/html>";
        Pattern pattern = Pattern.compile(regex);

        @Override
        public void tableChanged(TableModelEvent evt) {
            DefaultTableModel evtTableModel = (DefaultTableModel) evt.getSource();

            if (evt.getType() == TableModelEvent.UPDATE) {

                for (int i = evt.getFirstRow(); i <= evt.getLastRow(); i++) {
                    String content = (String) evtTableModel.getValueAt(i, evt.getColumn());
                    Matcher m = pattern.matcher(content);

                    if (m.find()) {

                        String imageSrc = m.group(1);
                        String imageFileName = m.group(2);

                        try (InputStream in = new URL(imageSrc).openStream()) {
                            File cacheDir = new File(System.getProperty("user.dir") + File.separator + "imgcache");

                            if (!cacheDir.exists()) {
                                cacheDir.mkdirs();
                            }

                            Path cachedFilePath = Paths.get(cacheDir.getCanonicalPath() + File.separator + imageFileName);

                            Files.copy(in, cachedFilePath, StandardCopyOption.REPLACE_EXISTING);

                            evtTableModel.setValueAt(content.replace(imageSrc, "file:" + cachedFilePath.toString()), i, evt.getColumn());

                        } catch (MalformedURLException ex) {
                            ex.printStackTrace();
                        } catch (IOException ex) {
                            ex.printStackTrace();
                        }
                    }
                }
            }
        }
    }

}

Спасибо за помощь, надеюсь, это пригодится кому-то еще.Спасибо artemis за помощь в части кода в регулярных выражениях.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...