Как создать независимые слои JPanel в JFrame и перерисовать каждый по отдельности

Я ищу способ рисовать несколько JComponents друг над другом (перекрываться) и при этом иметь возможность индивидуального доступа и изменения их.

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

В моем текущем проекте есть Jpanel с тысячами строк, и мне нужно изменить прямоугольник сзади при наведении курсора, если я перерисовываю весь Jpanel каждый раз, когда он сильно тормозит.

Есть ли достойный способ сделать это? Спасибо уже за ваши идеи!


person Matthias K    schedule 10.11.2016    source источник
comment
Лучшим способом было бы иметь один JPanel и несколько BufferedImages в качестве слоев. Закрасьте каждый BufferedImage по порядку, стараясь не закрашивать прозрачные области. Вы должны очищать и перекрашивать всю область рисования для каждого кадра анимации. Кроме того, метод paintComponent вашей панели рисования должен просто рисовать. Никаких расчетов. Ничего, кроме методов Graphics2D. Последней альтернативой было бы смоделировать ваши геометрические фигуры и нарисовать фигуры из модели.   -  person Gilbert Le Blanc    schedule 10.11.2016
comment
Взгляните на мой ответ Moving Eyes, чтобы увидеть как настроить панель рисования в Swing.   -  person Gilbert Le Blanc    schedule 10.11.2016
comment
Похоже, это может решить мою проблему! BufferedImages как слои - я попробую! Благодарю вас!   -  person Matthias K    schedule 11.11.2016


Ответы (2)


Мне нужно изменить прямоугольник сзади

Вы можете вызывать:

panel.repaint(rectangle); // or 
panel.repaint(x, y, width, height);

чтобы указать прямоугольную область, которую нужно перекрасить.

person camickr    schedule 10.11.2016
comment
Спасибо за быстрый ответ. Но в моем сценарии все jpanel лежат прямо друг над другом, поэтому у них одинаковые ограничивающие рамки. т.е. перерисовка прямоугольника приводит к полной перерисовке всех остальных слоев. В основном прямоугольник эквивалентен фону. - person Matthias K; 11.11.2016
comment
Это правильно. Swing будет смотреть на компонент, который вы хотите перерисовать, и смотреть на всех его родителей, пока не найдет компонент с непрозрачным фоном. Затем он рисует фон и все дочерние компоненты в этом месте. Это делается для того, чтобы убедиться, что область окрашена полностью без артефактов. Мое предложение состояло в том, чтобы рисовать не прямоугольник всей панели, а только часть измененной панели. Поэтому, когда вы меняете круг, вы перекрашиваете только область, полностью содержащуюся в круге. - person camickr; 11.11.2016
comment
@MatthiasK, перекрашивание панелей, содержащих круг, прямоугольник и линию, не проблема. Я нарисовал сотни объектов одновременно без проблем. У вас должны быть какие-то другие проблемы с покраской. - person camickr; 11.11.2016
comment
Спасибо за подсказки! В моем проекте я на самом деле рисую огромное количество (> 10000) путей (линий с более чем 100 ребрами), поэтому перерисовка не вариант. Частичная перерисовка также сложна, так как линии повсюду и только крошечные пятна между ними.. что мне нужно, так это какие-то прозрачные слои, которые вы рисуете один раз и показываете и скрываете, когда захотите - без каких-либо вычислений ... Угадайте, что подсказка от Гилберта Ле Блана может быть правильным путем - использовать буферизованные изображения - я обязательно посмотрю на это! - person Matthias K; 11.11.2016

Это сработало очень хорошо - вот мой код, если у кого-то еще есть похожая проблема! первое изображение может быть сохранено и отображено позже (buff). Обязательно сгенерируйте новое BufferedImage (здесь холст) при повторном отображении, так как в противном случае прозрачность будет потеряна. Спасибо Гилберту Ле Бланку.

@Override
protected void paintComponent(Graphics g1) {
    //Create image:
    BufferedImage buff = new BufferedImage(mywidth, myheight, BufferedImage.TYPE_INT_ARGB);

    //write to image:
    Graphics2D g2 = (Graphics2D) buff.getGraphics();
    g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,(float) 0.01f));
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    g2.draw(xxxRectanglewhatever);

    //then - later draw image again
    BufferedImage canvas = new BufferedImage(mywidth, myheight, BufferedImage.TYPE_INT_ARGB);
    canvas.getGraphics().drawImage(buff, 0, 0, null);
    ((Graphics2D) g1).setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
    g1.drawImage(canvas, 0, 0, null);
    canvas.flush();
}
person Matthias K    schedule 15.11.2016