2010-01-04 14 views
1

J'ai besoin d'afficher un grand nombre (500+) de petits cercles sur un formulaire pour simuler des LED. Cependant, ces cercles doivent être assez petits, d'environ 8 ou 9 pixels de diamètre. Jusqu'ici, dans mes tests, j'ai assemblé du code qui crée une classe Led qui utilise une forme (Ellipse2D.Double) et l'affiche directement sur le JFrame à partir de la méthode de peinture de JFrame.Java Mise à jour de petits cercles

Cela m'a conduit à deux observations/questions:

1) Tout d'abord, à moins d'une autre méthode, Java semble avoir du mal à dessiner de petits cercles. Ils semblent «casser» dans le coin inférieur droit avec une largeur de stylo de défaut (ou 1 pixel), qui coupe cette partie en laissant un cercle déformé. Si je peux dessiner (beaucoup) de petits cercles et les faire bien paraître?

2) Mon JFrame sous-classé remplace la méthode de peinture pour dessiner ces 'leds', bien qu'il appelle aussi super.paint pour s'assurer que le JFrame est dessiné. Cependant, je vois qu'il dessine rarement la LED lors de la première apparition, ou lorsque le formulaire est déplacé hors écran ou en arrière, ou lorsqu'une application est mise en avant et déplacée de nouveau, et la seule fois où la méthode de peinture est appelé est quand je minimiser/maximiser le formulaire. Ne devrait-on pas peindre la peinture à chaque fois que la forme a besoin d'être peinte?

Répondre

3

Vous ne devez pas remplacer la peinture(). Utilisez paintComponent() à la place. De plus, les JFrames sont des choses un peu étranges, j'utiliserais JPanel comme BaseClass.

À propos de votre observation: Cela pourrait-il être causé par un antialiasing? Avez-vous essayé d'éteindre antialiasing via setRenderingHints()?

EDIT: Après le commentaire ci-dessous, j'ai écrit un petit programme de test. Les cercles sont agréables avec ceci:

import javax.swing.*; 
import java.awt.Graphics2D; 
import java.awt.Graphics; 
import java.awt.Dimension; 
import java.awt.RenderingHints; 

class Test extends JFrame { 

    public Test() { 
     setContentPane(new JPanel() { 
       public void paintComponent(Graphics g){ 
        super.paintComponent(g); 
        Graphics2D g2d = (Graphics2D) g; 
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 
        for (int i = 0; i < 500; i++){ 
         int x = (int) (Math.random() * getWidth()); 
        int y = (int) (Math.random() * getHeight()); 
        g.fillOval(x,y,8,8); 
        } 
       } 
     }); 
    } 

    public static void main(String[] args){ 
     Test t = new Test(); 
     t.setSize(new Dimension(640, 480)); 
     t.setVisible(true); 
    } 
} 
+0

Non, j'ai modifié tout ce qui a trait à l'antialiasing. Ceci est juste très basique "créer et afficher un cercle sur un JFrame" – Dave

+0

Hmm, je pense que la valeur par défaut est d'avoir antialiasing sur. Cela montre comment l'activer (pour l'éteindre, utilisez RenderingHints.VALUE_ANTIALIAS_OFF): http://www.java2s.com/Code/JavaAPI/java.awt/Graphics2DsetRenderingHintsMaphints.htm – zedoo

+0

Je pensais que la valeur par défaut était * off *. Il doit être * sur *, en particulier pour les petits cercles: 'g2d.setRenderingHint (RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)'. – trashgod

1

Ces LED devraient être des composants comme tout le reste sur le formulaire. Je pense que vous devriez utiliser des icônes, peut-être ImageIcon s, pour représenter vos LEDs. De cette façon, vous pouvez essentiellement les rendre une fois et après que la même image sera affichée chaque fois que nécessaire. Il est pratique que vous puissiez utiliser des images, car vous pouvez alors utiliser une image qui a exactement la forme que vous souhaitez.

1

En ce qui concerne la «pause», je regarderais le réglage de biseau de votre objet graphique. Mais, je recommanderais de lire un fichier .png au démarrage du programme et de l'afficher au lieu de le dessiner seul.


RE: paint() n'est pas appelé tout le temps.

Oui, c'est comme ça que ça fonctionne. Si vous avez besoin que votre composant soit redessiné à un certain moment, vous devez le forcer. Appelez repaint() pour forcer un redessin.

Si vous un va appeler repeindre() d'un autre fil, (.-À-dire un fil de minuterie), assurez-vous d'envelopper l'appel SwingUtilities.invokeLater():

SwingUtilities.invokeLater(new Runnable() 
{ 
    @Override 
    public void run() 
    { 
     myForm.repaint(); 
    } 
}); 

Mise à jour: peut-être que vous devriez poster du code ... J'ai jeté ensemble une petite application de test et je n'ai vu aucun problème avec les petits cercles.

public class MyPanel extends JPanel 
{ 
    public void paint(Graphics _g) 
    { 
     Graphics2D g = (Graphics2D) _g; 

     g.setStroke(new BasicStroke(1f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); 
     for(int x = 10, w = 1; w < 20; x += w*2, w++) 
     { 
      Ellipse2D.Double ed = new Ellipse2D.Double(x, 10, w, w); 
      g.fill(ed); 
     } 

     for(int x = 10, w = 1; w < 20; x += w*2, w++) 
     { 
      Ellipse2D.Double ed = new Ellipse2D.Double(x, 80, w, w); 
      g.draw(ed); 
     } 
    } 

    public static void main(String[] args) 
    { 
     JFrame frame = new JFrame(); 
     frame.add(new MyPanel()); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setSize(400, 400); 

     frame.setVisible(true); 
    } 
} 

J'ai essayé faire varier la course params pour voir si je pouvais faire une pause visuelle, mais sans succès. Que vois-tu?


ne pas battre un cheval mort, mais quand je Zoomez sur la sortie de ce programme, mes cercles sont à peu près symétrique, moins un étron peu de pixels sur la gauche:

circle pics http://i50.tinypic.com/14b58wk.png

Est-ce similaire à ce que vous obtenez?

+0

Je n'ai modifié aucun paramètre de biseau. Tout ce que je veux, c'est un cercle simple (contour et remplissage). Aurais-je vraiment besoin de mettre un biseau sur ça? J'ai réfléchi à l'aide d'images pour les dessiner, même si je craignais que l'utilisation d'images soit beaucoup plus lente que de se connecter directement au cadre. Ces 'leds' seraient mises à jour régulièrement en temps réel (à partir d'un cours de communication) et étant donné que j'aurais beaucoup de ces choses, toute lenteur dans la led serait exagérée un peu. – Dave

+0

J'étais un peu vague et trompeur. Regardez BasicStroke et son paramètre de jointure. (C'est où ma mémoire a obtenu le biseau de ...) Vous voulez probablement JOIN_MITER ou JOIN_ROUND. Après avoir créé l'objet BasicStroke, faites un g.setStroke (basicStroke). –

+1

En outre, en ce qui concerne vos questions de vitesse ... si quoi que ce soit, copier une image de cercle pré-rendu sur votre toile sera plus rapide que dessiner des cercles à chaque fois. –

2

Je me suis battu la tête contre ce problème pendant un certain temps, avec des résultats similaires à ceux décrits ici, quand j'ai finalement été averti que fillOval() fait un bien meilleur travail que drawOval () ou Ellipse2D. L'approche légèrement hacky suivante m'a donné ce dont j'avais besoin:

g2d.setColor(Color.black);      
g2d.fillOval((int)x, (int)(y - w/2), (int)w, (int)w); 
g2d.setColor(Color.white);   
g2d.fillOval((int)x+1, (int)(y - w/2)+1, (int)w-2, (int)w-2); 
+0

Cela semble être vrai pour les fonctions de remplissage en général (c.-à-d. Si je crée un nouveau cercle de forme = Ellipse2D (...) 'pour mon cercle, puis j'appelle' g2d.fill (cercle); En utilisant votre approche 'hacky', vous obtenez des cercles ronds avec des contours arrondis, +1 pour résoudre mon problème mieux que la réponse acceptée, mais seulement parce que StackOverflow n'a pas encore implémenté les boutons 'acheter une bière': ^) – JVMATL