E' un componente piuttosto specifico, devi crealo da solo. E' un questione elementare (nel senso che è fatta di tante piccole parti relativamente facili). Ad esempio questo:
http://www.tukano.it/ssd.png
è generato dalla combinazione di questi tre tipi in un Main:
SSDModelListener.java
package sevensegmentdisplay;
/**
* Ascoltatore di eventi generati dal modello di un display a sette segmenti.
*/
public interface SSDModelListener {
/**
* Gestisce una notifica di aggiornamento inviato da un modello
* @param model il modello che è stato aggiornato
*/
public void update(SSDModel model);
}
SSDModel.java
package sevensegmentdisplay;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import static sevensegmentdisplay.SSDModel.State.ON;
import static sevensegmentdisplay.SSDModel.State.OFF;
/**
* Modello di un component SevenSegmentDisplay.
*/
public class SSDModel {
/**
* Identificatori dei segmenti di un display a sette segmenti. Vedi
* http://en.wikipedia.org/wiki/File:7_segment_display_labeled.svg
*/
public static enum SSDSegment {
A, B, C, D, E, F, G, DP
}
/**
* Lo stato attivo-inattivo di un segmento.
*/
public static enum State {
ON, OFF
}
/**
* Utilità per la definizione dell'insieme di stati che creano una lettera o una
* cifra.
*/
private static class StatePack {
private State[] states;
StatePack(State...states) {
this.states = states;
}
void apply(Map<SSDSegment, State> map) {
for (int i = 0; i < SSDSegment.values().length; i++) {
SSDSegment seg = SSDSegment.values()[i];
map.put(seg, states[i]);
}
}
}
private Map<SSDSegment, State> states = new HashMap<SSDSegment, State>();
private List<SSDModelListener> listeners = new CopyOnWriteArrayList<SSDModelListener>();
private Map<String, StatePack> packs = new HashMap<String, StatePack>();
/**
* inizializza questo modello per display a sette segmenti.
*/
public SSDModel() {
for (SSDSegment s : SSDSegment.values()) {
states.put(s, State.OFF);
}
packs.put("a", new StatePack(ON, ON, ON, ON, ON, OFF, ON, OFF));
packs.put("b", new StatePack(ON, ON, ON, ON, ON, ON, OFF, OFF));
packs.put("c", new StatePack(ON, OFF, OFF, ON, ON, ON, OFF, OFF));
packs.put("d", new StatePack(OFF, ON, ON, ON, ON, OFF, ON, OFF));
packs.put("e", new StatePack(ON, OFF, OFF, ON, ON, ON, ON, OFF));
packs.put("1", new StatePack(OFF, ON, ON, OFF, OFF, OFF, OFF, OFF));
packs.put("2", new StatePack(ON, ON, OFF, ON, ON, OFF, ON, OFF));
packs.put("3", new StatePack(ON, ON, ON, ON, OFF, OFF, ON, OFF));
packs.put("4", new StatePack(OFF, ON, ON, OFF, OFF, ON, ON, OFF));
packs.put("5", new StatePack(ON, OFF, ON, ON, OFF, ON, ON, OFF));
packs.put("6", new StatePack(ON, OFF, ON, ON, ON, ON, ON, OFF));
packs.put("7", new StatePack(ON, ON, ON, OFF, OFF, OFF, OFF, OFF));
packs.put("8", new StatePack(ON, ON, ON, ON, ON, ON, ON, OFF));
packs.put("9", new StatePack(ON, ON, ON, ON, OFF, ON, ON, OFF));
packs.put("0", new StatePack(ON, ON, ON, ON, ON, ON, OFF, OFF));
packs.put(".", new StatePack(OFF, OFF, OFF, OFF, OFF, OFF, OFF, ON));
packs.put("err", new StatePack(ON, ON, ON, ON, ON, ON, ON, ON));
packs.put("off", new StatePack(OFF, OFF, OFF, OFF, OFF, OFF, OFF, OFF));
}
/**
* Imposta lo stato corrente del modello.
* @param c un carattere o una combinazione di caratteri. Se il carattere
* non è riconosciuto il modello mostra un errore (tutti i segmenti saranno
* attivati). La stringa "err" imposta il modello su errore, la stringa "off"
* imposta il modello su off.
*/
public void setState(String c) {
StatePack pack = packs.get(c);
if(pack != null) {
pack.apply(states);
} else {
packs.get("err").apply(states);
}
fireEvent();
}
/**
* Imposta lo stato di un singolo segmento
* @param s il segmento da impostare
* @param state lo stato di quel segmento
*/
public void setState(SSDSegment s, State state) {
states.put(s, state);
}
/**
* Restituisce lo stato di un segmento
* @param s il segmento richiesto
* @return lo stato del segmento richiesto
*/
public State getState(SSDSegment s) {
return states.get(s);
}
/**
* Notifica un evento update a tutti gli ascoltatori
*/
protected void fireEvent() {
for (SSDModelListener listener : listeners) {
listener.update(this);
}
}
/**
* Aggiunge un ascoltatore di eventi a questo modello
* @param listener l'ascoltatore di eventi da aggiungere
*/
public void addListener(SSDModelListener listener) {
listeners.add(listener);
}
/**
* Rimuove un ascoltatore di eventi da questo modello
* @param listener l'ascoltatore di eventi da rimuovere
*/
public void removeListener(SSDModelListener listener) {
listeners.remove(listener);
}
}
SevenSegmentDisplay.java
package sevensegmentdisplay;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Paint;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
/**
* Display a sette segmenti.
*/
public class SevenSegmentDisplay extends JComponent {
/**
* Creatore di istanze. Crea e restituisce un nuovo SevenSegmentDisplay
* @return un nuovo display a sette segmenti.
*/
public static SevenSegmentDisplay newInstance() {
final SevenSegmentDisplay d = new SevenSegmentDisplay();
d.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
d.model.addListener(new SSDModelListener() {
public void update(SSDModel model) {
d.repaint();
}
});
return d;
}
private Paint displayBackground = Color.BLACK;
private Paint off = Color.DARK_GRAY;
private Paint on = Color.RED;
private SSDModel model = new SSDModel();
/**
* Inizializzazione protetta: per creare un SevenSegmentDisplay usare il metodo
* SevenSegmentDisplay.newInstance
*/
protected SevenSegmentDisplay() {}
/**
* Imposta il colore di sfondo del display
* @param p il colore di sfondo del display
*/
public void setDisplayBackgroundPaint(Paint p) {
if(p != null) {
displayBackground = p;
} else {
Logger.getLogger(getClass().getName()).log(Level.INFO, "Display Background cannot be null.");
}
}
/**
* Imposta il colore usato per i segmenti attivi
* @param p il colore per i segmenti attivi
*/
public void setSegmentOnPaint(Paint p) {
if(p != null) {
on = p;
} else {
Logger.getLogger(getClass().getName()).log(Level.INFO, "Segment on paint cannot be null.");
}
}
/**
* Imposta il colore usato per i segmenti non attivi
* @param p il colore per i segmenti non attivi.
*/
public void setSegmentOffPaint(Paint p) {
if(p != null) {
off = p;
} else {
Logger.getLogger(getClass().getName()).log(Level.INFO, "Segment off paint cannot be null");
}
}
/**
* Restituisce la dimensione preferita di questo display. Se il display non
* ha una dimensione preferita impostata, restituisce una dimension predefinita.
* @return la dimensione preferita di questo display.
*/
@Override
public Dimension getPreferredSize() {
Insets ins = getInsets();
Dimension pref = super.getPreferredSize();
if(pref == null || pref.getWidth() <= 1 || pref.getHeight() <= 1) {
return new Dimension(100 + ins.left + ins.right, 84 + ins.top + ins.bottom);
} else {
System.out.println("PD: " + pref);
return pref;
}
}
/**
* Disegna il contenuto di questo componente
* @param graphics il contesto grafico da usare per il disegno
*/
@Override
protected void paintComponent(Graphics graphics) {
JComponent comp = this;
Insets ins = comp.getInsets();
double ch = comp.getHeight();
double cw = comp.getWidth();
double x0 = ins.left;
double y0 = ins.top;
double x1 = cw - ins.right;
double y1 = ch - ins.bottom;
double w = x1 - x0;
double h = y1 - y0;
double qw = w / 6;
double qh = h / 5;
double hqw = qw / 2;
double hqh = qh / 2;
double qw4 = 4 * qw;
Point2D a = pt(hqw + x0, hqh + y0);
Point2D b = pt(qw4 + x0, hqh + y0);
Point2D c = pt(hqw + x0, ch / 2);
Point2D d = pt(qw4 + x0, ch / 2);
Point2D e = pt(hqw + x0, y1 - hqh);
Point2D f = pt(qw4 + x0, y1 - hqh);
Point2D g = pt(w - hqw, y1 - hqh);
double segWidth = 8;
double segHeight = 8;
Shape dp = new Ellipse2D.Double(g.getX() - hqw, f.getY() - segHeight, 2 * segWidth, 2 * segHeight);
Shape segA = new SegmentShapeBuilder(a, b, segWidth, segHeight).getShape();
Shape segB = new SegmentShapeBuilder(b, d, segWidth, segHeight).getShape();
Shape segC = new SegmentShapeBuilder(d, f, segWidth, segHeight).getShape();
Shape segD = new SegmentShapeBuilder(f, e, segWidth, segHeight).getShape();
Shape segE = new SegmentShapeBuilder(e, c, segWidth, segHeight).getShape();
Shape segF = new SegmentShapeBuilder(c, a, segWidth, segHeight).getShape();
Shape segG = new SegmentShapeBuilder(c, d, segWidth, segHeight).getShape();
Graphics2D graphics2D = (Graphics2D) graphics;
graphics2D.setPaint(displayBackground);
graphics2D.fillRect(0, 0, getWidth(), getHeight());
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
setPaint(SSDModel.SSDSegment.A, graphics2D);
graphics2D.fill(segA);
setPaint(SSDModel.SSDSegment.B, graphics2D);
graphics2D.fill(segB);
setPaint(SSDModel.SSDSegment.C, graphics2D);
graphics2D.fill(segC);
setPaint(SSDModel.SSDSegment.D, graphics2D);
graphics2D.fill(segD);
setPaint(SSDModel.SSDSegment.E, graphics2D);
graphics2D.fill(segE);
setPaint(SSDModel.SSDSegment.F, graphics2D);
graphics2D.fill(segF);
setPaint(SSDModel.SSDSegment.G, graphics2D);
graphics2D.fill(segG);
setPaint(SSDModel.SSDSegment.DP, graphics2D);
graphics2D.fill(dp);
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_DEFAULT);
}
/**
* Restituisce il modello di questo display a sette segmenti
* @return il modello di questo display a sette segmenti
*/
public SSDModel getModel() {
return model;
}
/* metodo di appoggio, imposta un colore in base allo stato di un segmento */
private void setPaint(SSDModel.SSDSegment s, Graphics2D g) {
g.setPaint(paintForSegment(s));
}
/* metodo di appoggio, restituisce un colore in base allo stato di un segmento */
private Paint paintForSegment(SSDModel.SSDSegment s) {
return model.getState(s) == SSDModel.State.ON ? on : off;
}
/* metodo di appoggio, istanzia un Point2D.Double */
private static Point2D pt(double x, double y) {
return new Point2D.Double(x, y);
}
}
Main.java
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package sevensegmentdisplay;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
/**
*
* @author pgi
*/
public class Main {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
JFrame win = new JFrame("test");
win.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
final SevenSegmentDisplay display = SevenSegmentDisplay.newInstance();
display.addMouseListener(new MouseAdapter() {
int number = 0;
String loop = "0123456789.";
public void mousePressed(MouseEvent e) {
number++;
if(number == loop.length()) number = 0;
display.getModel().setState(loop.substring(number, number + 1));
}
});
win.add(display);
win.pack();
win.setVisible(true);
display.getModel().setState("0");
}
});
}
}
Pardon, 4 tipi più un main (ne avevo dimenticato uno):
SegmentShapeBuilder.java
package sevensegmentdisplay;
import java.awt.Shape;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
/**
* Crea una figura corrispondente ad un segmento di un display a sette segmenti.
*/
public class SegmentShapeBuilder {
/**
* Utilita per il calcolo di direzioni e spostamenti
*/
private static class Vector2D extends Point2D {
private double x, y;
private double norm;
Vector2D(double x, double y) {
norm = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
this.x = x / norm;
this.y = y / norm;
}
Vector2D(Point2D a, Point2D b) {
this(b.getX() - a.getX(), b.getY() - a.getY());
}
/**
* Restituisce una nuova direzione ortogonale a quella espressa da questo vettore
* @return un vettore ortogonale a questo
*/
Vector2D ortho() {
return new Vector2D(-y, x);
}
@Override
public double getX() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public double getY() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void setLocation(double x, double y) {
throw new UnsupportedOperationException("Not supported yet.");
}
/**
* Genera la traslazione di un punto lungo la direttrice espressa da questa
* direzione
* @param p il punto da traslare
* @param len la quantità di spostamento
* @return un punto p pari a p traslato di len nella direzione espressa da questo vettore
*/
public Point2D translate(Point2D p, double len) {
return new Point2D.Double(p.getX() + x * len, p.getY() + y * len);
}
}
/* figura geometrica generata da questo creatore di segmenti */
private final Path2D SHAPE;
/**
* Initializza questo generatore di segmenti
* @param a il punto da cui parte il segmento
* @param b il punto in cui termina il segmento
* @param sizeX l'ampiezza assiale della punta del segmento
* @param sizeY l'ampiezza ortogonale dell'estremita del segmento
*/
public SegmentShapeBuilder(Point2D a, Point2D b, double sizeX, double sizeY) {
Vector2D dir = new Vector2D(a, b);
Vector2D ortho = dir.ortho();
a = dir.translate(a, 2);
b = dir.translate(b, -2);
Point2D f0 = dir.translate(a, sizeX);
Point2D f1 = dir.translate(b, -sizeX);
Point2D p0 = a;
Point2D p1 = ortho.translate(f0, -sizeY);
Point2D p2 = ortho.translate(f1, -sizeY);
Point2D p3 = b;
Point2D p4 = ortho.translate(f1, sizeY);
Point2D p5 = ortho.translate(f0, sizeY);
Path2D.Double shape = new Path2D.Double();
shape.moveTo(p0.getX(), p0.getY());
shape.lineTo(p1.getX(), p1.getY());
shape.lineTo(p2.getX(), p2.getY());
shape.lineTo(p3.getX(), p3.getY());
shape.lineTo(p4.getX(), p4.getY());
shape.lineTo(p5.getX(), p5.getY());
shape.closePath();
SHAPE = shape;
}
/**
* Restituisce la figura geometrica generata da questo creatore di segmenti
* sulla base dei dati forniti in costruzione
* @return la figura di un segmento
*/
public Shape getShape() {
return SHAPE;
}
}
Alla fine sì. Praticamente in SSDPanel ogni due SevenSegmentDisplay metti un ColonDisplay (per dire un nome) dove ColonDisplay è una classe che estende JComponent e nel suo metodo "paintComponent" disegna due cerchi. In pseudocodice:
class ColonDisplay extends JComponent {
@Override
protected void paintComponent(Graphics graphics) {
Graphics2D g = (Graphics2D) graphics;
g.setPaint(Color.BLACK);
g.fillRect(0, 0, getWidth(), getHeight());//sfondo nero
Shape dot01 = new Ellipse2D.Double(x0, y0, w, h);
Shape dot02 = new Ellipse2D.Double(x1, y1, w, h);
g.setPaint(Color.GREEN);
g.fill(dot01);
g.fill(dot02);
}
}
In SSDPanel avrai una cosa tipo:
//costruttore, pseudo codice
public SSDPanel(int displayCount) {
super(new GridLayout(1, displayCount + (1 colonPanel ogni 2 displayCount)));
for(...il numero di display count) {
ogni due display aggiungi un nuovo ColonPanel
}
}
Per calcolare la posizione dei due punti in ColonDisplay devi fare due conti. Nel metodo paintComponent sai che getWidth() ti dice quanto è largo il componente in cui stai disegnando e getHeight() ti dice quanto è alto. Sai che il sistema di coordinate Java2D stabilisce che il punto (x = 0, y = 0) è in alto a sinistra. Il costruttore di un ellisse (Ellipse2D.Double(x, y, w, h)) vuole come argomento un rettangolo in cui sarà iscritta l'ellisse: x è l'ascissa del punto di partenza del rettangolo, y è l'ordinata, w indica quanto è lungo e h quanto è alto quel rettangolo. Il punto di partenza è il vertice in alto a sinistra.
Così se vuoi centrare i pallini sulle ascisse parti dicendo che:
double xm = getWidth() / 2;
è l'asse verticale che divide in due il componente in lunghezza. Se i pallini devono avere un diametro di, poniamo, 20 pixel, allora l'ascissa del quadrato in cui è iscritta l'ellisse di entrambi i pallini è:
double x0 = xm - (20 / 2);
double x1 = xm - (20 / 2);
per l'ordinata devi vedere dove vuoi metterli, sempre tenendo come riferimento le dimensioni del componente su cui stai disegnando. Ad esempio se vuoi metterli ad un terzo e due terzi dell'altezza:
double h = getHeight();
double y0 = h / 3.0 - (20 / 2);//sempre per via dell'iscrizione nel rettangolo
double y1 = 2.0 * h / 3.0 - (20 / 2);
Quindi avrai:
Shape dp0 = new Ellipse2D.Double(x0, y0, 20, 20);
Shape dp1 = new Ellipse2D.Double(x1, y1, 20, 20);
Puoi fare delle considerazioni di proporzionalità anche sulla largezza dei pallini. Diciamo che vuoi farli grandi un decimo delle dimensioni del componente. Dirai (sempre conti fatti nel paintComponent):
double w = getWidth() / 10.0;
double h = getHeight() ( 10.0;
double x0 = xm - (w/ 2);
double x1 = xm - (w/ 2);
double y0 = getWidth() / 3.0 - (w/ 2);
double y1 = 2.0 * getHeight() / 3.0 - (h/ 2);
Shape dp0 = new Ellipse2D.Double(x0, y0, w, h);
Shape dp 1 = new Ellipse2D.Double(x1, y1, w, h);
In definitiva devi fare un paio di conti e qualche prova.
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.