Прозрачные JPanels
Я пишу графический интерфейс, который позволяет пользователю нарисовать график, где каждый узел представлен расширенной jlabel, и каждая стрелка должна быть представлена расширенной Jpanel с прозрачным фоном (setOpaque(false)), но я заметил, что только первая "панель стрелок" нарисована (или, по крайней мере, видна), а остальные не показаны. более того, узлы, добавленные после этой первой стрелки, не отображаются правильно: они окрашиваются только тогда, когда я нахожу на них мышь. все элементы добавляются в JPanel с менеджером макета null. Я знаю, что, вероятно, было бы лучше, если бы я использовал JLayeredPane, но мне было интересно, есть ли другие решения. РЕДАКТИРОВАТЬ: вот классы, которые я использую: это класс, который представляет узел
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.Iterator;
import java.util.LinkedList;
import javax.swing.JLabel;
import se.diag.exc.EccezioneDaMostrare;
public class AreaNodo extends JLabel implements MouseListener,
MouseMotionListener, Cloneable {
/**
*
*/
private static final long serialVersionUID = 1L;
protected boolean inCreazione;
protected Dimension size=new Dimension(100,40);
protected ObservableArea oss;
protected LinkedList<PannelloFreccia> collegamenti=new LinkedList<PannelloFreccia>();
protected LinkedList<EventoAreaListener> listeners=new LinkedList<EventoAreaListener>();
public AreaNodo(){
super();
setOpaque(true);
addMouseListener(this);
addMouseMotionListener(this);
oss=new ObservableArea(this);
inCreazione=true;
}
public AreaNodo clone(){
AreaNodo areaClonata=new AreaNodo();
areaClonata.setSize(this.size);
Iterator<PannelloFreccia> i=collegamenti.iterator();
while(i.hasNext()){
areaClonata.aggiungiColl(i.next().clone());
}
Iterator<EventoAreaListener> i2=listeners.iterator();
while(i2.hasNext()){
areaClonata.addEventoAreaListener(i2.next());
}
return areaClonata;
}
public void setSize(Dimension d){
size=new Dimension(d.width, d.height);
}
public void setInCreazione(boolean value){
inCreazione=value;
}
public void addEventoAreaListener(EventoAreaListener l){
if (!listeners.contains(l))
listeners.add(l);
}
public void removeEventoAreaListener(EventoAreaListener l){
listeners.remove(l);
}
public void lanciaEventoAreaFineCreazione(){
EventoArea e=new EventoArea(this, MotivazioneEvento.FINE_CREAZIONE);
Iterator<EventoAreaListener> i=listeners.iterator();
while(i.hasNext())
i.next().EventoAreaOccurred(e);
}
public void lanciaEventoAreaSelezionata(){
EventoArea e=new EventoArea(this, MotivazioneEvento.SELEZIONE);
System.out.println("lanciato evento area sel "+this.getText()+" "+this.getToolTipText());
Iterator<EventoAreaListener> i=listeners.iterator();
System.out.println(listeners.size());
while(i.hasNext()){
EventoAreaListener l=i.next();
l.EventoAreaOccurred(e);
System.out.println(l.toString());
}
}
public void aggiungiColl(PannelloFreccia pf){
collegamenti.add(pf);
}
public void removeSubscriber(AreaSubscriber a){
oss.removeSubscriber(a);
}
public void addSubscriber(AreaSubscriber a){
oss.addSubscriber(a);
}
public void aggiungiCollegamento(AreaNodo a) throws EccezioneDaMostrare{
PannelloFreccia p=new PannelloFreccia(getParent().getSize(), this, a);
System.out.println("chiamato aggiungiColl area");
ControllerGUI.aggiungiCollegamento(this, a);
getParent().add(p);
p.setBounds(0,0,getParent().getWidth(), getParent().getHeight());
p.paintImmediately(0,0,p.getWidth(), p.getHeight());
aggiungiColl(p);
a.aggiungiColl(p);
}
public Dimension getMinimumSize(){
return size;
}
public Dimension getPreferredSize(){
return size;
}
public Dimension getSize(){
return size;
}
private void sposta(Point p){
Point pNuovo=new Point(p.x+getLocation().x, p.y+getLocation().y);
setLocation(pNuovo);
}
public void spostaAssoluto(Point p){
setLocation(p);
}
@Override
public void mouseDragged(MouseEvent arg0) {
Point p=arg0.getPoint();
sposta(p);
oss.notifica();
}
@Override
public void mouseMoved(MouseEvent arg0) {
/*if(inCreazione){
Point p=arg0.getPoint();
sposta(p);
oss.notifica();
repaint();
}
*/
}
@Override
public void mouseClicked(MouseEvent arg0) {
if(inCreazione){
inCreazione=false;
lanciaEventoAreaFineCreazione();
}
else
lanciaEventoAreaSelezionata();
}
@Override
public void mouseEntered(MouseEvent arg0) {
Font f=getFont();
f=f.deriveFont(1);
this.setFont(f);
}
@Override
public void mouseExited(MouseEvent arg0) {
Font f=getFont();
f=f.deriveFont(0);
this.setFont(f);
}
@Override
public void mousePressed(MouseEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void mouseReleased(MouseEvent arg0) {
// TODO Auto-generated method stub
}
public Point getPuntoCollegamento(AreaNodo a){
Point posA=a.getLocation();
if(posA.x>getLocation().x+this.getWidth()){
return(new Point(getLocation().x+getWidth(), getLocation().y+getHeight()/2));
}
else{
if(posA.x>getLocation().x){
if(posA.y<getLocation().y){
return(new Point(getLocation().x+getWidth()/2, getLocation().y));
}
else
return(new Point(getLocation().x+getWidth()/2, getLocation().y+getHeight()));
}
else{
return (new Point(getLocation().x, getLocation().y+getHeight()/2));
}
}
}
public PannelloFreccia ricercaCollegamento(AreaNodo a){
Iterator<PannelloFreccia> i=collegamenti.iterator();
while(i.hasNext()){
PannelloFreccia cur=i.next();
if(cur.getArea2()==a || cur.getArea1()==a)
return cur;
}
return null;
}
protected void rimuoviFreccia(PannelloFreccia p){
collegamenti.remove(p);
}
public void svuota(){
Iterator<PannelloFreccia> i=collegamenti.iterator();
while(i.hasNext()){
PannelloFreccia p=i.next();
p.rimuoviDaSubscriber();
if(p.getArea2()!=this){
p.getArea2().cancellaCollegamento(this);
rimuoviFreccia(p);
}
else{
p.getArea1().cancellaCollegamento(this);
rimuoviFreccia(p);
}
}
listeners=new LinkedList<EventoAreaListener>();
}
public void cancellaCollegamento(AreaNodo a){
PannelloFreccia p=ricercaCollegamento(a);
if(p!=null){
p.rimuoviDaSubscriber();
rimuoviFreccia(p);
}
}
public int hashCode(){
return getText().hashCode();
}
public boolean equals(Object o){
if(o==this) return true;
if(!(o instanceof AreaNodo)) return false;
AreaNodo a=(AreaNodo)o;
return this.getText().equals(a.getText());
}
public Color getColoreNonSel(){
return Color.WHITE;
}
}
пока это панель со стрелками
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JPanel;
public class PannelloFreccia extends JPanel implements AreaSubscriber {
/**
*
*/
private static final long serialVersionUID = 1L;
Freccia f;
AreaNodo area1;
AreaNodo area2;
public PannelloFreccia(Dimension d, AreaNodo a1, AreaNodo a2){
setPreferredSize(d);
area1=a1;
area2=a2;
aggiungiASubscriber();
f=new Freccia(area1.getPuntoCollegamento(area2), area2.getPuntoCollegamento(area1));
setOpaque(false);
}
@Override
public void update(AreaNodo a) {
if (a==area1){
f=new Freccia(area1.getPuntoCollegamento(area2), area2.getPuntoCollegamento(area1));
}
if(a==area2){
f=new Freccia(area1.getPuntoCollegamento(area2), area2.getPuntoCollegamento(area1));
}
repaint();
}
public AreaNodo getArea2(){
return area2;
}
public AreaNodo getArea1(){
return area1;
}
public void aggiungiASubscriber(){
area1.addSubscriber(this);
area2.addSubscriber(this);
}
public void rimuoviDaSubscriber(){
area1.removeSubscriber(this);
area2.removeSubscriber(this);
}
public void paintComponent(Graphics g){
g.clearRect(0, 0, getWidth(), getHeight());
f.disegna(g);
}
public PannelloFreccia clone(){
PannelloFreccia pannelloClonato=new PannelloFreccia(getPreferredSize(), area1.clone(), area2.clone());
return pannelloClonato;
}
}
и это JPanel, где я добавляю их все
import java.awt.Color;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.LinkedList;
import javax.swing.JPanel;
import se.diag.control.clientspec.grafica.AreaNodo;
import se.diag.control.clientspec.grafica.AreaNodoO;
import se.diag.control.clientspec.grafica.ControllerGUI;
import se.diag.control.clientspec.grafica.EventoArea;
import se.diag.control.clientspec.grafica.EventoAreaListener;
import se.diag.control.clientspec.grafica.MotivazioneEvento;
import se.diag.control.clientspec.grafica.ObserverStato;
import se.diag.control.clientspec.grafica.PannelloDiagnosi;
public class PannelloInserim extends JPanel implements PannelloOp, PannelloDiagnosi, MouseMotionListener {
private boolean inCreazione=false;
private AreaNodo areaDaAggiungere=null;
private Selezione sel;
private ObserverStato btnDiag;
public PannelloInserim(ObserverStato btnDiag) {
super();
setLayout(null);
setBackground(Color.WHITE);
addMouseListener(this);
addMouseMotionListener(this);
ControllerGUI.addEventoAreaListener(this);
sel=new Selezione();
this.btnDiag=btnDiag;
}
public LinkedList<AreaNodo> getSelezione(){
return sel;
}
public void setInCreazione(boolean value){
inCreazione=value;
}
@Override
public void EventoAreaOccurred(EventoArea e) {
AreaNodo a=(AreaNodo)e.getSource();
MotivazioneEvento m=e.getMotivo();
switch(m){
case CREAZIONE:{
areaDaAggiungere=a;
setInCreazione(true);
}
break;
case ELIMINAZIONE:{
a.svuota();
remove(a);
}
break;
case FINE_CREAZIONE:{
setInCreazione(false);
}
}
}
@Override
public void mouseClicked(MouseEvent arg0) {
sel.svuota();
}
@Override
public void mouseEntered(MouseEvent arg0) {
if(inCreazione){
add(areaDaAggiungere);
areaDaAggiungere.setBounds(arg0.getX(), arg0.getY(), areaDaAggiungere.getSize().width, areaDaAggiungere.getSize().height);
areaDaAggiungere.setInCreazione(true);
areaDaAggiungere.addEventoAreaListener(this);
areaDaAggiungere.addEventoAreaListener(sel);
if(areaDaAggiungere instanceof AreaNodoO){
((AreaNodoO)areaDaAggiungere).addObserverStato(btnDiag);
}
}
}
@Override
public void mouseExited(MouseEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void mousePressed(MouseEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void mouseReleased(MouseEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public PannelloMostraDiagnosi mostraDiagnosi() {
return new PannelloMostraDiagnosi(this);
}
@Override
public void mouseDragged(MouseEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void mouseMoved(MouseEvent arg0) {
if(inCreazione){
areaDaAggiungere.spostaAssoluto(arg0.getPoint());
}
}
}
это структура данных, которая представляет выбранные узлы в pannelloInserim
public class Selezione extends LinkedList<AreaNodo> implements EventoAreaListener {
private SelezionePublisher selPub;
public Selezione(){
super();
selPub=new SelezionePublisher();
}
public void aggiungiObserver(ObserverSelezione os){
selPub.addObserverSelezione(os);
}
public void rimuoviObserver(ObserverSelezione os){
selPub.removeObserverSelezione(os);
}
public boolean add(AreaNodo a){
System.out.println("chiamato add");
System.out.println(this.toString());
if (contains(a)){
remove(a);
System.out.println("rimosso");
}
else
if(size()==2){
svuota();
a.setBackground(a.getColoreNonSel());
System.out.println("svuotata");
}
else{
if(size()==1 && getFirst().ricercaCollegamento(a)==null){
System.out.println("collegamento");
try {
super.add(a);
getFirst().aggiungiCollegamento(getLast());
} catch (EccezioneDaMostrare e) {
JOptionPane.showMessageDialog(get(0).getTopLevelAncestor(), e.getMessage());
}
finally{
svuota();
}
}
else{
System.out.println("aggiunta");
super.add(a);
}
}
selPub.notifica(isVuota(), isSingola(), isDoppia());
return true;
}
private void aggiungi(AreaNodo a){
System.out.println("Aggiungi");
add(a);
}
public void svuota(){
System.out.println("chiamato svuota");
Iterator<AreaNodo> i=iterator();
while (i.hasNext()){
AreaNodo a=i.next();
a.setBackground(a.getColoreNonSel());
i.remove();
}
selPub.notifica(isVuota(), isSingola(), isDoppia());
}
public boolean isVuota(){
return size()==0;
}
public boolean isSingola(){
return size()==1;
}
public boolean isDoppia(){
return size()==2;
}
@Override
public void EventoAreaOccurred(EventoArea e) {
if(e.getMotivo()==MotivazioneEvento.SELEZIONE){
aggiungi((AreaNodo)e.getSource());
System.out.println("evento area "+e.getMotivo().toString());
}
}
public String toString(){
StringBuffer sb=new StringBuffer();
int i=1;
sb.append(this.size()+"\n");
for(AreaNodo a:this){
sb.append(i+" "+a.getText()+" "+a.getToolTipText()+"\n");
i++;
}
return sb.toString();
}
}
это событие, которое вызывается, когда узел создается, удаляется или выбирается:
package se.diag.control.clientspec.grafica;
import java.util.EventObject;
public class EventoArea extends EventObject {
private MotivazioneEvento motivo;
public EventoArea(Object arg0, MotivazioneEvento m) {
super(arg0);
motivo=m;
}
public MotivazioneEvento getMotivo(){
return motivo;
}
}
это мотивация мероприятия:
package se.diag.control.clientspec.grafica;
public enum MotivazioneEvento {
CREAZIONE{
public String toString(){
return "Area creata";
}
},
SELEZIONE{
public String toString(){
return "Area selezionata";
}
},
ELIMINAZIONE{
public String toString(){
return "Area eliminata";
}
},
FINE_CREAZIONE{
public String toString(){
return "Fine Creazione";
}
}
}
это интерфейс слушателей EventoArea:
package se.diag.control.clientspec.grafica;
import java.util.EventListener;
public interface EventoAreaListener extends EventListener {
public void EventoAreaOccurred(EventoArea e);
}
это класс, используемый в шаблоне Observer с панелями стрелок, чтобы они следовали за узлами:
package se.diag.control.clientspec.grafica;
import java.util.LinkedList;
public class ObservableArea {
private LinkedList<AreaSubscriber> sub;
private AreaNodo area;
public ObservableArea(AreaNodo a){
area=a;
sub=new LinkedList<AreaSubscriber>();
}
public void notifica(){
for(AreaSubscriber elem:sub)
elem.update(area);
}
public void addSubscriber(AreaSubscriber a){
sub.add(a);
}
public void removeSubscriber(AreaSubscriber a){
sub.remove(a);
}
}
это подписчик относительно этого класса:
package se.diag.control.clientspec.grafica;
public interface AreaSubscriber {
public void update(AreaNodo a);
}
когда выбраны два узла, у которых нет связи между ними, Selezione вызывает aggiungiCollegamento, который создает новую панель стрелок и добавляет ее в pannelloInserim.
1 ответ
Не берите в голову, я нашел то, что было неправильно: был вызов clearRect() в методе paintComponent() панели стрелок. после удаления этой строки стрелка становится видимой, и с другими компонентами проблем нет.