I'm rewriting a Swing application in JavaFX, where I allow users to present multiple workspaces as either windows or tabs. However, my FX code will not display the contents moved from more than one tab into a new stage; only the contents of the currently-selected tab appear in my new stages. I've distilled my code into a small example below. Can anyone clue me in as to what's gone wrong?
package scenes;
import java.util.ArrayList;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class StageSwapper extends Application {
static public void main(String[] args) {
launch(args);
}
private TabPane tabs = new TabPane();
public void start(Stage stage) {
stage.setTitle("Stage Swapper");
BorderPane p = new BorderPane();
p.setCenter(tabs);
tabs.getTabs().addAll(new Swapee("First").createTab(), new Swapee("Second").createTab());
Scene s = new Scene(p);
stage.setScene(s);
stage.show();
launchSwap();
}
private void launchSwap() {
new Thread() {
public void run() {
try {
sleep(10000);
} catch (Exception e) {
e.printStackTrace();
}
Platform.runLater(new Runnable() {
public void run() {
for (Swapee s : Swapee.list) {
createWindow(s);
}
}
});
}
}.start();
}
public void createWindow(Swapee s) {
Stage window = new Stage();
window.setTitle("New Window");
window.setY(200);
window.setX(200);
BorderPane p = new BorderPane();
p.setCenter(s);
window.setScene(new Scene(p));
window.show();
}
}
class Swapee extends Label {
static private int count;
static ArrayList<Swapee> list = new ArrayList<>();
String name;
Swapee(String name) {
super("Swappable Item " + ++count);
this.name = name;
list.add(this);
}
Tab createTab() {
Tab t = new Tab(name);
t.setContent(this);
return t;
}
}
You haven't specified the size of the windows that you're creating. Right now they have width and length equal to 0. You may use the following approach:
BorderPane p = new BorderPane();
p.setPrefSize(Region.USE_COMPUTED_SIZE, Region.USE_COMPUTED_SIZE);
p.setCenter(s);
BorderPane will be resized according to its content and the window will be resized as well.
Related
I am new to JRI/rJava/JavaGD and have some problems with it. I drew a simple R plot with JRI and want to include this plot in my customized JFrame. I added the GDCanvas in which the plot should appear to my JFrame. However the plot is not displayed in the GDCanvas, but opens in a new Frame. How can I visualize my R plot in my JFrame, instead of appearing in its own frame?
For me, another possibility would be to modify the new frame in which my plot pops up. But I couldn't add or modify anything there either. Is there a special way to modify frames that appear with JavaGD()?
Can someone please help me? Many thanks in advance.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import org.rosuda.JRI.Rengine;
import org.rosuda.javaGD.GDCanvas;
public class RjavaGD extends JFrame implements ActionListener {
private Rengine engine;
public static GDCanvas gdc;
private JButton btn;
public RjavaGD() {
super();
super.setTitle("My R Plot");
btn = new JButton("show plot");
btn.addActionListener(this);
gdc = new GDCanvas(400, 400);
gdc.setBackground(Color.PINK);
this.getContentPane().setLayout(new BorderLayout());
this.getContentPane().add(btn, BorderLayout.PAGE_START);
this.getContentPane().add((GDCanvas) gdc, BorderLayout.CENTER);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.pack();
this.setVisible(true);
// initialize R
engine = new Rengine(new String[] { "--vanilla" }, false, null);
engine.eval("library(JavaGD)");
engine.eval("Sys.putenv('JAVAGD_CLASS_NAME'='RjavaGDInterface')");
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new RjavaGD();
}
});
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == btn) {
engine.eval("JavaGD()");
engine.eval("a <- c(1,2,3,2,4)");
engine.eval("plot(a,type=\"l\")");
gdc.initRefresh();
engine.end();
this.setTitle("new random plot");
}
}
}
import org.rosuda.javaGD.GDInterface;
public class RjavaGDInterface extends GDInterface {
public void gdOpen(double w, double h)
{
c = RjavaGD.gdc;
}
}
I used Sys.setenv() instead of Sys.putenv().
I also found a way to integrate the plot into my own customized frame, so that I can add buttons and other stuff directly below the plot, which was not possible with the standard frame that opens automatically.
This code worked fine for me:
import org.rosuda.JRI.Rengine;
import org.rosuda.javaGD.GDCanvas;
public class RjavaGD extends JFrame implements ActionListener {
private Rengine engine;
private JButton btn;
public RjavaGD() {
super();
super.setTitle("My R Plot");
btn = new JButton("show plot");
btn.addActionListener(this);
this.getContentPane().setLayout(new BorderLayout());
this.getContentPane().add(btn, BorderLayout.PAGE_START);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.pack();
this.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == btn) {
// initialize R
engine = new Rengine(new String[] { "--vanilla" }, false, null);
engine.eval("Sys.setenv('JAVAGD_CLASS_NAME'='RjavaGDInterface')");
engine.eval("library(JavaGD)");
engine.eval("JavaGD()");
engine.eval("a <- c(1,2,3,2,4)");
engine.eval("plot(a,type=\"l\")");
engine.end();
}
}
}
import org.rosuda.javaGD.GDInterface;
public class RjavaGDInterface extends GDInterface {
JFrame f;
#Override
public void gdOpen(double w, double h) {
super.gdOpen(w,h);
f = new JFrame();
f.setLayout(new BorderLayout());
c = new GDCanvas(w, h);
f.setTitle("New Plot");
f.getContentPane().add((GDCanvas) c, BorderLayout.CENTER);
f.getContentPane().add(buttonPanel(), BorderLayout.NORTH);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setVisible(true);
}
private JPanel buttonPanel(){
JPanel p = new JPanel();
p.setBackground(Color.pink);
p.add(new JLabel("Options“));
p.add(new JButton("option1“))
return p;
}
}
I hope this will help other people with the same problem :)
I have a problem and I have looked every where, so I am going to ask it: Do you need ContextAttribs? I have this error when I run my program:
org.lwjgl.LWJGLException: Could not create context (WGL_ARB_create_context)
at org.lwjgl.opengl.WindowsContextImplementation.nCreate(Native Method)
at org.lwjgl.opengl.WindowsContextImplementation.create(WindowsContextImplementation.java:50)
at org.lwjgl.opengl.ContextGL.<init>(ContextGL.java:132)
at org.lwjgl.opengl.Display.create(Display.java:850)
at org.lwjgl.opengl.Display.create(Display.java:797)
at renderEngine.DisplayManager.createDisplay(DisplayManager.java:22)
at engineTester.MainGameLoop.main(MainGameLoop.java:10)
Exception in thread "main" java.lang.IllegalStateException: Cannot determine close requested state of uncreated window
at org.lwjgl.opengl.Display.isCloseRequested(Display.java:549)
at engineTester.MainGameLoop.main(MainGameLoop.java:12)
This is my code(Main class):
import org.lwjgl.opengl.Display;
import renderEngine.DisplayManager;
public class MainGameLoop {
public static void main(String[] args) {
DisplayManager.createDisplay();
if (Display.isCloseRequested())
DisplayManager.closeDisplay();
while (true)
{
DisplayManager.updateDisplay();
}
}
Display Class:
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.ContextAttribs;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.PixelFormat;
import org.omg.CORBA.Context;
public class DisplayManager {
private static final int WIDTH = 1200;
private static final int HEIGHT = 650;
private static final int FPS_CAP = 60;
public static void createDisplay() {
ContextAttribs attribs = new ContextAttribs(3,2).withProfileCore(true).withForwardCompatible(true);
try {
Display.setDisplayMode(new DisplayMode(WIDTH, HEIGHT));
Display.create(new PixelFormat(), new ContextAttribs(3,2).withProfileCore(true).withForwardCompatible(true));
Display.setTitle("Knights of the Lord's Realm");
} catch (LWJGLException e) {
e.printStackTrace();
}
}
public static void updateDisplay() {
Display.sync(FPS_CAP);
}
public static void closeDisplay() {
Display.destroy();
}
}
Any ideas other than graphics card issue or even if I have to use "ContextAttribs"
Thanks!
ContextAttribs attribs = new ContextAttribs(3,2).withProfileCore(true).withForwardCompatible(true);
I'm assuming that you are follow "ThinMatrix" Youtube tutorial replace that line with
ContextAttribs attribs = new ContextAttribs(3,2);
attribs.withForwardCompatible(true);
attribs.withProfileCompatibility(true);
I want to create basic JUnit test for JavaFX 8 application. I have this simple code sample:
public class Main extends Application {
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Tabs");
Group root = new Group();
Scene scene = new Scene(root, 400, 250, Color.WHITE);
TabPane tabPane = new TabPane();
BorderPane borderPane = new BorderPane();
for (int i = 0; i < 5; i++) {
Tab tab = new Tab();
tab.setText("Tab" + i);
HBox hbox = new HBox();
hbox.getChildren().add(new Label("Tab" + i));
hbox.setAlignment(Pos.CENTER);
tab.setContent(hbox);
tabPane.getTabs().add(tab);
}
// bind to take available space
borderPane.prefHeightProperty().bind(scene.heightProperty());
borderPane.prefWidthProperty().bind(scene.widthProperty());
borderPane.setCenter(tabPane);
root.getChildren().add(borderPane);
primaryStage.setScene(scene);
primaryStage.show();
}
}
I only have this code so far:
import javafx.application.Application;
import javafx.stage.Stage;
import org.junit.BeforeClass;
public class BasicStart extends Application {
#BeforeClass
public static void initJFX() {
Thread t = new Thread("JavaFX Init Thread") {
#Override
public void run() {
Application.launch(BasicStart.class, new String[0]);
}
};
t.setDaemon(true);
t.start();
}
#Override
public void start(Stage primaryStage) throws Exception {
// noop
}
}
Can you tell me how I can create JUnit test for the above code?
I use a Junit Rule to run unit tests on the JavaFX thread. The details are in this post. Just copy the class from that post and then add this field to your unit tests.
#Rule public JavaFXThreadingRule javafxRule = new JavaFXThreadingRule();
This code works for both JavaFX 2 and JavaFX 8.
The easiest aproach is the following:
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.stage.Stage;
import org.junit.Test;
public class BasicStart {
#Test
public void testA() throws InterruptedException {
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
new JFXPanel(); // Initializes the JavaFx Platform
Platform.runLater(new Runnable() {
#Override
public void run() {
new Main().start(new Stage()); // Create and
// initialize
// your app.
}
});
}
});
thread.start();// Initialize the thread
Thread.sleep(10000); // Time to use the app, with out this, the thread
// will be killed before you can tell.
}
}
Hope it helps!
Based on Brian Blonski 's answer I created a JUnit-Testrunner, that does essentially the same thing, but is a bit simpler to use in my opinion.
Using it, your test would look like this:
#RunWith( JfxTestRunner.class )
public class MyUnitTest
{
#Test
public void testMyMethod()
{
//...
}
}
I am having some trouble with getting a JTree to redraw when an explicit call is made to its model (a call which I make once I have added some new nodes to it).
The code, which initially worked fine, fails now that the application is exported to RMI.
I store the DefaultTreeModel object in the Controller class, which is a Remote Object.
I add the DefaultTreeModel object to the JTree in my Client, using tree.addModel(controller.getModel());
I use an ActionListener subscribed to a button on the Client GUI to call a method in the Controller which performs the "Add new node" action.
I use a TreeModelListener to print a message to screen to prove that the Model Listener has fired.
Do Client side Swing listeners not work over RMI?
I have managed to reproduce the problem. I include the code for completeness but anticipate that someone will be able to reel off the answer based on experience.
Server Driver Class:
package server;
import java.io.IOException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import client.controller.TestTreeControllerService;
import server.controller.TestTreeControllerImpl;
public class TestTreeServerStart {
/**
* #param args
*/
public static void main(String[] args) {
new TestTreeServerStart();
}
public TestTreeServerStart() {
try {
LocateRegistry.createRegistry(1099);
TestTreeControllerService c = new TestTreeControllerImpl();
Registry registry = LocateRegistry.getRegistry();
registry.rebind("TestTreeControllerService", c);
System.out.println("Started the RMI Server");
}
catch (RemoteException e) {
System.out.println(e.getMessage());
}
}
}
Server Controller Implementation Class:
package server.controller;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import client.controller.TestTreeControllerService;
#SuppressWarnings("serial")
public class TestTreeControllerImpl extends UnicastRemoteObject implements TestTreeControllerService {
/**
*
*/
//private static final long serialVersionUID = -8137864611400855504L;
private DefaultTreeModel m ;
public DefaultTreeModel getModel() {
return m;
}
public TestTreeControllerImpl() throws RemoteException {
super();
m = new DefaultTreeModel(new DefaultMutableTreeNode("Root"));
}
public void addNodeAction() throws RemoteException {
DefaultTreeModel m = (DefaultTreeModel) getModel();
DefaultMutableTreeNode newNode = new DefaultMutableTreeNode("New Node");
DefaultMutableTreeNode root = (DefaultMutableTreeNode) m.getRoot();
root.add(newNode);
//m.insertNodeInto(newNode, (DefaultMutableTreeNode) m.getRoot(), m.getChildCount(m.getRoot()));
m.nodeStructureChanged(root);
}
}
Client Driver Class:
package client;
import java.rmi.Naming;
import java.rmi.RemoteException;
import client.controller.TestTreeControllerService;
import client.view.TreeTestClient;
public class TreeTestClientStart {
/**
* #param args
*/
public static void main(String[] args) {
try {
TestTreeControllerService c = (TestTreeControllerService) Naming.lookup("rmi://localhost:1099/TestTreeControllerService");
new TreeTestClient(c);
}
catch(RemoteException e) {
System.out.println("Remote service not found: " + e.getLocalizedMessage());
}
catch (Exception e) {
System.out.println("Splat");
}
}
}
Client Controller Interface:
package client.controller;
import javax.swing.tree.DefaultTreeModel;
public interface TestTreeControllerService extends java.rmi.Remote {
public DefaultTreeModel getModel() throws java.rmi.RemoteException;
public void addNodeAction() throws java.rmi.RemoteException;
}
Client UI:
package client.view;
import java.awt.Dimension;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import client.controller.TestTreeControllerService;
import client.view.action.AddNodeAction;
import client.view.action.RefreshTreeAction;
public class TreeTestClient {
private JTree t;
private TestTreeControllerService c;
public JTree getTree() {
return t;
}
public TestTreeControllerService getController() {
return c;
}
public void setTree(JTree tIn) {
t = tIn;
}
public TreeTestClient(TestTreeControllerService cIn) {
//Add controller
try {
c = cIn;
//Draw Frame & Panel - set dimensions
JFrame f = new JFrame();
f.setSize(new Dimension(800,600));
JPanel p = new JPanel();
p.setSize(new Dimension(800,600));
//Create a tree and add the Model from the Controller to it
t = new JTree();
t.setModel(c.getModel());
//Try a Tree Model Listener
t.getModel().addTreeModelListener(new RefreshTreeAction(this));
//Add listener to a button which adds nodes to the tree when clicked
JButton addNode = new JButton("Add node");
addNode.addActionListener(new AddNodeAction(this));
JScrollPane s = new JScrollPane(t);
p.add(s);
p.add(addNode);
p.setVisible(true);
f.add(p);
f.setVisible(true);
}
catch(Exception e) {
System.out.println("Splat");
}
}
}
*Client "Add Node" Action Listener (invokes Add Action in Controller) *
package client.view.action;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.rmi.RemoteException;
import javax.swing.table.DefaultTableModel;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import client.view.TreeTestClient;
public class AddNodeAction implements ActionListener {
private TreeTestClient treeTest;
public AddNodeAction(TreeTestClient treeTestIn) {
treeTest=treeTestIn;
}
#Override
public void actionPerformed(ActionEvent arg0) {
try {
treeTest.getController().addNodeAction();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Client "Refresh Action" Tree Listener (Prints to Screen to prove that Listener fired)
package client.view.action;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import client.view.TreeTestClient;
public class RefreshTreeAction implements PropertyChangeListener, TreeModelListener {
private TreeTestClient treeTest;
public RefreshTreeAction(TreeTestClient treeTestIn) {
treeTest = treeTestIn;
}
private void refreshTree() {
System.out.println("Refresh tree fired");
}
#Override
public void treeNodesChanged(TreeModelEvent arg0) {
refreshTree();
}
#Override
public void treeNodesInserted(TreeModelEvent arg0) {
refreshTree();
}
#Override
public void treeNodesRemoved(TreeModelEvent arg0) {
refreshTree();
}
#Override
public void treeStructureChanged(TreeModelEvent arg0) {
refreshTree();
}
#Override
public void propertyChange(PropertyChangeEvent arg0) {
refreshTree();
}
}
The TreeModel exported by the server is serialized to the client as the client's own copy. The server doesn't know anything about what happens to the client's copy, and the client doesn't know anything about what happens to the server's copy. They are not the same object.
By adding the following code to an ActionListener subscribed to a new button on the GUI, I have been able to examine the contents of the Model at the click of a button:
//Loop contents of model attached to Client Tree
for (int i=0; i<t.getModel().getChildCount(t.getModel().getRoot()); i++) {
System.out.println("From Tree: Row #" + i + ": " + t.getModel().getChild(t.getModel().getRoot(), i));
}
//Loop contents of model object stored in Controller
try {
for (int i=0; i<c.getModel().getChildCount(c.getModel().getRoot()); i++) {
System.out.println("From Controller: Row #" + i + ": " + c.getModel().getChild(c.getModel().getRoot(), i));
}
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
I found that the reference to the Client's Model was a different version to the state being maintained in the Controller's model object. There was no output in the Client loop, but the Controller's loop gave the correct state.
I have subsequently added a Swing Timer to the GUI to refresh the tree's model to match that of the Constructor. An updated GUI Class and GUI Refresh Action follow, which work:
Updated UI:
package client.view;
import java.awt.Dimension;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.Timer;
import client.controller.TestTreeControllerService;
import client.view.action.AddNodeAction;
import client.view.action.GUIRefreshAction;
import client.view.action.RefreshTreeAction;
public class TreeTestClient {
private JTree t;
private TestTreeControllerService c;
public JTree getTree() {
return t;
}
public TestTreeControllerService getController() {
return c;
}
public void setTree(JTree tIn) {
t = tIn;
}
public TreeTestClient(TestTreeControllerService cIn) {
//Add controller
try {
c = cIn;
//Draw Frame & Panel - set dimensions
JFrame f = new JFrame();
f.setSize(new Dimension(800,600));
JPanel p = new JPanel();
p.setSize(new Dimension(800,600));
//Create a tree and add the Model from the Controller to it
t = new JTree();
t.setModel(c.getModel());
//Try a listener that doesn't use the Remote object
t.addTreeSelectionListener(new RefreshTreeAction(this));
//Try a property change listener on the TreeModel
t.addPropertyChangeListener("treeModel", new RefreshTreeAction(this));
//Try a Tree Model Listener
t.getModel().addTreeModelListener(new RefreshTreeAction(this));
//Add listener to a button which adds nodes to the tree when clicked
JButton addNode = new JButton("Add node");
addNode.addActionListener(new AddNodeAction(this));
JScrollPane s = new JScrollPane(t);
//Add a GUI redraw timer
Timer timer = new Timer(1000, new GUIRefreshAction(this));
timer.setInitialDelay(1);
timer.start();
p.add(s);
p.add(addNode);
p.setVisible(true);
f.add(p);
f.setVisible(true);
}
catch(Exception e) {
System.out.println("Splat");
}
}
}
GUI Refresh Listener Class
package client.view.action;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.rmi.RemoteException;
import client.view.TreeTestClient;
public class GUIRefreshAction implements ActionListener {
private TreeTestClient client;
public GUIRefreshAction(TreeTestClient clientIn) {
client = clientIn;
}
#Override
public void actionPerformed(ActionEvent e) {
//Update the Tree's Model to match latest on Server
try {
client.getTree().setModel(client.getController().getModel());
} catch (RemoteException e1) {
e1.printStackTrace();
}
}
}
I hope this helps someone who has the same requirements for a RMI Client Swing GUI to update in reaction to changes on the Server.
I have two text fields and I can drag and drop the text between them. What I want is that every time I drag the text it will replace the existing text data with the text which was dragged and dropped.
import java.awt.Container;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JTextField;
public class DragDropText extends JFrame {
public static void main(String[] args) {
new DragDropText().setVisible(true);
}
public DragDropText() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JTextField field1 = new JTextField("Life's a drag", 20);
JTextField field2 = new JTextField("and then you drop", 20);
field1.setDragEnabled(true);
field2.setDragEnabled(true);
Container content = getContentPane();
content.setLayout(new BoxLayout(content, BoxLayout.Y_AXIS));
content.add(field1);
content.add(field2);
pack();
}
}
You can achieve the effect by creating and setting a subclass of TransferHandler.
This is an example that will work for any subclass of JTextComponent. You'll have to add the appropriate checks to make it robust.
You can find more info here: http://download.oracle.com/javase/tutorial/uiswing/dnd/transferhandler.html.
import java.io.*;
import java.awt.*;
import java.awt.datatransfer.*;
import javax.swing.*;
import javax.swing.text.*;
public class DragDropText extends JFrame {
public static void main(String[] args) {
new DragDropText().setVisible(true);
}
public DragDropText() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JTextField field1 = new JTextField("Life's a drag", 20);
JTextField field2 = new JTextField("and then you drop", 20);
field1.setDragEnabled(true);
field2.setDragEnabled(true);
field1.setTransferHandler(new CustomTransferHandler());
field2.setTransferHandler(new CustomTransferHandler());
Container content = getContentPane();
content.setLayout(new BoxLayout(content, BoxLayout.Y_AXIS));
content.add(field1);
content.add(field2);
pack();
}
}
class CustomTransferHandler extends TransferHandler {
public int getSourceActions(JComponent c) {
return COPY_OR_MOVE;
}
public Transferable createTransferable(JComponent c) {
return new StringSelection(((JTextComponent) c).getSelectedText());
}
public void exportDone(JComponent c, Transferable t, int action) {
if(action == MOVE)
((JTextComponent) c).replaceSelection("");
}
public boolean canImport(TransferSupport ts) {
return ts.getComponent() instanceof JTextComponent;
}
public boolean importData(TransferSupport ts) {
try {
((JTextComponent) ts.getComponent())
.setText((String) ts
.getTransferable()
.getTransferData(DataFlavor.stringFlavor));
return true;
} catch(UnsupportedFlavorException e) {
return false;
} catch(IOException e) {
return false;
}
}
}