PaintComponent() vs paint() и JPanel vs Canvas в графическом интерфейсе типа кисти

У меня есть интересные идеи и критика из этого, this и this (см. последний пост для кода соответствующего GUI). Тем не менее, я все еще довольно смущен некоторыми вещами. В основном, что является наименее дорогостоящим способом отображения пользовательской графики?

В частности, я использовал метод paintComponent() из класса JPanel, создав объект этого класса в методе MouseDragged() вместе с методом paintComponent(getGraphics()) (AuxClass2 и AuxClass1 соответственно).

По-видимому, использование getGraphics() и paintComponent() вместо repaint() - плохие идеи, я подозреваю, что это связано с использованием памяти. Также вызов AuxClass2 каждый раз, когда пользователь перетаскивает мышь, также является плохой идеей.

Также JPanel vs Canvas (т.е. swing vs awt) немного запутан. Что используется и когда?

Я пытался найти обходные пути, но не нашел их, особенно для метода getGraphics(): как еще можно добавить графику в панель?

Ответы

Ответ 1

Я пытался найти обходные пути, но не нашел их, особенно для метода getGraphics(): как еще можно рисовать графику добавлен в панель?

Вы помните, что нужно раскрасить как переменную и использовать в paintComponent(). Например, то, что вы пытались сделать в своем другом вопросе, будет выглядеть следующим образом:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class PaintRectangle extends JPanel {

    private Point mouseLocation;

    public PaintRectangle() {
        setPreferredSize(new Dimension(500, 500));

        MouseAdapter listener = new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                updateMouseRectangle(e);
            }

            private void updateMouseRectangle(MouseEvent e) {
                mouseLocation = e.getPoint();
                repaint();
            }

            @Override
            public void mouseDragged(MouseEvent e) {
                updateMouseRectangle(e);
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                mouseLocation = null;
                repaint();
            }
        };
        addMouseListener(listener);
        addMouseMotionListener(listener);
    }

    private Rectangle getRectangle() {
        if(mouseLocation != null) {
            return new Rectangle(mouseLocation.x - 5, mouseLocation.y - 5, 10, 10);
        }
        else {
            return null;
        }
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Rectangle rectangle = getRectangle();
        if(rectangle != null) {
            Graphics2D gg = (Graphics2D) g;
            gg.setColor(Color.BLUE);
            gg.fill(rectangle);
            gg.setColor(Color.BLACK);
            gg.draw(rectangle);
        }
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                frame.getContentPane().add(new PaintRectangle());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }
}

См. также http://docs.oracle.com/javase/tutorial/uiswing/painting/

Ответ 2

Тяжелый и легкий вес

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

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

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

Иллюзия управления

Одна из самых больших проблем для новичков Swing API - иллюзия, что у вас есть какой-то контроль над процессом рисования, вы не "т. Легче просто принять его.

Лучшее, что вы можете сделать, это попросить диспетчер repaint выполнить обновление как можно скорее.

Кроме того, вызов getGraphics не гарантированно возвращает ненулевое значение.

Правильный порядок вещей

paint vs paintComponent

Проблема здесь paint выполняет ряд важных заданий, вызывающих paintComponent только один из них.

В Swing нам очень рекомендуется использовать paintComponent всякий раз, когда мы хотим выполнить пользовательскую роспись, это, как правило, самый низкий уровень на компоненте и вызывается до окрашивания дочерних компонентов.

Если вы переопределяете paint, а затем рисуете на Graphics после вызова super.paint, вы закончите рисовать поверх всего, это не всегда желаемый результат

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

Полезные ссылки

Прощальные мысли

Только те компоненты, которые фактически добавлены к компоненту, который прикреплен к собственному одноранговому узлу, когда-либо будут иметь метод paint. Поэтому попытка рисовать компонент, который еще не добавлен в контейнер, довольно бессмысленна...

Ответ 3

.. кисть типа GUI..

Используйте BufferedImage как поверхность рисования. Отобразите его в JLabel. Поместите метку в центр панели внутри JScrollPane.

Вызовите bufferedImage.getGraphics() по мере необходимости, но запомните его dispose(), когда закончите, а затем вызовите label.repaint().

Используйте компоненты Swing повсюду и не переопределяйте что-либо.

Вот пример использования изображения в качестве поверхности рисования.

eAgUn.png

И вот лучший вариант!

cbeEm.png

Я не сказал, что экранный снимок был лучше, это лучший код.;)