Проблемы с JApplets и вызовом paint / paintComponent

Так что я просто готовлюсь к финалу здесь, и у меня проблемы с тем, чтобы это работало. То, что я всегда делал раньше, это вызов paintComponent (Graphics g), и все работало просто отлично. Но теперь я получаю сообщение об ошибке «paintComponent имеет защищенный доступ в JComponent», когда перехожу к компиляции. Единственный способ заставить его скомпилировать - сказать ему, чтобы он вызвал краску. Но даже если он компилируется, краска никогда не вызывается в окне апплета. Что я здесь не вижу?

 public class LineDraw extends JComponent
 {
private final Point p1;
private final Point p2;
private final JApplet callingWindow;
private final ArrayList<Line2D.Double> lines;

public LineDraw(JApplet callingWindow)
{
    this.p1 = new Point();
    this.p2 = new Point();
    this.callingWindow = callingWindow;
    this.lines = new ArrayList<Line2D.Double>();
    MouseListener mouse = new MouseHandler();
    callingWindow.addMouseListener(mouse);
}

public class MouseHandler extends MouseAdapter
{
    private boolean firstClick;
    public MouseHandler()
    {
        firstClick = true;
    }
    public void mouseClicked(MouseEvent e)
    {
        if(firstClick)
        {
            p1.setLocation(e.getPoint());
            firstClick = false;
        }
        else    
        {
            p2.setLocation(e.getPoint());
            lines.add(new Line2D.Double(p1, p2));
            p2.setLocation(p1.getLocation());
            callingWindow.repaint();        
        }
    }

    public void paintComponent(Graphics2D g2)
    {
        for(Line2D.Double e: lines)
        {
            g2.draw(e);
        }
    }
}

}

И сам класс апплета

    public class AppletWin extends JApplet
    {
private LineDraw lineDrawer;

public void init()
{
    setBackground(Color.white);
    lineDrawer = new LineDraw(this);
}

public void paint(Graphics h)
{
    Graphics2D g = (Graphics2D)h;
    //Clear background
    g.setColor(getBackground());
    g.fillRect(1, 1, getWidth(), getHeight());
    lineDrawer.paintComponent(g);  
}
    }

person Scuba Steve    schedule 05.12.2012    source источник


Ответы (2)


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

Похоже, вы столкнулись с проблемой коллизии имен.

JComponent определяет два метода рисования (на самом деле он определяет еще несколько, но давайте оставим это простым), paint и paintComponent.

Проблема, с которой вы столкнулись, связана с тем фактом, что вы унаследовали от JComponent, но, похоже, выполняете свою собственную картину. Это нормально, если вы хотите разработать собственные классы для рисования, но не подходят для компонентов Swing. Компонент Swing - это нечто большее, чем просто его рисование.

Другая проблема, с которой вы столкнулись, заключается в том, что вы определили метод «рисования» в побочном MouseHandler методе и, похоже, предполагаете, что он вызывается из класса LineDraw. Проблема в том, что вы фактически вызываете метод JComponent paint, а не тот, который вы хотите / думаете.

Попробуйте удалить extends JComponent и переместить метод paint в класс LineDraw.

Как указано в MouseEvent, в большинстве случаев вы никогда не должны вызывать paint или paintComponent напрямую.

Вы можете найти:

Полезный

ОБНОВЛЕНО

Рисование как компонент Swing

public class AppletWin extends JApplet {

    private LineDraw lineDrawer;

    public void init() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                setBackground(Color.white);
                lineDrawer = new LineDraw(AppletWin.this);
                setLayout(new BorderLayout());
                add(lineDrawer);
            }
        });
    }

    public class LineDraw extends JComponent {

        private final Point p1;
        private final Point p2;
        private final JApplet callingWindow;
        private final ArrayList<Line2D.Double> lines;

        public LineDraw(JApplet callingWindow) {
            this.p1 = new Point();
            this.p2 = new Point();
            this.callingWindow = callingWindow;
            this.lines = new ArrayList<Line2D.Double>();
            MouseListener mouse = new MouseHandler();
            addMouseListener(mouse);
        }

        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2 = (Graphics2D) g;
            g2.setColor(Color.RED);
            for (Line2D.Double e : lines) {
                g2.draw(e);
            }
        }

        public class MouseHandler extends MouseAdapter {

            private boolean firstClick;

            public MouseHandler() {
                firstClick = true;
            }

            public void mouseClicked(MouseEvent e) {
                if (firstClick) {
                    p1.setLocation(e.getPoint());
                    firstClick = false;
                } else {
                    p2.setLocation(e.getPoint());
                    lines.add(new Line2D.Double(p1, p2));
                    p2.setLocation(p1.getLocation());
                }
                repaint();
            }
        }
    }
}

Как художник

public class AppletWin extends JApplet {

    private LineDraw lineDrawer;

    public void init() {
        setBackground(Color.white);
        lineDrawer = new LineDraw(this);
    }

    public void paint(Graphics h) {
        // The the applet clear the background
        super.paint(h);
        Graphics2D g = (Graphics2D) h;
        lineDrawer.paintComponent(g);
    }
    public class LineDraw {

        private final Point p1;
        private final Point p2;
        private final JApplet callingWindow;
        private final ArrayList<Line2D.Double> lines;

        public LineDraw(JApplet callingWindow) {
            this.p1 = new Point();
            this.p2 = new Point();
            this.callingWindow = callingWindow;
            this.lines = new ArrayList<Line2D.Double>();
            MouseListener mouse = new MouseHandler();
            callingWindow.addMouseListener(mouse);
        }

        public void paintComponent(Graphics2D g2) {
            System.out.println("...");
            for (Line2D.Double e : lines) {
                g2.draw(e);
            }
        }

        public class MouseHandler extends MouseAdapter {

            private boolean firstClick;

            public MouseHandler() {
                firstClick = true;
            }

            public void mouseClicked(MouseEvent e) {
                if (firstClick) {
                    p1.setLocation(e.getPoint());
                    firstClick = false;
                } else {
                    p2.setLocation(e.getPoint());
                    lines.add(new Line2D.Double(p1, p2));
                    p2.setLocation(p1.getLocation());
                }
                callingWindow.repaint();
            }
        }
    }
}

Вам действительно следует избегать переопределения paint метода контейнеров верхнего уровня. Метод paint - очень сложный метод, и его обход только вызовет проблемы в долгосрочной перспективе, кроме того, он не имеет двойной буферизации;)

person MadProgrammer    schedule 05.12.2012
comment
Вы правы в том, что я определил компонент paint не в той области видимости. Наследование от JComponent нормально, если вы правильно перезаписываете метод paintComponent, поскольку он будет вызываться в процессе рисования java при вызове repaint (). - person Scuba Steve; 05.12.2012
comment
Я не перезаписал метод должным образом, но хе-хе. - person Scuba Steve; 05.12.2012
comment
@ScubaSteve Да, paintComponent будет вызываться подсистемой раскраски Swing, если 1- компонент был добавлен в контейнер и 2- он имел правильную подпись (JComponent не имеет paintComponent(Graphics2D) метода;)) - смотреть обновления - person MadProgrammer; 05.12.2012
comment
JComponent не нужно добавлять в контейнер, а нужно добавлять какие-то элементы, которые можно раскрашивать, например, JFrame или JApplet ... Но да, правильная подпись помогает. - person Scuba Steve; 09.12.2012
comment
Я знаю это, потому что я написал все guis без использования контейнера - person Scuba Steve; 09.12.2012
comment
В какой-то момент вам понадобится контейнер, в который подсистема рисования будет передавать допустимый контекст графов, чтобы рисовать на экране. - person MadProgrammer; 09.12.2012
comment
JFrame и JApplet также могут быть допустимыми графическими контекстами: D Container отлично подходит для управления вашим графическим интерфейсом, и я думаю, что он нужен, если вы хотите делать более продвинутые элементы макета графического интерфейса, но это не нужно просто для того, чтобы что-то рисовать. - person Scuba Steve; 10.12.2012
comment
Все окна (Window, Frame, Dialog, JWindow, JFrame, JDialog, Applet, JApplet) ЯВЛЯЮТСЯ контейнерами. Контейнеры верхнего уровня также не имеют двойной буферизации, что снижает их эффективность. Механизм рисования - сложный зверь, даже для простых программ рисования, вам следует избегать переопределения методов рисования контейнеров верхнего уровня, откладывая на что-то JPanel, он также делает компонент многоразовым, поскольку вы не привязываете себя к контейнер верхнего уровня летучей мыши. - person MadProgrammer; 10.12.2012

Проблема с этим кодом заключается в том, что метод paintComponent в LineDraw находится внутри внутреннего класса MouseHandler.

person Scuba Steve    schedule 05.12.2012
comment
JComponent не имеет paintComponent(Graphics2D) метода;) - person MadProgrammer; 05.12.2012
comment
Извините, но вы правы, что начало заявлено не в том месте;) - person MadProgrammer; 05.12.2012
comment
JComponent абсолютно имеет метод paintComponent docs.oracle.com/javase/6/docs/api/javax/swing/ - person Scuba Steve; 09.12.2012
comment
проверьте параметры, вы обнаружите, что JComponent # paintComponent принимает объект Graphics, а не объект Graphics2D. Предоставленная подпись метода никогда не будет вызываться подсистемой рисования. - person MadProgrammer; 09.12.2012
comment
Графика и Graphics2D в данном случае фактически взаимозаменяемы. Полиморфизм ftw. Система в любом случае фактически передает объект Graphics2D. - person Scuba Steve; 10.12.2012
comment
Нет, согласно моим тестам. Да, Swing использует Graphics2D с тех пор (я думаю, 1.4, может быть, 1.3), но для сигнатуры метода требуется объект Graphics, иначе вы не переопределите правильный метод, что означает, что подсистема рисования Swing не может его вызвать. - person MadProgrammer; 10.12.2012
comment
Graphics и Graphics2D не взаимозаменяемы. Graphics2D расширяется от Graphics, что означает, что Graphics2D можно передать методам, требующим параметра Graphics, но не наоборот. - person MadProgrammer; 10.12.2012