JTree & JButtons - Wrong Rendering when mouse hovers over Button - java

I have a Problem with JTree and JButton
It seems like when entering the Edit modus and hovering over the Buttons on the TreeCells, it Renderes some Part of the Tree inside the Button.
Even when Dragging from one Button to another in the Same Row it Renderes the one Button over the other one.
Here a Short Selfexplaining Sample that you can copy paste to See what i mean.
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.util.EventObject;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.UIManager;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellEditor;
import javax.swing.tree.DefaultTreeCellRenderer;
public class MyProblemWithTree {
public static void main(String...args) {
JFrame frame = new JFrame("Panel");
JScrollPane scroll = new JScrollPane();
DefaultMutableTreeNode node = new DefaultMutableTreeNode("Root");
DefaultMutableTreeNode nodeChild = new DefaultMutableTreeNode("childcaretaker1");
nodeChild.add(new DefaultMutableTreeNode("child1"));
nodeChild.add(new DefaultMutableTreeNode("child2"));
node.add(nodeChild);
final JTree tree = new JTree(node);
tree.setCellRenderer(new MyTreeCellRenderer());
tree.setEditable(true);
tree.setCellEditor(new MyTreeCellEditor(tree));
tree.addMouseMotionListener(new MouseMotionListener() {
#Override
public void mouseMoved(MouseEvent e) {
// TODO Auto-generated method stub
if (tree.getRowForLocation(e.getX(), e.getY()) != -1)
{
tree.startEditingAtPath(tree.getPathForLocation(e.getX(), e.getY()));
}
}
#Override
public void mouseDragged(MouseEvent arg0) {
// TODO Auto-generated method stub
}
});
scroll.setViewportView(tree);
frame.add(scroll);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
class MyTreeCellEditor extends DefaultTreeCellEditor {
JPanel leafPanel;
JLabel colorIcon;
PlayButton play;
PauseButton pause;
JLabel name;
public MyTreeCellEditor(JTree tree) {
super(tree, (MyTreeCellRenderer)tree.getCellRenderer());
leafPanel = new JPanel(new FlowLayout());
colorIcon = new JLabel(UIManager.getIcon("OptionPane.informationIcon"));
play = new PlayButton();
pause = new PauseButton();
name = new JLabel();
play.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
System.out.println("Playbutton klickt");
}
});
leafPanel.add(colorIcon);
leafPanel.add(name);
leafPanel.add(pause);
leafPanel.add(play);
}
#Override
public Component getTreeCellEditorComponent(JTree tree, Object value,
boolean selected, boolean expanded, boolean leaf, int row) {
name.setText((String)((DefaultMutableTreeNode)value).getUserObject());
pause.setVisible(!leaf);
return leafPanel;
}
#Override
public boolean isCellEditable(EventObject arg0) {
return true;
}
}
class MyTreeCellRenderer extends DefaultTreeCellRenderer {
private static final long serialVersionUID = 3691823996133806942L;
JPanel leafPanel;
JLabel colorIcon;
PlayButton play;
PauseButton pause;
JLabel name;
DefaultTreeCellRenderer defaultRenderer = new DefaultTreeCellRenderer();
Color backgroundSelectionColor;
Color backgroundNonSelectionColor;
public MyTreeCellRenderer() {
leafPanel = new JPanel(new FlowLayout());
colorIcon = new JLabel(UIManager.getIcon("OptionPane.informationIcon"));
play = new PlayButton();
pause = new PauseButton();
name = new JLabel();
leafPanel.add(colorIcon);
leafPanel.add(name);
leafPanel.add(pause);
leafPanel.add(play);
backgroundSelectionColor = new Color(200,200,255,50);
backgroundNonSelectionColor = new Color(0,0,0,0);
}
#Override
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
name.setText((String)((DefaultMutableTreeNode) value).getUserObject());
if (selected) {
leafPanel.setBackground(backgroundSelectionColor);
} else {
leafPanel.setBackground(backgroundNonSelectionColor);
}
leafPanel.setEnabled(tree.isEnabled());
pause.setVisible(!leaf);
return leafPanel;
}
}
class PlayButton extends JButton{
private static final long serialVersionUID = 550654173835539853L;
Dimension size = new Dimension(140,28);
public PlayButton() {
setIcon(UIManager.getIcon("OptionPane.informationIcon"));
setPressedIcon(UIManager.getIcon("OptionPane.errorIcon"));
setBackground(new Color(0,0,0,0));
setBorderPainted(false);
setPreferredSize(size);
setMaximumSize(size);
setMinimumSize(size);
}
}
class PauseButton extends JButton{
private static final long serialVersionUID = -5877843953696256070L;
Dimension size = new Dimension(140,28);
public PauseButton() {
setIcon(UIManager.getIcon("OptionPane.warningIcon"));
setPressedIcon(UIManager.getIcon("OptionPane.questionIcon"));
setBackground(new Color(0,0,0,0));
setBorderPainted(false);
setPreferredSize(size);
setMaximumSize(size);
setMinimumSize(size);
}
}
Even when i erase this Part. and i must click a Cell to enter the Edit Modus i still can get the Effect by leaving the Cell witzh the mouse and go back.
public void mouseMoved(MouseEvent e) {
// TODO Auto-generated method stub
if (tree.getRowForLocation(e.getX(), e.getY()) != -1)
{
tree.startEditingAtPath(tree.getPathForLocation(e.getX(), e.getY()));
}
}
I spend already 4 days into this JTree Customizing. But it really confuses me, how i could stop the rendering by entering the Button.

I don't know how to fix this, but it helps to use invokeLater and setRowHeight().
public static void main(String... args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Panel");
...
tree.setRowHeight(icon.getIconHeight());
...
frame.setVisible(true);
}
});
}

Related

Drag and Drop from JTable to JLayeredPane

How to create Drag and drop between JTable and JLayeredPane.
Does anyone have any ideas how to implement this?
I need transfer object by Drag and drop between JTable and JLayeredPane.
You have to do a few things at minimum to get this to work:
Call setDragEnabled(true) on your JTable instance
Set the JTables and JLayeredPanes DropTarget
Create a draggable Component to add to the JLayeredPane
To set a Components DropTarget, call the setDropTarget(DropTarget d) method and pass an anonymous inner class as the argument. Code that drops the Transferables data into the Component should be located in the drop(DropTargetDropEvent dtde) method.
The below snippet shows how to receive a Transferable and insert it into the row of a JTable where the drop was initiated:
table.setDropTarget(new DropTarget() {
#Override
public synchronized void drop(DropTargetDropEvent dtde) {
try {
// get row to put new item in
int row = table.rowAtPoint(dtde.getLocation());
// inserting row:
((DefaultTableModel) table.getModel()).insertRow(
//if the row wasn't found, add it to the end of the JTable
row == -1 ? table.getRowCount() : row,
// pass string flavor of transferable data as row data parameter
new Object[] {dtde.getTransferable()
.getTransferData(DataFlavor.stringFlavor)});
} catch(UnsupportedFlavorException | IOException e) {
e.printStackTrace();
}
}
});
This below snippet again receives a Transferable but instead adds it to the end of a JLayeredPane. Note that components are added to the end of the JLayeredPane because I assign a BoxLayout(SwingConstants.VERTICAL) to it.
layeredPane.setDropTarget(new DropTarget() {
#Override
public synchronized void drop(DropTargetDropEvent dtde) {
try {
// create draggable label to add to layered pane
// creating this class will be explained next
final DraggableLabel label = new DraggableLabel(
(String) dtde.getTransferable()
.getTransferData(DataFlavor.stringFlavor));
// add label to layered pane
layeredPane.add(label, JLayeredPane.DEFAULT_LAYER);
layeredPane.revalidate();
layeredPane.repaint();
} catch(UnsupportedFlavorException | IOException e) {
e.printStackTrace();
}
}
});
To create a draggable Component (In this example a JLabel), you must:
Create a new class that extends JLabel and implements DragGestureListener and DragSourceListener
Override all the necessary methods
In the constructor:
Create a new DragSource
Create a DragGestureRecognizer and assign it to this the JLabel subclass and this the DragGestureListener
Start a drag using the DragSource in the dragGestureRecognized(DragGestureEvent evt) method
class DraggableLabel extends JLabel implements DragGestureListener, DragSourceListener {
private DragSource dragSource;
DraggableLabel(String text) {
super(text);
// create the drag source
dragSource = new DragSource();
// assign this component a DragGestureRecognizer
dragSource.createDefaultDragGestureRecognizer(
this, DnDConstants.ACTION_COPY_OR_MOVE, this);
// for contrast with other items in layered pane
setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY));
}
#Override
public void dragGestureRecognized(DragGestureEvent evt) {
dragSource.startDrag(
evt, //trigger event
DragSource.DefaultMoveDrop, // icon
new StringSelection(getText()), // transferable data
this); // this the DragSourceListener
}
#Override
public void dragEnter(DragSourceDragEvent evt) {}
#Override
public void dragOver(DragSourceDragEvent evt) {}
#Override
public void dragExit(DragSourceEvent evt) {}
#Override
public void dropActionChanged(DragSourceDragEvent evt) {}
#Override
public void dragDropEnd(DragSourceDropEvent evt) {}
}
Full working example:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DragGestureEvent;
import java.awt.dnd.DragGestureListener;
import java.awt.dnd.DragSource;
import java.awt.dnd.DragSourceDragEvent;
import java.awt.dnd.DragSourceDropEvent;
import java.awt.dnd.DragSourceEvent;
import java.awt.dnd.DragSourceListener;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDropEvent;
import java.io.IOException;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JTable;
import javax.swing.WindowConstants;
import javax.swing.table.DefaultTableModel;
class DragDropExample {
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
final JFrame frame = new JFrame("JLabel Text Example");
final JTable table = new JTable(new DefaultTableModel(
new Object[][] {
{"Item 1"},
{"Item 2"},
{"Item 3"},
{"Item 4"},
{"Item 5"}},
new String[] {"Column Name"}));
table.setDragEnabled(true);
table.setDropTarget(new DropTarget() {
#Override
public synchronized void drop(DropTargetDropEvent dtde) {
try {
// get row to put new item in
int row = table.rowAtPoint(dtde.getLocation());
// inserting row:
((DefaultTableModel) table.getModel()).insertRow(
//if the row wasn't found, add it to the end of the JTable
row == -1 ? table.getRowCount() : row,
// pass string flavor of transferable data as row data parameter
new Object[] {dtde.getTransferable()
.getTransferData(DataFlavor.stringFlavor)});
} catch(UnsupportedFlavorException | IOException e) {
e.printStackTrace();
}
}
});
final JLayeredPane layeredPane = new JLayeredPane() {
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 300);
}
};
layeredPane.setBorder(BorderFactory.createLineBorder(Color.BLACK));
layeredPane.setLayout(new BoxLayout(layeredPane, BoxLayout.Y_AXIS));
layeredPane.setDropTarget(new DropTarget() {
#Override
public synchronized void drop(DropTargetDropEvent dtde) {
try {
// create draggable label to add to layered pane
// creating this class will be explained next
final DraggableLabel label = new DraggableLabel(
(String) dtde.getTransferable()
.getTransferData(DataFlavor.stringFlavor));
// add label to layered pane
layeredPane.add(label, JLayeredPane.DEFAULT_LAYER);
layeredPane.revalidate();
layeredPane.repaint();
} catch(UnsupportedFlavorException | IOException e) {
e.printStackTrace();
}
}
});
frame.getContentPane().add(table, BorderLayout.WEST);
frame.getContentPane().add(layeredPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setVisible(true);
});
}
static class DraggableLabel extends JLabel implements DragGestureListener, DragSourceListener {
private DragSource dragSource;
DraggableLabel(String text) {
super(text);
// create the drag source
dragSource = new DragSource();
// assign this component a DragGestureRecognizer
dragSource.createDefaultDragGestureRecognizer(
this, DnDConstants.ACTION_COPY_OR_MOVE, this);
// for contrast with other items
setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY));
}
#Override
public void dragGestureRecognized(DragGestureEvent evt) {
dragSource.startDrag(
evt, //trigger event
DragSource.DefaultMoveDrop,
new StringSelection(getText()),
this);
}
#Override
public void dragEnter(DragSourceDragEvent evt) {}
#Override
public void dragOver(DragSourceDragEvent evt) {}
#Override
public void dragExit(DragSourceEvent evt) {}
#Override
public void dropActionChanged(DragSourceDragEvent evt) {}
#Override
public void dragDropEnd(DragSourceDropEvent evt) {}
}
}
DropTarget dt = new DropTarget(Droptargetobject, new DropTargetAdapter() {
#Override
public void dragEnter(DropTargetDragEvent dtde) {
//executed if mouse with items enters object
}
#Override
public void drop(DropTargetDropEvent dtde) {
//executed if you drop the item
}
});
and to implement the drag use a java.awt.dnd.DragGestureEvent;.
i hope you understand what i mean
imports i used:
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetAdapter;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;

Drag two images and drop them in two different JButtons in the same JFrame

I have a code in which I must drag two images from my desktop and drop it on a frame in two draggable buttons. The buttons have already been made on the frame. But while dragging the images, they can only be dragged to one button. The images don't get dragged to the other one. I have made a DragListener class where the dragging methods prevail and the main class DragInitialListener where I have passed objects of class DragButton so that two draggable buttons are created. I have tried everything I could think of, made two DragListener classes, passed the methods differently but the image could only be dragged in one button. I want both the buttons to be able to hold images. Please help me with it. Here's the code that I have made so far:
//This is the main class
public class DragInitialListener extends javax.swing.JFrame {
private volatile int draggedAtX, draggedAtY;
public DragInitialListener() {
initComponents();
Droptargets();
Droptarget();
}
public void Droptarget()
{
DragListener d;
DragButton db = new DragButton();
db.setSize(170,140);
d= new DragListener(db);
DropTarget drop = new DropTarget(this,d);
this.getContentPane().add(db);
}
public void Droptargets()
{
DragListener dd;
DragButton db1 = new DragButton();
db1.setSize(170,140);
dd= new DragListener(db1);
DropTarget drop1 = new DropTarget(this,dd);
this.getContentPane().add(db1);
}
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 400, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 300, Short.MAX_VALUE)
);
pack();
}// </editor-fold>
public static void main(String args[]) {
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new DragInitialListener().setVisible(true);
}
});
}
// Variables declaration - do not modify
// End of variables declaration
}
//This is the DragListener class
public class DragListener extends JButton implements DropTargetListener
{
JButton imagebutton = new JButton();
// JButton imagebutton1 = new JButton();
private volatile int draggedAtX, draggedAtY;
DragListener(JButton image) {
imagebutton=image;
}
#Override
public void dragEnter(DropTargetDragEvent dtde) {
}
#Override
public void dragOver(DropTargetDragEvent dtde) {
}
#Override
public void dropActionChanged(DropTargetDragEvent dtde) {
}
#Override
public void dragExit(DropTargetEvent dte) {
}
#Override
public void drop(DropTargetDropEvent ev) {
ev.acceptDrop(DnDConstants.ACTION_COPY);
Transferable t = ev.getTransferable();
//DropTarget test = (DropTarget) ev.getSource();
DataFlavor[] df= t.getTransferDataFlavors();
for(DataFlavor f:df)
{
try
{
if(f.isFlavorJavaFileListType())
{
List<File> files =(List<File>) t.getTransferData(f);
for(File file : files)
{
displayImage(file.getPath());
}
}
}
catch(Exception ex)
{
JOptionPane.showMessageDialog(null, ex);
}
}
}
private void displayImage(String path)
{
BufferedImage img = null;
try
{
img =ImageIO.read(new File(path));
}
catch(Exception e)
{
}
ImageIcon icon = new ImageIcon(img);
imagebutton.setIcon(icon);
}
}
Start simple, get one button to work, if you can get one to work, you can get 100 to work
This is a very simple example, which makes use of the transfer API, because you really only care about dropping and not dragging
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.io.File;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.TransferHandler;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
JButton btn = new JButton("Drop here");
btn.setVerticalTextPosition(JButton.BOTTOM);
btn.setHorizontalTextPosition(JButton.CENTER);
btn.setTransferHandler(new ImageTransferHandler());
add(btn);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
}
public static class ImageTransferHandler extends TransferHandler {
public static final DataFlavor[] SUPPORTED_DATA_FLAVORS = new DataFlavor[]{
DataFlavor.javaFileListFlavor,
DataFlavor.imageFlavor
};
#Override
public boolean canImport(TransferHandler.TransferSupport support) {
boolean canImport = false;
for (DataFlavor flavor : SUPPORTED_DATA_FLAVORS) {
if (support.isDataFlavorSupported(flavor)) {
canImport = true;
break;
}
}
return canImport;
}
#Override
public boolean importData(TransferHandler.TransferSupport support) {
boolean accept = false;
if (canImport(support)) {
try {
Transferable t = support.getTransferable();
Component component = support.getComponent();
if (component instanceof JButton) {
Image image = null;
if (support.isDataFlavorSupported(DataFlavor.imageFlavor)) {
image = (Image) t.getTransferData(DataFlavor.imageFlavor);
} else if (support.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
List files = (List) t.getTransferData(DataFlavor.javaFileListFlavor);
if (files.size() > 0) {
image = ImageIO.read((File) files.get(0));
}
}
ImageIcon icon = null;
if (image != null) {
icon = new ImageIcon(image);
}
((JButton) component).setIcon(icon);
accept = true;
}
} catch (Exception exp) {
exp.printStackTrace();
}
}
return accept;
}
}
}
So, by doing nothing more then changing the layout and replicating the button using
public TestPane() {
setLayout(new GridLayout(5, 5));
for (int index = 0; index < 5 * 5; index++) {
JButton btn = new JButton("Drop here");
btn.setVerticalTextPosition(JButton.BOTTOM);
btn.setHorizontalTextPosition(JButton.CENTER);
btn.setTransferHandler(new ImageTransferHandler());
add(btn);
}
}
I was able to achieve...
Updated...
So apparently I might have misunderstood the question, not the first time. From what's been explained to me, you might want to drag multiple images and have them applied to the buttons. Surprising, the process doesn't change that much.
In this example, I've applied the TransferHandler to the JPanel instead of the button and supplied it the buttons I want updated. You could easily update this to have a variable number of buttons, but I've started with two.
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.io.File;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.TransferHandler;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
JButton left = makeButton("Left");
JButton right = makeButton("Right");
add(left);
add(right);
setTransferHandler(new ImageTransferHandler(left, right));
}
protected JButton makeButton(String text) {
JButton btn = new JButton(text);
btn.setVerticalTextPosition(JButton.BOTTOM);
btn.setHorizontalTextPosition(JButton.CENTER);
return btn;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
}
public static class ImageTransferHandler extends TransferHandler {
public static final DataFlavor[] SUPPORTED_DATA_FLAVORS = new DataFlavor[]{
DataFlavor.javaFileListFlavor,};
private JButton left, right;
public ImageTransferHandler(JButton left, JButton right) {
this.left = left;
this.right = right;
}
#Override
public boolean canImport(TransferHandler.TransferSupport support) {
boolean canImport = false;
for (DataFlavor flavor : SUPPORTED_DATA_FLAVORS) {
if (support.isDataFlavorSupported(flavor)) {
canImport = true;
break;
}
}
return canImport;
}
#Override
public boolean importData(TransferHandler.TransferSupport support) {
boolean accept = false;
if (canImport(support)) {
try {
Transferable t = support.getTransferable();
Image image = null;
if (support.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
List files = (List) t.getTransferData(DataFlavor.javaFileListFlavor);
JButton buttons[] = new JButton[]{left, right};
for (int index = 0; index < Math.min(files.size(), 2); index++) {
if (files.size() > 0) {
image = ImageIO.read((File) files.get(index));
ImageIcon icon = null;
if (image != null) {
icon = new ImageIcon(image);
}
buttons[index].setIcon(icon);
}
}
accept = true;
}
} catch (Exception exp) {
exp.printStackTrace();
}
}
return accept;
}
}
}
Now, there are rules you will need to define yourself, for example, what happens when the user only drags a single image? Do you apply it to the first button (as I have) every time, or do you try and find the button without an image and update it? What happens if all the buttons have images? Where does it go then?
Do you reject drags with more than 2 images?

jbutton does not work

Hi I have the following code where I have a start and stop button . when start is pressed canvas starts painting but I cannot press stop button until the start operation is done . I need to stop and resume the paint on the button press . Once the start button is pressed the other buttons cannot be pressed till the canvas is painted.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Hashtable;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.Timer;
public abstract class JUIApp extends JPanel implements ActionListener {
public static CACanvas cacanvas= null;
public ArrayList<int[]> genL;
public JFrame frame = null;
protected JPanel mainPanel = null;
private JButton btn0 = null;
private JButton btn1 = null;
private JButton btn2 = null;
#SuppressWarnings("rawtypes")
DefaultComboBoxModel rules = null;
#SuppressWarnings("rawtypes")
JComboBox rulesCombo =null;
JScrollPane ruleListScrollPane=null;
JLabel lable=null;
JTextField generation=null;
JLabel gLable=null;
public static String Rule;
public static String Generations;
public boolean isChanged =false;
public int gridCellSize=4;
private static final long serialVersionUID = 1L;
public int genCurrent=0;
public int posCurrent=0;
public int i;
public Color cellColor= null;
public Timer waitTimer;
public static boolean waitFlag;
public static boolean alert1Flag=false;
public boolean stopFlag=false;
public JLabel Alert1=new JLabel();
public int genCheck=0;
//private List<Point> fillCells;
public JUIApp() {
initGUI();
}
public void initGUI() {
//fillCells = new ArrayList<>(25);
frame = new JFrame();
frame.setTitle("Cellular Automata Demo");
frame.setSize(1050, 610);
frame.setResizable(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(getMainPanel(),BorderLayout.NORTH);
frame.setVisible(true);
Toolkit.getDefaultToolkit().setDynamicLayout(false);
cacanvas=new CACanvas();
frame.add(cacanvas);
}
#SuppressWarnings({ "unchecked", "rawtypes" })
public JPanel getMainPanel() {
mainPanel = new JPanel();
mainPanel.setLayout(new FlowLayout());
//cacanvas=new CACanvas();
btn0 = new JButton("Start");
btn0.addActionListener(this);
//waitTimer = new Timer(1000, this);
mainPanel.add(btn0);
JButton btn2 = new JButton("Stop");
btn2.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent s)
{
stopFlag=true;
//cacanvas.repaint();
}
});
mainPanel.add(btn2);
btn1 = new JButton("Clear");
btn1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
CACanvas.clearFlag=true;
generation.setText("");
alert1Flag=true;
rulesCombo.setSelectedIndex(0);
Alert1.setText("Please enter the number of generations");
Alert1.setBounds(30, 20, 5, 5);
Alert1.setVisible(alert1Flag);
mainPanel.add(Alert1);
cacanvas.repaint();
frame.setSize(1060, 610);
}
});
mainPanel.add(btn1);
lable=new JLabel();
lable.setText("Select Rule :");
mainPanel.add(lable);
rules=new DefaultComboBoxModel();
for (int i=0;i<=100;i++)
{
String p=String.valueOf(i);
rules.addElement(p);
}
rules.addElement("250");
rules.addElement("254");
rulesCombo = new JComboBox(rules);
rulesCombo.setSelectedIndex(0);
ruleListScrollPane = new JScrollPane(rulesCombo);
mainPanel.add(ruleListScrollPane);
//mainPanel.revalidate();
gLable=new JLabel();
gLable.setText("Enter the number of Generations (Max 64)");
generation=new JTextField(2);
mainPanel.add(gLable);
mainPanel.add(generation);
// mainPanel.add(cacanvas);
return mainPanel;
}
public abstract void run();
#Override
public void actionPerformed(ActionEvent arg0) {
Alert1.setVisible(false);
waitFlag=false;
System.out.println("We received an ActionEvent " + arg0);
Generations=generation.getText();
System.out.println(Generations);
Rule = "";
if (rulesCombo.getSelectedIndex() != -1) {
Rule =
(String) rulesCombo.getItemAt
(rulesCombo.getSelectedIndex());
}
System.out.println(Rule);
int rule=Integer.parseInt(Rule);
Hashtable<String,Integer> rules= new Hashtable<String,Integer>();
CARule ruleClass=new CARule();
rules=ruleClass.setRule(rule);
CAGenetationSet sa =new CAGenetationSet(100, false,rules);
genL=new ArrayList<int[]>();
genL=sa.runSteps(Integer.parseInt(Generations));
System.out.println("calling pattern set");
for(int i=0;i<=genL.size()-1;i++)
{
System.out.println("Painting generation :"+i);
if(stopFlag==false)
{
cacanvas.repaint();
}
//genPaint();
//sleep();
int[] newCell=genL.get(i);
for(int r=0;r<newCell.length;r++)
{
if(newCell[r]==1)
{
System.out.println("Generaton is"+i+"CellLife is"+r);
cacanvas.fillCell(i,r);
}
}
}
/*cacanvas.patternSet(genL);
waitFlag=true;
System.out.println("run completed");
// cacanvas.clearFlag=true;
*/
}
public void genPaint()
{
cacanvas.repaint();
}
public void sleep()
{
try
{
Thread.sleep(100);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
public static void main(String[] args) {
JUIApp app = new JUIApp() {
#Override
public void run() {
// TODO Auto-generated method stub
System.out.println("Run method");
}
};
}
}
Seems like you are using the current Thread on that task, you should create another Thread and add one listeners code to the new Thread.

Unable to resize JPanel in java Swing

I just started using Java Swing, and I was going through the following post: Dynamic fields addition in java/swing form.
I implement the code in this post with some modification, and it worked fine. As mentioned in the post, JPanel is not resizing itself when we add more rows. Can someone throw more light on this issue with easy to understand explanation that how can we resize JPanel as soon as we hit +/- button? Here is the code :
Row class
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JTextField;
#SuppressWarnings("serial")
public class Row extends JPanel {
private JTextField quantity;
private JTextField item;
private JTextField price;
private JButton plus;
private JButton minus;
private RowList parent;
public Row(String initialQuantity, String initalPrice, String initialItem, RowList list) {
this.parent = list;
this.plus = new JButton(new AddRowAction());
this.minus = new JButton(new RemoveRowAction());
this.quantity = new JTextField(10);
this.item = new JTextField(10);
this.price = new JTextField(10);
this.quantity.setText(initialQuantity);
this.price.setText(initalPrice);
this.item.setText(initialItem);
add(this.plus);
add(this.minus);
add(this.quantity);
add(this.item);
add(this.price);
}
public class AddRowAction extends AbstractAction {
public AddRowAction() {
super("+");
}
public void actionPerformed(ActionEvent e) {
parent.cloneRow(Row.this);
}
}
public class RemoveRowAction extends AbstractAction {
public RemoveRowAction() {
super("-");
}
public void actionPerformed(ActionEvent e) {
parent.removeItem(Row.this);
}
}
public void enableAdd(boolean enabled) {
this.plus.setEnabled(enabled);
}
public void enableMinus(boolean enabled) {
this.minus.setEnabled(enabled);
}
}
RowList class
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class RowList extends JPanel{
private List<Row> rows;
public RowList() {
this.rows = new ArrayList<Row>();
Row initial = new Row("1","0.00","", this);
//addHeaders();
//addGenerateBillButton();
addItem(initial);
}
public void addHeaders(){
JLabel qty = new JLabel("Quantity");
//qty.setBounds(10, 0, 80, 25);
add(qty);
JLabel item = new JLabel("Item");
//item.setBounds(70, 0, 80, 25);
add(item);
JLabel price = new JLabel("Price");
//price.setBounds(120, 0, 80, 25);
add(price);
}
public void addGenerateBillButton(){
JButton billGenerationButton = new JButton("Generate Bill");
add(billGenerationButton);
}
public void cloneRow(Row row) {
Row theClone = new Row("1","0.00","", this);
addItem(theClone);
}
private void addItem(Row row) {
rows.add(row);
add(row);
refresh();
}
public void removeItem(Row entry) {
rows.remove(entry);
remove(entry);
refresh();
}
private void refresh() {
revalidate();
repaint();
if (rows.size() == 1) {
rows.get(0).enableMinus(false);
}
else {
for (Row e : rows) {
e.enableMinus(true);
}
}
}
}
Main class
import javax.swing.JFrame;
public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame("Enter Items");
RowList panel = new RowList();
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
You can call the pack() of the frame again.
Try this: Add this in your Row class
public class AddRowAction extends AbstractAction
{
public AddRowAction()
{
super("+");
}
public void actionPerformed(ActionEvent e)
{
parent.cloneRow(Row.this);
((JFrame) SwingUtilities.getRoot(parent)).pack(); // <--- THIS LINE
}
}
public class RemoveRowAction extends AbstractAction
{
public RemoveRowAction()
{
super("-");
}
public void actionPerformed(ActionEvent e)
{
parent.removeItem(Row.this);
((JFrame) SwingUtilities.getRoot(parent)).pack(); // <--- THIS LINE
}
}
You can get the root component (JFrame) using the SwingUtilities.getRoot(comp) from the child component and call the pack() method after your new Row is added to your RowList.
This would resize your JPanel. But your RowList will be horizontal. This is where LayoutManager comes into play.
You can know more about different LayoutManagers here.
To fix this problem, in your RowList panel, set your layout to:
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
Within your refresh method call doLayout() method after revalidate()

Custom JComboBox editor

i got stuck at adding a button to a JComboBox editor, I succeeded to add a button but I got some issues like when I first enter to the editor an action perform event gets fired which is unacceptable and the other is I can't get the text typed.
Result:
Problems:
#Override
public Component getEditorComponent() {
return panel;
}
This is the problem, if I return panel.jtexfield I only get a text field without a button, so what's the trick here?
Here is my code
import Store.util.DatabaseHelper;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.plaf.basic.BasicComboBoxEditor;
import org.hibernate.HibernateException;
import org.netbeans.lib.awtextra.AbsoluteLayout;
public class NewComboTest extends JFrame {
private ArrayList<Object> shopCart = new ArrayList<Object>();
private JComboBox cb;
private static final Object[] comboContents = {
"First", "Second", "Third", "Fourth", "Fifth"
};
public NewComboTest() {
super("New Combo Test");
setLayout(null);
cb = new JComboBox();
cb.setRenderer(new NewComboRenderer());
cb.setEditor(new NewComboEditor());
cb.setEditable(true);
cb.setSize(new Dimension(350, 100));
for (int i = 0; i < comboContents.length; i++) {
cb.addItem(comboContents[ i]);
}
cb.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("_____________" + cb.getSelectedItem());
shopCart.add(cb.getSelectedItem());
System.out.println("items added" + shopCart);
}
});
cb.getEditor().getEditorComponent().addKeyListener(new KeyAdapter() {
#Override
public void keyReleased(KeyEvent e) {
System.out.println("KeyReleased" + cb.getEditor().getItem().toString());
populateModel(cb.getEditor().getItem().toString());
}
});
getContentPane().add(cb, new org.netbeans.lib.awtextra.AbsoluteConstraints(320, 200, 480, 50));
setSize(1200, 450);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] arg) {
new NewComboTest();
}
private class NewComboEditor extends JPanel implements ComboBoxEditor {
JTextField tf;
JButton eraseButton;
textPanel panel = new textPanel();
public NewComboEditor() {
}
#Override
public void addActionListener(ActionListener l) {
tf.addActionListener(l);
}
#Override
public Component getEditorComponent() {
return panel;
}
public Component getEditorComponent2() {
return panel;
}
#Override
public Object getItem() {
return tf.getText();
}
#Override
public void removeActionListener(ActionListener l) {
tf.removeActionListener(l);
}
#Override
public void selectAll() {
tf.selectAll();
}
#Override
public void setItem(Object o) {
if (o != null) {
tf.setText(tf.getText());
} else {
tf.setText("");
}
}
private class textPanel extends JPanel {
JTextField jTextField1 = new JTextField();
JButton jButton1 = new JButton();
public textPanel() {
setLayout(new BorderLayout());
jButton1.setBackground(new java.awt.Color(255, 255, 255));
jButton1.setForeground(new java.awt.Color(0, 51, 51));
jButton1.setText("X");
jButton1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
jTextField1.setText("");
}
});
add(jTextField1, BorderLayout.CENTER);
add(jButton1, BorderLayout.EAST);
}
public String getText(){
return jTextField1.getText();
}
}
}
private class NewComboRenderer extends JLabel implements ListCellRenderer {
public NewComboRenderer() {
setOpaque(true);
}
public Component getListCellRendererComponent(
JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
setText(value.toString());
setBackground(isSelected ? Color.BLUE : Color.white);
setForeground(isSelected ? Color.white : Color.red);
return this;
}
}
/* public void populateModel(String text) throws HibernateException {
java.util.List l = DatabaseHelper.GetProductsBy(text);
for (Object object : l) {
cb.addItem(object);
}
ignore this its unnecessary.
*/
}
}
I also wish to set the text font and size to the same as the set up at the combo box.
The first set of problems I can see is, you define a JTextField and JButton in the NewComboEditor, but also define a textPanel, which contains all these things any way. But instead of using the components on the textPane, you use the newly created components (in the NewComboEditor) instead...In fact, I'm not even sure how that could work, because you never initilise these components (in the NewComboEditor), so there should be a NullPointerException...
If that wasn't enough problems, the JTextField and JButton aren't added to anything anyway...
Instead...
NewComboEditor shouldn't need to extend from anything (or it could extend from textPane instead if you really wanted to).
All references to the field should be made to the text field in the textPane
As an example...
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionListener;
import javax.swing.ComboBoxEditor;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class CustomComboBoxEditor {
public static void main(String[] args) {
new CustomComboBoxEditor();
}
public CustomComboBoxEditor() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JComboBox cb = new JComboBox();
cb.addItem("Apple");
cb.addItem("Banana");
cb.addItem("Orange");
cb.setEditable(true);
cb.setEditor(new MyComboBoxEditor());
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridBagLayout());
frame.add(cb);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class MyComboBoxEditor implements ComboBoxEditor {
private EditorPane editorPane;
public MyComboBoxEditor() {
editorPane = new EditorPane();
}
#Override
public Component getEditorComponent() {
return editorPane;
}
#Override
public void setItem(Object anObject) {
editorPane.setText(anObject == null ? null : anObject.toString());
}
#Override
public Object getItem() {
return editorPane.getText();
}
#Override
public void selectAll() {
editorPane.selectAll();
}
#Override
public void addActionListener(ActionListener l) {
editorPane.addActionListener(l);
}
#Override
public void removeActionListener(ActionListener l) {
editorPane.removeActionListener(l);
}
}
public class EditorPane extends JPanel {
private JTextField field;
private JButton button;
public EditorPane() {
field = new JTextField(10);
button = new JButton("X");
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.weightx = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.gridx = 0;
add(field, gbc);
gbc.weightx = 0;
gbc.fill = GridBagConstraints.NONE;
gbc.gridx++;
add(button, gbc);
}
#Override
public void addNotify() {
super.addNotify();
field.requestFocusInWindow();
}
public void selectAll() {
field.selectAll();
}
public void setText(String text) {
field.setText(text);
}
public String getText() {
return field.getText();
}
public void addActionListener(ActionListener listener) {
field.addActionListener(listener);
}
public void removeActionListener(ActionListener listener) {
field.removeActionListener(listener);
}
}
}
Now, if you want to set the field's properties to be the same as the combo box, I would simply pass a reference of the combo box to the editor and allow it to extract the properties you need (i.e. font, color, etc.)

Categories