2013/02/22

How to customize Icon in Menu in TWaver Flex

Icon in Menu must be specified through iconField and iconFunction. But in the two methods above, Icon has to be done with Class name of embedded resources. So if you would like to set dynamic image (like URL) as Icon in Menu, MenuItemRenderer must be customized.
First, set a class CustomMenuItemRender to inherit MenuItemRenderer with a parameter added as the component of customized Icon.
 private var image:UIComponent = new UIComponent();
Then rewrite the method “measure” (to calculate the width and height of “MenuItem”).
 override protected function measure():void {
    super.measure();
  
    if (separatorIcon || listData == null) {
        return;
    }
  
    var imageAsset:IImageAsset = Utils.getImageAsset(data.@iconName);
    if(imageAsset == null){
        return;
    }
    measuredWidth += imageAsset.width;
    if(imageAsset.height > measuredHeight){
        measuredHeight = imageAsset.height;
    }
}
Rewrite the method “commitProperties” (Rewrite and add Icon & set the width and height of Icon).
 override protected function commitProperties():void {
    super.commitProperties();
   
    if (separatorIcon || listData == null) {
        return;
    }
   
    var imageAsset:IImageAsset = Utils.getImageAsset(data.@iconName);
    if(imageAsset == null){
        return;
    }
    image.width = imageAsset.width;
    image.height = imageAsset.height;
    image.graphics.beginBitmapFill(imageAsset.getBitmapData());
    image.graphics.drawRect(0, 0, image.width, image.height);
    image.graphics.endFill();
    if(!this.contains(image)){
        this.addChild(image);
    }
}
Rewrite the method “updateDisplayList”(specify the position of Icon: since Icon is at the left side, so we’d better first call the method “super” before the movement of Label):
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void{
    super.updateDisplayList(unscaledWidth, unscaledHeight);
   
    if (separatorIcon || listData == null) {
        return;
    }
   
    var imageAsset:IImageAsset = Utils.getImageAsset(data.@iconName);
    if(imageAsset == null){
        return;
    }
    if(typeIcon){
        typeIcon.x += imageAsset.width;
    }
    if(label){
        label.x += imageAsset.width;
    }
}
Rewrite the method “measuredIconWidth” (to calculate the width of Icon):
override public function get measuredIconWidth():Number {
    var imageAsset:IImageAsset = Utils.getImageAsset(data.@iconName);
    if(imageAsset == null){
        return 0 ;
    }else{
        var horizontalGap:Number = getStyle("horizontalGap");
        return imageAsset.width + horizontalGap;
    }
}
At last, specify “ItemRenderer” of Menu with customized CustomMenuItemRenderer. Notice that the name of icon specified by iconName should be used. (Here is the name of the registered image in TWawer.) Also, other names can be used. Do not forget to change “@iconNme” in “CustomMenuItemRenderer”.
var menu:Menu = Menu.createMenu(network, myMenuData, false);
menu.labelField = "@label";
menu.itemRenderer = new ClassFactory(CustomMenuItemRenderer);
var point:Point = network.getLogicalPoint(event.mouseEvent);
network.callLater(function():void{
    menu.show(point.x, point.y);
});
Specify the XML file of the data in Menu as follows:
    <mx:XML format="e4x" id="myMenuData">
        <root>
            <menuitem label="www.servasoftware.com" iconName="databox_icon">
                <menuitem label="TWaver" type="check" toggled="true">
                    <menuitem label="Java" type="radio" groupName="one"/>
                    <menuitem label="Web" type="radio" groupName="one" toggled="true"/>
                    <menuitem label="Flex" type="radio" groupName="one" iconName="bus_icon"/>
                    <menuitem label="Silverlight" type="radio" groupName="one"/>
                </menuitem>
                <menuitem type="separator"/>
                <menuitem label="2BizBox" iconName="data_icon"/>
            </menuitem>
            <menuitem label="www.2bizbox.com"/>
            <menuitem label="twaver.servasoft.com"/>
        </root>
    </mx:XML>
</code>

Please see the official document for more on the method MenuItemRenderer:

http://livedocs.adobe.com/flex/3/html/help.html?content=menucontrols_3.htmlhttp://livedocs.adobe.com/flex/3/html/help.html?content=menucontrols_3.html
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/controls/menuClasses/MenuItemRenderer.html
 

 

2013/01/24

A Different Way to use JPopupMenu

To Swing developers, JPopupMenu must be a familiar component. However, most people only take it as 'right-click popup menu’. Actually, there are much more usages of JPopupMenu, so with the help of it, all the requirement involving popup effects can be met. For example, if we input "import java.util." with development tools and the drop up menu with the probable options listed will pop up automatically when inputting ".".

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;

import twaver.TWaverUtil;

public class PopupTipDemo extends JFrame {

    String[] messages = new String[] {
            "getTWaverJava()",
            "getTWaverWeb()",
            "getTWaverFlex()",
            "getTWaverDotNET()",
            "getTWaverGIS()",
            "getTWaverHTML5()",
            "getTWaverJavaFX()",
            "getTWaver...", };

    JLabel label = new JLabel("TWaver makes everything easy!");
    JList list = new JList(messages);
    JComponent tip = new JScrollPane(list);
    JTextArea text = new JTextArea();
    JPopupMenu popup = new JPopupMenu();

    public PopupTipDemo() {
        super("www.servasoftware.com");
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.getContentPane().setLayout(new BorderLayout());
        this.getContentPane().add(new JScrollPane(text), BorderLayout.CENTER);
        this.tip.setPreferredSize(new Dimension(230, 80));
        this.label.setForeground(Color.BLUE);
        this.label.setHorizontalAlignment(SwingConstants.CENTER);
        this.popup.setLayout(new BorderLayout());
        this.popup.add(label, BorderLayout.NORTH);
        this.popup.add(tip, BorderLayout.CENTER);

        this.text.setText("// Try to press '.'\nimport twaver.Node;\nimport twaver.Link;\nimport twaver.network");
        this.text.setBackground(Color.WHITE);
        this.text.setForeground(Color.BLUE);
        this.text.setCaretColor(Color.RED);

        this.text.addKeyListener(new KeyAdapter() {
            public void keyReleased(KeyEvent e) {
                if (popup.isShowing()) {
                    popup.setVisible(false);
                } else if (e.getKeyCode() == KeyEvent.VK_PERIOD) {
                    Point point = text.getCaret().getMagicCaretPosition();
                    if (point != null) {
                        popup.show(text, point.x, point.y);
                    }
                    text.requestFocus();
                }
            }
        });
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                PopupTipDemo demo = new PopupTipDemo();
                demo.setSize(400, 200);
                TWaverUtil.centerWindow(demo);
                demo.setVisible(true);
            }
        });
    }
}
In fact, in Demo of TWaver Java, QuickSearch (the well-encapsulated component--twaver.swing.TDropDownSelector) is equipped with the feature described above. Through the following several lines of codes in demo.DemoUtil can realize the drop-down effect. What you need to do is only to focus on the contents you want to show on the menu.

// create drop down selector
final TDropDownSelector selector = new TDropDownSelector(txtSearch, new JScrollPane(list)){
    public Dimension getSelectorSize(){
        int width = this.getSize().width;
        if(width < 200){
            width = 200;
        }
        return new Dimension(width, 320);
    }
};

2013/01/17

To Test the Memory Usage of TWaver Java

We have already seen the high performance of TWaver Java, but what about its memory usage? What about it with different amounts of data? How does view component have effects on memory? We have tested the following amounts of data respectively:
  • to only add elements into the DataBox
  • to add elements into DataBox and show them on Network
  • to add elements into the DataBox and show them on Tree
  • to add elements into the DataBox and show them on Tree and Network
The following is the four situations of the memory usage of different number of elements. (x-axis: the number of nodes, unit: K; y-axis: the memory that elements take, unit: MB)
  1. To only add elements into the DataBox:
  2. To add elements into DataBox and show them on Network:
  3. To add elements into the DataBox and show them on Tree:
  4. To add elements into the DataBox and show them on Tree and Network:
We can see from the graphs above: the view components do have effects on the memory. But it is good that 100 thousand of nodes take only less than 500MB. During the process of the test, we find that system environment has had affected the results. (Here we have taken the average value.)

2013/01/07

Bundled links in Flex

We have already introduced the link-bundles in TWaver Java and found that there are quite some functions therein. More powerful functions have been provided in link-bundles in TWaver Flex.
Now let's first see the similar functions offered in TWaver Java:
link.setStyle(Styles.LINK_BUNDLE_ENABLE,false); //to judge whether the link is in a link-bundle or not
link.setStyle(Styles.LINK_BUNDLE_EXPANDED,false);  //to set whether the link-bundle is expanded or not
link.setStyle(Styles.LINK_BUNDLE_GAP,10); //to set the gap between every two links in the link-bundle
link.setStyle(Styles.LINK_HANDLER_YOFFSET, -5); //to set the vertical offset when bundled
link.setStyle(Styles.LINK_HANDLER_XOFFSET, -5); //to set the horizontal offset when bundled
 What's more, the grouped link-bundles are available in TWaver Flex as follows:
link.setStyle(Styles.LINK_BUNDLE_INDEPENDENT,true); //to set whether the link is bundled independently
link.setStyle(Styles.LINK_BUNDLE_ID, 0);  //to set the index of the groups of link-bundles

More functions supplied in bundleHandler:
link.setStyle(Styles.LINK_HANDLER_POSITION, position); //to set the position of the link handler and the value of position can be obtained from Consts
link.setStyle(Styles.LINK_HANDLER_COLOR, 0xFF0000);  //to set the color of the texts in the link handler
link.setStyle(Styles.LINK_HANDLER_FILL, true); //whether the link handler has the background color
link.setStyle(Styles.LINK_HANDLER_FILL_COLOR, 0x00FFFF); //to set the background color in the link handler
link.setStyle(Styles.LINK_HANDLER_XOFFSET, -5);   //to set the horizontal offset of the link handler
link.setStyle(Styles.LINK_HANDLER_YOFFSET, -5);  //to set the vertical offset of the link handler
The label of BundleHandle can be set by linkHandlerFunction of network to implement the functions mentioned in the last article.

In addition, the label which is used to be double-clicked to expand the bundled links can be set as being gradient, bold, italic and underlined.
link.setStyle(Styles.LINK_HANDLER_GRADIENT,Consts.GRADIENT_LINEAR_EAST); //to set the gradient type of the background color in the link handler
link.setStyle(Styles.LINK_HANDLER_GRADIENT_COLOR,0xFF00FF); //to set the gradient color of the background in the link handler
link.setStyle(Styles.LINK_HANDLER_BOLD,true); //to set the text in the link handler as bold
link.setStyle(Styles.LINK_HANDLER_ITALIC,true); //to set the text in the link handler as italic
link.setStyle(Styles.LINK_HANDLER_UNDERLINE,true); //to set the text in the link handler to be underlined
There are functions on looped link different from those on link in TWaver Flex:
link.setStyle(Styles.LINK_LOOPED_GAP, 10); //to set the gap between every two looped links
link.setStyle(Styles.LINK_LOOPED_TYPE, type); //to set the style of the looped links
link.setStyle(Styles.LINK_LOOPED_DIRECTION, direction); //to set the direction of looped links

2012/12/27

Bundled Links in Java

Link-bundling is the way to solve the problems arising from links in TWaver: when there are several links between two nodes, we can double-click one of them to bundle them and represent them with only a link-agent, hence the simplification visually.
There will appear the number of the links once they are bundled together. However, in so much link- bundles, how can we know that a particular number is of which link-bundle?

In fact, if you make some adjustment, you will see clearly how many links every link-bundle has on the network. For example, the sentence link.putLinkLabelRotatable(true); is used to rotate the label to be paralleled to the link-agent and the label of links can also be set to be placed in the middle. What’s more, the content to be shown in the label can also be edited by labelgenerator. For instance:

Before:
After:

In this way, the label is directly shown on the link to clearly divide up the links in the image above. The code is quite simple:
network.setElementLabelGenerator(new Generator(){
   public Object generate(Object object) {
    if (object instanceof Link) {
     Link link = (Link)object;
     if(link.isLinkBundleExpand()){
      return link.getName();
     }else if(link.isBundleAgent()){
      return "spring will come ("+link.getLinkBundleSize()+")"//
     }else{
      return null;
     }
    } else {
     return ((Element) object).getName();
    }
   }
  });
The functions on link-bundle provided in TWaver Java are listed as below:
Link:
isLinkBundleExpand() //to judge whether the links are bundled or not

isBundleAgent() // to judge whether a link is the agent-link or not

getLinkBundleSize() // to obtain the number of the links bundled together

getLinkBundleIndex // to obtain the index of a link in a link-bundle

setBundleExpand(boolean bundleExpand) //to set whether a link-bundle is expanded or not

putLinkBundleExpand  //to set whether the links are expanded or not

putLinkBundleIndex  //to set the index of a link in a link-bundle

putLinkBundleSize  //to set the number of the links bundled together
The functions related to bundle are also provided in DataBox:

setLinkBundleFilter(VisibleFilter linkBundleFilter) //to set the filter which filters out the links to be bundled: to specify which links are to be bundled and which are not

setLinkBundleAgentGenerator //This method is used to set the generator of link-agent in a link-bundle to change the default that a random link is specified as the agent-link in TWaver.

getBundledLinks(Node node1, Node node2) //to obtain the bundled links between two nodes


2012/12/13

To Add Icons at Any Place on Elements in TWaver Flex

With the help of iconAttachment system provided in TWaver Java, we can be able to put any number of images, characters and figures on an element as you want. For example:

The following codes can also be called to show the icons on an element in TWaver Flex.


server1.setStyle(Styles.ICONS_NAMES, ["att5","att6", "att7","att8"]);
server1.setStyle(Styles.ICONS_POSITION, Consts.POSITION_BOTTOMRIGHT_TOPRIGHT);
server1.setStyle(Styles.ICONS_ORIENTATION, Consts.ORIENTATION_TOP);
server1.setStyle(Styles.ICONS_XOFFSET, 5);

The function to add icons at different positions on an element is not provided in TWaver Flex as default, but it can be realized through function-expansion, since the FlexMVC model is so flexible.
Several iconAttachments can be created to show icons at different places with the Attachment component in TWaver.

If you are interested in it, you can try to show attachments at different places and directions, mainly by changing the following two methods in CustomIconAttachment:
private function getIconsSize(names:Array, orientation:String, xgap:Number, ygap:Number):Size
and
override public function draw(graphics:Graphics):void

2012/12/02

Tree of files in JTree

In fact, what this article will say has nothing to do with the components in TWaver just because I find it quite interesting. Therefore, I would like to share it with you. The file tree is completely based on JTree of swing. Now let's first see the final effect:

Screenshot:



Introduction on Functions:
  • to show the structure of files in tree
  • the icon of files should be systematic ones
  • The background color of the current node will be changed when you mouse over it.(such as the bricky-red background of the text "Windows" in the image above)
First let' s see the class structure:
  • main program
  • file tree, which inherits from JTree
  • the encapsulated node, including the name and the icon of a file, the File class and other identity
  • The customized node renderer which inherits from DefaultTreeCellRenderer
  • the customized TreeModel which inherits from DefaultTreeModel
Considering that there will be quite a few system files, it is not reasonable to initialize the whole tree at starting a program. So we have taken measures to delay loading: to only initialize the child nodes of a node only when it is to be expanded. Now add a listener into the construction of FileTree:
addTreeWillExpandListener(new TreeWillExpandListener() {
            @Override
            public void treeWillExpand(TreeExpansionEvent event) throws ExpandVetoException {
                DefaultMutableTreeNode lastTreeNode =
(DefaultMutableTreeNode) event.getPath().getLastPathComponent();
                FileNode fileNode = (FileNode) lastTreeNode.getUserObject();
                if (!fileNode.isInit) {
                    File[] files;
                    if (fileNode.isDummyRoot) {
                        files = fileSystemView.getRoots();
                    } else {
                        files = fileSystemView.getFiles(
                                ((FileNode) lastTreeNode.getUserObject()).file,
                                false);
                    }
                    for (int i = 0; i < files.length; i++) {
                       //The name and the icon of the file is obtained through fileSystemView.
                        FileNode childFileNode = new FileNode(
                                fileSystemView.getSystemDisplayName(files[i]),
                                fileSystemView.getSystemIcon(files[i]), files[i],
                                false);
                        DefaultMutableTreeNode childTreeNode = new DefaultMutableTreeNode(childFileNode);
                        lastTreeNode.add(childTreeNode);
                    }
                    //To notify that a node has been changed
                    DefaultTreeModel treeModel1 = (DefaultTreeModel) getModel();
                    treeModel1.nodeStructureChanged(lastTreeNode);
                }
                //to change the identifier to avoid loading repeatedly
                fileNode.isInit = true;
            }
            @Override
            public void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException {

            }
        });
Of course, this method must be combined with TableModel. I have reloaded DefaultTreeModel and initialized the root node in the construction. Then load the method isLeaf.

Now let's think how to change the background color of a node when you mouse over it.

Right at this time I recalled the mistake I made during the time when I first learned Renderer that every node has a Renderer and I even tend to add a listener to it! The thing I have to emphasize is that Renderer is just a renderer. JTree will call it to render nodes onto the screen to show them. But remember however nodes there are, there is only one Renderer in a JTree!

Since it is useless to add a listener to Renderer, we have to change our focus, that is, to add listener which listens to mouse-moves in JTree and then repaint the node on which the mouse is.

addMouseMotionListener(new MouseAdapter() {
            @Override
            public void mouseMoved(MouseEvent e) {
//to obtain the TreePath of the mouse
                TreePath path=getPathForLocation(e.getX(), e.getY());

//to calculate the area to be reprinted and to repaint JTree
                if(path!=null){
                    if(mouseInPath!=null){
                        Rectangle oldRect=getPathBounds(mouseInPath);
                        mouseInPath=path;
                        repaint(getPathBounds(path).union(oldRect));
                    }else{
                        mouseInPath=path;
                        Rectangle bounds=getPathBounds(mouseInPath);
                        repaint(bounds);
                    }
                }else if(mouseInPath!=null){
                    Rectangle oldRect=getPathBounds(mouseInPath);
                    mouseInPath=null;
                    repaint(oldRect);
                }
            }
        });
The background color of mouseInPath can be changed in Renderer only when the TreePath(mouseInPath) of MouseOver is saved in JTree.
FileTree fileTree=(FileTree)tree;
        JLabel label= (JLabel) super.getTreeCellRendererComponent(tree,value,sel,expanded,leaf,row,hasFocus);

        DefaultMutableTreeNode node=(DefaultMutableTreeNode)value;
        FileNode fileNode=(FileNode)node.getUserObject();
        label.setText(fileNode.name);
        label.setIcon(fileNode.icon);

        label.setOpaque(false);
//to change the background color if the node in rendering now is the node under the mouse over
        if(fileTree.mouseInPath!=null&&
                fileTree.mouseInPath.getLastPathComponent().equals(value)){
            label.setOpaque(true);
            label.setBackground(new Color(255,0,0,90));
        }
        return label;
Now it is the end of the article. If you have interest in it, welcome for your communication and good ideas.