Peinture avec Swing Java


Tout d'abord salut à tous!

J'ai un gros problème avec ceci: j'ai besoin de construire un programme qui consiste à construire une interface java swing qui contient 5 carrés et un bouton. La fonction de bouton est de dessiner un cercle à l'intérieur des carrés. J'ai ce code, mais je ne sais pas comment continuer.

La classe de trame:

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);       
    }

}

La classe de volet:

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++;
        }
    }

}

J'ai ces problèmes et questions:

  • Lorsque j'appuie pour la première fois sur le bouton "Suivant", le cercle apparaît et disparaît instantanément dans le premier carré. Comment puis-je faire pour que le cercle soit visible pour la première fois?
  • Lorsque j'appuie pour la deuxième fois sur le bouton, il apparaît le cercle dans le deuxième carré. Ce que je ne sais pas et que je voulais demander, c'est ceci: comment puis-je faire disparaître le cercle dans le premier carré et ne laisser visible que le cercle dans le deuxième carré? Ce que je veux faire, c'est la même chose pour le cas lorsque le cercle est à la troisième place, je veux faire disparaître le cercle dans le deuxième carré.
  • , Si je veux faire le cercle apparaissent au début du programme, mais je veux un cercle bleu, et puis les 2°, 3°, 4° et 5° de position je veux un cercle rouge à l'intérieur, comment puis-je le faire? (Rappelez-vous que les cercles apparaîtront lorsque je cliquerai sur le bouton "Suivant".

Merci beaucoup à tous!

Author: Joaco Terniro, 2015-04-12

2 answers

Il y a des choses que vous ne faites pas dans le bon sens.

  1. Tout d'abord, vous définissez la propriété visible du JFrame sur visible bien avant d'y ajouter tous les composants et de lui faire réaliser sa taille.
  2. Deuxièmement, vous utilisez un Absolute Layout, que l'on devrait éviter dans la plupart des situations.
  3. Troisièmement, vous créez explicitement un objet Graphics, que l'on devrait éviter et utiliser à la place celui fourni par la méthode paintComponent ( ... ) de Java par par défaut

Regardez cet exemple:

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 ) ;
    }
}

MODIFIER concernant le commentaire:

Toutes lesInterfaces utilisateur graphiques nécessitent une sorte de cadre d'application principal dans lequel s'afficher. Dans Swing, c'est une instance de javax.swing.JFrame. Par conséquent, notre première étape consiste à instancier cette classe et à nous assurer que tout fonctionne comme prévu. Notez que lors de la programmation dans Swing , votre code de création d'interface graphique doit être placé sur l'événement Dispatch Thread (EDT), plus d'informations sur Concurrence dans Swing. Cela permettra d'éviter des conditions de course potentielles qui pourraient conduire à l'impasse.

DrawingBoard remplace également les getPreferredSize, qui retourne la hauteur et la largeur du panneau (dans ce cas - 400 est l'width, 300 est à la hauteur.) Pour cette raison, la classe DrawingCircleExample n'a plus besoin de spécifier la taille du cadre en pixels. Il ajoute simplement le panneau au cadre, puis appelle pack.

Le paintComponent la méthode est l'endroit où toute votre peinture personnalisée a lieu. Cette méthode est définie par javax.swing.JComponent, puis remplacée par vos sous-classes pour fournir leur comportement personnalisé. Son seul paramètre, un java.awt.Graphics object, expose un certain nombre de méthodes pour dessiner des formes 2D et obtenir des informations sur l'environnement graphique de l'application. Dans la plupart des cas, l'objet réellement reçu par cette méthode sera une instance de java.awt.Graphics2D (une sous-classe graphique), qui prend en charge le rendu graphique 2D sophistiqué.

La plupart des composants Swing standard ont leur apparence implémentée par des objets "UI Delegate" séparés. L'invocation de super.paintComponent (g) transmet le contexte graphique au délégué de l'interface utilisateur du composant, qui peint l'arrière-plan du panneau.

Pour garder notre peinture personnalisée aussi efficace que possible, nous suivrons les coordonnées X ( moveXBy variable dans notre cas) et repeindre seulement le les zones de l'écran qui ont changé. C'est une pratique recommandée qui gardera votre application de fonctionner aussi efficacement que possible.

L'invocation de la méthode repaint. Cette méthode est définie par java.awt.Component et est le mécanisme qui vous permet de repeindre par programme la surface d'un composant donné. Il a une version no-arg (qui repeint tout le composant) et une version multi-arg (qui repeint uniquement la zone spécifiée.) Cette zone est également connue sous le nom de clip. Invoquer la version multi-arg de repaint demande un petit effort supplémentaire, mais garantit que votre code de peinture ne gaspillera pas les cycles repeindre les zones de l'écran qui n'ont pas changé.

Parce que nous définissons manuellement le clip, notre méthode setState appelle la méthode repaint pas une fois, mais deux fois. La première invocation indique à Swing de repeindre la zone du composant où se trouvait précédemment l'ovale (le comportement hérité utilise le délégué de l'interface utilisateur pour remplir cette zone avec l'arrière-plan actuel couleur.) La deuxième invocation peint la zone du composant où se trouve actuellement l'ovale. Un point important à noter est que bien que nous ayons invoqué repaintdeux fois de suite dans le même gestionnaire d'événements, Swing est assez intelligent pour prendre ces informations et repeindre ces sections de l'écran en une seule opération de peinture. En d'autres termes, Swing ne repeindra pas le composant deux fois de suite, même si c'est ce que le code semble faire.

Se référer plus loin sur le sujet à effectuer une peinture personnalisée

 1
Author: nIcE cOw, 2015-04-12 05:26:11
//Graphics g = this.getGraphics();

N'utilisez pas getGraphics() pour faire de la peinture. Cette peinture n'est que temporaire et sera perdue lorsque les composants se repeindront.

Toute la peinture DOIT être faite dans la méthode paintComponent(). Cela signifie que vous devez définir une propriété dans votre classe qui dira au paintComponent() quoi peindre.

Une façon de faire est de garder un List d'objets à peindre. Ensuite, dans la méthode paintComponent(), vous parcourez le List et peignez les objets.

Vous pouvez donc créer la liste avec code comme:

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

L'interface Shape vous permet de représenter des formes géométriques, comme des cercles, des rectangles, des polygones, etc. Ensuite, lorsque vous voulez peindre le premier cercle, vous ajoutez une forme de cercle à la liste avec du code comme:

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

Enfin dans la méthode paintComponent (), après avoir peint vos rectangles, vous ajoutez du code pour peindre les formes de la liste.

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

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

g2d.dispose()

Donc, chaque fois que vous cliquez sur le bouton suivant, vous effacez la liste et ajoutez une nouvelle forme à peindre. Ou si vous ne dégagez pas la liste alors vous pouvez ajouter plus de cercles et ils seront tous peints.

 3
Author: camickr, 2015-04-12 02:50:22