View Full Version : [Java] Problema con JScrollPane con Canvas
arthurgp
21-05-2008, 14:09
Ciao a tutti,
ho un piccolo problemino riguardante la visualizzazione delle scrollBar con Java. Vi spiego la situazione:
ho un cavas nel quale eseguo un disegno , che deve avere la possibilità di essere zoomato, questo canvas viene inserito in un JScrollPane il quale a sua volta è contenuto in un pannello. Il problema è che non vengono visualizzate la barre di scrorrimento quando il canvas è piu grande della finestra..
Ecco il codice (solo quello utile)
CLASSE FRAME:
canvas=new DBCanvas();
canvas.setBackground(Color.WHITE);
canvas.setLayout( new FlowLayout());
canvasScrollPane = new JScrollPane();
canvasScrollPane.add(canvas);
inoltre nella classe DBCanvas nel metodo paint() viene disegnato un grafico..
Qualcuno sa darmi qualche consiglio ??
Grazie giulio
Penso che nel canvas tu debba reimplementare getPreferredSize(),
altrimenti lo scrollpane non puo' conoscere la dimensione del pannello
arthurgp
22-05-2008, 10:46
Ho provato a reinplementere il metodo ma non funziona.
Ho già provato anche a inserire il classico ScrollPane della libreria AWT, ma non risulta adatto alla mia situazione perchè ho tutti componenti Swing che nonn si comportano in modo corretto durante la visualizzazione.
Qualcuno ha qualche idea, anche che non sia strettamante legata alle scrollBar per esempio nello spostare il canvas..?
Sicuro che getPreferredSize() ritorni le dim. giuste?
Prova anche con getSize() o getMinimumSize()
banryu79
22-05-2008, 11:08
Qualcuno ha qualche idea, anche che non sia strettamante legata alle scrollBar per esempio nello spostare il canvas..?
Butto lì quello che mi passa in mente:
1) invece di usare la classe Canvas potresti usare un JPanel dentro un JScrollPane: JPanel espone più metodi del Canvas e magari trovi quello che fa per te. Però se non ho capito male tu vorresti le scroll bar per navigare nell'area completa di visualizzazione del canvas/jpanel che ovviamente "virtualmente" si dovrebbe ridimensionare rispetto al valore corrente di zoom utlizzato rispetto ad un valore base di riferimento (cioè la tua vista a zoom = 100%).
Questo perchè lo JScrollPane deve poter valutare le dimensioni dell'oggetto che contiene per decidere come saranno le barre di scorrimento...
Quindi dovresti legare il valore di zoom ad un ridimensionamento dinamico del componente in cui disegni, se non ho capito male.
2) invece delle barre di scorrimento, potresti attaccare un MouseMotionListener alla tua classe che implementa/estende il Canvas/JPanel in cui disegni.
Puoi fare in modo che quando l'utente esegue un "drag" con un pulsante del mouse a tua scelta tu trasli in maniera equivalente il sistema di coordinate in cui disegni. In pratica implementi una funzione di "pan" che permette all'utente di scorrere la vista come vuole.
arthurgp
22-05-2008, 19:23
con i metodi che riguardano le dimensioni ho fatto tutte le prove possibili,
ma non ho risolto nulla...
No mi sembra male nemmeno la possibilità di ispezionare il Canvas (Che per problemi di progetto non posso sostituire con un pannello) con l'operazione di drag , ora sto facendo delle prove e sto iniziando a vedere dei miglioramenti ma non mi è molto chiaro come lavorare con questi spostamenti...
Sapete darmi qualche indicazione in modo tale da fare delle prove ?
banryu79
23-05-2008, 08:42
Sapete darmi qualche indicazione in modo tale da fare delle prove ?
Pronti:
- questa è la tua classe dove disegni:
File MyCanvas.java
public class MyCanvas extends Canvas
{
//membri della classe
//bla bla bla...
// costruttore: agganciarsi al listener desiderato
public MyCanvas()
{
....
// creo il listener per il mouse e lo registro a questo componente
CanvasMouseAdapter mouseManager = new CanvasMouseAdapter(this);
addMouseListener(mouseManager );
addMouseMotionListener(mouseManager );
}
//metodi pubblic/privati vari ed eventuali
public myUsefulMethodOne(...){...}
public myUsefulMethodTwo(...){...}
// override del metodo paint
public void paint(Graphics g)
{
super.paint(g)
// cast Graphics to Graphics2D
Graphics2D g2D = (Graphisc2D) g;
// IMPORTANTE: save the affineTransform in the Graphics object
AfineTransform originalAT = g2D.getTransform();
// Transforming...
// Rendering...
// IMPORTANT: restore the original affineTransform in the Graphics
g2D.setTransform(originalAT);
}
}
/**
* con questo MouseAdapter implementiamo solo un sistema per intercettare un "drag" del mouse.
*/
class CanvasMouseAdapter extends MouseAdapter
{
MyCanvas canvas;
boolean dragging = false;
Point draggingStart; // punto di partenza evento Dragging
public CanvasMouseAdapter(MyCanvas canvas)
{
this.canvas = canvas;
}
// override dei metodi che ti interessano, per il drag è una gestione combinata di:
// + mousePressed (un pulsante del mouse è stato premuto)
// + mouseDragged (il puntatore del mouse si sta mouvendo mentre un pulsante viene tenuto premuto)
// + mouseReleased (un pulsante del mouse è stato rilasciato)
public void mousePressed(MouseEvent e)
{
// vogliamo eseguire il drag quando l'utente trascina col tasto destro
if (e.getModifiers() == MouseEvent.BUTTON3_MASK)
{
dragging = true;
Point ptCliccato = e.getPoint();
draggingStart = ptCliccato;
}
}
public void mouseDragged(MouseEvent e)
{
// il puntatore del mouse si sta mouvendo con un pulsante premuto,
// è il pulsante destro allora stiamo intercettando l'evento che ci interessa
if (dragging )
{
Point p = e.getPoint
int deltaX = p.x - draggingStart.x;
int deltaY = p.y - draggingStart.y;
// calcolati i valori di deltaX/deltaY, vanno passati al Canvas in modo che questo li possa utilizzare
// internamente per eseguire una traslazione (vedi class AffineTransform, e sue relazioni con Graphics2D)
draggingStart = p;
}
}
public void mouseReleased(MouseEvent e)
{
dragging = false;
}
}
Si tratta quindi di:
> creare un MouseAdapter che gestisca il "drag" del mouse nel componente a cui sarà agganciato;
> durante il "drag" calcolare il valore deltaX e deltaY dello spostamento catturato;
> passare questi valori al Componente a cui si è registrato il Listener del mouse;
|
> questo Componente userà questi valori per istanziare un'AffineTransform appropriata che esprima la traslazione
> questa AffineTransform verrà utilizzata dal Graphics2D al posto di quella originale;
oppure
> questo Componente userà questi valori per eseguire l'opportuna trasformazione (.translate) dirattamente sull'oggetto Graphics2D
Spero che come spunto iniziale ti basti; ti lascio il piacere di investigare ulteriormente sulle classi Graphics-Graphics2D-AffineTransform.
Inoltre consiglio la lettura di questo: Painting in AWT and Swing (http://java.sun.com/products/jfc/tsc/articles/painting/)
P.S.: scusami eventuali errori: ho scritto il codice di getto e direttamente dell'editor del post del Forum, non in un IDE, quindi posso aver commesso errori di sintassi/vaccate varie.
P.P.S.: nota che non ho implementato tutto quello che ti servirà, ma solo il neccsario per mostrare come legare il MouseListener al Componente su cui disegni, e un abbozzo iniziale di gestione del "drag".
Manca completamente come gestirai lo Zoom. (Graphics2D.scale).
Manca anche la gestione delle coordinate, cioè Screen Space / User Space.
Nota che nei metodi del MouseAdapter le coordinate del punto restituito dal MouseEvent sono sempre in Screen Space, cioè "al netto" di eventuali trasformazioni: se e quando ti sarà neccessiario rimapparle in User Space butta un occhio alla classe AffineTransform, il suo metodo statico AffineTransform.createInverse() e il suo metodo .transform() in particolare ti potranno essere utili.
P.P.(eccheppalle :D)P.S.:
il sistema di coordinate in Screen Space che trovi nel Graphics di un Component è mappato così:
- l'origine è alto a sinistra (0,0)
- l'asse delle ascisse si estende con verso positivo verso destra, a partire da X0 fino all'infinito, visibile nel Component è fino a X = Component.getWidth()
- l'asse delle ordinate sis estende con verso positivo verso il basso, a partire da Y0 fino all'infinito, visibile nel Component è fino a Y = Component.getHeight().
Ciao :)
arthurgp
23-05-2008, 11:09
Innanzitutto grazie ... ho fatto dei tentativi e non mi sembra male come soluzione... io l'ho applicata, in modo tale da potere fare scorrere il canvas e funziona ma ci sono alcuni bachi..
Se ho degli altri oggetti nel frame , il canvas si va a sovrapporre a questi oggetti...
Credo che il problema sia per il fatto che il canvas sia un componente awt, per cio piu "pesante" degli altri oggetti swing...
Come mi devo comportare ?
Inoltre come posso fare per mettere delle condizioni in modo tale che quando il canvas non c'è non deve essere validato il trascinamento....
Vi posto il mio codice, perchè potrebbe essere che ci sianco anche errori che magari non riesco a capire..
....
banryu79
23-05-2008, 11:35
Appena ho tempo guardo il tuo codice, ora devo scappare, però la prossima volta mettilo tra i tag "["CODE"]""["/CODE"]" (senza le virgolette), almeno è leggibile (puoi sempre editare il post).
Ciao :)
arthurgp
23-05-2008, 11:55
ok chiedo scusa..
//classe evento
public class list implements MouseListener,MouseMotionListener {
Canvas dd=null;
JScrollPane scroll=null;
public list(Canvas a,JScrollPane ppp)
{
dd=a;
scroll=ppp;
}
boolean dragging = false;
Point draggingStart; // punto di partenza evento Dragging
// override dei metodi che ti interessano, per il drag è una gestione combinata di:
// + mousePressed (un pulsante del mouse è stato premuto)
// + mouseDragged (il puntatore del mouse si sta mouvendo mentre un pulsante viene tenuto premuto)
// + mouseReleased (un pulsante del mouse è stato rilasciato)
public void mousePressed(MouseEvent e)
{
dragging = true;
Point ptCliccato = e.getPoint();
draggingStart = ptCliccato;
}
public void mouseDragged(MouseEvent e)
{
// il puntatore del mouse si sta mouvendo con un pulsante premuto,
// è il pulsante destro allora stiamo intercettando l'evento che ci interessa
if (dragging )
{
Point p = e.getPoint();
int deltaX = p.x - draggingStart.x;
int deltaY = p.y - draggingStart.y;
// calcolati i valori di deltaX/deltaY, vanno passati al Canvas in modo che questo li possa utilizzare
// internamente per eseguire una traslazione (vedi class AffineTransform, e sue relazioni con Graphics2D)
draggingStart = p;
Point viewPosition = scroll.getViewport().getViewPosition();
viewPosition.y=viewPosition.y-deltaY;
viewPosition.x=viewPosition.x-deltaX;
scroll.getViewport().setViewPosition(viewPosition);
System.out.println(viewPosition.toString());
scroll.revalidate();
}
}
public void mouseReleased(MouseEvent e)
{
dd.repaint();
dragging = false;
}
//classe Jframe
public class aaa extends JFrame {
JScrollPane pane=null;
boolean valore=false;
public aaa()
{
Canvas a=new Canvas(){
/**
*
* Draw the tree in canvas
*/
public void paint(Graphics g)
{
if(valore){
g.setColor(Color.black);
g.fillOval(100, 100,200, 200);
g.setColor(Color.red);
g.drawLine(0, 0, 500, 500);
g.draw3DRect(1, 1, 20, 20, false);
}
}
public Dimension getPreferredSize()
{
return new Dimension(600,600);
}
};
pane=new JScrollPane(a);
pane.setLayout(new ScrollPaneLayout());
list listener=new list(a,pane);
a.addMouseMotionListener(listener);
a.addMouseListener(listener);
JButton bottone=new JButton("inizia");
bottone.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
valore=true;
repaint();
}
});
this.setLayout(new BorderLayout());
this.add(bottone,BorderLayout.NORTH);
this.add(pane,BorderLayout.CENTER);
this.setSize(200,200);
repaint();
}
}
banryu79
23-05-2008, 13:49
Innanzitutto grazie ... ho fatto dei tentativi e non mi sembra male come soluzione... io l'ho applicata, in modo tale da potere fare scorrere il canvas e funziona ma ci sono alcuni bachi..
Se ho degli altri oggetti nel frame , il canvas si va a sovrapporre a questi oggetti...
Credo che il problema sia per il fatto che il canvas sia un componente awt, per cio piu "pesante" degli altri oggetti swing...
Come mi devo comportare ?
Devi sostituire java.awt.Canvas con java.swing.JPanel :sofico:
Perchè non puoi usare JPanel? E' la versione ligthweight in Swing di Canvas.
Inoltre come posso fare per mettere delle condizioni in modo tale che quando il canvas non c'è non deve essere validato il trascinamento....
Ma il Canvas dove disegni non è sempre presente?
Comunque, ti basta gestire una variabile boolean e aggiungere due metodi: uno per registrare i mouse listener al canvas, e uno per deregistrarli.
Quando la variabile cambia di stato, a seconda del valore chiami il metodo opportuno, in un caso registrando il listener (canvas.addMouseListener(myListener) e canvas.addMouseMotionListener(myListener)) e nell'altro deregistrandolo (canvas.removeMouseListener() e remove.mouseMotionListener).
Dai un occhio ai Javadoc per la class Component (http://java.sun.com/j2se/1.5.0/docs/api/java/awt/Component.html)
banryu79
23-05-2008, 14:38
EDIT:
una buona lettura su JPanel: How to Use Panels (from Sun Java Tutorials) (http://java.sun.com/docs/books/tutorial/uiswing/components/panel.html)
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.