Change name of node in JTree - java

I am trying to change the name of a node in my JTree. I use the following code to do so:
/**
* Change the name of the currently selected node
* #param newName Name to change the node too
*/
public void changeNodeName(String newName) {
//get the path to the selected nod
TreePath selectedPath = mainWindow.getStructureTree().getSelectionPath() ;
//make sure there is no other node with this name
DefaultMutableTreeNode node = (DefaultMutableTreeNode) selectedPath.getLastPathComponent();
//change its name
node.setUserObject(newName);
}
This code works ok. So say I want to rename node b in the picture below to c. The code does it correctly as the pictures illustrate.
However, if I then drag the node and place it somewhere else in the tree, its name returns to the original name of b.
So obviously I am not changing something correctly here. How do I or what do I change so the nodes value stays changed?
Thanks
EDIT:
I have a class which extends DefaultMutableTreeNode. Here is the source
package Structure;
import GUI.Window;
import Logging.LogRunner;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JSeparator;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
/**
* This class provides the basic functionality that all subclass of the structre
* will need such as a pop up menu, and adding new nodes.
* #author dvargo
*/
public abstract class BCStructure extends DefaultMutableTreeNode
{
/**
* The root node to which this class belongs
*/
DefaultMutableTreeNode root;
/**
* Reference to the main window
*/
Window mainWindow;
/**
* Name of this node
*/
String name;
/**
* The pop up menu
*/
JPopupMenu Pmenu;
/**
* The pop up menu intems
*/
JMenuItem deleteMenuItem,renameMenuItem,newSectionMenuItem,newPageMenuItem;
/**
* What type of node this is
*/
String type;
/**
* Basic constructor that adds a pop up menu, sets the name, and initalizes values
* #param newName - Name for this node
* #param inWindow - Reference to the main window.
*/
public BCStructure(String newName,Window inWindow)
{
this(newName,inWindow,true);
}
/**
* Returns the type of node this is
* #return Page if the node is a page, Module if the node is a module, Section
* if the node is a section
*/
public String getType()
{
return type;
}
/**
* Returns a copy of this node
* #return
*/
public abstract BCStructure copy();
/**
* If this is a page, this constructor should be called, it will not allof a page to
*have any children
* #param newName - Name for the page
* #param inWindow - Refernce to the main window
* #param letChildren - False to disallow this node from having children
*/
public BCStructure(String newName,Window inWindow,boolean letChildren)
{
super(newName,letChildren);
mainWindow = inWindow;
name = newName;
//add the popup menu
addPopUp();
}
/**
* Updates a specific node
* #param parentNode The parent node to update
*/
public void update(DefaultMutableTreeNode parentNode)
{
((DefaultTreeModel)mainWindow.getStructureTree().getModel()).reload(parentNode);
mainWindow.getStructureTree().repaint();
}
/**
* Returns the node that is currently selected (by being clicked on) in the tree
* #return Node that is selected in the tree
*/
public DefaultMutableTreeNode getSelectedNode()
{
return (DefaultMutableTreeNode)mainWindow.getStructureTree().getLastSelectedPathComponent();
}
/**
* Returns the TreePath to this node
* #return The TreePath to this node
*/
public TreePath getTreePath()
{
return new TreePath(this.getPath());
}
/**
* Sets the selected node in the tree
* #param node The node to set selected in the tree
*/
public void setSelectedNode(BCStructure node)
{
mainWindow.getStructureTree().setSelectionPath(new TreePath(node.getPath()));
update(node);
}
/**
* Change the name of the currently selected node
* #param newName Name to change the node too
*/
public void changeNodeName(String newName) {
//get the path to the selected nod
TreePath selectedPath = mainWindow.getStructureTree().getSelectionPath() ;
//make sure there is no other node with this name
DefaultMutableTreeNode node = (DefaultMutableTreeNode) selectedPath.getLastPathComponent();
DefaultMutableTreeNode nodeParent = (DefaultMutableTreeNode) node.getParent();
if(nodeParent != null)
{
for(int i = 0; i lt nodeParent.getChildCount(); i++)
{
DefaultMutableTreeNode currNode = (DefaultMutableTreeNode) nodeParent.getChildAt(i);
if(currNode.getUserObject().equals(newName))
{
JOptionPane.showMessageDialog(mainWindow,"Another page or section already has this name in this level. Please select another.");
return;
}
}
}
//change its name
node.setUserObject(newName);
//mainWindow.getStructureTree().getModel().valueForPathChanged(selectedPath, newName);
update(getSelectedNode());
}
/**
* Adds a new section node to the tree
* #param newName Name for this node
*/
public void addNewSectionNode(String newName) {
DefaultMutableTreeNode temp = getSelectedNode();
Section newNode = null;
if(temp == null)
{
LogRunner.dialogMessage(this.getClass(),"Please select a node to add this section to.");
}
else
{
newNode = new Section(newName,mainWindow);
try
{
temp.add(newNode);
}
catch(java.lang.IllegalStateException e)
{
LogRunner.getLogger().warning("You can not add a section to a page");
temp = (DefaultMutableTreeNode) temp.getParent();
temp.add(newNode);
}
}
//set the selected node to the previously selected node
update(temp);
if(newNode != null)
{
mainWindow.getStructureTree().setSelectionPath(new TreePath(newNode.getPath()));
}
}
/**
* Adds a new page to this tree
* #param newName Name for the node
* #return The newly created page
*/
public Page addNewPageNode(String newName)
{
TreePath oldPath = mainWindow.getStructureTree().getSelectionPath();
//Section newSection = new Section(newSectionName);
DefaultMutableTreeNode temp = getSelectedNode();
Page newPage = null;
if(temp == null)
{
LogRunner.dialogMessage(this.getClass(),"Please select a module or section to add this section to.");
}
else
{
newPage = new Page(newName,mainWindow);
try
{
temp.add(newPage);
}
catch(java.lang.IllegalStateException e)
{
LogRunner.getLogger().warning("You can not add any more nodes to a page.");
temp = (DefaultMutableTreeNode) temp.getParent();
temp.add(newPage);
}
}
update(temp);
mainWindow.getStructureTree().setSelectionPath(oldPath);
return newPage;
}
/**
* Propmpts the user to entere a new name for a node that is selected
*/
private void rename()
{
String newname = JOptionPane.showInputDialog("New name?");
changeNodeName(newname);
}
/**
* Deletes the selected node from the tree
*/
private void delete()
{
DefaultMutableTreeNode node = (DefaultMutableTreeNode)mainWindow.getStructureTree().getLastSelectedPathComponent();
if(node == null) return;
DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode)(node.getParent());
if(parentNode == null) return;
//remove node
parentNode.remove(node);
((DefaultTreeModel)mainWindow.getStructureTree().getModel()).reload(parentNode);
}
/**
* Deletes a specific node from the tree
* #param node The node to delete
*/
protected void delete(DefaultMutableTreeNode node)
{
if(node == null) return;
DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode)(node.getParent());
if(parentNode == null) return;
//remove node
parentNode.remove(node);
((DefaultTreeModel)mainWindow.getStructureTree().getModel()).reload(parentNode);
}
/**
* Adds the popup menu functionality to the tree
*/
private void addPopUp()
{
Pmenu = new JPopupMenu();
newSectionMenuItem = new JMenuItem("Add New Section");
Pmenu.add(newSectionMenuItem);
newPageMenuItem = new JMenuItem("Add New Page");
Pmenu.add(newPageMenuItem);
Pmenu.add(new JSeparator());
deleteMenuItem = new JMenuItem("Delete");
Pmenu.add(deleteMenuItem);
renameMenuItem = new JMenuItem("Rename");
Pmenu.add(renameMenuItem);
//add actionlisteners to the menu items
deleteMenuItem.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
delete();}
}
);
renameMenuItem.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
rename();}
}
);
newSectionMenuItem.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
mainWindow.createNewSectionPublicCall();}
}
);
newPageMenuItem.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
mainWindow.createNewPagePublicCall();}
}
);
//add action listener to the tree
mainWindow.getStructureTree().addMouseListener(new MouseAdapter()
{
public void mouseReleased(MouseEvent Me)
{
if(Me.isPopupTrigger())
{
Pmenu.show(Me.getComponent(), Me.getX(), Me.getY());
}
}
});
if(getClass().equals(Page.class))
{
newSectionMenuItem.setEnabled(false);
}
}
/**
* Returns all the nodes in this tree from doing a left heavy recursive
* traversal of the tree from the given root
* #param root The root from which to start the search
* #return A list of the nodes
*/
public ArrayList getAllNodesInOrder(BCStructure root)
{
ArrayList nodes = new ArrayList();
getAllNodesInOrderRec(root, nodes);
return nodes;
}
/**
* Recursive function that gets the nodes in the tree
* #param currNode
* #param theNodes
*/
private void getAllNodesInOrderRec(BCStructure currNode, ArrayList theNodes)
{
theNodes.add(currNode);
for(int i = 0; i lt currNode.getChildCount(); i++)
{
currNode.getAllNodesInOrderRec((BCStructure) currNode.getChildAt(i), theNodes);
}
}
}
And in the example above, the actual nodes you are seeing are a subclass of BCStructure called Page. This is the actual class that I am renaming.
package Structure;
import Components.BCFrame;
import Components.Basic.BackGroundImage;
import GUI.Window;
import Logging.LogRunner;
import XMLProcessing.XMLWriter;
import java.awt.Color;
import java.awt.Dimension;
import java.util.ArrayList;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.tree.DefaultTreeCellRenderer;
/**
* This class is responcible for holding the components the make up a page and
* is accessible through the tree structure. In other words, this class is what
* actually makes up a page. It holds the componenets in an array, and since it
* node in a tree, it can be notified when it has been clicked, and load the
* compoenents it is holding.
* #author dvargo
*/
public class Page extends BCStructure
{
/**
* Holds all the componenets in the content pane so an action can be done on
* all componenets. Also sets the added component to the current component.
*/
private ArrayList theComponents = new ArrayList()
{
#Override
public boolean add(BCFrame e)
{
e.setPage(selfReference);
return super.add(e);
}
};
/**
* Self reference to this page
*/
private Page selfReference = this;
/**
* The dimensions of this page. It defualts to a medium page size
*/
private Dimension pageSize = Window.NORMAL;
/**
* This bages background;
*/
private BackGroundImage background;
/**
* Constructor that sets the node up in the tree and inializes values.
* #param newName - Name for this node
* #param inWindow - Reference to the main window
* #param inRoot - The section or module that is the root for this page.
*/
public Page(String newName, Window inWindow)
{
super(newName, inWindow,false);
DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer();
ImageIcon theImage = new ImageIcon(new JFrame().getToolkit().getImage(getClass().getResource("/GUI/fileIcon.png")));
renderer.setLeafIcon(theImage);
//set the background color to white, there will always be a background
background = new BackGroundImage(0,0,pageSize.width,pageSize.height,mainWindow);
background.setColor(Color.WHITE);
theComponents.add(background);
//you must add this to the content pane to keep indexes correct. it will not display anything though
mainWindow.getComponentContentPane().add(background,0);
mainWindow.getContentPanePanel().repaint();
}
/**
* Loads all the componenets held in the arraylist to to the screen.
*/
public void loadPage()
{
//remove the background of the previous page
mainWindow.getComponentContentPane().removeAll();
mainWindow.setPageSizeComboSeleted(pageSize);
background.setSize(pageSize);
mainWindow.getComponentContentPane().setPreferredSize(pageSize);
mainWindow.getComponentContentPane().setSize(pageSize);
for(BCFrame currentComp : theComponents)
{
mainWindow.getComponentContentPane().add(currentComp);
currentComp.setVisible(true);
currentComp.revalidate();
currentComp.repaint();
currentComp.setPage(this);
}
mainWindow.getComponentContentPane().repaint();
mainWindow.getComponentContentPane().revalidate();
}
/**
* Writes the componenets to file in XML.
* #param filePath - The path and name of the file to write.
*/
public void save(String filePath)
{
XMLWriter theWriter = new XMLWriter();
for(int i = 0; i newComponents)
{
theComponents = newComponents;
boolean backgroundExists = false;
for(BCFrame curr : theComponents)
{
if(curr.getClass().equals(BackGroundImage.class))
{
background = (BackGroundImage) curr; //make sure background isnt null
backgroundExists = true;
}
curr.setPage(this);
}
if(backgroundExists)
{
return;
}
LogRunner.getLogger().severe("Could not find a background while setting the components, adding a new dfualt white one");
BackGroundImage bgi= new BackGroundImage();
bgi.setSize(pageSize);
bgi.setColor(Color.WHITE);
theComponents.add(bgi);
background = bgi;
}
public ArrayList getComponents()
{
return theComponents;
}
}

I figured it out. If you notice in BCStructure, it has a value called name. Whenever I change the name of the node I did not update this value. Then if you notice in the copy() of the Page class, it uses this name variable. Copy gets used in the drag and drop process. If name was not updated, it would be using the old value which is why I saw the behavior I did. Kind of simple to see but hard to explain. Thanks all for your help.

I cannot see the code you are using to create the TreeModel, however i am guessing that you are not using mutable nodes:
http://download.oracle.com/javase/1.5.0/docs/api/javax/swing/tree/MutableTreeNode.html#setUserObject%28java.lang.Object%29

Related

Create a nice-looking listview in Java

I'm new to Java swing and I'm trying to create a list view showing content of a directory. I expect to create a view like following image:
I know how to use JList, but I don't know how to show icons matching with types of files. As you can see, from the image, we can visually differentiate pdf files with text files and others. Should I try to use JList or another UI component?
I have done something similar; here's an example of my output.
I used a custom renderer for the tree; it produces the indentation, icon, and text that you see in one cell of the leftmost column of the display. Here's the source for that:
package spacecheck.ui.renderer;
import java.awt.Component;
import javax.swing.ImageIcon;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
import spacecheck.filedata.FileCollection;
import spacecheck.images.TreeIcon;
/**
* renders the name of a collection for the tree display.
* #author rcook
*
*/
public class CollectionNameRenderer extends DefaultTableCellRenderer // which implements JLabel
// implements TableCellRenderer
{
private static final long serialVersionUID = 1L;
#SuppressWarnings({"unused"})
private void say(String msg) { System.out.println(msg); }
private static TreeIcon tIcon = null;
/**
* set the value of the CollectionName for the JTable; includes using
* indent so that the correct icon can be obtained (icons are different widths
* to implement different indent levels).
*/
public void setValue(Object value)
{
FileCollection fc = (FileCollection)value;
boolean expanded = fc.isExpanded();
int level = fc.getDisplayLevel();
// boolean isSelected = table.
ImageIcon icon = tIcon.getIcon(level, expanded);
if (icon != null) { setIcon(icon); }
setText(value.toString());
}
/**
* get the renderer component for a collection name.
*/
public Component getTableCellRendererComponent
(JTable table, Object value, boolean isSelected, boolean hasFocus,
int rowIndex, int colIndex)
{
if (tIcon == null) { tIcon = new TreeIcon(table.getBackground()); }
return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, rowIndex, colIndex);
}
}
That class uses another of mine named TreeIcon; it implements the indentation of the folder icon as shown in the picture as well as choosing the icon depending on the expanded/unexpanded state of the folder. Here's that class:
package spacecheck.images;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
/**
* represents an icon used in the directory tree; handles 'expanded' and
* 'unexpanded' directories as well as indentation representing different
* levels.
* #author rcook
*
*/
public class TreeIcon
{
public static int UNEXPANDED = 1;
public static int EXPANDED = 2;
#SuppressWarnings({"unused"})
private void say (String msg) { System.out.println(msg); }
private static ImageIcon expandedIcon = null;
private static ImageIcon unexpandedIcon = null;
private static int iconHeight = 0;
private static int iconWidth = 0;
private static ArrayList<ImageIcon> cachedExpandedIcons = new ArrayList<ImageIcon>();
private static ArrayList<ImageIcon> cachedUnexpandedIcons = new ArrayList<ImageIcon>();
static
{
expandedIcon = new ImageIcon(TreeIcon.class.getResource("images/Expanded.png"));
unexpandedIcon = new ImageIcon(TreeIcon.class.getResource("images/Unexpanded.png"));
iconHeight = unexpandedIcon.getIconHeight();
iconWidth = unexpandedIcon.getIconWidth();
}
public TreeIcon(Color givenColor) { }
public static void main(String ... arguments)
{
JFrame frame = new JFrame("icon test");
JLabel label = new JLabel("background test");
label.setBackground(Color.blue);
TreeIcon treeIcon = new TreeIcon(Color.black);
ImageIcon icon = treeIcon.getIcon(2, false);
label.setIcon(icon);
frame.add(label);
frame.pack();
frame.setVisible(true);
}
/**
* return the icon for an expanded or unexpanded level
* #param int level of folder relative to other levels displayed;
* starts at 0 and increases with depth
* #param boolean indicates whether this level is expanded or not.
* #return ImageIcon appropriate for expansion flag and level.
*/
public ImageIcon getIcon(int level, boolean expanded)
{
ImageIcon result = null;
if (level < 0)
{ System.out.println("level is " + level + ", setting to 0");
level = 0;
}
// set our list of icons depending on whether we are expanded.
ArrayList<ImageIcon> cachedIcons = cachedUnexpandedIcons;
if (expanded) { cachedIcons = cachedExpandedIcons; }
// if we already have this icon in our cache, return it.
if (cachedIcons.size() >= (level+1) && cachedIcons.get(level) != null)
{
result = cachedIcons.get(level);
}
else
{
// generate this icon and store it in the cache before returning it.
ImageIcon baseIcon = unexpandedIcon;
if (expanded) { baseIcon = expandedIcon; }
int iconH = iconHeight;
int iconW = iconWidth*(level+1);
BufferedImage bufferedImage = new BufferedImage(iconW,iconH,BufferedImage.TYPE_INT_ARGB);
Graphics g = bufferedImage.getGraphics();
g.drawImage(baseIcon.getImage(), iconWidth*level, 0, null);
result = new ImageIcon(bufferedImage);
// we've created an icon that was not in the cached list;
// the cached list may have a null at this slot, or it may not yet be
// long enough to have this slot. Ensure that we have enough slots
// in the list, and then add this icon.
for (int i=cachedIcons.size(); i<=level; i++)
{
cachedIcons.add(null);
}
// if (cachedIcons.size() < level + 1) { cachedIcons.add(result); }
// else {
cachedIcons.set(level, result);
// }
// say("adding icon, level = " + level + (expanded ? " " : " un") + "expanded, width = " + iconW);
}
return result;
}
}
To choose icons for different kinds of files, you could have your renderer and icon-chooser look at the file extension (or whatever) to determine which icon out of a map to use.
Hope that helps!

Swing events not passed to upwards to base component

I have a class called ComponentMover that allows you to drag around any object that's registered with it. This works if you pass it bare JPanels, but it doesn't work if the JPanel has anything inside of it, and it just stays put.
This is ComponentMover:
public class ComponentMover extends MouseAdapter {
private Insets dragInsets = new Insets(0, 0, 0, 0);
private Dimension snapSize = new Dimension(1, 1);
private Insets edgeInsets = new Insets(0, 0, 0, 0);
private boolean changeCursor = true;
private boolean autoLayout = false;
private Class<?> destinationClass;
private Component destinationComponent;
private Component destination;
private Component source;
private Point pressed;
private Point location;
private Cursor originalCursor;
private boolean autoscrolls;
private boolean potentialDrag;
private boolean shouldLock = true;
/**
* Constructor for moving individual components. The components must be
* regisetered using the registerComponent() method.
*/
public ComponentMover() {
}
/**
* Constructor to specify a Class of Component that will be moved when drag
* events are generated on a registered child component. The events will be
* passed to the first ancestor of this specified class.
*
* #param destinationClass
* the Class of the ancestor component
* #param component
* the Components to be registered for forwarding drag events to
* the ancestor Component.
*/
public ComponentMover(Class<?> destinationClass, JComponent... components) {
this.destinationClass = destinationClass;
registerComponent(components);
}
/**
* Constructor to specify a parent component that will be moved when drag
* events are generated on a registered child component.
*
* #param destinationComponent
* the component drage events should be forwareded to
* #param components
* the Components to be registered for forwarding drag events to
* the parent component to be moved
*/
public ComponentMover(JComponent destinationComponent,
JComponent... components) {
this.destinationComponent = destinationComponent;
registerComponent(components);
}
public void setLock(boolean shouldLock) {
this.shouldLock = shouldLock;
}
/**
* Get the auto layout property
*
* #return the auto layout property
*/
public boolean isAutoLayout() {
return autoLayout;
}
/**
* Set the auto layout property
*
* #param autoLayout
* when true layout will be invoked on the parent container
*/
public void setAutoLayout(boolean autoLayout) {
this.autoLayout = autoLayout;
}
/**
* Get the change cursor property
*
* #return the change cursor property
*/
public boolean isChangeCursor() {
return changeCursor;
}
/**
* Set the change cursor property
*
* #param changeCursor
* when true the cursor will be changed to the Cursor.MOVE_CURSOR
* while the mouse is pressed
*/
public void setChangeCursor(boolean changeCursor) {
this.changeCursor = changeCursor;
}
/**
* Get the drag insets
*
* #return the drag insets
*/
public Insets getDragInsets() {
return dragInsets;
}
/**
* Set the drag insets. The insets specify an area where mouseDragged events
* should be ignored and therefore the component will not be moved. This
* will prevent these events from being confused with a MouseMotionListener
* that supports component resizing.
*
* #param dragInsets
*/
public void setDragInsets(Insets dragInsets) {
this.dragInsets = dragInsets;
}
/**
* Get the bounds insets
*
* #return the bounds insets
*/
public Insets getEdgeInsets() {
return edgeInsets;
}
/**
* Set the edge insets. The insets specify how close to each edge of the
* parent component that the child component can be moved. Positive values
* means the component must be contained within the parent. Negative values
* means the component can be moved outside the parent.
*
* #param edgeInsets
*/
public void setEdgeInsets(Insets edgeInsets) {
this.edgeInsets = edgeInsets;
}
/**
* Remove listeners from the specified component
*
* #param component
* the component the listeners are removed from
*/
public void deregisterComponent(JComponent... components) {
for (JComponent component : components)
component.removeMouseListener(this);
}
/**
* Add the required listeners to the specified component
*
* #param component
* the component the listeners are added to
*/
public void registerComponent(JComponent... components) {
for (JComponent component : components){
component.addMouseListener(this);
}
}
/**
* Get the snap size
*
* #return the snap size
*/
public Dimension getSnapSize() {
return snapSize;
}
/**
* Set the snap size. Forces the component to be snapped to the closest grid
* position. Snapping will occur when the mouse is dragged half way.
*/
public void setSnapSize(Dimension snapSize) {
if (snapSize.width < 1 || snapSize.height < 1)
throw new IllegalArgumentException(
"Snap sizes must be greater than 0");
this.snapSize = snapSize;
}
/**
* Setup the variables used to control the moving of the component:
*
* source - the source component of the mouse event destination - the
* component that will ultimately be moved pressed - the Point where the
* mouse was pressed in the destination component coordinates.
*/
#Override
public void mousePressed(MouseEvent e) {
source = e.getComponent();
int width = source.getSize().width - dragInsets.left - dragInsets.right;
int height = source.getSize().height - dragInsets.top
- dragInsets.bottom;
Rectangle r = new Rectangle(dragInsets.left, dragInsets.top, width,
height);
if (r.contains(e.getPoint()))
setupForDragging(e);
}
private void setupForDragging(MouseEvent e) {
source.addMouseMotionListener(this);
potentialDrag = true;
// Determine the component that will ultimately be moved
if (destinationComponent != null) {
destination = destinationComponent;
} else if (destinationClass == null) {
destination = source;
} else // forward events to destination component
{
destination = SwingUtilities.getAncestorOfClass(destinationClass,
source);
}
pressed = e.getLocationOnScreen();
location = destination.getLocation();
if (changeCursor) {
originalCursor = source.getCursor();
source.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
}
// Making sure autoscrolls is false will allow for smoother dragging of
// individual components
if (destination instanceof JComponent) {
JComponent jc = (JComponent) destination;
autoscrolls = jc.getAutoscrolls();
jc.setAutoscrolls(false);
}
}
/**
* Move the component to its new location. The dragged Point must be in the
* destination coordinates.
*/
#Override
public void mouseDragged(MouseEvent e) {
Point dragged = e.getLocationOnScreen();
int dragX = getDragDistance(dragged.x, pressed.x, snapSize.width);
int dragY = getDragDistance(dragged.y, pressed.y, snapSize.height);
int locationX = location.x + dragX;
int locationY = location.y + dragY;
// Mouse dragged events are not generated for every pixel the mouse
// is moved. Adjust the location to make sure we are still on a
// snap value.
if (shouldLock) {
while (locationX < edgeInsets.left)
locationX += snapSize.width;
while (locationY < edgeInsets.top)
locationY += snapSize.height;
Dimension d = getBoundingSize(destination);
while (locationX + destination.getSize().width + edgeInsets.right > d.width)
locationX -= snapSize.width;
while (locationY + destination.getSize().height + edgeInsets.bottom > d.height)
locationY -= snapSize.height;
}
// Adjustments are finished, move the component
destination.setLocation(locationX, locationY);
}
/*
* Determine how far the mouse has moved from where dragging started (Assume
* drag direction is down and right for positive drag distance)
*/
private int getDragDistance(int larger, int smaller, int snapSize) {
int halfway = snapSize / 2;
int drag = larger - smaller;
drag += (drag < 0) ? -halfway : halfway;
drag = (drag / snapSize) * snapSize;
return drag;
}
/*
* Get the bounds of the parent of the dragged component.
*/
private Dimension getBoundingSize(Component source) {
if (source instanceof Window) {
GraphicsEnvironment env = GraphicsEnvironment
.getLocalGraphicsEnvironment();
Rectangle bounds = env.getMaximumWindowBounds();
return new Dimension(bounds.width, bounds.height);
} else {
return source.getParent().getSize();
}
}
/**
* Restore the original state of the Component
*/
#Override
public void mouseReleased(MouseEvent e) {
if (!potentialDrag)
return;
source.removeMouseMotionListener(this);
potentialDrag = false;
if (changeCursor)
source.setCursor(originalCursor);
if (destination instanceof JComponent) {
((JComponent) destination).setAutoscrolls(autoscrolls);
}
// Layout the components on the parent container
if (autoLayout) {
if (destination instanceof JComponent) {
((JComponent) destination).revalidate();
} else {
destination.validate();
}
}
}
}
What should I do with this code (or the other GUI's building code) to make me able to drag and drop components with children?
You have an adaptation of a ComponentMover by #camickr. The original and your version work fine with components that have children. Perhaps the problem is elsewhere. Consider posting an MCVE that illustrates the problem.
Here is a simple demo:
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TestMove extends JPanel{
public TestMove() {
setLayout(null);
JPanel panel = new JPanel();
panel.add(new JLabel("label"));
panel.add(new JButton("button"));
panel.setBorder(BorderFactory.createLineBorder(Color.GREEN));
panel.setBounds(50, 50, 200, 50);
add(panel);
ComponentMover cm = new ComponentMover();
cm.registerComponent(panel);
}
public Dimension getPreferredSize() {
return new Dimension(300, 200);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
TestMove panel = new TestMove();
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
});
}
}

How can I solve different types of collection

There are a lot of questions in here.
I wrote a code this far, but hard to write in code in some methods.
1.I don't know how to do setDice(List dice) method. If I use for(JButton b:dice), then it keeps giving me compile-time error.
2.Help me to implement setWordIsCorrect(boolean isCorrect) & clearCurrentWord() methods
Make sure you cannot touch other methods and modify the method signatures.
package cse1030.games.boggle;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
/**
* The view for the Boggle app. Please see the lab for a detailed description of
* the view.
*
* #author CSE1030_F13_14
*
*/
public class BoggleView extends JFrame implements ActionListener {
/**
* The string representing the clear command. The view listens for its own
* clear event.
*/
public static final String CLEAR_COMMAND = "clear";
/**
* The string representing the roll command.
*/
public static final String ROLL_COMMAND = "roll";
/**
* The string repesenting the submit command.
*/
public static final String SUBMIT_COMMAND = "submit";
/**
* A list that contains references to the buttons representing the dice.
*/
private List<JButton> diceButtons;
/**
* The text field that displays the current word.
*/
private JTextField word;
/**
* The set of dice buttons that have already been used to form the current
* word.
*/
private Set<JButton> usedButtons;
/**
* The text area that displays the list of correct words.
*/
private JTextArea correctWords;
/**
* The text area that displays the list of incorrect words.
*/
private JTextArea incorrectWords;
/**
* Create the Boggle user interface. Please see the lab for a detailed
* description of the user interface.
*
* #param controller
* the controller that listens for submit and roll events
*/
public BoggleView(BoggleController controller) {
super("Boggle");
this.diceButtons = new ArrayList<JButton>();
this.usedButtons = new HashSet<JButton>();
JPanel contentPanel = new JPanel();
JPanel leftPanel = this.makeLeftPanel();
JPanel rightPanel = this.makeRightPanel();
JPanel middlePanel = this.makeMiddlePanel(controller);
contentPanel.add(leftPanel);
contentPanel.add(middlePanel);
contentPanel.add(rightPanel);
this.setContentPane(contentPanel);
this.pack();
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
/**
* Creates the panel that contains the buttons representing the Boggle dice.
*
* #return the <code>JPanel</code> that contains the buttons representing the
* Boggle dice.
*
*/
private JPanel makeDicePanel() {
Font font = new Font(Font.SANS_SERIF, Font.BOLD, 32);
JPanel p = new JPanel();
p.setLayout(new GridLayout(4, 4));
p.setMaximumSize(new Dimension(450, 450));
for (int i = 0; i < 16; i++) {
JButton b = new JButton("" + i);
b.setPreferredSize(new Dimension(100, 100));
b.setMaximumSize(b.getSize());
b.setFont(font);
b.setBackground(Color.WHITE);
b.setActionCommand("" + i);
b.addActionListener(this);
p.add(b);
this.diceButtons.add(b);
}
return p;
}
/**
* Returns the buttons surrounding the button representing the die that was
* last selected by the user. These are the buttons that could legally be
* chosen next by the user when forming a word.
*
* #param idx
* the index of the button representing the die that was last
* selected by the user
* #return the buttons surrounding the last selected die
*/
private List<JButton> findNeighbors(int idx) {
List<JButton> neighbors = new ArrayList<JButton>();
final int row = idx / 4;
final int col = idx % 4;
final int minRow = Math.max(0, row - 1);
final int maxRow = Math.min(3, row + 1);
final int minCol = Math.max(0, col - 1);
final int maxCol = Math.min(3, col + 1);
for (int i = minRow; i <= maxRow; i++) {
for (int j = minCol; j <= maxCol; j++) {
int n = i * 4 + j;
if (n != idx) {
neighbors.add(this.diceButtons.get(n));
}
}
}
return neighbors;
}
/**
* Disable all of the buttons representing the dice.
*/
private void disableAllDiceButtons() {
for (JButton b : this.diceButtons) {
b.setEnabled(false);
}
}
/**
* Enable all of the buttons representing the dice.
*/
private void enableAllDiceButtons() {
for (JButton b : this.diceButtons) {
b.setEnabled(true);
b.setBackground(Color.WHITE);
}
}
/**
* Responds to events from the view. This method responds to an event where
* the action command is either <code>BoggleView.CLEAR_COMMAND</code>,
* <code>BoggleView.ROLL_COMMAND</code>, or
* <code>BoggleView.SUBMIT_COMMAND</code>.
*
* #param event
* an event emitted by the view
*
* #see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
*/
#Override
public void actionPerformed(ActionEvent event) {
String command = event.getActionCommand();
if (command.equals(CLEAR_COMMAND)) {
this.clearCurrentWord();
} else if (command.equals(ROLL_COMMAND)) {
this.clearCorrectWords();
this.clearIncorrectWords();
this.clearCurrentWord();
} else {
try {
int d = Integer.parseInt(command);
JButton b = this.diceButtons.get(d);
b.setBackground(Color.BLUE);
this.word.setText(this.word.getText() + b.getText());
this.usedButtons.add(b);
this.disableAllDiceButtons();
List<JButton> neighbors = findNeighbors(d);
for (JButton n : neighbors) {
if (!this.usedButtons.contains(n)) {
n.setEnabled(true);
}
}
} catch (NumberFormatException ex) {
}
}
}
/**
* Creates the left-hand panel. Please see the lab for a detailed description
* of the panel's contents.
*
* #return the left-hand <code>JPanel</code> with all of its necessary
* components
*/
private JPanel makeLeftPanel() {
// create the panel
JPanel p = new JPanel();
// set the layout for the panel to use a BoxLayout;
// BoxLayout stacks its components vertically or horizontally
p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
// create a label for the list of correct words and add it to the panel
JLabel label = new JLabel("Correct Words");
p.add(label);
// create the list of correct words, remove the ability for the user to
// edit the list, and add it to the panel
this.correctWords = new JTextArea(30, 16);
this.correctWords.setEditable(false);
p.add(this.correctWords);
return p;
}
/**
* Creates the right-hand panel. Please see the lab for a detailed description
* of the panel's contents.
*
* #return the right-hand <code>JPanel</code> with all of its necessary
* components
*/
private JPanel makeRightPanel() {
JPanel p = new JPanel();
p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
JLabel label = new JLabel("Incorrect Words");
p.add(label);
this.incorrectWords = new JTextArea(30, 16);
this.incorrectWords.setEditable(false);
p.add(this.incorrectWords);
return p;
}
/**
* Creates the middle panel. Please see the lab for a detailed description of
* the panel's contents.
*
* #return the middle <code>JPanel</code> with all of its necessary components
*/
private JPanel makeMiddlePanel(BoggleController controller) {
JPanel p = new JPanel();
// 1. set the layout to a BoxLayout (same as makeLeftPanel)
p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
// 2. make the dice panel and add it to p; there is a method that makes the
// dice panel for you!
p.add(makeDicePanel());
// 3. make the contorl panel and add it to p; there is a method that makes
// the control for you!
p.add(makeControlPanel(controller));
return p;
}
/**
* Creates the panel that contains the clear, submit, and re-roll buttons, and
* the text field for the word.
*
* #return the <code>JPanel</code> that contains the controls below the dice
*
*/
private JPanel makeControlPanel(BoggleController controller) {
JPanel p = new JPanel();
// You don't need to create a lay out. JPanel uses FlowLayout if you don't
// specify a lay out.
// Make the clear button
JButton clear = new JButton("Clear");
// Set its action command to the clear command
clear.setActionCommand(BoggleView.CLEAR_COMMAND);
// Add this as an action listener; see the actionPerformed method above.
// The controller does not need to listen to this button because the model
// is not needed to clear the current word.
clear.addActionListener(this);
// Add the clear button to the panel.
p.add(clear);
// Make a text field that can display a 16 character word
this.word = new JTextField(16);
// Disable editing by the user.
this.word.setEditable(false);
// Add the text field to the panel.
p.add(this.word);
// - make the submit button
JButton submit = new JButton("Submit");
// - set its action command
submit.setActionCommand(BoggleView.SUBMIT_COMMAND);
// - add the controller as an action listener
submit.addActionListener(controller);
// - add the submit button to the panel
p.add(submit);
// - make the re-roll button
JButton roll = new JButton("Re-roll");
// - set its action command
roll.setActionCommand(BoggleView.ROLL_COMMAND);
// - add the controller as an action listener
roll.addActionListener(controller);
// - add this as an action listener
roll.addActionListener(this);
// - add the re-roll button to the panel
p.add(roll);
return p;
}
/**
* Get the current string that is in the word text field.
*
* #return the current string that is in the word text field
*/
public String getWord() {
// change the return statement below
return this.word.getText();
}
/**
* Sets the text on the buttons representing the dice.
*
* #pre. <code>dice.size() == 16</code>
*
* #param dice
* a list of 16 Boggle dice
*/
public void setDice(List<BoggleDie> dice) {
**for (JButton b : dice) {
b.setText(b.getText());
}**
}
/**
* Causes the view to update after the submitted word is evaluated for
* correctness. If <code>isCorrect == true</code> then the current word is
* added to the list of correct words. If <code>isCorrect == false</code> then
* the current word is added to the list of incorrect words. In both cases,
* the current word is cleared.
*
* #param isCorrect
* <code>true</code> if the current word has been determined to be a
* legal Boggle word, <code>false</code> otherwise
*/
public void setWordIsCorrect(boolean isCorrect) {
if(isCorrect == true) {
} else {
}
}
/**
* Clears the list of correct words.
*/
private void clearCorrectWords() {
this.correctWords.setText(null);
}
/**
* Clears the list of incorrect words.
*/
private void clearIncorrectWords() {
this.incorrectWords.setText(null);
}
/**
* Clears the current word and prepares the view to accept a new word. This
* requires re-enabling all of the dice buttons and clearing the set
* this.usedButtons
*/
private void clearCurrentWord() {
// 1. enable all of the dice buttons; there is a method that does this for
// you
enableAllDiceButtons();
// 2. set the text of this.word to the empty string
// 3. remove all of the buttons from this.usedButtons
}
public static void main(String[] args) {
BoggleView v = new BoggleView(null);
v.setVisible(true);
}
}
I will appreciate you if you can help me how to do these methods...
You need to use for (BoggleDie b : dice) or (List<JButton> dice). If the list contains BoggleDie, you must use the former.
You may want to have a list of JButtons instead
public void setDice(List<JButton> dice) {
for (JButton b : dice) {
b.setText(b.getText());
}
}
You need to make sure you actually initialize the list and add JButtons to the list before you can do anything with it.
List<JButton> diceButtons = new List<JButton>();
for (int i = 0; i < 16; i++){
diceButton.add(new JButton("" + i + 1);
}
Try this for your method
public void setDice(){
for (int i = 0; i < 16; i++){
diceButtons.add(new JButton("SomeText");
}
}
Edit: with BoggleDie class
public class BoggleDie{
int value;
public BoggleDie(int value){
this.value = value;
}
}
public class BoggleView ... {
...
private List<BoggleDie> dice = new List<BoggleDie>();
private List<JButton> diceButton = new ArrayList<JButton>();
public BoggleView(){
for (int i = 0; i < 16; i++){
dice.add(new BoggleDie(i)); // or whatever value you want for the die
}
setDice(dice);
}
public void setDice(List<BoggleDie> dice) {
for (BoggleDie b : dice) {
diceButtons.add(new JButton(b.value));
}
}
}
Change the code as follows
public void setDice(List<JButton> dice) {
for (JButton b : dice) {
b.setText(b.getText());
}
}

JTree shows same node as child node

I am using a custom TreeModel for my JTree. I have a root node and only 1 child node that is retrieved by a query from the database. I am able to populate the tree with the desired output.
However, when I click on the child node, it keeps recursively dispalying the same child node and it keeps adding child nodes with the same output. I tried to use static nodes i.e. I created a root node and then added 2 child nodes to it and I observe the same behavior.
My main program
import javax.swing.JFrame;
import javax.swing.JSplitPane;
import javax.swing.SwingUtilities;
public class RunApp {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
ShowFrame f = new ShowFrame();
f.setSize(600, 600);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
});
}
}
My show_frame class
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.HeadlessException;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.tree.DefaultMutableTreeNode;
public class ShowFrame extends JFrame {
private JSplitPane splitPane;
private FormPanel formPanel;
private TreePanel treePanel;
private JTabbedPane tabPane;
private List<Objects> instanceDetails= new ArrayList<Objects>();
public ShowFrame() {
super("new frame");
formPanel = new FormPanel();
instanceDetails.add(new Objects(" "," "," "," "));
treePanel = new TreePanel(instanceDetails);
tabPane = new JTabbedPane();
tabPane.add(treePanel);
splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, formPanel,
tabPane);
splitPane.setOneTouchExpandable(true);
setMinimumSize(new Dimension(500, 500));
add(splitPane, BorderLayout.CENTER);
}
}
This is where I create my TreePanel
import java.util.List;
import javax.swing.JPanel;
import javax.swing.JTree;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
public class TreePanel extends JPanel {
private int count = 0;
private JTree tree;
private List<Objects> instanceDetails;
private MyTreeModel gm;
private DefaultMutableTreeNode root = new DefaultMutableTreeNode();
private Controller c = new Controller();
public TreePanel(List<Objects> instanceDetails) {
this.instanceDetails = instanceDetails;
tree = new JTree();
if (instanceDetails.get(0).getObjectId() == " ") {
tree.setModel(new MyTreeModel(root));
} else {
tree.setModel(new MyTreeModel(treeNodes(instanceDetails)));
}
gm = new MyTreeModel(root);
gm.fireTreeStructureChanged(root);
tree.getSelectionModel().setSelectionMode(
TreeSelectionModel.SINGLE_TREE_SELECTION);
add(tree);
}
private DefaultMutableTreeNode treeNodes(List<Objects> instanceDetails) {
for (Objects id : instanceDetails) {
count++;
DefaultMutableTreeNode objs = new DefaultMutableTreeNode(count + " : " + id.getType()
+ " : " + id.getObjectId() + " : " + id.getStatus() + " : "
+ id.getCondition());
root.add(objs);
}
return root;
}
}
My tree model
import java.util.Vector;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
public class MyTreeModel implements TreeModel {
public static Vector<TreeModelListener> treeModelListeners =
new Vector<TreeModelListener>();
private static DefaultMutableTreeNode rootPerson;
public MyTreeModel(DefaultMutableTreeNode nodes) {
rootPerson = nodes;
}
//////////////// Fire events //////////////////////////////////////////////
/**
* The only event raised by this model is TreeStructureChanged with the
* root as path, i.e. the whole tree has changed.
*/
protected void fireTreeStructureChanged(DefaultMutableTreeNode rootPerson) {
TreeModelEvent e = new TreeModelEvent(this, new Object[] {rootPerson});
for (TreeModelListener tml : treeModelListeners) {
tml.treeStructureChanged(e);
}
}
//////////////// TreeModel interface implementation ///////////////////////
/**
* Adds a listener for the TreeModelEvent posted after the tree changes.
*/
public void addTreeModelListener(TreeModelListener l) {
treeModelListeners.addElement(l);
}
/**
* Returns the child of parent at index index in the parent's child array.
*/
public Object getChild(Object parent, int index) {
return rootPerson.getChildAt(index);
}
/**
* Returns the number of children of parent.
*/
public int getChildCount(Object parent) {
return 1;
//rootPerson.getLeafCount()
}
/**
* Returns the index of child in parent.
*/
public int getIndexOfChild(Object parent, Object child) {
return rootPerson.getIndex((DefaultMutableTreeNode) child);
}
/**
* Returns the root of the tree.
*/
public Object getRoot() {
return rootPerson;
}
/**
* Returns true if node is a leaf.
*/
public boolean isLeaf(Object node) {
return rootPerson.isLeaf();
}
/**
* Removes a listener previously added with addTreeModelListener().
*/
public void removeTreeModelListener(TreeModelListener l) {
//removeTreeModelListener(l);
}
/**
* Messaged when the user has altered the value for the item
* identified by path to newValue. Not used by this model.
*/
public void valueForPathChanged(TreePath path, Object newValue) {
}
}
Your implementation of TreeModel is clumsy and is the cause of your issues:
public static Vector<TreeModelListener> treeModelListeners =
new Vector<TreeModelListener>();
private static DefaultMutableTreeNode rootPerson;
--> Bad, Bad, Bad, ... real bad. There is absolutely no need to make these statements static and this will cause severe issues if you happen to create 2 different instances
/**
* Returns the child of parent at index index in the parent's child array.
*/
public Object getChild(Object parent, int index) {
return rootPerson.getChildAt(index);
}
Here, no matter which parent is provided, you return always the same child (hence this is why you see the same child over and over). The code should be return (parent==rootPerson?rootPerson.getChildAt(index):null);
/**
* Returns the number of children of parent.
*/
public int getChildCount(Object parent) {
return 1;
//rootPerson.getLeafCount()
}
Same as previous comment, you don't look what is the parent. Code should be return (parent==rootPerson?1:0);
/**
* Returns the index of child in parent.
*/
public int getIndexOfChild(Object parent, Object child) {
return rootPerson.getIndex((DefaultMutableTreeNode) child);
}
Same as previous comment, you don't look what is the parent. Code should be return (parent==rootPerson?rootPerson.getIndex((DefaultMutableTreeNode) child):-1);
/**
* Returns true if node is a leaf.
*/
public boolean isLeaf(Object node) {
return rootPerson.isLeaf();
}
Again, same mistake, you don't care about node
/**
* Removes a listener previously added with addTreeModelListener().
*/
public void removeTreeModelListener(TreeModelListener l) {
//removeTreeModelListener(l);
}
Why don't you implement properly removeTreeModelListener? (and as suggested by #trashgod, you can always use the default EventListenerList which does most of the work for you)
Conclusion: your implementation of TreeModel is full of bugs and this is why you get the problem you describe. Now, since you are using DefaultMutableTreeNode, I can only encourage you to also use DefaultTreeModel which will handle everything for you and avoid you to have to re-implement this, with all the "risks" it implies.

Touch Events for Resize Panel in GWT

I have a Panel whose size needs to be changed for better view as i am loading lots of different widgets inside it. i went on using a Resizable Panel in GWT. It was all working fine.
My Question is : How can i implement it for Touch Enabled Devices like Android Tablets, iPads etc.
The Resize Panel uses Mouse Drag Events i hope. So how can i implement the same for Touch Events.
I have seen GWT-DND API where it provides Resibale Panels and was working in Touch Also.
But it will be a more tedious Task for me if i use it.
Can Anyone help?
Finally i figured it out. It was quite Simple, Just Added Touch Handlers similar to Mouse Events that i used.
ONTOUCHSTART = ONMOUSEDOWN
ONTOUCHMOVE = ONMOUSEMOVE
ONTOUCHEND = ONMOUSEUP
ONTOUCHCANCEL = ONLOSECAPTURE
ResizePanel.java
/**
* Abstract base class for {#link VerticalResizePanel}.
*/
abstract class ResizePanel extends Panel implements HasResizeHandlers {
/* **************************************** */
// Private Static Fields
/* **************************************** */
/**
* The element that masks the screen so we can catch mouse events over
* iframes.
*/
private static Element glassElem = null;
/** The handler manager for our events. */
/* **************************************** */
// Private Fields
/* **************************************** */
// The elements containing the widgets.
/** The elements. */
private final Element[] elements = new Element[1];
/** The handler manager for our events. */
private final EventBus resizeHandlerManager = new SimpleEventBus();
// Indicates whether drag resizing is active.
/** The is resizing. */
private boolean isResizing = false;
// The element that acts as the splitter.
/** The split elem. */
private final Element splitElem;
// The enclosed widgets.
/** The widgets. */
private final Widget[] widgets = new Widget[2];
/* **************************************** */
// Constructors
/* **************************************** */
/**
* Initializes the split panel.
*
* #param mainElem
* the root element for the split panel
* #param splitElem
* the element that acts as the splitter
* #param headElem
* the element to contain the top or left most widget
*/
ResizePanel(final Element mainElem, final Element splitElem,final Element headElem) {
this.setElement(mainElem);
this.splitElem = splitElem;
this.elements[0] = headElem;
this.sinkEvents(Event.MOUSEEVENTS | Event.ONLOSECAPTURE | Event.TOUCHEVENTS | Event.ONTOUCHCANCEL);
if (ResizePanel.glassElem == null) {
ResizePanel.glassElem = DOM.createDiv();
ResizePanel.glassElem.getStyle()
.setProperty("position", "absolute");
ResizePanel.glassElem.getStyle().setProperty("top", "0px");
ResizePanel.glassElem.getStyle().setProperty("left", "0px");
ResizePanel.glassElem.getStyle().setProperty("margin", "0px");
ResizePanel.glassElem.getStyle().setProperty("padding", "0px");
ResizePanel.glassElem.getStyle().setProperty("border", "0px");
// We need to set the background color or mouse events will go right
// through the glassElem. If the SplitPanel contains an iframe, the
// iframe will capture the event and the slider will stop moving.
ResizePanel.glassElem.getStyle().setProperty("background", "white");
ResizePanel.glassElem.getStyle().setProperty("opacity", "0.0");
ResizePanel.glassElem.getStyle().setProperty("filter",
"alpha(opacity=0)");
ResizePanel.glassElem.setId("glassElementId");
}
}
/* **************************************** */
// Package Static Properties
/* **************************************** */
/**
* Returns the offsetHeight element property.
*
* #param elem
* the element
* #return the offsetHeight property
*/
static final int getOffsetHeight(final Element elem) {
return DOM.getElementPropertyInt(elem, "offsetHeight");
}
/**
* Returns the offsetWidth element property.
*
* #param elem
* the element
* #return the offsetWidth property
*/
static final int getOffsetWidth(final Element elem) {
return DOM.getElementPropertyInt(elem, "offsetWidth");
}
/**
* Adds zero or none CSS values for padding, margin and border to prevent
* stylesheet overrides. Returns the element for convenience to support
* builder pattern.
*
* #param elem
* the element
* #return the element
*/
static final Element preventBoxStyles(final Element elem) {
DOM.setIntStyleAttribute(elem, "padding", 0);
DOM.setIntStyleAttribute(elem, "margin", 0);
DOM.setStyleAttribute(elem, "border", "none");
return elem;
}
/**
* Convenience method to set bottom offset of an element.
*
* #param elem
* the element
* #param size
* a CSS length value for bottom
*/
static void setBottom(final Element elem, final String size) {
DOM.setStyleAttribute(elem, "bottom", size);
}
/**
* Sets the elements css class name.
*
* #param elem
* the element
* #param className
* the class name
*/
static final void setClassname(final Element elem, final String className) {
DOM.setElementProperty(elem, "className", className);
}
/**
* Convenience method to set the height of an element.
*
* #param elem
* the element
* #param height
* a CSS length value for the height
*/
static final void setHeight(final Element elem, final String height) {
DOM.setStyleAttribute(elem, "height", height);
}
/**
* Convenience method to set the left offset of an element.
*
* #param elem
* the element
* #param left
* a CSS length value for left
*/
static final void setLeft(final Element elem, final String left) {
DOM.setStyleAttribute(elem, "left", left);
}
/**
* Convenience method to set the right offset of an element.
*
* #param elem
* the element
* #param right
* a CSS length value for right
*/
static final void setRight(final Element elem, final String right) {
DOM.setStyleAttribute(elem, "right", right);
}
/**
* Convenience method to set the top offset of an element.
*
* #param elem
* the element
* #param top
* a CSS length value for top
*/
static final void setTop(final Element elem, final String top) {
DOM.setStyleAttribute(elem, "top", top);
}
/**
* Convenience method to set the width of an element.
*
* #param elem
* the element
* #param width
* a CSS length value for the width
*/
static final void setWidth(final Element elem, final String width) {
DOM.setStyleAttribute(elem, "width", width);
}
/* **************************************** */
// Public Properties
/* **************************************** */
/**
* Gets the element that is acting as the splitter.
*
* #return the element
*/
public Element getSplitElement() {
return this.splitElem;
}
/**
* Gets the value of resizeHandlerManager.
*
* #return Gets the value of resizeHandlerManager.
*/
public EventBus getResizeHandlerManager() {
return resizeHandlerManager;
}
/**
* Indicates whether the split panel is being resized.
*
* #return if the user is dragging the splitter, otherwise
*/
public boolean isResizing() {
return this.isResizing;
}
/* **************************************** */
// Public Static Methods
/* **************************************** */
/**
* Sets an elements positioning to absolute.
*
* #param elem
* the element
*/
static void addAbsolutePositoning(final Element elem) {
DOM.setStyleAttribute(elem, "position", "absolute");
}
/**
* Adds clipping to an element.
*
* #param elem
* the element
*/
static final void addClipping(final Element elem) {
DOM.setStyleAttribute(elem, "overflow", "hidden");
}
/**
* Adds as-needed scrolling to an element.
*
* #param elem
* the element
*/
static final void addScrolling(final Element elem) {
DOM.setStyleAttribute(elem, "overflow", "auto");
}
/**
* Sizes and element to consume the full area of its parent using the CSS
* properties left, right, top, and bottom. This method is used for all
* browsers except IE6/7.
*
* #param elem
* the element
*/
static final void expandToFitParentUsingCssOffsets(final Element elem) {
final String zeroSize = "0px";
ResizePanel.addAbsolutePositoning(elem);
ResizePanel.setLeft(elem, zeroSize);
ResizePanel.setRight(elem, zeroSize);
ResizePanel.setTop(elem, zeroSize);
ResizePanel.setBottom(elem, zeroSize);
}
/**
* Sizes an element to consume the full areas of its parent using 100% width
* and height. This method is used on IE6/7 where CSS offsets don't work
* reliably.
*
* #param elem
* the element
*/
static final void expandToFitParentUsingPercentages(final Element elem) {
final String zeroSize = "0px";
final String fullSize = "100%";
ResizePanel.addAbsolutePositoning(elem);
ResizePanel.setTop(elem, zeroSize);
ResizePanel.setLeft(elem, zeroSize);
ResizePanel.setWidth(elem, fullSize);
ResizePanel.setHeight(elem, fullSize);
}
/* **************************************** */
// Public Methods
/* **************************************** */
/** {#inheritDoc} */
#Override
public void add(final Widget widget) {
boolean canAddWidget = false;
for (int index = 0; index < this.widgets.length; index++) {
if (this.getWidget(index) == null) {
this.setWidget(index, widget);
canAddWidget = true;
break;
}
}
if (!canAddWidget) {
throw new IllegalStateException(
"A Resizable panel can only contain two Widgets.");
}
}
/** {#inheritDoc} */
public HandlerRegistration addResizeHandler(final ResizeEventHandler handler) {
return this.resizeHandlerManager.addHandler(ResizeEvent.TYPE, handler);
}
/** {#inheritDoc} */
#Override
public Iterator<Widget> iterator() {
return ResizableControlIterator
.createWidgetIterator(this, this.widgets);
}
/** {#inheritDoc} */
#Override
public void onBrowserEvent(final Event event) {
switch (DOM.eventGetType(event)) {
case Event.ONMOUSEDOWN:
final Element target = DOM.eventGetTarget(event);
if (DOM.isOrHasChild(this.splitElem, target)) {
this.startResizingFrom(DOM.eventGetClientX(event) - this.getAbsoluteLeft(),DOM.eventGetClientY(event) - this.getAbsoluteTop());
DOM.setCapture(this.getElement());
DOM.eventPreventDefault(event);
}
break;
case Event.ONMOUSEUP:
if (this.isResizing()) {
// The order of these two lines is important. If we release
// capture
// first, then we might trigger an onLoseCapture event
// before we set
// isResizing to false.
DOM.releaseCapture(this.getElement());
this.splitPositionSetDone();
if (this.isResizing()) {
this.stopResizing();
}
}
break;
case Event.ONMOUSEMOVE:
if (this.isResizing()) {
assert DOM.getCaptureElement() != null;
this.onSplitterResize(DOM.eventGetClientX(event) - this.getAbsoluteLeft(),DOM.eventGetClientY(event) - this.getAbsoluteTop());
DOM.eventPreventDefault(event);
}
break;
// IE automatically releases capture if the user switches
// windows, so we
// need to catch the event and stop resizing.
case Event.ONLOSECAPTURE:
if (this.isResizing()) {
this.stopResizing();
}
break;
case Event.ONTOUCHSTART:
final Element touchableTarget = DOM.eventGetTarget(event);
if (DOM.isOrHasChild(this.splitElem, touchableTarget)) {
this.startResizingFrom((event.getTouches().get(0).getClientX() - this.getAbsoluteLeft()),(event.getTouches().get(0).getClientY() - this.getAbsoluteTop()));
DOM.setCapture(this.getElement());
event.preventDefault();
}
break;
case Event.ONTOUCHMOVE:
if (this.isResizing()) {
assert DOM.getCaptureElement() != null;
this.onSplitterResize((event.getTouches().get(0).getClientX() - this.getAbsoluteLeft()),(event.getTouches().get(0).getClientY() - this.getAbsoluteTop()));
event.preventDefault();
}
break;
// IE automatically releases capture if the user switches
// windows, so we
// need to catch the event and stop resizing.
case Event.ONTOUCHEND:
if (this.isResizing()) {
// The order of these two lines is important. If we release
// capture
// first, then we might trigger an onLoseCapture event
// before we set
// isResizing to false.
DOM.releaseCapture(this.getElement());
this.splitPositionSetDone();
if (this.isResizing()) {
this.stopResizing();
}
}
break;
case Event.ONTOUCHCANCEL:
if (this.isResizing()) {
this.stopResizing();
}
break;
default:
break;
}
super.onBrowserEvent(event);
}
/** {#inheritDoc} */
#Override
public boolean remove(final Widget widget) {
if (widget != null) {
for (int index = 0; index < this.widgets.length; index++) {
if ((this.widgets[index] == widget)) {
this.setWidget(index, null);
return true;
}
}
}
return false;
}
/**
* Moves the position of the splitter.
*
* #param size
* the new size of the left region in CSS units (e.g. "10px",
* "1em")
*/
public abstract void setSplitPosition(String size);
/**
* Split position set done.
*
*/
public abstract void splitPositionSetDone();
/**
* Called on each mouse drag event as the user is dragging the splitter.
*
* #param x
* the x coordinate of the mouse relative to the panel's extent
* #param y
* the y coordinate of the mouse relative to the panel's extent
*/
abstract void onSplitterResize(int x, int y);
/**
* Called when the user starts dragging the splitter.
*
* #param x
* the x coordinate of the mouse relative to the panel's extent
* #param y
* the y coordinate of the mouse relative to the panel's extent
*/
abstract void onSplitterResizeStarted(int x, int y);
/* **************************************** */
// Protected Methods
/* **************************************** */
/**
* Gets the content element for the given index.
*
* #param index
* the index of the element, only 0 and 1 are valid.
* #return the element
*/
protected Element getElement(final int index) {
return this.elements[index];
}
/**
* Gets one of the contained widgets.
*
* #param index
* the index of the widget, only 0 and 1 are valid.
* #return the widget
*/
protected Widget getWidget(final int index) {
return this.widgets[index];
}
/**
* <b>Affected Elements:</b>
* <ul>
* <li>-splitter = the container containing the splitter element.</li>
* </ul>
*
* #param baseId
* The base id.
* #see UIObject#onEnsureDebugId(String)
*/
#Override
protected void onEnsureDebugId(final String baseId) {
super.onEnsureDebugId(baseId);
UIObject.ensureDebugId(this.splitElem, baseId, "splitter");
}
/**
* Sets one of the contained widgets.
*
* #param index
* the index, only 0 and 1 are valid
* #param widget
* the widget
*/
protected final void setWidget(final int index, final Widget widget) {
final Widget oldWidget = this.widgets[index];
// Validate.
if (oldWidget == widget) {
return;
}
// Detach the new child.
if (widget != null) {
widget.removeFromParent();
}
// Remove the old child.
if (oldWidget != null) {
// Orphan old.
try {
this.orphan(oldWidget);
} finally {
// Physical detach old.
DOM.removeChild(this.elements[0], oldWidget.getElement());
this.widgets[index] = null;
}
}
// Logical attach new.
this.widgets[index] = widget;
if (widget != null) {
// Physical attach new.
DOM.appendChild(this.elements[0], widget.getElement());
// Adopt new.
this.adopt(widget);
}
}
/* **************************************** */
// Private Methods
/* **************************************** */
/**
* Start resizing from.
*
* #param x
* the x coordinate of the mouse relative to the panel's extent
* #param y
* the y coordinate of the mouse relative to the panel's extent
*/
public void startResizingFrom(final int x, final int y) {
this.isResizing = true;
this.onSplitterResizeStarted(x, y);
// Resize glassElem to take up the entire scrollable window area
final int height = RootPanel.getBodyElement().getScrollHeight() - 1;
final int width = RootPanel.getBodyElement().getScrollWidth() - 1;
ResizePanel.glassElem.getStyle().setProperty("height", height + "px");
ResizePanel.glassElem.getStyle().setProperty("width", width + "px");
RootPanel.getBodyElement().appendChild(ResizePanel.glassElem);
}
/**
* Stop resizing.
*/
void stopResizing() {
this.isResizing = false;
// FIXME:: Why is the remove causing error.
try {
RootPanel.getBodyElement().removeChild(ResizePanel.glassElem);
} catch (final Exception e) {
GWT.log("Got error removing the glassElem: " + e);
}
}
}
Also Adding my Event And Event Handlers
ResizeEvent.java
/**
* When panels (Ex: VerticalSplitPanel) are resized, adjust the positions.
*/
public class ResizeEvent extends GwtEvent<ResizeEventHandler> {
/* **************************************** */
// Public Static Fields
/* **************************************** */
/** The Constant TYPE. */
public static final Type<ResizeEventHandler> TYPE = new Type<ResizeEventHandler>();
/* **************************************** */
// Private Fields
/* **************************************** */
/** The split size. */
private final int splitSize;
/* **************************************** */
// Constructors
/* **************************************** */
/**
* Instantiates a new view set event.
*
* #param splitSize
* The split size.
*/
public ResizeEvent(final int splitSize) {
this.splitSize = splitSize;
}
/* **************************************** */
// Public Properties
/* **************************************** */
/** {#inheritDoc} */
#Override
public Type<ResizeEventHandler> getAssociatedType() {
return ResizeEvent.TYPE;
}
/**
* Gets the top position.
*
* #return The split position.
*/
public int getSplitSize() {
return splitSize;
}
/* **************************************** */
// Protected Methods
/* **************************************** */
/** {#inheritDoc} */
#Override
protected void dispatch(final ResizeEventHandler handler) {
handler.onResize(this);
}
}
ResizeEventHandler.java
/**
* The Interface ResizeEventHandler.
*/
public interface ResizeEventHandler extends EventHandler {
/**
* On move.
*
* #param event
* The event.
*/
void onResize(ResizeEvent event);
}

Categories