2013/05/16

The Setting of Dynamic Editors

In the interface of editing properties, editor can be extended as you can customize two Editors A and B, in which the value of B changes with that of A.

The method is quite simple that an ElementPropertyChangeListener is to be added to TDataBox and that when property A has been changed and thus the value the value in the DataBox is changed the Editor of property B will load that value.
public void propertyChange(PropertyChangeEvent evt) {
    String pro = TWaverUtil.getPropertyName(evt);
    Element element = (Element)evt.getSource();
    if("A".equals(pro)){
        CustomUtil.ref = CustomUtil.getBRefs((Integer)element.getUserProperty("A"));
    }
}
public static String[] getBRefs(int v){
    switch(v){
    case 1:
    case 2:
        return REF1;
    default:
        return REF2;
    }
}
public Component getTableCellEditorComponent(JTable table, Object value,
        boolean isSelected, int row, int column) {
    JComboBox comboBox = (JComboBox)this.getComponent();
    comboBox.removeAllItems();   
    if(CustomUtil.ref!=null){
        for(int i=0;i<CustomUtil.ref.length;i++){
            comboBox.addItem(CustomUtil.ref[i]);
        }
    }
   
    return super.getTableCellEditorComponent(table, value, isSelected, row, column);
}



2013/04/15

Add the Function “AutoComplete” in JTextField(2)

In the article Add the Function “AutoComplete” in JTextField,we receive many feedback. One is: “Can you help me, make a search like in facebook? every search there are pictures and text”。 It's not very hard to do this, we can just set the JComboBox's Renderer, By default the Renderer of JComboBox is a JLabel, and the JLabel itself has a function "setIcon", so we can set the Icon to the JLabel, the Code is like this:

cbInput.setRenderer(new DefaultListCellRenderer(){
 public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
 super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
 if(value != null){
 this.setText(value.toString());
 String url = value.toString().replaceAll(" ", "_") + ".png";
 ImageIcon icon = getImageIcon(url, IMAGE_ICON_CACHE);
 if(icon != null){
 this.setIcon(icon);
 }
 }
 return this;
 }
 });


In the "getImageIcon" method ,we cache the images, so it no need create a new ImageIcon every time where the UI is Refreshed, which can improve the response time.


public static ImageIcon getImageIcon(String url,Map<String, ImageIcon> IMAGE_ICON_CACHE) {
 if (url == null) {
 return null;
 }
 if (IMAGE_ICON_CACHE.get(url) == null) {
 ImageIcon image = null;
 InputStream in =ResourceAgent.class.getResourceAsStream(url);
 if (in != null) {
 try {
 byte buffer[] = new byte[in.available()];
 for (int i = 0, n = in.available(); i < n; i++) {
 buffer[i] = (byte) in.read();
 }
 Toolkit toolkit = Toolkit.getDefaultToolkit();
 Image img = toolkit.createImage(buffer);
 image = new ImageIcon(img);
 in.close();
 } catch (IOException ex) {
 ex.printStackTrace();
 return null;
 }
 }
 if (image == null) {
 if (ClassLoader.getSystemResource(url) != null) {
 image = new ImageIcon(ClassLoader.getSystemResource(url));
 } else {
 image = new ImageIcon(url);
 }
 }
 if (image == null) {
 System.err.println("can't load image '" + url + "'");
 } else {
 IMAGE_ICON_CACHE.put(url, image);
 }
 }
 return (ImageIcon) IMAGE_ICON_CACHE.get(url);
 }
Finally, it's like this:
The full code file:
package demo; import java.awt.*; import java.awt.event.*; import java.io.*; import java.util.*; import javax.swing.*; import javax.swing.event.*; import demo.images.*; public class Test { public static void main(String[] args) throws Exception { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); JFrame frame = new JFrame(); frame.setTitle("Auto Completion Test"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setBounds(200, 200, 500, 400); ArrayList<String> items = new ArrayList<String>(); // Locale[] locales = Locale.getAvailableLocales(); // for (int i = 0; i < locales.length; i++) { // String item = locales[i].getDisplayName(); // items.add(item); // } items.add("China"); items.add("China Hongkong"); items.add("China Taiwan"); items.add("USA"); items.add("Japan"); JTextField txtInput = new JTextField(); setupAutoComplete(txtInput, items); txtInput.setColumns(30); frame.getContentPane().setLayout(new FlowLayout()); frame.getContentPane().add(txtInput, BorderLayout.NORTH); frame.setVisible(true); } private static boolean isAdjusting(JComboBox cbInput) { if (cbInput.getClientProperty("is_adjusting") instanceof Boolean) { return (Boolean) cbInput.getClientProperty("is_adjusting"); } return false; } private static void setAdjusting(JComboBox cbInput, boolean adjusting) { cbInput.putClientProperty("is_adjusting", adjusting); } public static ImageIcon getImageIcon(String url,Map<String, ImageIcon> IMAGE_ICON_CACHE) { if (url == null) { return null; } if (IMAGE_ICON_CACHE.get(url) == null) { ImageIcon image = null; InputStream in =ResourceAgent.class.getResourceAsStream(url); if (in != null) { try { byte buffer[] = new byte[in.available()]; for (int i = 0, n = in.available(); i < n; i++) { buffer[i] = (byte) in.read(); } Toolkit toolkit = Toolkit.getDefaultToolkit(); Image img = toolkit.createImage(buffer); image = new ImageIcon(img); in.close(); } catch (IOException ex) { ex.printStackTrace(); return null; } } if (image == null) { if (ClassLoader.getSystemResource(url) != null) { image = new ImageIcon(ClassLoader.getSystemResource(url)); } else { image = new ImageIcon(url); } } if (image == null) { System.err.println("can't load image '" + url + "'"); } else { IMAGE_ICON_CACHE.put(url, image); } } return (ImageIcon) IMAGE_ICON_CACHE.get(url); } public static void setupAutoComplete(final JTextField txtInput, final ArrayList<String> items) { final DefaultComboBoxModel model = new DefaultComboBoxModel(); final Map<String,ImageIcon> IMAGE_ICON_CACHE = new HashMap<String, ImageIcon>(); final JComboBox cbInput = new JComboBox(model) { public Dimension getPreferredSize() { return new Dimension(super.getPreferredSize().width, 0); } }; setAdjusting(cbInput, false); for (String item : items) { model.addElement(item); } cbInput.setSelectedItem(null); cbInput.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (!isAdjusting(cbInput)) { if (cbInput.getSelectedItem() != null) { txtInput.setText(cbInput.getSelectedItem().toString()); } } } }); cbInput.setRenderer(new DefaultListCellRenderer(){ public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); if(value != null){ this.setText(value.toString()); String url = value.toString().replaceAll(" ", "_") + ".png"; ImageIcon icon = getImageIcon(url, IMAGE_ICON_CACHE); if(icon != null){ this.setIcon(icon); } } return this; } }); txtInput.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { setAdjusting(cbInput, true); if (e.getKeyCode() == KeyEvent.VK_SPACE) { if (cbInput.isPopupVisible()) { e.setKeyCode(KeyEvent.VK_ENTER); } } if (e.getKeyCode() == KeyEvent.VK_ENTER || e.getKeyCode() == KeyEvent.VK_UP || e.getKeyCode() == KeyEvent.VK_DOWN) { e.setSource(cbInput); cbInput.dispatchEvent(e); if (e.getKeyCode() == KeyEvent.VK_ENTER) { txtInput.setText(cbInput.getSelectedItem().toString()); cbInput.setPopupVisible(false); } } if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { cbInput.setPopupVisible(false); } setAdjusting(cbInput, false); } }); txtInput.getDocument().addDocumentListener(new DocumentListener() { public void insertUpdate(DocumentEvent e) { updateList(); } public void removeUpdate(DocumentEvent e) { updateList(); } public void changedUpdate(DocumentEvent e) { updateList(); } private void updateList() { setAdjusting(cbInput, true); model.removeAllElements(); String input = txtInput.getText(); if (!input.isEmpty()) { for (String item : items) { if (item.toLowerCase().startsWith(input.toLowerCase())) { model.addElement(item); } } } cbInput.hidePopup(); cbInput.setPopupVisible(model.getSize() > 0); setAdjusting(cbInput, false); } }); txtInput.setLayout(new BorderLayout()); txtInput.add(cbInput, BorderLayout.SOUTH); } }
The ResourceAgent class:

package demo.images;


public class ResourceAgent {
}

and at the some folder, put the icons related to the text show on the list. 



2013/03/28

To Customize Interactions in TWaver

Recently, there comes a fairly demanding requirement that a node dragged from the toolbar will be inserted in the link under the mouse, during which that the the section of the link to be inserted by the node will protrude over its original height.
Nodes can be inserted in to a link through the deletion of the original one and the addition of two new ones, but the protruding part is troublesome, which, however can be realized with the help of ShapeLink in TWaverFlex.
Method:
  1. Listen to the event "DragEvent.DRAG_OVER" in network and judge whether there is Link under the mouse by the method "network#getElementsByDisplayObject". If there is, set this link as transparent(link.setStyle(Styles.LINK_ALPHA, 0) and then add a ShapeLink; if there is not, set it as transparent, restore it and delete ShapeLink. Please refer to the method "updateMark" or "removeMark" for detailed codes:
    private function updateMark(link:Link, data:Object, point:Point):void {
        if(!network.elementBox.contains(markLink)){
            markLink.fromNode = link.fromNode;
            markLink.toNode = link.toNode;
            markLink.setStyle(Styles.SHAPELINK_TYPE, Consts.SHAPELINK_TYPE_QUADTO);
            markLink.setStyle(Styles.LINK_WIDTH, link.getStyle(Styles.LINK_WIDTH));
            markLink.setStyle(Styles.LINK_COLOR, link.getStyle(Styles.LINK_COLOR));
            markLink.setStyle(Styles.LINK_ALPHA, link.getStyle(Styles.LINK_ALPHA));
           
            network.elementBox.add(markLink);
            lastLink = link;
            link.setStyle(Styles.LINK_ALPHA, 0);
        }
       
        var points:Collection = new Collection();
       
        var fromCenter:Point = markLink.fromNode.centerLocation;
        var toCenter:Point = markLink.toNode.centerLocation;
        var radius:Number = Math.sqrt(data.width*data.width + data.height*data.height)/2;
        var crossPoints:Object = getCrossPoints(fromCenter, toCenter, point, radius*2);
        if (crossPoints){
            if(fromCenter.x&lt;toCenter.x){
                points.addItem(crossPoints.p2);
                points.addItem(crossPoints.p2);
            }else{
                points.addItem(crossPoints.p1);
                points.addItem(crossPoints.p1);
            }
           
            var crossPoint:Point = new Point(crossPoints.p1.x + (crossPoints.p2.x-crossPoints.p1.x)/2,
                crossPoints.p1.y + (crossPoints.p2.y-crossPoints.p1.y)/2);
            var controlPoints:Object = getCrossPoints(crossPoint, point, point, radius*3);
            if(controlPoints){
                if(crossPoint.y &gt;= point.y){
                    points.addItem(controlPoints.p2);
                }else{
                    points.addItem(controlPoints.p1);
                }
            }else{
                if(point.y&gt;=fromCenter.y){
                    point.y = point.y - radius * 3;
                }else{
                    point.y = point.y + radius * 3;
                }
                points.addItem(point);
            }
            if(fromCenter.x&lt;toCenter.x){
                points.addItem(crossPoints.p1);
                points.addItem(crossPoints.p1);
            }else{
                points.addItem(crossPoints.p2);
                points.addItem(crossPoints.p2);
            }
        }else{
            points.addItem(fromCenter);
        }
        markLink.points = points;
    }

    private function removeMark(moving:Boolean):void {
        if(network.elementBox.contains(markLink)){
            var fromNode:Node = markLink.fromNode;
            var toNode:Node = markLink.toNode;
            network.elementBox.remove(markLink);
            if(lastLink &amp;&amp; moving){
                lastLink.setStyle(Styles.LINK_ALPHA, markLink.getStyle(Styles.LINK_ALPHA));
                lastLink = null;
            }
        }
    }

  2. The key is how to make sure which points among ShapeLink will protrude. The solution is to calculate the intersection of the semi-circle and line. Please refer to the method "getCrossPoints" for detailed codes: 
    private function getCrossPoints(p1:Point, p2:Point, circleCenter:Point, radius:Number):Object{
        var line_p1_x:Number = p1.x;
        var line_p1_y:Number = p1.y;
        var line_p2_x:Number = p2.x;
        var line_p2_y:Number = p2.y;
        var circle_center_x:Number = circleCenter.x;
        var circle_center_y:Number = circleCenter.y;
        var circle_radius:Number = radius;
        var line_k:Number =(line_p2_y-line_p1_y)/(line_p2_x-line_p1_x);
        var line_b:Number =line_p1_y-line_k*line_p1_x;
        var a:Number =1+line_k*line_k;
        var b:Number =-2*circle_center_x+2*line_k*line_b-2*line_k*circle_center_y;
        var c:Number =circle_center_x*circle_center_x+(line_b-circle_center_y)*(line_b-circle_center_y)-circle_radius*circle_radius; 
        var delta:Number =b*b-4*a*c;
        var x1:Number =(-b+Math.sqrt(delta))/(2*a);
        var x2:Number =(-b-Math.sqrt(delta))/(2*a);
        var y1:Number =line_k*x1+line_b;
        var y2:Number =line_k*x2+line_b;
       
        if(delta&gt;=0){
            return {p1: new Point(x1, y1), p2: new Point(x2, y2)};
        }else{
            return null;
        }
    }
  3. Delete ShapeLink and establish two Links in the event "DragEvent.DRAG_DROP".

2013/03/10

An Overview of TWaver Android

The characteristics of Android
Accounting for a large part in smartphone market, Android of Google is an open source operating system which is based on Linux kernel, mainly used on mobiles devices. The application layer of Android is developed by Java. It runs in Dalvik virtual machine. Every Android application functions in separate virtual machine, which ensures the protection and the thread safety of the resources between applications.

Android framework
Programming languages in Android: Java, NDK, HTML

Other programming languages can also be used to develop Android application apart from the usually used Java in Android application.

The three languages above have their own features. Java is the native-support language of Android, so it can be used in local development. As the improvement of Android system, it becomes more and more efficient; the development of Android NDK is comparatively complicated, but with the advantage in performance of C programming language, the efficiency of the program can be improved(As a cross-platform programming language, C programming language is widely used in games); now HTML has become a tendency and the applications on cross-browsers and cross-platforms can also be available through Web App.

There are quite some devices supporting Android and it is frequently updated. Progress has been made to the improvement on Dalvik virtual machine and Android application framework by Google. For example, the JIT system has been introduced in Android 2.2, so the efficiency has been increased twice to four times. At the same time, Android 4.1 has also made its contribution to UI fluency. The efforts Google made deserve praise, however, at the other hand, that also tells the inefficiency in the earlier versions. Then how much room of improvement remains? Let's see the data. We will test Android Java and SunJava on Android tablet and PC respectively to see their difference in performance and the suitable scenario to them.

The difference between Dalvik VM and SunJavaVM in perfomance

Devices: MacBook Pro(2.26 GHz Intel Core 2 Duo),Google Nexus 7(1.3GHz quad-core Tegra 3)
Software environment: Java 1.6.0_37 and Android 4.2.1
Contents: basic APIs including arithmetics, set operation(List and Map operation)

Here only the results are listed as the test codes in Java 1.6.0_37 are also java programming language. Please refer to PerformanceDemo.java in TWaver Android Demo:

Android 4.2.1 takes 12-50 times as Java 6 does in running a same program. In addition, the efficiency with other programming language on PC (like Flex or JavaScript) is also better than Nexus 7 tablet.

What about HTML? HTML on desktop is four times quicker than on mobile Chrome server, which mainly reflect the reality of the hardware; Android with JavaScript is superior to with original Java, at least in Chrome browser. However, this test only reflects the basic performance of programming languages. As for the convenience of development, Java is still the first choice.

The test indicates that compared to PC android devices is obviously deficient while Dalvik VM is not able to fully exert the performance of hardware, which should be noticed in developing applications in order to balance user experience and functions.

The difference in performance under platforms with programming languages:

The Target Platform of TWaver Android

There are many developing languages can be chosen in TWaver graphical components while there is still a vacancy on mobile platform. Although TWaver HTML5 is capable of running on Android and iOS, it is quite difficult to have the same user experience as in local application. In order to make that come true, TWaver Android is set to run on mobile platforms for graphical presentation of data with brand-new design architecture and higher UI efficiency to compensate for the deficiency in the performance of the mobile device itself. What's more, a smooth user experience with new multi-touch and roaming operation.

The Support of large amounts of data in TWaver Android

Compared to other edition of TWaver, some changes have been made in TWaver Android framework. The efficiency of DataBox has been improved several times and the problems existing in Link and Group have also been solved; the delay-invalid system has also been advanced in UI presentation; touch operations have been completely compatible; the scenarios in which Node, Link and Group have been used together are available. Even operations with more than one thousand data are still smooth on Nexus 7 tablet. The result is quite agreeable as it can be widely applied considering the problem that lies in the difference between PC and tablet and the efficiency of DM.

The contrast between the loading time of network with different amounts of elements.

Suggested Platforms of TWaver Android

A better view of graphical presentation of data can be enjoyed with a big screen, so tablets are suggested. Versions higher than Android 3.0 (Android 3.0 in which Drag and Drop is available is also included) are supported. Actually TWaver Android is tested and adjusted mainly with the help of Nexus 7/10 and Samsung Android, which, however, does not mean that it is incapable of functioning in mobile phones or low-version Android devices. Instead, TWaver Android Demo is able to run smoothly on Google Nexus S mobile phones. The simplified version of TWaver Android can be applied if you would like your device with Android 2.* to be compatible with it.

Run on Nexus 7 and Nexus S

2013/02/27

Customized Interactions on Network in TWaver Flex

The following several interactive modes have been provided in TWaver as default:


In most cases, they are sufficient, but customized interactions are also available. Now we will introduce how to customize interactive mode with the combination of just a "pan" and the general interactive modes:
If an element is selected, then all the operations will be performed on it; if not, then the "pan" interactive mode as dragging the background.
Generally, in "pan" interactive mode, elements cannot be selected and dragged. It is the same as general map interactive mode and they can only show the range of dragging. But through some operations element-dragging and background-dragging can be separated.
The logic of the method "handleMouseDown" has been changed.
public class CustomInteractionHandler extends BasicInteractionHandler {
        private var pressPoint:Point;
        private var oldButtonMode:Boolean;
        private var olduseHandCursor:Boolean;

        public function CustomInteractionHandler(network:Network) {
            super(network);
            installListeners();
        }

        override public function installListeners():void {
            this.network.addEventListener(MouseEvent.MOUSE_DOWN, handleMouseDown);
            this.network.addEventListener(MouseEvent.MOUSE_UP, handleMouseUp);
        }

        /**
         * @inheritDoc
         *
         */
        override public function uninstallListeners():void {
            this.network.removeEventListener(MouseEvent.MOUSE_DOWN, handleMouseDown);
            this.network.removeEventListener(MouseEvent.MOUSE_UP, handleMouseUp);
        }

        private function handleMouseDown(e:MouseEvent):void {
            if (!this.network.isValidMouseEvent(e) || this.network.isMovingElement || this.network.isEditingElement) {
                return;
            }
            var element:IElement=network.getElementByMouseEvent(e);
            if (element) {
                if (!this.network.selectionModel.contains(element)) {
                    this.network.selectionModel.setSelection(element);
                }
            } else {
                this.network.selectionModel.clearSelection();
                pressPoint=new Point(e.stageX, e.stageY);
                this.network.addEventListener(MouseEvent.MOUSE_MOVE, handleMouseMove);
                oldButtonMode=this.network.buttonMode;
                olduseHandCursor=this.network.useHandCursor;
                this.network.useHandCursor=true
                this.network.buttonMode=true
                this.network.cursorManager.removeAllCursors();
            }

        }

        private function handleMouseUp(e:MouseEvent):void {
            if (pressPoint != null) {
                pressPoint=null;
                this.network.buttonMode=oldButtonMode;
                this.network.useHandCursor=olduseHandCursor;
                this.network.removeEventListener(MouseEvent.MOUSE_MOVE, handleMouseMove);
            }
        }

        private function handleMouseMove(e:MouseEvent):void {
            if (!e.buttonDown) {
                pressPoint=null;
                this.network.buttonMode=oldButtonMode;
                this.network.useHandCursor=olduseHandCursor;
                this.network.removeEventListener(MouseEvent.MOUSE_MOVE, handleMouseMove);
                return;
            }
            if (this.network.verticalScrollBar == null &amp;&amp; this.network.horizontalScrollBar == null) {
                return;
            }
            var xOffset:Number=pressPoint.x - e.stageX;
            var yOffset:Number=pressPoint.y - e.stageY;
            pressPoint.x-=xOffset;
            pressPoint.y-=yOffset;
            this.network.horizontalScrollPosition+=xOffset;
            this.network.verticalScrollPosition+=yOffset;
        }
    }
Now it has become much more simpler.
network.interactionHandlers=new Collection([
       new CustomInteractionHandler(this),
new DefaultInteractionHandler(this),]);

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 &gt; 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(&quot;horizontalGap&quot;);
        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 = &quot;@label&quot;;
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:
    &lt;mx:XML format=&quot;e4x&quot; id=&quot;myMenuData&quot;&gt;
        &lt;root&gt;
            &lt;menuitem label=&quot;www.servasoftware.com&quot; iconName=&quot;databox_icon&quot;&gt;
                &lt;menuitem label=&quot;TWaver&quot; type=&quot;check&quot; toggled=&quot;true&quot;&gt;
                    &lt;menuitem label=&quot;Java&quot; type=&quot;radio&quot; groupName=&quot;one&quot;/&gt;
                    &lt;menuitem label=&quot;Web&quot; type=&quot;radio&quot; groupName=&quot;one&quot; toggled=&quot;true&quot;/&gt;
                    &lt;menuitem label=&quot;Flex&quot; type=&quot;radio&quot; groupName=&quot;one&quot; iconName=&quot;bus_icon&quot;/&gt;
                    &lt;menuitem label=&quot;Silverlight&quot; type=&quot;radio&quot; groupName=&quot;one&quot;/&gt;
                &lt;/menuitem&gt;
                &lt;menuitem type=&quot;separator&quot;/&gt;
                &lt;menuitem label=&quot;2BizBox&quot; iconName=&quot;data_icon&quot;/&gt;
            &lt;/menuitem&gt;
            &lt;menuitem label=&quot;www.2bizbox.com&quot;/&gt;
            &lt;menuitem label=&quot;twaver.servasoft.com&quot;/&gt;
        &lt;/root&gt;
    &lt;/mx:XML&gt;
&lt;/code&gt;

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[] {
            &quot;getTWaverJava()&quot;,
            &quot;getTWaverWeb()&quot;,
            &quot;getTWaverFlex()&quot;,
            &quot;getTWaverDotNET()&quot;,
            &quot;getTWaverGIS()&quot;,
            &quot;getTWaverHTML5()&quot;,
            &quot;getTWaverJavaFX()&quot;,
            &quot;getTWaver...&quot;, };

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

    public PopupTipDemo() {
        super(&quot;www.servasoftware.com&quot;);
        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(&quot;// Try to press '.'\nimport twaver.Node;\nimport twaver.Link;\nimport twaver.network&quot;);
        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 &lt; 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