Torna indietro   Hardware Upgrade Forum > Software > Programmazione

Ecovacs Deebot X11 Omnicyclone: niente più sacchetto per lo sporco
Ecovacs Deebot X11 Omnicyclone: niente più sacchetto per lo sporco
Deebot X11 Omnicyclone implementa tutte le ultime tecnologie Ecovacs per l'aspirazione dei pavimenti di casa e il loro lavaggio, con una novità: nella base di ricarica non c'è più il sacchetto di raccolta dello sporco, sostituito da un aspirapolvere ciclonico che accumula tutto in un contenitore rigido
Narwal Flow: con il mocio orizzontale lava i pavimenti al meglio
Narwal Flow: con il mocio orizzontale lava i pavimenti al meglio
Grazie ad un mocio rotante che viene costantemente bagnato e pulito, Narwal Flow assicura un completo e capillare lavaggio dei pavimenti di casa. La logica di intellignza artificiale integrata guida nella pulizia tra i diversi locali, sfruttando un motore di aspirazione molto potente e un sistema basculante per la spazzola molto efficace sui tappeti di casa
Panasonic 55Z95BEG cala gli assi: pannello Tandem e audio senza compromessi
Panasonic 55Z95BEG cala gli assi: pannello Tandem e audio senza compromessi
Con un prezzo di 2.999 euro, il Panasonic Z95BEG entra nella fascia ultra-premium dei TV OLED: pannello Primary RGB Tandem, sistema di raffreddamento ThermalFlow, audio Technics integrato e funzioni gaming avanzate lo pongono come un punto di riferimento
Tutti gli articoli Tutte le news

Vai al Forum
Rispondi
 
Strumenti
Old 25-01-2007, 14:56   #1
Nurring
Member
 
Iscritto dal: Jan 2006
Messaggi: 38
[JAVA]Drag & Drop di oggetti fra finestre

Dunque...sono due giorni che ci sto sbattendo la capoccia per fare una cosa che a prima vista sembrava una cavolata mentre ora piango lacrime amare .
Precondizioni:
Ho una finestra (JFrame) che a sua volta continene un JDesktopPane, per effettuare operazioni di MDI (Multi Document Interface).
Quello che vorrei realizzare è che i documenti aperti dentro il DesktopPane contenessero degli oggetti, visualizzati tramite icone che:
1)Si possano muovere liberamente all'interno di uno spazio delimitato.
2)Si possano copiare/spostare da un internal frame all'altro, portandosi appresso tutte le informazioni che l'oggetto contiene.

Ho letto vari tutorial, ma devo ammettere che non ci ho capito molto , e sembra che nessuno si interessi a come far viaggiare "oggetti grafici" da una finestra a un'altra.

Cerco aiuto da chi sia disposto, dandomi quelche dritta e/o consigliandomi altre vie se quella che sto intrapendendo è sbagliata .

(per maggiore chiarezza allego un'immagine di come vorrei realizzare il tutto )
Immagini allegate
File Type: gif help.gif (14.2 KB, 25 visite)
Nurring è offline   Rispondi citando il messaggio o parte di esso
Old 25-01-2007, 16:41   #2
PGI-Bis
Senior Member
 
L'Avatar di PGI-Bis
 
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
Non è complicato tuttavia un esempio significativo richiede qualche articolazione. Se hai tempo vedo di mettere insieme qualcosa entro sera.
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me!
PGI-Bis è offline   Rispondi citando il messaggio o parte di esso
Old 25-01-2007, 18:30   #3
Nurring
Member
 
Iscritto dal: Jan 2006
Messaggi: 38
Quote:
Originariamente inviato da PGI-Bis
Non è complicato tuttavia un esempio significativo richiede qualche articolazione. Se hai tempo vedo di mettere insieme qualcosa entro sera.
Si ti prego ne avrei veramente bisogno ......in PVT ti mando anche i contatti di ICQ & Skype
Nurring è offline   Rispondi citando il messaggio o parte di esso
Old 25-01-2007, 21:49   #4
PGI-Bis
Senior Member
 
L'Avatar di PGI-Bis
 
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
E' un po' rapido ma dovrebbe rendere l'idea.

La storia è questa. C'è un desktop pane con dei JInternalFrame. All'interno di ognuno di questi JInternalFrame c'è un panello. Questo pannello contiene delle cose. Col drag and drop queste passano da un pannello all'altro, tra i JInternalFrame.

Puoi trasferire di tutto. Nell'esempio il trasferendo è Sprite.

Codice:
import java.awt.*;
import java.awt.image.*;

public class Sprite {
	private Point location = new Point();
	private BufferedImage image;

	public Sprite(BufferedImage image) {
		this.image = image;
	}

	public Point getLocation() {
		return (Point)location.clone();
	}

	public boolean contains(Point p) {
		return
			p.x >= location.x &&
			p.x < location.x + image.getWidth() &&
			p.y >= location.y &&
			p.y < location.y + image.getHeight();
	}

	public void setLocation(Point p) {
		location.setLocation(p);
	}

	public void paint(Graphics g) {
		g.drawImage(image, location.x, location.y, null);
	}
}
E' un'immagine in un punto di uno schermo. Niente di più. Poi tu dovrai scegliere cosa trasferire. Trattandosi di spostamenti all'interno della stessa JVM, puoi metterci tutto quello che vuoi: quello che circola è un riferimento ad un oggetto. Diverso è il caso di spostamenti tra JVM diverse o tra JVM e il window manager del sistema operativo. In questo caso occorre fornire una rappresentazione indipendente da Java e ricostruibile nativamente. Ma noi abbiamo la fortuna di trattare il caso più semplice :

Ciò che trasferisci con il Drag And Drop AWT è incapsulato in un oggetto di tipo Transferable (Trasferibile). L'incapsulamento è richiesto anche se si tratti, come nel nostro caso, di cose arcinote e immutabili. Se guardi, l'interfaccia Transferable è molto semplice. Fa due cose: è in grado di dire se quello che contiene è compatibile con un certo DataFlavor (isDataFlavorSupported) e può restituirle quel qualcosa in una forma compatibile con un DataFlavor, se questo sia supportato (getTransferData(DataFlavor)).

Noi vogliamo trasferire uno Sprite (tu vorrai trasferire qualcos'altro, il modus operandi è lo stesso), ci serve una capsula Transferable. E' questione di poche righe.

Codice:
import java.awt.datatransfer.*;

/** Capsula per il trasferimento di uno Sprite nella stessa JVM */
public class SpriteTransferable implements Transferable {

	/* Identifica un Transferable che trasporta uno Sprite */
	public static final DataFlavor SPRITE_FLAVOR = new DataFlavor(
		Sprite.class , "sprite");

	/* Sprite trasferito */
	private final Sprite SPRITE;

	/** Crea un Transferable che incapsula lo Sprite in
	argomento */
	public SpriteTransferable(Sprite sprite) {
		SPRITE = sprite;
	}

	/** Restituisce un oggetto SPRITE se la classe di rappresentazione
	del DataFlavor in argomento sia compatibile in assegnamento
	con Sprite.class */
	public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException {
		if(flavor.getRepresentationClass().isAssignableFrom(Sprite.class)) {
			return SPRITE;
		} else {
			throw new UnsupportedFlavorException(flavor);
		}
	}

	/* True se la classe di rappresentazione del DataFlavor in
	argomento sia compatibile in assegnamento con Sprite.class */
	public boolean isDataFlavorSupported(DataFlavor flavor) {
		return flavor.getRepresentationClass().isAssignableFrom(Sprite.class);
	}

	public DataFlavor[] getTransferDataFlavors() {
		return new DataFlavor[] { SPRITE_FLAVOR };
	}
}
Tutto quello che fa SpriteTransferable è immagazzinare un riferimento ad uno Sprite e restituire quel riferimento se qualcuno glielo chieda passandogli SPRITE_FLAVOR come DataFlavor.

A questo punto è tutto fatto. Il Drag And Drop funziona come fosse un MouseListener. In particolare, quello che a noi interessa di più è l'esistenza di un metodo "dragMouseMoved". E' l'alter ego di "mouseDragged" solo che è invocato quando il trascinamento del mouse è quello che corrisponde ad un drag and drop in corso. La cosa comunque funziona così.

Il componente che voglia iniziare un "Drag" viene agganciato ad un DragSource (solitamente il DragSource predefinito della piattaforma) attraverso il metodo createDragGestureRecognizer di quest'ultimo. Al DragSource puoi agganciare un DragSourceListener, che registra in particolare un evento "qualcosa di trascinato sta entrando" e un DragSourceMotionListener, che registra l'evento "qualcosa di trascinato si sta muovendo".

Il componente che vuole ricevere un drop, l'atto terminale del drag and drop, può farlo usando DropTarget. DropTarget ha un costruttore che richiede un Component e un DropTargetListener. Il component è quello su cui avverrà il drop e il DropTargetListener è l'oggetto il cui metodo drop è invocato quando avviene il rilascio.

Riassunto. Per fare di un Component l'attivatore di un Drag:

Codice:
DragSource source = DragSource.getDefaultDragSource();
DragGestureRecognizer dgr = source.createDragGestureRecognizer(
    IL_COMPONENTE,
    uno dei valori di DnDConstants, ad esempio MOVE,
    l'ascoltatore di eventi DragSourceListener);
Dopo questi due passaggi, quando il sistema rileva un qualcosa che somiglia ad un "drag", invoca il metodo "dragGestureRecognized" dell'ascoltatore di eventi DragSourceListener. Là dentro si fanno i controlli necessari a stabilire se sia il caso di iniziare il drag. Per noi questo significherà capire se nel punto in cui il mouse è stato premuto ci sia uno Sprite (che non a caso ha un metodo contains(Point) ). Per registrare il movimento del mouse, si prende il DragSource e gli si aggiunge un DragSourceListener (quando un drag entra nell'area di un componente) e un DragSourceMotionListener (quando si sta muovendo qualcosa sul componente).

Per attivare il drop:

Codice:
DropTarget dropTarget = new DropTarget(COMPONENTE, DropTargetListener);
Quello che segue è il pannello che contiene le icone trascinabili.

Codice:
import java.awt.*;
import java.awt.dnd.*;
import java.awt.datatransfer.*;
import java.util.*;
import javax.swing.*;
import javax.swing.border.*;

public class FloatingPanel extends JPanel {
	private ArrayList<Sprite> sprites = new ArrayList<Sprite>();
	private DropTarget dropTarget;
	private DragSource dragSource = DragSource.getDefaultDragSource();

	public FloatingPanel() {
		setBackground(Color.WHITE);

		/* Quando si rilascia qualcosa è invocato il metodo drop di
		dropManager */
		dropTarget = new DropTarget(this, dropManager);

		/* Quando un "droppable" entra nella regione di questo componente
		è invocato il metodo dragEnter */
		dragSource.addDragSourceListener(dragProgressManager);

		/* Quando il mouse si muove in corrispondenza di un evento drag and
		drop è invocato il metodo dragMouseMoved */
		dragSource.addDragSourceMotionListener(dragProgressManager);
		DragGestureRecognizer dragStarter = dragSource.createDefaultDragGestureRecognizer(
			this, DnDConstants.ACTION_MOVE,
			dragManager);
	}

	/** Aggiunge lo sprite in argomento (non accetta duplicati) */
	public void addSprite(Sprite sprite) {
		if(sprites.contains(sprite) == false) {
			sprites.add(sprite);
			repaint();
		}
	}

	/** Rimuove uno sprite */
	public void removeSprite(Sprite sprite) {
		int index = sprites.indexOf(sprite);
		if(index >= 0) {
			sprites.remove(index);
			repaint();
		}
	}

	/** Restituisce lo sprite in posizione location o null,
	se non ci siano sprite in quella posizione */
	public Sprite getSpriteAt(Point location) {
		for(Sprite s : sprites) {
			if(s.contains(location)) {
				return s;
			}
		}
		return null;
	}

	/** Disegna gli sprite */
	protected void paintComponent(Graphics g) {
		super.paintComponent(g);
		for(Sprite s : sprites) {
			s.paint(g);
		}
	}

	/** Gestisce l'avvio del drag */
	private DragGestureListener dragManager = new DragGestureListener() {
		public void dragGestureRecognized(DragGestureEvent dge) {
			Point p = dge.getDragOrigin();
			Sprite sprite = getSpriteAt(p);
			if(sprite != null) {
				dge.startDrag(DragSource.DefaultMoveDrop, new SpriteTransferable(sprite));
			}
		}
	};

	/** Gestisce il drop */
	private DropTargetAdapter dropManager = new DropTargetAdapter() {
		public void drop(DropTargetDropEvent e) {
			if(e.isDataFlavorSupported(SpriteTransferable.SPRITE_FLAVOR)) {
				e.acceptDrop(DnDConstants.ACTION_MOVE);
				dropSprite(e);
			} else {
				e.rejectDrop();
			}
		}
	};

	/** Gestisce il movimento in drag */
	private DragSourceAdapter dragProgressManager = new DragSourceAdapter() {
		public void dragMouseMoved(DragSourceDragEvent e) {
			DragSourceContext context = e.getDragSourceContext();
			Transferable t = context.getTransferable();
			if(t.isDataFlavorSupported(SpriteTransferable.SPRITE_FLAVOR)) {
				moveSprite(t, e.getLocation());
			}
		}

		public void dragEnter(DragSourceDragEvent e) {
			DragSourceContext context = e.getDragSourceContext();
			Transferable t = context.getTransferable();
			if(t.isDataFlavorSupported(SpriteTransferable.SPRITE_FLAVOR)) {
				acquireSprite(t, e.getLocation());
			}
		}
	};

	/* Invocato quando lo sprite trascinato entra nel pannello */
	private void acquireSprite(Transferable t, Point p) {
		try {
			SwingUtilities.convertPointFromScreen(p, this);
			Sprite sprite = (Sprite)t.getTransferData(SpriteTransferable.SPRITE_FLAVOR);
			sprite.setLocation(p);
			addSprite(sprite);
		} catch(Exception ex) {
			System.err.println(ex.getMessage());
		}
	}

	/* Invocato quando lo sprite trascinato esce dal pannello */
	private void releaseSprite(Transferable t) {
		try {
			Sprite sprite = (Sprite)t.getTransferData(SpriteTransferable.SPRITE_FLAVOR);
			removeSprite(sprite);
		} catch(Exception ex) {
			System.err.println(ex.getMessage());
		}
	}

	/* Invocato durante il trascinamento di uno sprite */
	private void moveSprite(Transferable t, Point p) {
		try {
			Rectangle bounds = getBounds(); //JComponent
			Point onScreen = getLocationOnScreen(); //JComponent
			bounds.x += onScreen.x;
			bounds.y += onScreen.y;
			Sprite sprite = (Sprite)t.getTransferData(SpriteTransferable.SPRITE_FLAVOR);

			/* Se il movimento avviene all'interno del componente, muove lo sprite */
			if(bounds.contains(p)) {
				p.x -= onScreen.x;
				p.y -= onScreen.y;
				sprite.setLocation(p);
				repaint();
			} else {
				/* Se il movimento avviene al di fuori del componente, lo sprite
				viene rimosso */
				removeSprite(sprite);
			}
		} catch(Exception ex) {
			System.err.println(ex.getMessage());
		}
	}

	/* Azioni conseguenti ad una richiesta di rilascio */
	private void dropSprite(DropTargetDropEvent e) {
		try {
			Transferable t = e.getTransferable();
			Sprite sprite = (Sprite)t.getTransferData(SpriteTransferable.SPRITE_FLAVOR);
			addSprite(sprite);
			repaint();
			e.dropComplete(true);
		} catch(Exception ex) {
			e.dropComplete(false);
		}
	}
}
Quando trascini il mouse su un'icona di questo pannello (uno sprite) quello sprite si muove all'interno del pannello. Quando, per effetto del trascinamento, lo sprite esce dal pannello, lo sprite viene rimosso. Quando uno sprite viene trascinato all'interno del pannello, lo sprite viene acquisito e si muove.

Per provare si possono creare due pannelli, infilarli in altrettanti JInternalFrame, creare uno sprite e infilarlo in uno dei due pannelli. Apri un finestrone e potrai trascinare l'icona da un pannello all'altro. Oltre che sperimentare un tot di problemi.

Codice:
import java.awt.*;
import java.awt.image.*;
import javax.swing.*;
import javax.imageio.*;
import java.util.*;
import java.io.*;

public class Main implements Runnable {
	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Main());
	}

	private final String IMAGE_PATH = "/icon.png";

	public void run() {
		Dimension panelSize = new Dimension(200, 200);
		FloatingPanel firstPanel = new FloatingPanel();
		firstPanel.setPreferredSize(panelSize);
		JInternalFrame firstFrame = new JInternalFrame(
			"First Frame", true, false, true, false);
		firstFrame.add(firstPanel, BorderLayout.CENTER);

		FloatingPanel secondPanel = new FloatingPanel();
		secondPanel.setPreferredSize(panelSize);
		JInternalFrame secondFrame = new JInternalFrame(
			"Second Frame", true, false, true, false);
		secondFrame.add(secondPanel, BorderLayout.CENTER);

		JDesktopPane desktop = new JDesktopPane();
		desktop.add(firstFrame);
		desktop.add(secondFrame);

		JFrame window = new JFrame("Sample");
		window.add(desktop, BorderLayout.CENTER);
		window.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		window.pack();

		/* Carica uno sprite e lo introduce nel primo pannello */
		GraphicsConfiguration screenConfig = window.getGraphicsConfiguration();
		Sprite sprite = loadSprite(screenConfig, IMAGE_PATH);
		sprite.setLocation(new Point(5, 5));
		firstPanel.addSprite(sprite);

		window.setSize(640, 480);
		window.setVisible(true);

		firstFrame.pack();
		firstFrame.setLocation(new Point(300, 50));
		firstFrame.setVisible(true);
		secondFrame.pack();
		secondFrame.setLocation(new Point(20, 50));
		secondFrame.setVisible(true);
	}

	private Sprite loadSprite(GraphicsConfiguration cfg, String iconPath) {
		try {
			InputStream in = getClass().getResourceAsStream(iconPath);
			BufferedImage image = ImageIO.read(in);
			BufferedImage fastImage = cfg.createCompatibleImage(
				image.getWidth(), image.getHeight());
			fastImage.getGraphics().drawImage(image, 0, 0, null);
			return new Sprite(fastImage);
		} catch(IOException ex) {
			throw new RuntimeException(ex);
		}
	}
}
La prima cosa da notare è che si tratta di un rapido esperimento. Ciò che certamente non va è il fatto che se l'oggetto trascinato può perdersi per strada se il drop non avviene all'interno dell'altro JInternalFrame. Considerando questa possibilità si dovrebbe rimuovere lo sprite dal pannello di origine se e solo se esso abbia effettivamente raggiunto un altro pannello. Poi se sovrapponi parzialmente i due JInternalFrame noti uno spostamento strano dell'immagine che deriva dall'uso del metodo dragEnter per gestire l'acquisizione dello sprite. Sarebbe preferibile fare tutto con il solo movimento. C'è da ricamare un bel po'.

La cosa un po' meno agevole da risolvere è il fatto che nel passaggio tra un frame e l'altro l'icona scompare. Deriva da ciò che la proiezione dell'icona avviene sui pannelli e non è associata al cursore del trascinamento. C'è un metodo di DragGestureEvent che potrebbe farlo ma non lo fa in tutte le piattaforme dunque è da scartare.

C'è più di una soluzione all'ultimo e più consistente problema. Si può usare il DesktopPane come ulteriore oggetto bersaglio del drop e disegnare su di esso l'icona quando si trovi a svolazzare tra due pannelli oppure si può passare per il glass pane della finestra. A dirla tutta l'opzione GlassPane è appettibile per gestire tutto l'ambaradan perchè ha notevoli potenzialità "artistiche". Tuttavia non saremmo più nel campo del drag and drop, almeno non in senso comune. Ma, se vuoi, possiamo provare a vedere cosa si cava da questa seconda opzione.
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me!
PGI-Bis è offline   Rispondi citando il messaggio o parte di esso
Old 25-01-2007, 22:12   #5
Nurring
Member
 
Iscritto dal: Jan 2006
Messaggi: 38
Innanzitutto grazie davvero di cuore.
Ammetto di essere troppo stanco ora per leggere il tutto, ma domani con mente lucida mi ci metto e mi studio tutto per bene.
Inoltre sono strabiliato con la facilità con la quale hai scritto (e descritto) questo codice, per me ancora oscuro, ma per te contenente concetti ormai chiari. Beato te!
Sinceramente la storia del GlassPane mi incuriosisce, visto che gli oggetti che porti da un frame all'altro dovranno anche avere un collegamento fra di loro tramite linee definite in una certa maniera......ma questa è un'altra storia, per ora vedo di riuscire a risolvere questa.

Ancora grazie
Nurring è offline   Rispondi citando il messaggio o parte di esso
Old 26-01-2007, 16:44   #6
PGI-Bis
Senior Member
 
L'Avatar di PGI-Bis
 
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
Ho provato a farlo in versione "glass pane" e viene molto più carino e direi anche meno complicato. Se ti interessa incollo il codice in un messaggio. Prima devo dargli una sistemata perchè è 'na schifezza .
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me!
PGI-Bis è offline   Rispondi citando il messaggio o parte di esso
Old 26-01-2007, 23:21   #7
Nurring
Member
 
Iscritto dal: Jan 2006
Messaggi: 38
Quote:
Originariamente inviato da PGI-Bis
Ho provato a farlo in versione "glass pane" e viene molto più carino e direi anche meno complicato. Se ti interessa incollo il codice in un messaggio. Prima devo dargli una sistemata perchè è 'na schifezza .
Incolla incolla!!! Intanto io mi sono studiato il tuo codice e l'ho provato in parte, ho ridefinito il JPanel exstendendolo con la classe che mi avevi dato, l'ho compilato, ho agginuto il pannello nei posti dove mi interessava e funziona .
Solo che non sono riuscito a provare a mettterci un oggetto dentro perché non ho avuto tanto tempo oggi. ...

PS Io uso NetBeans 5.0.....mi ci trovo molto bene, tu che hai sicuramente piu' esperienza di me , se lo hai usato,come lo valuti?
Nurring è offline   Rispondi citando il messaggio o parte di esso
Old 27-01-2007, 16:54   #8
PGI-Bis
Senior Member
 
L'Avatar di PGI-Bis
 
Iscritto dal: Nov 2004
Città: Tra Verona e Mantova
Messaggi: 4553
Conosco NetBeans e mi piace tuttavia io programmo con un editor che una sorta di Notepad con le schede, senza evidenziazione del codice, indentazione, compilazione o ammennicoli del genere. Preferisco così, non lo consiglio a nessuno. Capirai che io non sia la persona più indicata per valutare la bontà di un IDE .

Ho tradotto in qualcosa di usabile il drag and drop tramite glass pane. Funziona e apre un tot di possibilità molto simpatiche, graficamente parlando. Qui sotto c'è il minimo sindacale. Non si vede il cursore del mouse perchè "stamp" non lo prende, ma c'è.

Partenza


Trascinamento


Arrivo


L'ambaradan si appoggia a tre elementi. Due interfacce e un JComponent da usare come pannello trasparente.

L'interfaccia DragData dichiara le capacità di qualcosa che può essere "trascinato".

DragData.java
Codice:
package softdnd;

/** Dati trasferiti attraverso il soft drag and drop */
public interface DragData {

	/** Restituisce la sorgente dei dati trasferiti o null */
	<T> T getSource(Class<T> type);

	/** Restituisce i dati trasferiti o null */
	<T> T getData(Class<T> type);

	/** Restituisce il punto di origine dei dati nel
	sistema di coordinate dello schermo */
	java.awt.Point getOriginOnScreen();

	/** Restituisce l'icona dei dati trasferiti */
	java.awt.Image getImage();
}
Serve a questo. Quando sul pannello è rilevata la pressione del mouse, il pannello richiede ad un certo oggetto se in quel punto ci sia qualcosa di trascinabile. Se c'è, allora il glasspane imposta un campo DragData sul valore restituito da quell'oggetto. Durante il trascinamento del mouse, il glass pane disegna lungo il percorso del cursore l'immagine restituita dal metodo getImage di quel dragData. Nulla di più.

Le proprietà di chi può fornire e ricevere un DragData sono dichiarare nell'interfaccia che segue.

DDUnit.java
Codice:
package softdnd;

import java.awt.Point;

/** Sorgente, bersaglio e destinazione del "soft"
drag and drop */
public interface DDUnit {

	/** Estrae i dati trasferibili dal punto screenPoint.
	Il sistema di coordinate di screenPoint è quello
	dello schermo. Restituisce null se non ci siano dati
	da trasferire. */
	DragData carve(Point screenPoint);

	/** Riceve una notifica di trascinamento dei dati
	trasferiti. Il punto screenPoint è la posizione
	attuale del trascinamento nel sistema di coordinate
	dello schermo. data sono i dati in trasferimento. */
	void drag(Point screenPoint, DragData data);

	/* Richiesta di rilascio dei dati data nel punto
	screenPoint. Il punto screenPoint è relativo al
	sistema di coordinate dello schermo. Restituisce true
	se il drop sia avvenuto con successo. */
	boolean drop(Point screenPoint, DragData data);
}
Anche qui il funzionamento dovrebbe essere evidente. Il glass pane ha un riferimento ad uno DDUnit. Quando il mouse è premuto, il glass pane preleva dal suo ddUnit - carve(Point) - un DragData. Se lo ddUnit risponde con qualcosa allora il glasspane considera iniziato il draganddrop. Durante il trascinamento, che per il glass pane corrisponde ad un evento "MOUSE_DRAGGED" in presenza di un dragData diverso da null, il glass pane notifica al suo ddUnit gli spostamenti invocandone il metodo drag. Nel concreto esempio non faccio uso di questa notifica ma può servire nel caso in cui, ad esempio, il componente che vede passarsi sopra un DragData voglia in qualche modo reagire - lampeggiando, gridando "a me, a me" o quant'altro.

La classe che segue concretizza DragData. Lo fa semplicemente fornendo un get ed un set per ogni proprietà che eredita.

DefaultMutableDragData.java
Codice:
package softdnd;

import java.awt.*;

public class DefaultMutableDragData implements DragData {
	private Object source;
	private Object data;
	private Image image;
	private Point originOnScreen;

	public Image getImage() {
		return image;
	}

	public void setImage(Image image) {
		this.image = image;
	}

	public void setOriginOnScreen(Point p) {
		originOnScreen = (Point)p.clone();
	}

	public Point getOriginOnScreen() {
		return originOnScreen;
	}

	public void setSource(Object source) {
		this.source = source;
	}

	public void setData(Object data) {
		this.data = data;
	}

	public <T> T getSource(Class<T> type) {
		if(source != null && type.isAssignableFrom(source.getClass())) {
			return type.cast(source);
		} else {
			return null;
		}
	}
	
	public <T> T getData(Class<T> type) {
		if(data != null && type.isAssignableFrom(data.getClass())) {
			return type.cast(data);
		} else {
			return null;
		}
	}
}
C'è poi una classe che contiene due metodi di servizio per la conversione di coordinate da un componente allo schermo e viceversa.

PointService.java
Codice:
package softdnd;

import java.awt.*;

public class PointService {

	/* Restituisce la conversione di un punto dal sistema di
	coordinate del componente source a quello dello schermo */
	public static Point convertPointToScreen(Point p, Component source) {
		Point location = source.getLocationOnScreen();
		return new Point(p.x + location.x, p.y + location.y);
	}

	/* Restituisce la conversione di un punto dal sistema di
	coordinate dello schermo a quello di questo componente */
	public static Point convertPointFromScreen(Point p, Component source) {
		Point location = source.getLocationOnScreen();
		return new Point(p.x - location.x, p.y - location.y);
	}
}
Ci sono dei metodi analoghi in SwingUtilities ma fanno qualcosa in più che ho preferito evitare.

La classe UnitPane è un JPanel che concretizza l'interfaccia DDUnit. Cioè un JPanel da cui si può estrarre e su cui si può rilasciare un certo DragData. Il DragData prodotto e acquisibile è un DragData che contenga un Component.

UnitPane.java
Codice:
package softdnd;

import java.awt.*;
import java.awt.image.*;
import javax.swing.*;
import static softdnd.PointService.convertPointToScreen;
import static softdnd.PointService.convertPointFromScreen;

/** Unità soft drag and drop JPanel */
public class UnitPane extends JPanel implements DDUnit {
	public UnitPane() {}

	public UnitPane(LayoutManager layout) {
		super(layout);
	}

	/** @inheritDoc */
	public DragData carve(Point screenPoint) {
		/* Cerca un Component nel punto corrispondente a
		screenPoint. Se lo trova lo impacchetta in un
		DefaultMutableDragData e lo restituisce. Elimina
		da sè il componente trasferito */
		DragData answer = null;
		Point location = convertPointFromScreen(screenPoint, this);
		Component component = getComponentAt(location);
		if(component != null && component != this) {
			answer = packComponent(component);
			remove(component);
			revalidate();
		}
		return answer;
	}

	/** Inerte */
	public void drag(Point screenPoint, DragData data) {}

	/** @inheritDoc */
	public boolean drop(Point screenPoint, DragData data) {
		/* Se data contiene un Component allora questo
		pannello ingloba quel componente. */
		boolean answer = false;
		Component component = data.getData(Component.class);
		if(component != null) {
			add(component);
			revalidate();
			answer = true;
		}
		return answer;
	}

	/* Incapsula un componente in un DefaultMutableDragData.
	Crea uno "screenshot" del componente come immagine da
	usare per il trasferimento */
	private DragData packComponent(Component c) {
		BufferedImage image = newBuffer(c.getWidth(), c.getHeight());
		c.print(image.getGraphics());
		DefaultMutableDragData data = new DefaultMutableDragData();
		data.setSource(this);
		data.setData(c);
		data.setOriginOnScreen(c.getLocationOnScreen());
		data.setImage(image);
		return data;
	}

	/* Crea un buffer di formato compatibile con lo schermo */
	private BufferedImage newBuffer(int width, int height) {
		GraphicsConfiguration config = getGraphicsConfiguration();
		BufferedImage image = config.createCompatibleImage(
			width, height, Transparency.TRANSLUCENT);
		return image;
	}
}
Gli UnitPane sono usati nell'esempio come pannelli del contenuto per i due JInternalFrame. Tra questi UnitPane e il glass pane c'è uno strato intermedio. Questo strato intermedio è ciò che è usato come DDUnit dal glass pane ed è definito nella classe DesktopUnit.

DesktopUnit.java
Codice:
package softdnd;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import static softdnd.PointService.convertPointToScreen;
import static softdnd.PointService.convertPointFromScreen;

/** Unità drag and drop associata ad un JDesktopPane */
public class DesktopUnit implements DDUnit {
	private JDesktopPane desktopPane = new JDesktopPane();

	/** Restituisce il DesktopPane associato a questo
	DesktopUnit */
	public JDesktopPane getDesktopPane() {
		return desktopPane;
	}

	/** @inheritDoc */
	public DragData carve(Point screenPoint) {
		/* Per estrarre un DragData questo DesktopUnit
		interroga i JInternalFrame contenuti nel suo
		desktopPane. */

		DragData answer = null;
		DDUnit unit = ddUnitAt(screenPoint);
		if(unit != null) {
			answer = unit.carve(screenPoint);
		}
		return answer;
	}

	/** Inerte. */
	public void drag(Point screenPoint, DragData data) {}

	/** @inheritDoc */
	public boolean drop(Point screenPoint, DragData data) {
		/* Se c'è un DDUnit che può ricevere il drop allora
		lascia quell'unità il compito di gestire l'acquisizione.
		Altrimenti annulla il trasferimento. Per farlo usa
		la proprietà "source" del DragData (sorgente del
		trasferimento). */

		DDUnit unit = ddUnitAt(screenPoint);
		if(unit == null || !unit.drop(screenPoint, data)) {
			undoCarving(data);
		}
		return true;
	}

	/** Annulla, se possibile, l'operazione di drag and drop
	rappresentata dal DragData in argomento */
	private void undoCarving(DragData data) {
		/* Se il DragData ha un contentire di origine e
		trasporta un Component allora aggiunge il componente
		al contenitore originale. */
		Container container = data.getSource(Container.class);
		Component component = data.getData(Component.class);
		if(component != null && container != null) {
			container.add(component);
			container.validate();
		}
	}

	/** Restituisce l'unità drag and drop che si trova nel punto
	screenPoint o null se non ve ne sia una. */
	private DDUnit ddUnitAt(Point screenPoint) {
		/* Tutto si fonda sull'assunto che il pannello del
		contenuto di ogni JInternalFrame sia un DDUnit. */
		DDUnit answer = null;
		Point point = convertPointFromScreen(screenPoint, desktopPane);
		Component component = desktopPane.getComponentAt(point);
		if(component instanceof JInternalFrame) {
			JInternalFrame frame = (JInternalFrame)component;
			Container contentPane = frame.getContentPane();
			if(contentPane instanceof DDUnit) {
				answer = (DDUnit)contentPane;
			}
		}
		return answer;
	}
}
DesktopUnit gestisce un JDesktopPane. In questo JDesktopPane possono esseri un toto di JInternalFrame. Quando qualcuno (il glass pane) richiede al DesktopUnit di compiere l'estrazione di un DragData in un certo punto, DesktopUnit controlla se in quel punto ci sia un JInternalFrame e, in caso affermativo, se il suo pannello del contenuto sia un DDUnit. Se il pannello del contenuto è un DDUnit gli passa la palla. Nell'esempio, il pannello del contenuto sarà uno UnitPane.

L'ultimo partecipante al magheggio è DDGlass. DDGlass è un JComponent che sarà usato come glass pane di una finestra. Un glass pane è un componente idealmente trasparente che viene proiettato sopra al pannello del contenuto della finestra.

DDGlass.java
Codice:
package softdnd;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import static java.awt.AWTEvent.*;
import static java.awt.event.MouseEvent.*;
import static softdnd.PointService.convertPointToScreen;
import static softdnd.PointService.convertPointFromScreen;

/** Pannello trasparente che gestisce il "soft" drag and drop */
public class DDGlass extends JComponent implements AWTEventListener {
	/* Punto di trascinamento corrente */
	private Point currentDataPoint;

	/* Dati in trasferimento */
	private DragData dragData;

	/* Sorgente e destinazione dei dati trasferibili */
	private DDUnit ddUnit;
	
	/* May throw a SecurityException */
	public DDGlass(DDUnit ddUnit) {
		this.ddUnit = ddUnit;
		setOpaque(false);
		Toolkit.getDefaultToolkit().addAWTEventListener(
			this,
			MOUSE_EVENT_MASK | MOUSE_MOTION_EVENT_MASK);
	}

	/** Called by constructor */
	public void setOpaque(boolean val) {
		super.setOpaque(val);
	}

	/** Riceve gli eventi AWT ovunque siano generati */
	public void eventDispatched(AWTEvent e) {
		if(e.getID() == MOUSE_PRESSED) {
			handleMousePressed((MouseEvent)e);
		} else if(dragData != null && e.getID() == MOUSE_DRAGGED) {
			handleMouseDragged((MouseEvent)e);
		} else if(dragData != null && e.getID() == MOUSE_RELEASED) {
			handleMouseReleased((MouseEvent)e);
		}
	}

	/* Gestisce la pressione del mouse estraendo da ddUnit i dati
	da trascinare */
	private void handleMousePressed(MouseEvent e) {
		Point screenPoint = convertPointToScreen(
			e.getPoint(), e.getComponent());
		dragData = ddUnit.carve(screenPoint);
		if(dragData != null) {
			setVisible(true);
			currentDataPoint = convertPointFromScreen(screenPoint, this);
			repaint();
		}
	}

	/* Gestice il trascinamento del mouse spostando i dati
	estratti */
	private void handleMouseDragged(MouseEvent e) {
		Point screenPoint = convertPointToScreen(
			e.getPoint(), e.getComponent());
		ddUnit.drag(screenPoint, dragData);
		currentDataPoint = convertPointFromScreen(screenPoint, this);
		repaint();
	}

	/** Gestice il rilascio del mouse rilasciando i dati estratti
	e spostati */
	private void handleMouseReleased(MouseEvent e) {
		Point screenPoint = convertPointToScreen(
			e.getPoint(), e.getComponent());
		ddUnit.drop(screenPoint, dragData);
		dragData = null;
		repaint();
	}

	@Override
	protected void paintComponent(Graphics g) {
		if(dragData != null) {
			paintDragData(g);
		}
	}

	/** Disegna l'immagine associata a dragData nel punto
	di trascinamento corrente */
	private void paintDragData(Graphics g) {
		g.drawImage(
			dragData.getImage(), 
			currentDataPoint.x,
			currentDataPoint.y,
			null);
	}
}
Praticamente ci sono solo due cose su cui fare mente locale. Una è il fatto che la gestione degli eventi passa per un AWTEventListener associato al Toolkit. Si fa per evitare che il glass pane consumi gli eventi che intercetta, come avverrebbe con un normale addMouseListener o con un enableEvents. La seconda è quel "setVisible" in handleMousePressed. Non chiedermi perchè ma pare che se si ridimensiona un JInternalFrame allora il glass pane della finestra perde lo stato "visible". Tale stato è necessario per determinare la posizione del mouse sul glass pane. Probabilmente ha a che fare con la strategia di aggiornamento del contesto grafico da parte di JDesktopPane ma non ci metterei la mano sul fuoco. La successione di eventi che capita al glass pane è questa. Quando si preme il mouse, se il DDUnit associato dice che c'è qualcosa di trascinabile DDGlass lo imposta come valore del campo "dragData" e si ridisegna. Quando il mouse viene trascinato e se esiste un dragData allora DDGlass aggiorna la posizione in cui deve essere disegnata l'immagine del dragData e si ridisegna. Quanto il mouse viene rilasciato e se esiste un dragData allora DDGlass semplicemente rilascia i dati trascinati sul suo DDUnit. Spetta a questo sapere cosa fare sia nel caso in cui ci sia un qualcosa disposto ad accettare il drop sia nel caso in cui questo qualcosa non ci sia.

La classe Main che mette insieme il tutto in un esempio è molto semplice. Crea un'etichetta con un'immagine come icona. Poi crea due JInternalFrame e imposta per ognuno di essi uno UnitPane come pannello del contenuto. Così facendo DesktopUnit sarà il grando di prelevare e rilasciare oggetti nelle finestre. Main crea uno DesktopUnit, gli aggiunge i due JInternalFrame, crea una finestra, crea un DDGlass lo imposta come glass pane della finestra, si apre e via.

Main.java
Codice:
package softdnd;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Main implements Runnable {
	public static void main(String...args) {
		SwingUtilities.invokeLater(new Main());
	}

	private final String ICON_PATH = "/icons/icon.png";
	private final Dimension PANEL_SIZE = new Dimension(200, 200);

	public void run() {
		/* Icona usata per l'etichetta trascinabile */
		ImageIcon icon =
			new ImageIcon(getClass().getResource(ICON_PATH));

		/* Etichetta trascinabile */
		JLabel label = new JLabel(icon);

		/* Pannello del contenuto del primo frame interno */
		UnitPane firstPane = new UnitPane(new FlowLayout());
		/* che contiene l'etichetta trascinabile */
		firstPane.add(label);

		/* Pannello del contenuto del secondo frame interno */
		UnitPane secondPane = new UnitPane(new FlowLayout());

		/* Assegna una dimensione predefinita ai due pannelli
		del contenuto. */
		firstPane.setPreferredSize(PANEL_SIZE);
		secondPane.setPreferredSize(PANEL_SIZE);

		/* DesktopUnit il cui desktop pane contiene i due
		frame interni e che sarà usato come DDUnit per il
		glass pane DDGlass */
		DesktopUnit desktop = new DesktopUnit();

		/* Frame interno che contiene il primo UnitPane */
		JInternalFrame firstFrame = new JInternalFrame(
			"First frame", true, false, true);

		/* Frame interno che contiene il secondo UnitPane */
		JInternalFrame secondFrame = new JInternalFrame(
			"Second frame", true, false, true);

		/* Imposta i pannelli del contenuto per i due
		JInternalFrame */
		firstFrame.setContentPane(firstPane);
		secondFrame.setContentPane(secondPane);

		/* Aggiunge i due frame interni al desktop dello
		DesktopUnit */
		desktop.getDesktopPane().add(firstFrame);
		desktop.getDesktopPane().add(secondFrame);

		/* Assegna una dimensione ai due frame interni e
		li rende visibili */
		firstFrame.pack();
		firstFrame.setVisible(true);
		secondFrame.pack();
		secondFrame.setVisible(true);

		/* Crea il glass pane usando il desktop come
		sua DDUnit */
		DDGlass glass = new DDGlass(desktop);

		/* Crea una finestra */ 
		JFrame window = new JFrame();

		/* le assegna un glass pane e lo rende visibile */
		window.setGlassPane(glass);
		glass.setVisible(true);

		/* apre la finestra sullo schermo */
		window.add(desktop.getDesktopPane(), BorderLayout.CENTER);
		window.setSize(640, 480);
		window.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		window.setVisible(true);
	}
}
Può darsi che ci sia qualcosa da sistemare perchè, in fondo, è solo uno showcase. Però ha l'aria di funzionare.
__________________
Uilliam Scecspir ti fa un baffo? Gioffri Cioser era uno straccione? E allora blogga anche tu, in inglese come me!
PGI-Bis è offline   Rispondi citando il messaggio o parte di esso
Old 28-01-2007, 10:37   #9
Nurring
Member
 
Iscritto dal: Jan 2006
Messaggi: 38
Ancora una volta grazie;
devo ammettere pero' che, al momento, trovo piu' facile l'altro codice, mi da l'idea di riuscire a gestirlo meglio.

Questo ultimo l'ho appena letto, ma non ti nascondo che ho trovato notevoli difficoltà anche solo nel leggere il codice (I feel noob! ).

Ancora una volta grazie per la tua disponibilità!
Nurring è offline   Rispondi citando il messaggio o parte di esso
Old 28-01-2007, 11:51   #10
franksisca
Senior Member
 
L'Avatar di franksisca
 
Iscritto dal: May 2005
Città: Roma
Messaggi: 7938
mi inserisco solo per dire
PGI
__________________
My gaming placement
franksisca è offline   Rispondi citando il messaggio o parte di esso
Old 20-08-2010, 00:33   #11
nucarote
Senior Member
 
Iscritto dal: Mar 2004
Messaggi: 2992
Riporto in alto tale topic per chiedere come si deve procedere in tal caso:
Quote:
Originariamente inviato da PGI-Bis
... Diverso è il caso di spostamenti tra JVM diverse o tra JVM e il window manager del sistema operativo. In questo caso occorre fornire una rappresentazione indipendente da Java e ricostruibile nativamente. Ma noi abbiamo la fortuna di trattare il caso più semplice ...
Grazie fin da ora per la vostre risposte.
nucarote è offline   Rispondi citando il messaggio o parte di esso
Old 20-08-2010, 10:28   #12
ndakota
Senior Member
 
L'Avatar di ndakota
 
Iscritto dal: Oct 2006
Città: milano
Messaggi: 1439
Wow. Questo me l'ero perso, ai tempi non seguivo. PGI
ndakota è offline   Rispondi citando il messaggio o parte di esso
Old 20-08-2010, 17:05   #13
Nurring
Member
 
Iscritto dal: Jan 2006
Messaggi: 38
Quote:
Originariamente inviato da ndakota Guarda i messaggi
Wow. Questo me l'ero perso, ai tempi non seguivo. PGI
Eccomi...il "destinatario" del codice tre anni dopo....

Ancora oggi, dopo tre anni di lavoro pieno su Java e WebTechnology ,lo ringrazio
Grazie a lui la mia tesi è letteralmente volata ed è stata valutata con il massimo dei punti...
Nurring è offline   Rispondi citando il messaggio o parte di esso
Old 20-08-2010, 18:10   #14
banryu79
Senior Member
 
L'Avatar di banryu79
 
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
Quote:
Originariamente inviato da nucarote Guarda i messaggi
Riporto in alto tale topic per chiedere come si deve procedere in tal caso:
Quote:
Originariamente inviato da PGI-Bis
... Diverso è il caso di spostamenti tra JVM diverse o tra JVM e il window manager del sistema operativo. In questo caso occorre fornire una rappresentazione indipendente da Java e ricostruibile nativamente. Ma noi abbiamo la fortuna di trattare il caso più semplice ...
Grazie fin da ora per la vostre risposte.
Ciao nucaronte, ti aiuterei volentieri ma non mi sono mai cimentato con il Drag&Drop, percui non saprei, anche se sento puzza di API del window manage del SO specifico e JNI, almeno per quanto riguarda il secondo scenario tra i due indicati da PGI.

Comunque pare che PGI sia in vacanza o comunque lontano dal forum, almeno per un po'.

[FAN MODE ON]
Mitico questo thread, non l'avevo ancora letto.
E grande PGI!
__________________

As long as you are basically literate in programming, you should be able to express any logical relationship you understand.
If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it.
(Chris Crawford)
banryu79 è offline   Rispondi citando il messaggio o parte di esso
Old 20-08-2010, 18:51   #15
nucarote
Senior Member
 
Iscritto dal: Mar 2004
Messaggi: 2992
Quote:
Originariamente inviato da banryu79 Guarda i messaggi
Ciao nucaronte, ti aiuterei volentieri ma non mi sono mai cimentato con il Drag&Drop, percui non saprei, anche se sento puzza di API del window manage del SO specifico e JNI...
E' quello che penso pure io.
Mi aggiungo al fatto che questo sia uno di quei topic da mettere tra le guide.
nucarote è offline   Rispondi citando il messaggio o parte di esso
Old 20-08-2010, 18:55   #16
ndakota
Senior Member
 
L'Avatar di ndakota
 
Iscritto dal: Oct 2006
Città: milano
Messaggi: 1439
La cosa che più stupisce è la sua incredibile conoscenza della libreria standard di Java. Non pensavo nemmeno si potesse fare qualcosa del genere
ndakota è offline   Rispondi citando il messaggio o parte di esso
Old 23-08-2010, 10:39   #17
banryu79
Senior Member
 
L'Avatar di banryu79
 
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
Quote:
Originariamente inviato da ndakota Guarda i messaggi
La cosa che più stupisce è la sua incredibile conoscenza della libreria standard di Java.
Bhe, quello è il meno: "basta" studiare, con dedizione (il che implica un bel po' di tempo)
__________________

As long as you are basically literate in programming, you should be able to express any logical relationship you understand.
If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it.
(Chris Crawford)
banryu79 è offline   Rispondi citando il messaggio o parte di esso
Old 07-09-2010, 17:29   #18
banryu79
Senior Member
 
L'Avatar di banryu79
 
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
@nucarote: piccolo update.

Ovviamente non so se nel frattempo hai già risolto oppure abbandonato. Oggi mentre cercavo delle info nella bug parade, ho buttato l'occhio e ho visto che tra le 25 più votate, in prima posizione c'era una di queste due entry; contengo informazioni che potrebbero esserti utili (butta un occhio sui work-around):
- No way to set drag icon: TransferHandler.getVisualRepresentation() is not used
- invoking DragSource's startDrag with an Image renders no image on drag
__________________

As long as you are basically literate in programming, you should be able to express any logical relationship you understand.
If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it.
(Chris Crawford)

Ultima modifica di banryu79 : 08-09-2010 alle 13:24.
banryu79 è offline   Rispondi citando il messaggio o parte di esso
Old 08-09-2010, 12:41   #19
nucarote
Senior Member
 
Iscritto dal: Mar 2004
Messaggi: 2992
Per il momento tutto il "progettino" è fermo, comunque è molto più pulita della "soluzione" (a base di Observer) che avevo cominciato a pensare, ti ringrazio molto, ho provato il workaround proposto e mi sembra una buona soluzione, appena avrò un pò di tempo cercherò di svilupparlo meglio.
Comunque sarei nucarote
nucarote è offline   Rispondi citando il messaggio o parte di esso
Old 08-09-2010, 13:24   #20
banryu79
Senior Member
 
L'Avatar di banryu79
 
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
Quote:
Originariamente inviato da nucarote Guarda i messaggi
Comunque sarei nucarote
Facciamo caronte e non se ne parli più
(spiacente per il typo, ho corretto )
__________________

As long as you are basically literate in programming, you should be able to express any logical relationship you understand.
If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it.
(Chris Crawford)
banryu79 è offline   Rispondi citando il messaggio o parte di esso
 Rispondi


Ecovacs Deebot X11 Omnicyclone: niente più sacchetto per lo sporco Ecovacs Deebot X11 Omnicyclone: niente più...
Narwal Flow: con il mocio orizzontale lava i pavimenti al meglio Narwal Flow: con il mocio orizzontale lava i pav...
Panasonic 55Z95BEG cala gli assi: pannello Tandem e audio senza compromessi Panasonic 55Z95BEG cala gli assi: pannello Tande...
HONOR Magic V5: il pieghevole ultra sottile e completo! La recensione HONOR Magic V5: il pieghevole ultra sottile e co...
Recensione Google Pixel 10 Pro XL: uno zoom 100x assurdo sempre in tasca (e molto altro) Recensione Google Pixel 10 Pro XL: uno zoom 100x...
God of War: le riprese della serie TV ta...
Volkswagen ID. Cross Concept: design Pur...
DAZN e ACE smantellano "Calcio"...
Insta360 a IFA 2025: partnership con Lei...
Intel: il processo produttivo 14A sar&ag...
Fiat porta in Algeria la produzione di G...
Spazio Lenovo riapre a Milano. Cosa camb...
Prime foto di ID. Polo GTI: Volkswagen p...
BYD ha grandi novità per IAA: la ...
ASML investe 1,3 miliardi in Mistral AI ...
Tecnologia d'altri tempi e benessere del...
Come va il modem Apple C1 di iPhone 16e?...
smart alla IAA Mobility 2025, elogia i n...
Star Wars, chiusa l'asta per la spada or...
Nova Launcher è morto? Il fondato...
Chromium
GPU-Z
OCCT
LibreOffice Portable
Opera One Portable
Opera One 106
CCleaner Portable
CCleaner Standard
Cpu-Z
Driver NVIDIA GeForce 546.65 WHQL
SmartFTP
Trillian
Google Chrome Portable
Google Chrome 120
VirtualBox
Tutti gli articoli Tutte le news Tutti i download

Strumenti

Regole
Non Puoi aprire nuove discussioni
Non Puoi rispondere ai messaggi
Non Puoi allegare file
Non Puoi modificare i tuoi messaggi

Il codice vB è On
Le Faccine sono On
Il codice [IMG] è On
Il codice HTML è Off
Vai al Forum


Tutti gli orari sono GMT +1. Ora sono le: 15:27.


Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Served by www3v