How can I open file explorer, select a photo file, add some effects, and then save it but by opening file explorer to let me choose where to save the new photo with effect added. I have no idea. Please help me.
public class Imagine extends JFrame {
DisplayPanel displayPanel;
JButton brightenButton, darkenButton, contrastIncButton, contrastDecButton, reverseButton, resetButton, addPhotoButton,savePhoto;
public Imagine()
{
super();
Container container = getContentPane();
displayPanel = new DisplayPanel();
container.add(displayPanel);
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(4, 4));
panel.setBorder(new TitledBorder("Choose option"));
addPhotoButton = new JButton("Select photo");
addPhotoButton.addActionListener(new ButtonListener());
savePhoto = new JButton("Save photo");
savePhoto.addActionListener(new ButtonListener());
brightenButton = new JButton("Luminozitate +");
brightenButton.addActionListener(new ButtonListener());
darkenButton = new JButton("Luminozitate -");
darkenButton.addActionListener(new ButtonListener());
contrastIncButton = new JButton("Contrast +");
contrastIncButton.addActionListener(new ButtonListener());
contrastDecButton = new JButton("Contrast -");
contrastDecButton.addActionListener(new ButtonListener());
reverseButton = new JButton("Negative");
reverseButton.addActionListener(new ButtonListener());
resetButton = new JButton("Reset");
resetButton.addActionListener(new ButtonListener());
panel.add(addPhotoButton);
panel.add(savePhoto);
panel.add(brightenButton);
panel.add(darkenButton);
panel.add(contrastIncButton);
panel.add(contrastDecButton);
panel.add(reverseButton);
panel.add(resetButton);
container.add(BorderLayout.SOUTH, panel);
addWindowListener(new WindowEventHandler());
setSize(displayPanel.getWidth(), displayPanel.getHeight() + 25);
show();
}
class WindowEventHandler extends WindowAdapter
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
}
public static void main(String arg[])
{
new Imagine();
//select file
//ImagesLoading a = new ImagesLoading();
//a.initialize();
}
class ButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
JButton button = (JButton) e.getSource();
if (button.equals(brightenButton))
{
displayPanel.brightenLUT();
displayPanel.applyFilter();
displayPanel.repaint();
}
else
if (button.equals(darkenButton))
{
displayPanel.darkenLUT();
displayPanel.applyFilter();
displayPanel.repaint();
}
else
if (button.equals(contrastIncButton))
{
displayPanel.contrastIncLUT();
displayPanel.applyFilter();
displayPanel.repaint();
} else
if (button.equals(contrastDecButton))
{
displayPanel.contrastDecLUT();
displayPanel.applyFilter();
displayPanel.repaint();
}
else
if (button.equals(reverseButton))
{
displayPanel.reverseLUT();
displayPanel.applyFilter();
displayPanel.repaint();
} else
if (button.equals(resetButton))
{
displayPanel.reset();
displayPanel.repaint();
}
else
if (button.equals(addPhotoButton))
{
JFrame fr = new JFrame("Image loading program Using awt");
FileDialog fd = new FileDialog(fr, "Open", FileDialog.LOAD);
fd.show();
String d = (fd.getDirectory() + fd.getFile());
System.out.println(d);
}
else
if (button.equals(savePhoto))
{
//
}
}
}
}
class DisplayPanel extends JPanel
{
Image displayImage;
BufferedImage bi;
Graphics2D big;
LookupTable lookupTable;
DisplayPanel()
{
setBackground(Color.black); // panel background color
loadImage();
setSize(displayImage.getWidth(this), displayImage.getWidth(this)); // panel
createBufferedImage();
}
public void loadImage()
{
displayImage = Toolkit.getDefaultToolkit().getImage("a.jpg");
MediaTracker mt = new MediaTracker(this);
mt.addImage(displayImage, 1);
try {
mt.waitForAll();
} catch (Exception e) {
System.out.println("exception while loading.");
}
if (displayImage.getWidth(this) == -1) {
System.out.println("no jpg file");
System.exit(0);
}
}
public void createBufferedImage()
{
bi = new BufferedImage(displayImage.getWidth(this), displayImage.getHeight(this), BufferedImage.TYPE_INT_ARGB);
big = bi.createGraphics();
big.drawImage(displayImage, 0, 0, this);
}
public void brightenLUT()
{
short brighten[] = new short[256];
for (int i = 0; i < 256; i++) {
short pixelValue = (short) (i + 10);
if (pixelValue > 255)
pixelValue = 255;
else if (pixelValue < 0)
pixelValue = 0;
brighten[i] = pixelValue;
}
lookupTable = new ShortLookupTable(0, brighten);
}
public void darkenLUT()
{
short brighten[] = new short[256];
for (int i = 0; i < 256; i++) {
short pixelValue = (short) (i - 10);
if (pixelValue > 255)
pixelValue = 255;
else if (pixelValue < 0)
pixelValue = 0;
brighten[i] = pixelValue;
}
lookupTable = new ShortLookupTable(0, brighten);
}
public void contrastIncLUT()
{
short brighten[] = new short[256];
for (int i = 0; i < 256; i++) {
short pixelValue = (short) (i * 1.2);
if (pixelValue > 255)
pixelValue = 255;
else if (pixelValue < 0)
pixelValue = 0;
brighten[i] = pixelValue;
}
lookupTable = new ShortLookupTable(0, brighten);
}
public void contrastDecLUT()
{
short brighten[] = new short[256];
for (int i = 0; i < 256; i++) {
short pixelValue = (short) (i / 1.2);
if (pixelValue > 255)
pixelValue = 255;
else if (pixelValue < 0)
pixelValue = 0;
brighten[i] = pixelValue;
}
lookupTable = new ShortLookupTable(0, brighten);
}
public void reverseLUT()
{
byte reverse[] = new byte[256];
for (int i = 0; i < 256; i++) {
reverse[i] = (byte) (255 - i);
}
lookupTable = new ByteLookupTable(0, reverse);
}
public void reset()
{
big.setColor(Color.black);
big.clearRect(0, 0, bi.getWidth(this), bi.getHeight(this));
big.drawImage(displayImage, 0, 0, this);
}
public void applyFilter()
{
LookupOp lop = new LookupOp(lookupTable, null);
lop.filter(bi, bi);
}
public void update(Graphics g)
{
g.clearRect(0, 0, getWidth(), getHeight());
paintComponent(g);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2D = (Graphics2D) g;
g2D.drawImage(bi, 0, 0, this);
}
}
How to save the added photo with new effects that I selected to a location that I can select from file explorer
How can I open file explorer, select a photo file, add some effects, and then save it but by opening file explorer to let me choose where to save the new photo with effect added. I have no idea. Please help me.
I have a simple task to implement, it works quite ok, but I am facing a very tricky issue regarding custom drag images in Swing.
The idea behind the task is just to allow the user to perform some DND between a list component and a text component, but during the drag operation to display following the mouse the exact same drawing as the renderer inside the list.
For this I use the cell renderer for the selected elements in the list and paint it over a temporary image. Then send this image to the TransferHandler and everything is fine. The problem is evident when I modify the size of the overall component and make it larger. After a certain extent, the picture that is draw no longer appears correct, but instead it has some gradient applied to it, making the content difficult to read. Following is a snippet of code that reproduces the issue:
import java.awt.Color;
import java.awt.Component;
import java.awt.GridLayout;
import javax.swing.DefaultListCellRenderer;
import javax.swing.DefaultListModel;
import javax.swing.DropMode;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
public class BasicTextListDND {
private JList<String> makeList() {
DefaultListModel<String> m = new DefaultListModel<String>();
for(int i = 0; i<10; i++) {
m.addElement("Element "+i);
}
JList<String> list = new JList<String>(m);
list.setTransferHandler(new BasicListTransferHandler());
list.setDropMode(DropMode.ON_OR_INSERT);
list.setDragEnabled(true);
list.setCellRenderer(new DefaultListCellRenderer() {
/**
* Comment for <code>serialVersionUID</code>
*/
private static final long serialVersionUID = 1L;
/** {#inheritDoc} */
public Component getListCellRendererComponent(JList<?> list, Object value, int index,
boolean isSelected, boolean cellHasFocus) {
Component listCellRendererComponent = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (cellHasFocus == false && isSelected == false) {
if (index % 2 == 0) {
listCellRendererComponent.setBackground(Color.RED);
} else if (index % 3==0) {
listCellRendererComponent.setBackground(Color.GREEN);
} else {
listCellRendererComponent.setBackground(Color.BLUE);
}
}
return listCellRendererComponent;
}
});
return list;
}
private JTextArea makeTextArea() {
JTextArea textArea = new JTextArea("Drag here from JList!");
return textArea;
}
public JComponent makeUI() {
JPanel panel = new JPanel(new GridLayout(2,1));
panel.add(new JScrollPane(makeTextArea()));
panel.add(new JScrollPane(makeList()));
return panel;
}
private static void createAndShowGUI() {
JFrame f = new JFrame("BasicDnD");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
BasicTextListDND app = new BasicTextListDND();
JComponent appContent = app.makeUI();
f.setContentPane(appContent);
f.setSize(600, 320);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
createAndShowGUI();
}
});
}
}
/**
*
*/
public class BasicListTransferHandler extends TransferHandler {
/**
* Comment for <code>serialVersionUID</code>
*/
private static final long serialVersionUID = 1L;
#Override
public boolean canImport(TransferHandler.TransferSupport info) {
if (!info.isDataFlavorSupported(DataFlavor.stringFlavor)) {
return false;
}
JList.DropLocation dl = (JList.DropLocation)info.getDropLocation();
if (dl.getIndex() == -1) {
return false;
}
return true;
}
#Override
public int getSourceActions(JComponent c) {
BufferedImage dragImage = makeImageFromString(c);
if (dragImage != null) {
setDragImage(dragImage);
Point mousePosition = c.getMousePosition();
if (mousePosition != null) {
setDragImageOffset(mousePosition);
}
}
return COPY;
}
private final JPanel tempDrawPanel = new JPanel();
private BufferedImage createDragImage(JList<String> list) {
int width = 0;
int height = 0;
int[] selectedIndices = list.getSelectedIndices();
for(int i =0; i<selectedIndices.length; i++){
int idx = selectedIndices[i];
Rectangle cellBounds = list.getCellBounds(idx, idx);
height += cellBounds.height;
width = Math.max(width, cellBounds.width); // we want to create a drag image as big as the largest cell
}
BufferedImage br = null;
if (width > 0 && height > 0) {
br = list.getGraphicsConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT);
}
return br;
}
private BufferedImage makeImageFromString(JComponent src) {
JList<String> sourceList = (JList<String>)src;
BufferedImage br = createDragImage(sourceList);
if (br != null) {
int[] selectedIndices = sourceList.getSelectedIndices();
int yD = 0;
Graphics g = br.getGraphics();
try{
for(int idx: selectedIndices) {
ListCellRenderer<? super String> cellRenderer = sourceList.getCellRenderer();
String valueAt = sourceList.getModel().getElementAt(idx);
Component c = cellRenderer.getListCellRendererComponent(sourceList, valueAt, idx, false, false);
Rectangle itemCellBounds = sourceList.getCellBounds(idx, idx);
SwingUtilities.paintComponent(g, c, tempDrawPanel, itemCellBounds.x, yD, itemCellBounds.width, itemCellBounds.height);
yD = itemCellBounds.y+itemCellBounds.height;
}
}finally {
g.dispose();
}
br.coerceData(true);
}
return br;
}
#Override
protected Transferable createTransferable(JComponent c) {
JList<String> list = (JList<String>)c;
List<String> selectedValuesList = list.getSelectedValuesList();
StringBuffer buff = new StringBuffer();
for (int i = 0; i < selectedValuesList.size(); i++) {
String val = selectedValuesList.get(i);
buff.append(val == null ? "" : val.toString());
if (i != selectedValuesList.size()- 1) {
buff.append("\n");
}
}
return new StringSelection(buff.toString());
}
}
The problem lies, I think, somewhere in the makeImageFromString method, but after 2 days of digging through Swing/AWT libraries and understanding how the drag image is drawn, I still fail to fix this issue. The bottom-line question: is there any obscure logic in AWT that applies this gradient if the drag image is over a certain size?
Any help would be greatly appreciated!
Marius.
How about translates the origin of the graphics context:
//SwingUtilities.paintComponent(g, c, tempDrawPanel, itemCellBounds.x, yD, itemCellBounds.width, itemCellBounds.height);
//yD = itemCellBounds.y+itemCellBounds.height;
SwingUtilities.paintComponent(g, c, tempDrawPanel, 0, 0, itemCellBounds.width, itemCellBounds.height);
g.translate(0, itemCellBounds.height);
Edit:
#user3619696: I misunderstood.
I would guess that the "blurred drag image" opacity depend on the Windows desktop theme. So try using translucent JWindow instead of TransferHandler#setDragImage(...).
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.dnd.*;
import java.awt.image.*;
import java.util.List;
import javax.swing.*;
public class BasicTextListDND2 {
private JList<String> makeList() {
DefaultListModel<String> m = new DefaultListModel<String>();
for(int i = 0; i<10; i++) {
m.addElement("Element "+i);
}
JList<String> list = new JList<String>(m);
list.setTransferHandler(new BasicListTransferHandler());
list.setDropMode(DropMode.ON_OR_INSERT);
list.setDragEnabled(true);
list.setCellRenderer(new DefaultListCellRenderer() {
/**
* Comment for <code>serialVersionUID</code>
*/
private static final long serialVersionUID = 1L;
/** {#inheritDoc} */
public Component getListCellRendererComponent(JList<?> list, Object value, int index,
boolean isSelected, boolean cellHasFocus) {
Component listCellRendererComponent = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (cellHasFocus == false && isSelected == false) {
if (index % 2 == 0) {
listCellRendererComponent.setBackground(Color.RED);
} else if (index % 3==0) {
listCellRendererComponent.setBackground(Color.GREEN);
} else {
listCellRendererComponent.setBackground(Color.BLUE);
}
}
return listCellRendererComponent;
}
});
return list;
}
private JTextArea makeTextArea() {
JTextArea textArea = new JTextArea("Drag here from JList!");
return textArea;
}
public JComponent makeUI() {
JPanel panel = new JPanel(new GridLayout(2,1));
panel.add(new JScrollPane(makeTextArea()));
panel.add(new JScrollPane(makeList()));
return panel;
}
private static void createAndShowGUI() {
JFrame f = new JFrame("BasicDnD");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
BasicTextListDND2 app = new BasicTextListDND2();
JComponent appContent = app.makeUI();
f.setContentPane(appContent);
f.setSize(600, 320);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
createAndShowGUI();
}
});
}
}
/**
*
*/
class BasicListTransferHandler extends TransferHandler {
/**
* Comment for <code>serialVersionUID</code>
*/
private static final long serialVersionUID = 1L;
private final JLabel label = new JLabel() {
#Override public boolean contains(int x, int y) {
return false;
}
};
private final JWindow window = new JWindow();
public BasicListTransferHandler() {
super();
window.add(label);
//window.setBackground(new Color(0, true));
window.setOpacity(.8f);
DragSource.getDefaultDragSource().addDragSourceMotionListener(new DragSourceMotionListener() {
#Override public void dragMouseMoved(DragSourceDragEvent dsde) {
Point pt = dsde.getLocation();
pt.translate(10, 10); // offset
if (!window.isVisible()) {
window.setVisible(true);
}
window.setLocation(pt);
}
});
}
#Override protected void exportDone(JComponent c, Transferable data, int action) {
super.exportDone(c, data, action);
window.setVisible(false);
}
#Override
public boolean canImport(TransferHandler.TransferSupport info) {
if (!info.isDataFlavorSupported(DataFlavor.stringFlavor)) {
return false;
}
JList.DropLocation dl = (JList.DropLocation)info.getDropLocation();
if (dl.getIndex() == -1) {
return false;
}
return true;
}
#Override
public int getSourceActions(JComponent c) {
BufferedImage dragImage = makeImageFromString(c);
if (dragImage != null) {
//setDragImage(dragImage);
//Point mousePosition = c.getMousePosition();
//if (mousePosition != null) {
// setDragImageOffset(mousePosition);
//}
label.setIcon(new ImageIcon(dragImage));
window.setLocation(-2000, -2000);
window.pack();
}
return COPY;
}
private final JPanel tempDrawPanel = new JPanel();
private BufferedImage createDragImage(JList<String> list) {
int width = 0;
int height = 0;
int[] selectedIndices = list.getSelectedIndices();
for(int i =0; i<selectedIndices.length; i++){
int idx = selectedIndices[i];
Rectangle cellBounds = list.getCellBounds(idx, idx);
height += cellBounds.height;
width = Math.max(width, cellBounds.width); // we want to create a drag image as big as the largest cell
}
BufferedImage br = null;
if (width > 0 && height > 0) {
br = list.getGraphicsConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT);
}
return br;
}
private BufferedImage makeImageFromString(JComponent src) {
JList<String> sourceList = (JList<String>)src;
BufferedImage br = createDragImage(sourceList);
if (br != null) {
int[] selectedIndices = sourceList.getSelectedIndices();
int yD = 0;
Graphics g = br.getGraphics();
try{
for(int idx: selectedIndices) {
ListCellRenderer<? super String> cellRenderer = sourceList.getCellRenderer();
String valueAt = sourceList.getModel().getElementAt(idx);
Component c = cellRenderer.getListCellRendererComponent(sourceList, valueAt, idx, false, false);
Rectangle itemCellBounds = sourceList.getCellBounds(idx, idx);
//SwingUtilities.paintComponent(g, c, tempDrawPanel, itemCellBounds.x, itemCellBounds.y + yD, itemCellBounds.width, itemCellBounds.height);
//yD = itemCellBounds.y+itemCellBounds.height;
SwingUtilities.paintComponent(g, c, tempDrawPanel, 0, 0, itemCellBounds.width, itemCellBounds.height);
g.translate(0, itemCellBounds.height);
}
}finally {
g.dispose();
}
br.coerceData(true);
}
return br;
}
#Override
protected Transferable createTransferable(JComponent c) {
JList<String> list = (JList<String>)c;
List<String> selectedValuesList = list.getSelectedValuesList();
StringBuffer buff = new StringBuffer();
for (int i = 0; i < selectedValuesList.size(); i++) {
String val = selectedValuesList.get(i);
buff.append(val == null ? "" : val.toString());
if (i != selectedValuesList.size()- 1) {
buff.append("\n");
}
}
return new StringSelection(buff.toString());
}
}
I have two SWT Tables in a Shell.
When the user clicks on a row in one table, I want the corresponding row in the next Table to be selected too.
However, in the current setup (I'm demonstrating with a Snippet I found online) when one row is clicked, the corresponding row is highlighted too but it's in grey. I'd like the selection to be the same purple everywhere.
The Source Code:
import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;
public class Snippet234 {
public static void main (String [] args) {
int rowCount = 40;
int columnCount = 15;
final Display display = new Display ();
Shell shell = new Shell (display);
shell.setLayout(new FillLayout());
Composite parent = new Composite(shell, SWT.BORDER);
GridLayout layout = new GridLayout(2, false);
layout.marginWidth = layout.marginHeight = layout.horizontalSpacing = 0;
parent.setLayout(layout);
final Table leftTable = new Table(parent, SWT.MULTI | SWT.FULL_SELECTION);
leftTable.setLayoutData(new GridData(SWT.LEFT, SWT.FILL, false, true));
leftTable.setHeaderVisible(true);
final Table rightTable = new Table(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION);
rightTable.setHeaderVisible(true);
GridData table2Data = new GridData(SWT.FILL, SWT.FILL, true, true, 1, 2);
rightTable.setLayoutData(table2Data);
// Create columns
TableColumn column1 = new TableColumn(leftTable, SWT.NONE);
column1.setText("Name");
column1.setWidth(150);
for (int i = 0; i < columnCount; i++) {
TableColumn column = new TableColumn(rightTable, SWT.NONE);
column.setText("Value "+i);
column.setWidth(200);
}
// Create rows
for (int i = 0; i < rowCount; i++) {
TableItem item = new TableItem(leftTable, SWT.NONE);
item.setText("item "+i);
item = new TableItem(rightTable, SWT.NONE);
for (int j = 0; j < columnCount; j++) {
item.setText(j, "Item "+i+" value # "+j);
}
}
// Make selection the same in both tables
leftTable.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event event) {
rightTable.setSelection(leftTable.getSelectionIndices());
}
});
rightTable.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event event) {
leftTable.setSelection(rightTable.getSelectionIndices());
}
});
// On Windows, the selection is gray if the table does not have focus.
// To make both tables appear in focus, draw the selection background here.
// This part only works on version 3.2 or later.
/*
Listener eraseListener = new Listener() {
public void handleEvent(Event event) {
event.detail &= ~SWT.HOT;
if((event.detail & SWT.SELECTED) != 0) {
GC gc = event.gc;
Rectangle rect = event.getBounds();
gc.setForeground(display.getSystemColor(SWT.COLOR_LIST_SELECTION_TEXT));
gc.setBackground(display.getSystemColor(SWT.COLOR_LIST_SELECTION));
gc.fillRectangle(rect);
event.detail &= ~SWT.SELECTED;
}
}
};
leftTable.addListener(SWT.EraseItem, eraseListener);
rightTable.addListener(SWT.EraseItem, eraseListener);
*/
// Make vertical scrollbars scroll together
ScrollBar vBarLeft = leftTable.getVerticalBar();
vBarLeft.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event event) {
rightTable.setTopIndex(leftTable.getTopIndex());
}
});
ScrollBar vBarRight = rightTable.getVerticalBar();
vBarRight.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event event) {
leftTable.setTopIndex(rightTable.getTopIndex());
}
});
// Horizontal bar on second table takes up a little extra space.
// To keep vertical scroll bars in sink, force table1 to end above
// horizontal scrollbar
ScrollBar hBarRight = rightTable.getHorizontalBar();
Label spacer = new Label(parent, SWT.NONE);
GridData spacerData = new GridData();
spacerData.heightHint = hBarRight.getSize().y;
spacer.setVisible(false);
parent.setBackground(leftTable.getBackground());
shell.setSize(600, 400);
shell.open ();
while (!shell.isDisposed ()) {
if (!display.readAndDispatch ()) display.sleep ();
}
display.dispose ();
}
}
Ok, I threw something together for you. Don't mind the crappy way of handling the selection, that's not what I want to show. The important part is where I draw the background of the item, i.e. the MyLabelProviders paint() method:
public static void main(String[] args)
{
Display display = new Display();
final Shell shell = new Shell(display);
shell.setText("StackOverflow");
shell.setLayout(new FillLayout());
final TableViewer first = new TableViewer(shell);
addColumn(first);
first.setContentProvider(ArrayContentProvider.getInstance());
final List<MyObject> firstInput = getInput();
first.setInput(firstInput);
first.setLabelProvider(new MyLabelProvider());
final TableViewer second = new TableViewer(shell);
addColumn(second);
second.setContentProvider(ArrayContentProvider.getInstance());
final List<MyObject> secondInput = getInput();
second.setInput(secondInput);
second.setLabelProvider(new MyLabelProvider());
first.addSelectionChangedListener(new ISelectionChangedListener()
{
#Override
public void selectionChanged(SelectionChangedEvent e)
{
int index = first.getTable().getSelectionIndex();
second.getTable().setSelection(index);
setSelection(firstInput, index);
setSelection(secondInput, index);
}
});
second.addSelectionChangedListener(new ISelectionChangedListener()
{
#Override
public void selectionChanged(SelectionChangedEvent e)
{
int index = second.getTable().getSelectionIndex();
first.getTable().setSelection(index);
setSelection(firstInput, index);
setSelection(secondInput, index);
}
});
shell.pack();
shell.open();
while (!shell.isDisposed())
{
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
private static void setSelection(List<MyObject> input, int index)
{
for(MyObject obj : input)
{
obj.setSelected(false);
}
input.get(index).setSelected(true);
}
private static List<MyObject> getInput()
{
List<MyObject> result = new ArrayList<MyObject>();
result.add(new MyObject("First"));
result.add(new MyObject("Second"));
result.add(new MyObject("Third"));
return result;
}
private static void addColumn(TableViewer viewer)
{
TableViewerColumn col = new TableViewerColumn(viewer, SWT.NONE);
col.getColumn().setWidth(200);
col.getColumn().setText("Name:");
col.setLabelProvider(new ColumnLabelProvider()
{
#Override
public String getText(Object element)
{
MyObject value = (MyObject) element;
return value.getName();
}
});
}
private static class MyObject
{
private String name;
private boolean isSelected;
public MyObject(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public boolean isSelected()
{
return isSelected;
}
public void setSelected(boolean isSelected)
{
this.isSelected = isSelected;
}
#Override
public String toString()
{
return name;
}
}
private static class MyLabelProvider extends StyledCellLabelProvider
{
#Override
protected void paint(Event event, Object element)
{
int width = 1000;
int x = event.x - 2;
int y = event.y;
int height = event.height;
GC gc = event.gc;
MyObject object = (MyObject) element;
Color oldBackground = gc.getBackground();
Color color = object.isSelected ? Display.getCurrent().getSystemColor(SWT.COLOR_LIST_SELECTION) : Display.getCurrent().getSystemColor(SWT.COLOR_LIST_BACKGROUND);
gc.setBackground(color);
gc.fillRectangle(x, y, width, height);
gc.setBackground(oldBackground);
super.paint(event, element);
}
}
Here are two screenshots after selecting the first and then the third row (doesn't matter which TableViewer):
How do I implement a draggable tab using Java Swing? Instead of the static JTabbedPane I would like to drag-and-drop a tab to different position to rearrange the tabs.
EDIT: The Java Tutorials - Drag and Drop and Data Transfer.
Curses! Beaten to the punch by a Google search. Unfortunately it's true there is no easy way to create draggable tab panes (or any other components) in Swing. So whilst the example above is complete this one I've just written is a bit simpler. So it will hopefully demonstrate the more advanced techniques involved a bit clearer. The steps are:
Detect that a drag has occurred
Draw the dragged tab to an offscreen buffer
Track the mouse position whilst dragging occurs
Draw the tab in the buffer on top of the component.
The above example will give you what you want but if you want to really understand the techniques applied here it might be a better exercise to round off the edges of this example and add the extra features demonstrated above to it.
Or maybe I'm just disappointed because I spent time writing this solution when one already existed :p
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.image.BufferedImage;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTabbedPane;
public class DraggableTabbedPane extends JTabbedPane {
private boolean dragging = false;
private Image tabImage = null;
private Point currentMouseLocation = null;
private int draggedTabIndex = 0;
public DraggableTabbedPane() {
super();
addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent e) {
if(!dragging) {
// Gets the tab index based on the mouse position
int tabNumber = getUI().tabForCoordinate(DraggableTabbedPane.this, e.getX(), e.getY());
if(tabNumber >= 0) {
draggedTabIndex = tabNumber;
Rectangle bounds = getUI().getTabBounds(DraggableTabbedPane.this, tabNumber);
// Paint the tabbed pane to a buffer
Image totalImage = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics totalGraphics = totalImage.getGraphics();
totalGraphics.setClip(bounds);
// Don't be double buffered when painting to a static image.
setDoubleBuffered(false);
paintComponent(totalGraphics);
// Paint just the dragged tab to the buffer
tabImage = new BufferedImage(bounds.width, bounds.height, BufferedImage.TYPE_INT_ARGB);
Graphics graphics = tabImage.getGraphics();
graphics.drawImage(totalImage, 0, 0, bounds.width, bounds.height, bounds.x, bounds.y, bounds.x + bounds.width, bounds.y+bounds.height, DraggableTabbedPane.this);
dragging = true;
repaint();
}
} else {
currentMouseLocation = e.getPoint();
// Need to repaint
repaint();
}
super.mouseDragged(e);
}
});
addMouseListener(new MouseAdapter() {
public void mouseReleased(MouseEvent e) {
if(dragging) {
int tabNumber = getUI().tabForCoordinate(DraggableTabbedPane.this, e.getX(), 10);
if(tabNumber >= 0) {
Component comp = getComponentAt(draggedTabIndex);
String title = getTitleAt(draggedTabIndex);
removeTabAt(draggedTabIndex);
insertTab(title, null, comp, null, tabNumber);
}
}
dragging = false;
tabImage = null;
}
});
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// Are we dragging?
if(dragging && currentMouseLocation != null && tabImage != null) {
// Draw the dragged tab
g.drawImage(tabImage, currentMouseLocation.x, currentMouseLocation.y, this);
}
}
public static void main(String[] args) {
JFrame test = new JFrame("Tab test");
test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
test.setSize(400, 400);
DraggableTabbedPane tabs = new DraggableTabbedPane();
tabs.addTab("One", new JButton("One"));
tabs.addTab("Two", new JButton("Two"));
tabs.addTab("Three", new JButton("Three"));
tabs.addTab("Four", new JButton("Four"));
test.add(tabs);
test.setVisible(true);
}
}
I liked Terai Atsuhiro san's DnDTabbedPane, but I wanted more from it. The original Terai implementation transfered tabs within the TabbedPane, but it would be nicer if I could drag from one TabbedPane to another.
Inspired by #Tom's effort, I decided to modify the code myself.
There are some details I added. For example, the ghost tab now slides along the tabbed pane instead of moving together with the mouse.
setAcceptor(TabAcceptor a_acceptor) should let the consumer code decide whether to let one tab transfer from one tabbed pane to another. The default acceptor always returns true.
/** Modified DnDTabbedPane.java
* http://java-swing-tips.blogspot.com/2008/04/drag-and-drop-tabs-in-jtabbedpane.html
* originally written by Terai Atsuhiro.
* so that tabs can be transfered from one pane to another.
* eed3si9n.
*/
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.dnd.*;
import java.awt.geom.*;
import java.awt.image.*;
import javax.swing.*;
public class DnDTabbedPane extends JTabbedPane {
public static final long serialVersionUID = 1L;
private static final int LINEWIDTH = 3;
private static final String NAME = "TabTransferData";
private final DataFlavor FLAVOR = new DataFlavor(
DataFlavor.javaJVMLocalObjectMimeType, NAME);
private static GhostGlassPane s_glassPane = new GhostGlassPane();
private boolean m_isDrawRect = false;
private final Rectangle2D m_lineRect = new Rectangle2D.Double();
private final Color m_lineColor = new Color(0, 100, 255);
private TabAcceptor m_acceptor = null;
public DnDTabbedPane() {
super();
final DragSourceListener dsl = new DragSourceListener() {
public void dragEnter(DragSourceDragEvent e) {
e.getDragSourceContext().setCursor(DragSource.DefaultMoveDrop);
}
public void dragExit(DragSourceEvent e) {
e.getDragSourceContext()
.setCursor(DragSource.DefaultMoveNoDrop);
m_lineRect.setRect(0, 0, 0, 0);
m_isDrawRect = false;
s_glassPane.setPoint(new Point(-1000, -1000));
s_glassPane.repaint();
}
public void dragOver(DragSourceDragEvent e) {
//e.getLocation()
//This method returns a Point indicating the cursor location in screen coordinates at the moment
TabTransferData data = getTabTransferData(e);
if (data == null) {
e.getDragSourceContext().setCursor(
DragSource.DefaultMoveNoDrop);
return;
} // if
/*
Point tabPt = e.getLocation();
SwingUtilities.convertPointFromScreen(tabPt, DnDTabbedPane.this);
if (DnDTabbedPane.this.contains(tabPt)) {
int targetIdx = getTargetTabIndex(tabPt);
int sourceIndex = data.getTabIndex();
if (getTabAreaBound().contains(tabPt)
&& (targetIdx >= 0)
&& (targetIdx != sourceIndex)
&& (targetIdx != sourceIndex + 1)) {
e.getDragSourceContext().setCursor(
DragSource.DefaultMoveDrop);
return;
} // if
e.getDragSourceContext().setCursor(
DragSource.DefaultMoveNoDrop);
return;
} // if
*/
e.getDragSourceContext().setCursor(
DragSource.DefaultMoveDrop);
}
public void dragDropEnd(DragSourceDropEvent e) {
m_isDrawRect = false;
m_lineRect.setRect(0, 0, 0, 0);
// m_dragTabIndex = -1;
if (hasGhost()) {
s_glassPane.setVisible(false);
s_glassPane.setImage(null);
}
}
public void dropActionChanged(DragSourceDragEvent e) {
}
};
final DragGestureListener dgl = new DragGestureListener() {
public void dragGestureRecognized(DragGestureEvent e) {
// System.out.println("dragGestureRecognized");
Point tabPt = e.getDragOrigin();
int dragTabIndex = indexAtLocation(tabPt.x, tabPt.y);
if (dragTabIndex < 0) {
return;
} // if
initGlassPane(e.getComponent(), e.getDragOrigin(), dragTabIndex);
try {
e.startDrag(DragSource.DefaultMoveDrop,
new TabTransferable(DnDTabbedPane.this, dragTabIndex), dsl);
} catch (InvalidDnDOperationException idoe) {
idoe.printStackTrace();
}
}
};
//dropTarget =
new DropTarget(this, DnDConstants.ACTION_COPY_OR_MOVE,
new CDropTargetListener(), true);
new DragSource().createDefaultDragGestureRecognizer(this,
DnDConstants.ACTION_COPY_OR_MOVE, dgl);
m_acceptor = new TabAcceptor() {
public boolean isDropAcceptable(DnDTabbedPane a_component, int a_index) {
return true;
}
};
}
public TabAcceptor getAcceptor() {
return m_acceptor;
}
public void setAcceptor(TabAcceptor a_value) {
m_acceptor = a_value;
}
private TabTransferData getTabTransferData(DropTargetDropEvent a_event) {
try {
TabTransferData data = (TabTransferData) a_event.getTransferable().getTransferData(FLAVOR);
return data;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private TabTransferData getTabTransferData(DropTargetDragEvent a_event) {
try {
TabTransferData data = (TabTransferData) a_event.getTransferable().getTransferData(FLAVOR);
return data;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private TabTransferData getTabTransferData(DragSourceDragEvent a_event) {
try {
TabTransferData data = (TabTransferData) a_event.getDragSourceContext()
.getTransferable().getTransferData(FLAVOR);
return data;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
class TabTransferable implements Transferable {
private TabTransferData m_data = null;
public TabTransferable(DnDTabbedPane a_tabbedPane, int a_tabIndex) {
m_data = new TabTransferData(DnDTabbedPane.this, a_tabIndex);
}
public Object getTransferData(DataFlavor flavor) {
return m_data;
// return DnDTabbedPane.this;
}
public DataFlavor[] getTransferDataFlavors() {
DataFlavor[] f = new DataFlavor[1];
f[0] = FLAVOR;
return f;
}
public boolean isDataFlavorSupported(DataFlavor flavor) {
return flavor.getHumanPresentableName().equals(NAME);
}
}
class TabTransferData {
private DnDTabbedPane m_tabbedPane = null;
private int m_tabIndex = -1;
public TabTransferData() {
}
public TabTransferData(DnDTabbedPane a_tabbedPane, int a_tabIndex) {
m_tabbedPane = a_tabbedPane;
m_tabIndex = a_tabIndex;
}
public DnDTabbedPane getTabbedPane() {
return m_tabbedPane;
}
public void setTabbedPane(DnDTabbedPane pane) {
m_tabbedPane = pane;
}
public int getTabIndex() {
return m_tabIndex;
}
public void setTabIndex(int index) {
m_tabIndex = index;
}
}
private Point buildGhostLocation(Point a_location) {
Point retval = new Point(a_location);
switch (getTabPlacement()) {
case JTabbedPane.TOP: {
retval.y = 1;
retval.x -= s_glassPane.getGhostWidth() / 2;
} break;
case JTabbedPane.BOTTOM: {
retval.y = getHeight() - 1 - s_glassPane.getGhostHeight();
retval.x -= s_glassPane.getGhostWidth() / 2;
} break;
case JTabbedPane.LEFT: {
retval.x = 1;
retval.y -= s_glassPane.getGhostHeight() / 2;
} break;
case JTabbedPane.RIGHT: {
retval.x = getWidth() - 1 - s_glassPane.getGhostWidth();
retval.y -= s_glassPane.getGhostHeight() / 2;
} break;
} // switch
retval = SwingUtilities.convertPoint(DnDTabbedPane.this,
retval, s_glassPane);
return retval;
}
class CDropTargetListener implements DropTargetListener {
public void dragEnter(DropTargetDragEvent e) {
// System.out.println("DropTarget.dragEnter: " + DnDTabbedPane.this);
if (isDragAcceptable(e)) {
e.acceptDrag(e.getDropAction());
} else {
e.rejectDrag();
} // if
}
public void dragExit(DropTargetEvent e) {
// System.out.println("DropTarget.dragExit: " + DnDTabbedPane.this);
m_isDrawRect = false;
}
public void dropActionChanged(DropTargetDragEvent e) {
}
public void dragOver(final DropTargetDragEvent e) {
TabTransferData data = getTabTransferData(e);
if (getTabPlacement() == JTabbedPane.TOP
|| getTabPlacement() == JTabbedPane.BOTTOM) {
initTargetLeftRightLine(getTargetTabIndex(e.getLocation()), data);
} else {
initTargetTopBottomLine(getTargetTabIndex(e.getLocation()), data);
} // if-else
repaint();
if (hasGhost()) {
s_glassPane.setPoint(buildGhostLocation(e.getLocation()));
s_glassPane.repaint();
}
}
public void drop(DropTargetDropEvent a_event) {
// System.out.println("DropTarget.drop: " + DnDTabbedPane.this);
if (isDropAcceptable(a_event)) {
convertTab(getTabTransferData(a_event),
getTargetTabIndex(a_event.getLocation()));
a_event.dropComplete(true);
} else {
a_event.dropComplete(false);
} // if-else
m_isDrawRect = false;
repaint();
}
public boolean isDragAcceptable(DropTargetDragEvent e) {
Transferable t = e.getTransferable();
if (t == null) {
return false;
} // if
DataFlavor[] flavor = e.getCurrentDataFlavors();
if (!t.isDataFlavorSupported(flavor[0])) {
return false;
} // if
TabTransferData data = getTabTransferData(e);
if (DnDTabbedPane.this == data.getTabbedPane()
&& data.getTabIndex() >= 0) {
return true;
} // if
if (DnDTabbedPane.this != data.getTabbedPane()) {
if (m_acceptor != null) {
return m_acceptor.isDropAcceptable(data.getTabbedPane(), data.getTabIndex());
} // if
} // if
return false;
}
public boolean isDropAcceptable(DropTargetDropEvent e) {
Transferable t = e.getTransferable();
if (t == null) {
return false;
} // if
DataFlavor[] flavor = e.getCurrentDataFlavors();
if (!t.isDataFlavorSupported(flavor[0])) {
return false;
} // if
TabTransferData data = getTabTransferData(e);
if (DnDTabbedPane.this == data.getTabbedPane()
&& data.getTabIndex() >= 0) {
return true;
} // if
if (DnDTabbedPane.this != data.getTabbedPane()) {
if (m_acceptor != null) {
return m_acceptor.isDropAcceptable(data.getTabbedPane(), data.getTabIndex());
} // if
} // if
return false;
}
}
private boolean m_hasGhost = true;
public void setPaintGhost(boolean flag) {
m_hasGhost = flag;
}
public boolean hasGhost() {
return m_hasGhost;
}
/**
* returns potential index for drop.
* #param a_point point given in the drop site component's coordinate
* #return returns potential index for drop.
*/
private int getTargetTabIndex(Point a_point) {
boolean isTopOrBottom = getTabPlacement() == JTabbedPane.TOP
|| getTabPlacement() == JTabbedPane.BOTTOM;
// if the pane is empty, the target index is always zero.
if (getTabCount() == 0) {
return 0;
} // if
for (int i = 0; i < getTabCount(); i++) {
Rectangle r = getBoundsAt(i);
if (isTopOrBottom) {
r.setRect(r.x - r.width / 2, r.y, r.width, r.height);
} else {
r.setRect(r.x, r.y - r.height / 2, r.width, r.height);
} // if-else
if (r.contains(a_point)) {
return i;
} // if
} // for
Rectangle r = getBoundsAt(getTabCount() - 1);
if (isTopOrBottom) {
int x = r.x + r.width / 2;
r.setRect(x, r.y, getWidth() - x, r.height);
} else {
int y = r.y + r.height / 2;
r.setRect(r.x, y, r.width, getHeight() - y);
} // if-else
return r.contains(a_point) ? getTabCount() : -1;
}
private void convertTab(TabTransferData a_data, int a_targetIndex) {
DnDTabbedPane source = a_data.getTabbedPane();
int sourceIndex = a_data.getTabIndex();
if (sourceIndex < 0) {
return;
} // if
Component cmp = source.getComponentAt(sourceIndex);
String str = source.getTitleAt(sourceIndex);
if (this != source) {
source.remove(sourceIndex);
if (a_targetIndex == getTabCount()) {
addTab(str, cmp);
} else {
if (a_targetIndex < 0) {
a_targetIndex = 0;
} // if
insertTab(str, null, cmp, null, a_targetIndex);
} // if
setSelectedComponent(cmp);
// System.out.println("press="+sourceIndex+" next="+a_targetIndex);
return;
} // if
if (a_targetIndex < 0 || sourceIndex == a_targetIndex) {
//System.out.println("press="+prev+" next="+next);
return;
} // if
if (a_targetIndex == getTabCount()) {
//System.out.println("last: press="+prev+" next="+next);
source.remove(sourceIndex);
addTab(str, cmp);
setSelectedIndex(getTabCount() - 1);
} else if (sourceIndex > a_targetIndex) {
//System.out.println(" >: press="+prev+" next="+next);
source.remove(sourceIndex);
insertTab(str, null, cmp, null, a_targetIndex);
setSelectedIndex(a_targetIndex);
} else {
//System.out.println(" <: press="+prev+" next="+next);
source.remove(sourceIndex);
insertTab(str, null, cmp, null, a_targetIndex - 1);
setSelectedIndex(a_targetIndex - 1);
}
}
private void initTargetLeftRightLine(int next, TabTransferData a_data) {
if (next < 0) {
m_lineRect.setRect(0, 0, 0, 0);
m_isDrawRect = false;
return;
} // if
if ((a_data.getTabbedPane() == this)
&& (a_data.getTabIndex() == next
|| next - a_data.getTabIndex() == 1)) {
m_lineRect.setRect(0, 0, 0, 0);
m_isDrawRect = false;
} else if (getTabCount() == 0) {
m_lineRect.setRect(0, 0, 0, 0);
m_isDrawRect = false;
return;
} else if (next == 0) {
Rectangle rect = getBoundsAt(0);
m_lineRect.setRect(-LINEWIDTH / 2, rect.y, LINEWIDTH, rect.height);
m_isDrawRect = true;
} else if (next == getTabCount()) {
Rectangle rect = getBoundsAt(getTabCount() - 1);
m_lineRect.setRect(rect.x + rect.width - LINEWIDTH / 2, rect.y,
LINEWIDTH, rect.height);
m_isDrawRect = true;
} else {
Rectangle rect = getBoundsAt(next - 1);
m_lineRect.setRect(rect.x + rect.width - LINEWIDTH / 2, rect.y,
LINEWIDTH, rect.height);
m_isDrawRect = true;
}
}
private void initTargetTopBottomLine(int next, TabTransferData a_data) {
if (next < 0) {
m_lineRect.setRect(0, 0, 0, 0);
m_isDrawRect = false;
return;
} // if
if ((a_data.getTabbedPane() == this)
&& (a_data.getTabIndex() == next
|| next - a_data.getTabIndex() == 1)) {
m_lineRect.setRect(0, 0, 0, 0);
m_isDrawRect = false;
} else if (getTabCount() == 0) {
m_lineRect.setRect(0, 0, 0, 0);
m_isDrawRect = false;
return;
} else if (next == getTabCount()) {
Rectangle rect = getBoundsAt(getTabCount() - 1);
m_lineRect.setRect(rect.x, rect.y + rect.height - LINEWIDTH / 2,
rect.width, LINEWIDTH);
m_isDrawRect = true;
} else if (next == 0) {
Rectangle rect = getBoundsAt(0);
m_lineRect.setRect(rect.x, -LINEWIDTH / 2, rect.width, LINEWIDTH);
m_isDrawRect = true;
} else {
Rectangle rect = getBoundsAt(next - 1);
m_lineRect.setRect(rect.x, rect.y + rect.height - LINEWIDTH / 2,
rect.width, LINEWIDTH);
m_isDrawRect = true;
}
}
private void initGlassPane(Component c, Point tabPt, int a_tabIndex) {
//Point p = (Point) pt.clone();
getRootPane().setGlassPane(s_glassPane);
if (hasGhost()) {
Rectangle rect = getBoundsAt(a_tabIndex);
BufferedImage image = new BufferedImage(c.getWidth(),
c.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics g = image.getGraphics();
c.paint(g);
image = image.getSubimage(rect.x, rect.y, rect.width, rect.height);
s_glassPane.setImage(image);
} // if
s_glassPane.setPoint(buildGhostLocation(tabPt));
s_glassPane.setVisible(true);
}
private Rectangle getTabAreaBound() {
Rectangle lastTab = getUI().getTabBounds(this, getTabCount() - 1);
return new Rectangle(0, 0, getWidth(), lastTab.y + lastTab.height);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (m_isDrawRect) {
Graphics2D g2 = (Graphics2D) g;
g2.setPaint(m_lineColor);
g2.fill(m_lineRect);
} // if
}
public interface TabAcceptor {
boolean isDropAcceptable(DnDTabbedPane a_component, int a_index);
}
}
class GhostGlassPane extends JPanel {
public static final long serialVersionUID = 1L;
private final AlphaComposite m_composite;
private Point m_location = new Point(0, 0);
private BufferedImage m_draggingGhost = null;
public GhostGlassPane() {
setOpaque(false);
m_composite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.7f);
}
public void setImage(BufferedImage draggingGhost) {
m_draggingGhost = draggingGhost;
}
public void setPoint(Point a_location) {
m_location.x = a_location.x;
m_location.y = a_location.y;
}
public int getGhostWidth() {
if (m_draggingGhost == null) {
return 0;
} // if
return m_draggingGhost.getWidth(this);
}
public int getGhostHeight() {
if (m_draggingGhost == null) {
return 0;
} // if
return m_draggingGhost.getHeight(this);
}
public void paintComponent(Graphics g) {
if (m_draggingGhost == null) {
return;
} // if
Graphics2D g2 = (Graphics2D) g;
g2.setComposite(m_composite);
g2.drawImage(m_draggingGhost, (int) m_location.getX(), (int) m_location.getY(), null);
}
}
Found this code out there on the tubes:
class DnDTabbedPane extends JTabbedPane {
private static final int LINEWIDTH = 3;
private static final String NAME = "test";
private final GhostGlassPane glassPane = new GhostGlassPane();
private final Rectangle2D lineRect = new Rectangle2D.Double();
private final Color lineColor = new Color(0, 100, 255);
//private final DragSource dragSource = new DragSource();
//private final DropTarget dropTarget;
private int dragTabIndex = -1;
public DnDTabbedPane() {
super();
final DragSourceListener dsl = new DragSourceListener() {
public void dragEnter(DragSourceDragEvent e) {
e.getDragSourceContext().setCursor(DragSource.DefaultMoveDrop);
}
public void dragExit(DragSourceEvent e) {
e.getDragSourceContext().setCursor(DragSource.DefaultMoveNoDrop);
lineRect.setRect(0,0,0,0);
glassPane.setPoint(new Point(-1000,-1000));
glassPane.repaint();
}
public void dragOver(DragSourceDragEvent e) {
//e.getLocation()
//This method returns a Point indicating the cursor location in screen coordinates at the moment
Point tabPt = e.getLocation();
SwingUtilities.convertPointFromScreen(tabPt, DnDTabbedPane.this);
Point glassPt = e.getLocation();
SwingUtilities.convertPointFromScreen(glassPt, glassPane);
int targetIdx = getTargetTabIndex(glassPt);
if(getTabAreaBound().contains(tabPt) && targetIdx>=0 &&
targetIdx!=dragTabIndex && targetIdx!=dragTabIndex+1) {
e.getDragSourceContext().setCursor(DragSource.DefaultMoveDrop);
}else{
e.getDragSourceContext().setCursor(DragSource.DefaultMoveNoDrop);
}
}
public void dragDropEnd(DragSourceDropEvent e) {
lineRect.setRect(0,0,0,0);
dragTabIndex = -1;
if(hasGhost()) {
glassPane.setVisible(false);
glassPane.setImage(null);
}
}
public void dropActionChanged(DragSourceDragEvent e) {}
};
final Transferable t = new Transferable() {
private final DataFlavor FLAVOR = new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType, NAME);
public Object getTransferData(DataFlavor flavor) {
return DnDTabbedPane.this;
}
public DataFlavor[] getTransferDataFlavors() {
DataFlavor[] f = new DataFlavor[1];
f[0] = this.FLAVOR;
return f;
}
public boolean isDataFlavorSupported(DataFlavor flavor) {
return flavor.getHumanPresentableName().equals(NAME);
}
};
final DragGestureListener dgl = new DragGestureListener() {
public void dragGestureRecognized(DragGestureEvent e) {
Point tabPt = e.getDragOrigin();
dragTabIndex = indexAtLocation(tabPt.x, tabPt.y);
if(dragTabIndex<0) return;
initGlassPane(e.getComponent(), e.getDragOrigin());
try{
e.startDrag(DragSource.DefaultMoveDrop, t, dsl);
}catch(InvalidDnDOperationException idoe) {
idoe.printStackTrace();
}
}
};
//dropTarget =
new DropTarget(glassPane, DnDConstants.ACTION_COPY_OR_MOVE, new CDropTargetListener(), true);
new DragSource().createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY_OR_MOVE, dgl);
}
class CDropTargetListener implements DropTargetListener{
public void dragEnter(DropTargetDragEvent e) {
if(isDragAcceptable(e)) e.acceptDrag(e.getDropAction());
else e.rejectDrag();
}
public void dragExit(DropTargetEvent e) {}
public void dropActionChanged(DropTargetDragEvent e) {}
public void dragOver(final DropTargetDragEvent e) {
if(getTabPlacement()==JTabbedPane.TOP || getTabPlacement()==JTabbedPane.BOTTOM) {
initTargetLeftRightLine(getTargetTabIndex(e.getLocation()));
}else{
initTargetTopBottomLine(getTargetTabIndex(e.getLocation()));
}
repaint();
if(hasGhost()) {
glassPane.setPoint(e.getLocation());
glassPane.repaint();
}
}
public void drop(DropTargetDropEvent e) {
if(isDropAcceptable(e)) {
convertTab(dragTabIndex, getTargetTabIndex(e.getLocation()));
e.dropComplete(true);
}else{
e.dropComplete(false);
}
repaint();
}
public boolean isDragAcceptable(DropTargetDragEvent e) {
Transferable t = e.getTransferable();
if(t==null) return false;
DataFlavor[] f = e.getCurrentDataFlavors();
if(t.isDataFlavorSupported(f[0]) && dragTabIndex>=0) {
return true;
}
return false;
}
public boolean isDropAcceptable(DropTargetDropEvent e) {
Transferable t = e.getTransferable();
if(t==null) return false;
DataFlavor[] f = t.getTransferDataFlavors();
if(t.isDataFlavorSupported(f[0]) && dragTabIndex>=0) {
return true;
}
return false;
}
}
private boolean hasGhost = true;
public void setPaintGhost(boolean flag) {
hasGhost = flag;
}
public boolean hasGhost() {
return hasGhost;
}
private int getTargetTabIndex(Point glassPt) {
Point tabPt = SwingUtilities.convertPoint(glassPane, glassPt, DnDTabbedPane.this);
boolean isTB = getTabPlacement()==JTabbedPane.TOP || getTabPlacement()==JTabbedPane.BOTTOM;
for(int i=0;i<getTabCount();i++) {
Rectangle r = getBoundsAt(i);
if(isTB) r.setRect(r.x-r.width/2, r.y, r.width, r.height);
else r.setRect(r.x, r.y-r.height/2, r.width, r.height);
if(r.contains(tabPt)) return i;
}
Rectangle r = getBoundsAt(getTabCount()-1);
if(isTB) r.setRect(r.x+r.width/2, r.y, r.width, r.height);
else r.setRect(r.x, r.y+r.height/2, r.width, r.height);
return r.contains(tabPt)?getTabCount():-1;
}
private void convertTab(int prev, int next) {
if(next<0 || prev==next) {
//System.out.println("press="+prev+" next="+next);
return;
}
Component cmp = getComponentAt(prev);
String str = getTitleAt(prev);
if(next==getTabCount()) {
//System.out.println("last: press="+prev+" next="+next);
remove(prev);
addTab(str, cmp);
setSelectedIndex(getTabCount()-1);
}else if(prev>next) {
//System.out.println(" >: press="+prev+" next="+next);
remove(prev);
insertTab(str, null, cmp, null, next);
setSelectedIndex(next);
}else{
//System.out.println(" <: press="+prev+" next="+next);
remove(prev);
insertTab(str, null, cmp, null, next-1);
setSelectedIndex(next-1);
}
}
private void initTargetLeftRightLine(int next) {
if(next<0 || dragTabIndex==next || next-dragTabIndex==1) {
lineRect.setRect(0,0,0,0);
}else if(next==getTabCount()) {
Rectangle rect = getBoundsAt(getTabCount()-1);
lineRect.setRect(rect.x+rect.width-LINEWIDTH/2,rect.y,LINEWIDTH,rect.height);
}else if(next==0) {
Rectangle rect = getBoundsAt(0);
lineRect.setRect(-LINEWIDTH/2,rect.y,LINEWIDTH,rect.height);
}else{
Rectangle rect = getBoundsAt(next-1);
lineRect.setRect(rect.x+rect.width-LINEWIDTH/2,rect.y,LINEWIDTH,rect.height);
}
}
private void initTargetTopBottomLine(int next) {
if(next<0 || dragTabIndex==next || next-dragTabIndex==1) {
lineRect.setRect(0,0,0,0);
}else if(next==getTabCount()) {
Rectangle rect = getBoundsAt(getTabCount()-1);
lineRect.setRect(rect.x,rect.y+rect.height-LINEWIDTH/2,rect.width,LINEWIDTH);
}else if(next==0) {
Rectangle rect = getBoundsAt(0);
lineRect.setRect(rect.x,-LINEWIDTH/2,rect.width,LINEWIDTH);
}else{
Rectangle rect = getBoundsAt(next-1);
lineRect.setRect(rect.x,rect.y+rect.height-LINEWIDTH/2,rect.width,LINEWIDTH);
}
}
private void initGlassPane(Component c, Point tabPt) {
//Point p = (Point) pt.clone();
getRootPane().setGlassPane(glassPane);
if(hasGhost()) {
Rectangle rect = getBoundsAt(dragTabIndex);
BufferedImage image = new BufferedImage(c.getWidth(), c.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics g = image.getGraphics();
c.paint(g);
image = image.getSubimage(rect.x,rect.y,rect.width,rect.height);
glassPane.setImage(image);
}
Point glassPt = SwingUtilities.convertPoint(c, tabPt, glassPane);
glassPane.setPoint(glassPt);
glassPane.setVisible(true);
}
private Rectangle getTabAreaBound() {
Rectangle lastTab = getUI().getTabBounds(this, getTabCount()-1);
return new Rectangle(0,0,getWidth(),lastTab.y+lastTab.height);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
if(dragTabIndex>=0) {
Graphics2D g2 = (Graphics2D)g;
g2.setPaint(lineColor);
g2.fill(lineRect);
}
}
}
class GhostGlassPane extends JPanel {
private final AlphaComposite composite;
private Point location = new Point(0, 0);
private BufferedImage draggingGhost = null;
public GhostGlassPane() {
setOpaque(false);
composite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f);
}
public void setImage(BufferedImage draggingGhost) {
this.draggingGhost = draggingGhost;
}
public void setPoint(Point location) {
this.location = location;
}
public void paintComponent(Graphics g) {
if(draggingGhost == null) return;
Graphics2D g2 = (Graphics2D) g;
g2.setComposite(composite);
double xx = location.getX() - (draggingGhost.getWidth(this) /2d);
double yy = location.getY() - (draggingGhost.getHeight(this)/2d);
g2.drawImage(draggingGhost, (int)xx, (int)yy , null);
}
}
#Tony: It looks like Euguenes solution just overlooks preserving TabComponents during a swap.
The convertTab method just needs to remember the TabComponent and set it to the new tabs it makes.
Try using this:
private void convertTab(TabTransferData a_data, int a_targetIndex) {
DnDTabbedPane source = a_data.getTabbedPane();
System.out.println("this=source? " + (this == source));
int sourceIndex = a_data.getTabIndex();
if (sourceIndex < 0) {
return;
} // if
//Save the tab's component, title, and TabComponent.
Component cmp = source.getComponentAt(sourceIndex);
String str = source.getTitleAt(sourceIndex);
Component tcmp = source.getTabComponentAt(sourceIndex);
if (this != source) {
source.remove(sourceIndex);
if (a_targetIndex == getTabCount()) {
addTab(str, cmp);
setTabComponentAt(getTabCount()-1, tcmp);
} else {
if (a_targetIndex < 0) {
a_targetIndex = 0;
} // if
insertTab(str, null, cmp, null, a_targetIndex);
setTabComponentAt(a_targetIndex, tcmp);
} // if
setSelectedComponent(cmp);
return;
} // if
if (a_targetIndex < 0 || sourceIndex == a_targetIndex) {
return;
} // if
if (a_targetIndex == getTabCount()) {
source.remove(sourceIndex);
addTab(str, cmp);
setTabComponentAt(getTabCount() - 1, tcmp);
setSelectedIndex(getTabCount() - 1);
} else if (sourceIndex > a_targetIndex) {
source.remove(sourceIndex);
insertTab(str, null, cmp, null, a_targetIndex);
setTabComponentAt(a_targetIndex, tcmp);
setSelectedIndex(a_targetIndex);
} else {
source.remove(sourceIndex);
insertTab(str, null, cmp, null, a_targetIndex - 1);
setTabComponentAt(a_targetIndex - 1, tcmp);
setSelectedIndex(a_targetIndex - 1);
}
}
Add this to isDragAcceptable to avoid Exceptions:
boolean transferDataFlavorFound = false;
for (DataFlavor transferDataFlavor : t.getTransferDataFlavors()) {
if (FLAVOR.equals(transferDataFlavor)) {
transferDataFlavorFound = true;
break;
}
}
if (transferDataFlavorFound == false) {
return false;
}