Рисовать с помощью Swing Java

1

в первую очередь привет всем!

У меня возникла большая проблема: мне нужно создать программу, состоящую в создании интерфейса java swing, который содержит 5 квадратов и одну кнопку. Функция кнопки состоит в том, чтобы нарисовать круг внутри квадратов. У меня есть этот код, но я не знаю, как продолжить.

Класс Frame:

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.io.*;
public class Window extends JFrame{

    private static Pane pane;

    private Window(){
        setResizable(false);
        setVisible(true);
        setBounds(0,0,350,200);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    public static void main(String[] args){
        Window window = new Window();
        window.setLocationRelativeTo(null);

        pane = new Pane();
        window.add(pane);       
    }

}

Класс панели:

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JLayeredPane;

public class Pane extends JPanel implements ActionListener{

    private JButton next;

    public Pane(){
        setBounds(0,0,350,200);
        setVisible(true);
        setLayout(null);
        repaint();

        next = new JButton("Next");
        next.setBounds(125,125,100,30);
        next.addActionListener(this);
        add(next);

    }

    public void actionPerformed (ActionEvent e){
        Object source = e.getSource();
        if (source == next){
            Graphics g = this.getGraphics();
            drawing(g);
        }
    }

    public void paintComponent(Graphics g){
        super.paintComponent(g);
        g.drawRect(50,50,50,50);
        g.drawRect(100,50,50,50);
        g.drawRect(150,50,50,50);
        g.drawRect(200,50,50,50);
        g.drawRect(250,50,50,50);
    }

    private int times = 0;
    public void drawing(Graphics g){
        if(times<5){
            g.setColor(Color.RED);
            g.fillOval(50+times*50, 50, 50, 50);
            times++;
        }
    }

}

У меня есть эти проблемы и вопросы:

  • Когда я впервые нажал кнопку "Далее", кружок появляется и мгновенно исчезает на первом квадрате. Как я могу сделать, чтобы круг был виден в первый раз?
  • Когда я во второй раз нажимаю кнопку, она появляется на втором круге. То, что я не знаю, и я хотел спросить это: как я могу сделать, чтобы исчезнуть круг в первом квадрате и только позволить видимый круг во втором квадрате? То, что я хочу сделать, одинаково для случая, когда круг находится на третьем квадрате, я хочу, чтобы исчезнуть круг во втором квадрате.
  • Если я хочу, чтобы круг появился в начале программы, но мне нужен синий круг, а затем позиция 2 °, 3 °, 4 ° и 5 °, я хочу, чтобы внутри них был красный круг, как я могу это сделать? (Помните, что круги появятся, когда я кликнул кнопку "Далее".

Большое вам спасибо!

Теги:
paintcomponent
repaint
jlayeredpane
paint

2 ответа

1
Лучший ответ

Вот некоторые вещи, которые вы не делаете в правильном смысле.

  1. Во-первых, вы устанавливаете видимое свойство JFrame на видимость намного раньше, чем фактически добавили к нему все компоненты, и заставьте его реализовать свой размер.
  2. Во-вторых, вы используете Absolute Layout, которого следует избегать в большинстве ситуаций.
  3. В-третьих, вы явно создаете объект Graphics, который следует избегать, и вместо этого используйте тот, который предоставляется методом paintComponent (... ) по умолчанию

Взгляните на этот пример:

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

public class DrawingCircleExample {

    private JPanel drawingBoard;
    private JButton button;

    private static final int GAP = 5;

    private void displayGUI () {
        JFrame frame = new JFrame ( "" );
        frame.setDefaultCloseOperation ( JFrame.DISPOSE_ON_CLOSE );

        JPanel contentPane = new JPanel ();
        contentPane.setLayout ( new BorderLayout ( GAP, GAP ) );
        drawingBoard = new DrawingBoard ();
        contentPane.add ( drawingBoard, BorderLayout.CENTER );

        button = new JButton ( "Draw" );
        button.addActionListener ( new ActionListener () {
            @Override
            public void actionPerformed ( ActionEvent ae ) {
                 DrawingBoard board = ( DrawingBoard ) drawingBoard;
                 board.setState ();
            }
        } );
        contentPane.add ( button, BorderLayout.PAGE_END );

        frame.setContentPane ( contentPane );
        frame.pack ();
        frame.setLocationByPlatform ( true );
        frame.setVisible ( true );
    }

    public static void main ( String [] args ) {
        Runnable runnable = new Runnable () {
            @Override
            public void run () {
                new DrawingCircleExample ().displayGUI ();
            }
        };
        EventQueue.invokeLater ( runnable );
    }
}

class DrawingBoard extends JPanel {

    private static final int TOTAL_RECTANGLES = 5;
    private static final int WIDTH = 400;
    private static final int HEIGHT = 300;
    private static final int RADIUS = 50;
    private static final int X = 50;
    private static final int Y = 50;
    private int counter;
    private int moveXBy;
    private boolean isActive;
    private int count;

    public DrawingBoard () {
        setOpaque ( true );
        counter = 0;
        count = 0;
        isActive = false;
        moveXBy = ( RADIUS + ( counter ) * RADIUS );
    }

    public boolean setState () {        
        isActive = true;
        System.out.println ( "Outside MoveXBy: " + moveXBy );
        ++counter;
        counter %= TOTAL_RECTANGLES;
        int x = ( RADIUS + ( counter ) * RADIUS );
        if ( moveXBy != x ) {
            System.out.println ( "Inside First MoveXBy: " + moveXBy );
            repaint ( moveXBy, RADIUS, X, Y );
            moveXBy = x;
            System.out.println ( "Inside Second MoveXBy: " + moveXBy );
            repaint ( moveXBy, RADIUS, X, Y );          
        }       

        return isActive;
    }

    @Override
    public Dimension getPreferredSize () {
        return new Dimension ( WIDTH, HEIGHT );
    }

    @Override
    protected void paintComponent ( Graphics g ) {
        super.paintComponent ( g );
        g.drawRect ( 50, RADIUS, X, Y );
        g.drawRect ( 100, RADIUS, X, Y );
        g.drawRect ( 150, RADIUS, X, Y );
        g.drawRect ( 200, RADIUS, X, Y );
        g.drawRect ( 250, RADIUS, X, Y );

        g.setColor ( Color.RED );
        g.fillOval ( moveXBy, RADIUS, X, Y ) ;
    }
}

EDIT относительно комментария:

Для всех графических пользовательских интерфейсов требуется какой-то основной фрейм приложения для отображения. В Swing это пример javax.swing.JFrame. Поэтому наш первый шаг - создать экземпляр этого класса и убедиться, что все работает так, как ожидалось. Обратите внимание, что при программировании в Swing ваш код создания GUI должен быть помещен в Thread Dispatch Thread (EDT), больше информации о Concurrency в Swing. Это предотвратит потенциальные условия гонки, которые могут привести к тупиковой ситуации.

DrawingBoard также переопределяет getPreferredSize, который возвращает желаемую ширину и высоту панели (в этом случае 400 - это width, 300 - высота). Из-за этого классу DrawingCircleExample больше не нужно указывать размер кадра в пикселях. Он просто добавляет панель в фрейм, а затем вызывает пакет.

Метод paintComponent - это место, где выполняется ваша обычная картина. Этот метод определяется javax.swing.JComponent и затем переопределяется вашими подклассами для обеспечения их пользовательского поведения. Его единственный параметр, объект java.awt.Graphics, предоставляет ряд методов для рисования 2D-фигур и получения информации о среде графических приложений. В большинстве случаев объект, который фактически получен этим методом, будет экземпляром java.awt.Graphics2D (подкласс Graphics), который обеспечивает поддержку сложного 2D-рендеринга.

Большинство стандартных компонентов Swing имеют внешний вид, реализованный отдельными объектами "UI Delegate". Вызов super.paintComponent(g) передает графический контекст делегату компонента компонента, который рисует фон панели.

Чтобы наша пользовательская картина была максимально эффективной, мы будем отслеживать координаты X (переменная moveXBy в нашем случае) и перерисовывать только те области экрана, которые изменились. Это рекомендуемая передовая практика, которая будет поддерживать ваше приложение как можно эффективнее.

Вызов метода repaint. Этот метод определяется java.awt.Component и является механизмом, который позволяет вам программно перерисовывать поверхность любого данного компонента. Он имеет версию no-arg (которая реплицирует весь компонент) и версию multi-arg (которая реплицирует только указанную область.) Эта область также известна как клип. Вызов многопользовательской версии repaint требует немного дополнительных усилий, но гарантирует, что ваш код рисования не будет тратить циклы, перерисовывая области экрана, которые не изменились.

Поскольку мы ручная настройка клипа, наш setState метод вызывает repaint метод не один раз, а дважды. Первое обращение указывает Swing на перерисовку области компонента, где ранее был овал (унаследованное поведение использует делегат интерфейса пользователя, чтобы заполнить эту область текущим цветом фона.) Второй вызов создает область компонента, где в настоящее время овал, Важно отметить, что хотя мы дважды вызывали repaint в одном и том же обработчике событий, Swing достаточно умен, чтобы воспринимать эту информацию и перерисовывать все разделы экрана в одной операции с краской. Другими словами, Swing не будет перекрашивать компонент дважды подряд, даже если это то, что делает код.

Дополнительную информацию см. В разделе " Выполнение пользовательской живописи"

  • 1
    Привет Ницца COW, спасибо за ваш ответ. Я новичок в Swing, и я много чего не понимаю в этом коде. Это работает, но я действительно не могу понять код. Я буду очень признателен, если вы объясните мне лучше. Я знаю только основы Swing, поэтому мой код не очень хороший, и поэтому я не понимаю ваш.
  • 0
    Свойство класса (т. Е. Counter) НЕ должно изменяться в методе рисования. Вы не можете контролировать, когда Swing вызывает метод paintComponent () и счетчик может быть ложно увеличен.
Показать ещё 2 комментария
3
//Graphics g = this.getGraphics();

Не используйте getGraphics() для рисования. Эта картина носит временный характер и будет потеряна, когда компоненты будут перекрашиваться.

Все рисунки ДОЛЖНЫ выполняться в методе paintComponent(). Это означает, что вам нужно установить свойство в своем классе, которое сообщит paintComponent() что рисовать.

Один из способов сделать это - сохранить List объектов для рисования. Затем в методе paintComponent() вы перебираете List и нарисовываете объекты.

Таким образом, вы можете создать список с кодом типа:

List<Shape> shapes = new ArrayList<Shape>();

Интерфейс Shape позволяет вам представлять геометрические фигуры, такие как круги, прямоугольники, многоугольники и т.д. Затем, когда вы хотите нарисовать первый круг, вы добавляете круг Shape в список с кодом типа:

shapes.add( new Ellipse2D.Double(50, 50, 50, 50) );

Наконец, в методе paintComponent(), после рисования ваших прямоугольников, вы добавляете код для рисования фигур в списке.

Graphics2D g2d = (Graphics2D)g.create();

for (Shape shape: shapes)
{
    g2d.setColor( Color.RED );
    g2d.fill( shape );
}

g2d.dispose()

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

  • 0
    Привет, camickr, большое спасибо за ответ. Я новичок в использовании Java Swing, и я знаю только основы. Эти части кода я понимаю, но когда я пытаюсь изменить свой код, это не работает. Я буду очень признателен, если вы приложите к ответу, каким должен быть код, изменив все, что вы считаете необходимым, чтобы он работал.
  • 1
    @JoacoTerniro, обновите ваш вопрос кодом, который вы пытались использовать, и я мог бы дать дополнительные указания, но я не собираюсь писать код. Вы ничему не научитесь таким образом.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню