Ускоряйте 2D изображения в Java *, не мешая JMenus
-
05-07-2019 - |
Вопрос
Уже реализовано повышение производительности: - Получить совместимое изображение GraphicsConfiguration для рисования - Включить конвейер OpenGL в версии 1.5: невозможно из-за серьезных артефактов
Пока все в порядке, основным узким местом программы является рисование изображения с несколькими тысячами плиток. К сожалению это не регулярно, иначе я просто мог бы установить пиксели и масштабировать их. Я связал изображение с VolatileImages и собственными процедурами рендеринга (игнорируйте перерисовку и нарисуйте его сам с таймером). Результат был приятным и достаточным, НО: Выбор JMenu, который обычно находится над частью изображения, серьезно нарушен, потому что JMenu перезаписан. Недопустимо, и макет не может быть изменен.
Я пробовал GLJPanel из JOGL, но видимого улучшения производительности нет. Так есть ли возможность использовать VolatileImages (или другие ускоренные легковесные компоненты, такие как GLCanvas) и при этом получить нормальное отображение JMenu, и если да, то как? Р>
Решение
Вы можете попытаться установить всплывающие окна не в легком весе. Я не совсем уверен, если это работает, но это может, потому что всплывающее окно является нативным компонентом и не будет перезаписано. Установка всплывающих окон в супертяжелом: JPopupMenu.setDefaultLightWeightPopupEnabled (false)
Дополнительная информация: Смешивание тяжелых и легких компонентов р>
Другие советы
Вот пример кода:
import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.VolatileImage;
import java.io.File;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;
public final class FastDraw extends JFrame {
private static final transient double NANO = 1.0e-9;
private BufferStrategy bs;
private BufferedImage frontImg;
private BufferedImage backImg;
private int PIC_WIDTH,
PIC_HEIGHT;
private Timer timer;
public FastDraw() {
timer = new Timer(true);
JMenu menu = new JMenu("Dummy");
menu.add(new JMenuItem("Display me !"));
menu.add(new JMenuItem("Display me, too !"));
JMenuBar menuBar = new JMenuBar();
menuBar.add(menu);
setJMenuBar(menuBar);
setIgnoreRepaint(true);
setVisible(true);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent evt) {
super.windowClosing(evt);
timer.cancel();
dispose();
System.exit(0);
}
});
try {
backImg = javax.imageio.ImageIO.read(new File(<insert a jpg picture here>));
frontImg = javax.imageio.ImageIO.read(<here, too>));
}
catch (IOException e) {
System.out.println(e.getMessage());
}
PIC_WIDTH = backImg.getWidth();
PIC_HEIGHT = backImg.getHeight();
setSize(PIC_WIDTH, PIC_HEIGHT);
createBufferStrategy(1); // Double buffering
bs = getBufferStrategy();
timer.schedule(new Drawer(),0,20);
}
public static void main(String[] args) {
new FastDraw();
}
private class Drawer extends TimerTask {
private VolatileImage img;
public void run() {
long begin = System.nanoTime();
Graphics2D g = (Graphics2D) bs.getDrawGraphics();
GraphicsConfiguration gc = g.getDeviceConfiguration();
if (img == null)
img = gc.createCompatibleVolatileImage(PIC_WIDTH, PIC_HEIGHT);
Graphics2D g2 = img.createGraphics();
do {
int valStatus = img.validate(gc);
if (valStatus == VolatileImage.IMAGE_OK)
g2.drawImage(backImg,0,0,null);
else {
g.drawImage(frontImg, 0, 0, null);
}
// volatile image is ready
g.drawImage(img,0,50,null);
bs.show();
} while (img.contentsLost());
}
}
}
Измените размер окна, чтобы сделать JMenuBar
видимым. Попробуйте выбрать пункт меню. См?
Ну, я не уверен, что полностью понимаю вашу проблему, но, похоже, основная проблема заключается в перерисовке панели, на которой отображается изображение. Не могли бы вы предоставить свою процедуру рисования, которая рисует изображение на панели? Р>