Showing posts with label java. Show all posts
Showing posts with label java. Show all posts

Java Image Utility

Few days ago I did some image manipulation tasks like resizing, cropping, etc. java awt provides some useful functionality to do this type of tasks. Here I am going to share how I accomplish the tasks and finally and ImageUtility Class which you can use in your project.

Image Resizing
First read the image with the ImageIO which returns a BufferedImage. Then create another BufferedImage instance with the new width, height and image type.

BufferedImage originalImage = ImageIO.read(imageFile); 
BufferedImage scaledBI = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB);

Now get the Graphics2D component of the new scaled image and draw it.

g.drawImage(originalImage, 0, 0, 100, 100, null);
g.dispose();

If you want to preserve the image quality, add following line of code before disposing the graphics component.

g.setComposite(AlphaComposite.Src);
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);

It's simple, is not it?

Image Croping

Read the image with ImageIO as stated previously and get the sub image of the original image.

BufferedImage originalImage = ImageIO.read(imageFile); 
originalImage .getSubimage(0,0, 100, 100);

First two parameter of the getSubimage method is the x,y coordinate, from where you want to begin cropping.


Get Byte Array of an Image

Sometimes you need this specially when you want to save an image in database in blob data type . We can get byte[] of an image with the help of ByteArrayOutputStream and ImageIO class.


BufferedImage originalImage = ImageIO.read(imageFile); 
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(originalImage , getImageExtension(), baos);
//getImageExtension method is stated later
baos.flush();
byte[] imageData = baos.toByteArray();
baos.close();

ImageUtility.java

All the above actions can be encapsulated into a simple ImageUtility class.

import java.awt.AlphaComposite;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import org.openide.util.Exceptions;

/**
 *
 * @author ratul
 */
public class ImageUtility
{
    private File imageFile;
    private BufferedImage image;
    public ImageUtility()
    {
    }

    public ImageUtility(File imageFile)
    {
        try
        {
            this.imageFile = imageFile;
            image = ImageIO.read(imageFile);
        }
        catch (IOException ex)
        {
            Exceptions.printStackTrace(ex);
        }
    }

    public ImageUtility(File imageFile, BufferedImage image)
    {
        this.imageFile = imageFile;
        this.image = image;
    }


    public File getImageFile()
    {
        return imageFile;
    }

    public void setImageFile(File imageFile)
    {
        this.imageFile = imageFile;
    }

    public BufferedImage getImage()
    {
        return image;
    }

    public void setImage(BufferedImage image)
    {
        this.image = image;
    }
    
    public String getImageExtension()
    {
        String fName = imageFile.getName();
        return fName.substring(fName.indexOf(".")+1, fName.length());
    }
    public BufferedImage getResizedCopy(int scaledWidth, int scaledHeight, boolean preserveAlpha)
    {
        return getResizedCopyOfImage(image, scaledWidth, scaledHeight, preserveAlpha);
    }
    
    public byte[] getByte()
    {
        return getByteOfImage(image);
    }
    public ImageIcon getImageIcon()
    {
        return new ImageIcon(image);
    }
    public BufferedImage getCropedImage(int x, int y, int width, int height)
    {
        return getCropedImageOfImage(image, x, y, width, height);
    }
    public BufferedImage getCropedImageFromCenter(Dimension panelDimension,int clipedWidth, int clipedHeight)
    {
        return getCropedImageOfImageFromCenter(image, panelDimension, clipedWidth, clipedHeight);
    }

    public BufferedImage getResizedCopyOfImage(BufferedImage originalImage,int scaledWidth, int scaledHeight, boolean preserveAlpha)
    {
        int imageType = preserveAlpha ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
        BufferedImage scaledBI = new BufferedImage(scaledWidth, scaledHeight, imageType);
        Graphics2D g = scaledBI.createGraphics();
        if (preserveAlpha)
        {
                g.setComposite(AlphaComposite.Src);
        }
        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
        RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g.setRenderingHint(RenderingHints.KEY_RENDERING,
        RenderingHints.VALUE_RENDER_QUALITY);
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
        RenderingHints.VALUE_ANTIALIAS_ON);
        g.drawImage(originalImage, 0, 0, scaledWidth, scaledHeight, null);
        g.dispose();
        return scaledBI;
    }

    public byte[] getByteOfImage(BufferedImage sourceImage)
    {
        try
        {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(sourceImage, getImageExtension(), baos);
            baos.flush();
            byte[] imageData = baos.toByteArray();
            baos.close();
            return imageData;
        }
        catch (IOException ex)
        {
            Exceptions.printStackTrace(ex);
            return null;
        }
    }

    public ImageIcon getImageIconFromImage(BufferedImage sourceImage)
    {
        return new ImageIcon(sourceImage);
    }

    public BufferedImage  getCropedImageOfImage(BufferedImage sourceImage, int x, int y, int width, int height)
    {
        return sourceImage.getSubimage(x, y, width, height);
    }
    public BufferedImage getCropedImageOfImageFromCenter(BufferedImage sourceImage, Dimension panelDimension,int clipedWidth, int clipedHeight)
    {
        Rectangle clip = new Rectangle(clipedWidth, clipedHeight);
        clip.x = (panelDimension.width - clip.width) / 2;
        clip.y = (panelDimension.height - clip.height) / 2;
        int x0 = (panelDimension.width - sourceImage.getWidth()) / 2;
        int y0 = (panelDimension.height - sourceImage.getHeight()) / 2;
        int x = clip.x - x0;
        int y = clip.y - y0;
        return sourceImage.getSubimage(x, y, clip.width, clip.height);
    }
}

Entity Inheritance Using Abstract Entity

In my previous blog I shared my code re-factoring experience by using Mapped Superclass. Using Abstract Entity was another interesting experience. In our project there are some Entities like Customer, Vendor which have some common attributes like 'First Name', 'Last Name', etc. These attributes were defined  in both Customer and Vendor Class. This approach not only produced code duplication but also column duplication in underlying Datastore. JPA Abstract Entity feature inspires me to use a third Entity Class which is abstract to avoid this duplication.

Let's see how it works. Suppose you have two Entities Student and Teacher, and they have following attributes



Three attributes are common in this case and you can introduce a Person class which is abstract and has these common properties. Student and Teacher class will extend Person and only have their individual properties.

Your  Person, Student and Teacher Entity classes will be like this

@Entity
@Inheritance(strategy=InheritanceType.JOINED)
@Table(name = "persons")
public abstract class Person implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "id_nr")
    protected Long idNr;
    @Column(name = "first_name")
    protected String firstName;
    @Column(name = "last_name")
    protected String lastName;
    
    public Person() {
    } 
    //getter setter of the properties ....


@Entity
@Table(name = "teachers")
public class Teacher extends Person {
    private static final long serialVersionUID = 1L;
    @Column(name = "designation")
    protected String designation;
    // constructor, getter setter of the property....


@Entity
@Table(name = "students")
public class Student extends Person {
    private static final long serialVersionUID = 1L;
    @Column(name = "role_number")
    protected String roleNumber;
    // constructor, getter setter of the property.... 

For above scenario three tables will be generated in the database, persons, students and teachers. Mapping strategy of @Inheritance annotation has a great impact in table generation process. As we have used InheritanceType.JOINED as the mapping strategy, three different tables are created. If we were using default mapping strategy which is InheritanceType.SINGLE_TABLE, only persons table will be created with all the attributes. In both cases Persistence provider will also create a discriminator column in the person table called DTYPE, which will store the name of the inherited entity used to create the person.

Now run the following code and see how data is stored in the database in this design.

        @PersistenceContext(unitName = "TaskBoard-ejbPU")
        EntityManager em;

        Teacher teacher = new Teacher();
        teacher.setFirstName("Sarwar");
        teacher.setLastName("Hossain");
        teacher.setDesignation("Associate Proffessor");
        teacher.setIdNr(null);
        em.persist(teacher);
        
        Student student = new Student();
        student.setFirstName("Shams");
        student.setLastName("Zawoad");
        student.setRoleNumber("001525");
        student.setIdNr(null);
        em.persist(student);
        em.flush();



If you try with InheritanceType.SINGLE_TABLE mapping strategy you will get the following output by running the same code

Attractive feature of abstract entities is that they can be queried just like concrete queries, which were not possible in Mapped Superclass. If an abstract entity is the target of a query, the query operates on all the concrete subclasses of the abstract entity.

Entity Inheritance Using Mapped Superclass

When I engaged myself into code re-factoring of our VELACORE project, I found that almost all Entities have four common properties createdBy, creationDate, modifiedBy and modificationDate.  I wanted to reduce this code duplication and found that JPA is providing Mapped Superclass for this type of requirement where state and mapping information are common to multiple Entity classes. It contains persistent state and mapping information, but is not Entitity. That is, it is not decorated with the @Entity annotation and is not mapped as an entity by JPA.

Mapped Superclasses do not have any corresponding tables in the underlying Datastore (that was also my requirement). Entities that inherit from the mapped Superclass define the table mappings. Mapped superclasses are specified by decorating the class with the javax.persistence.MappedSuperclass annotation.

Here is an example of using Mapped Superclass for entity inheritance

@MappedSuperclass
public class BaseEntity
{
    @Column(name = "created_by")
    private String createdBy;
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "creation_date")
    private Calendar creationDate;
    
   //getter setter of the properties ....
}

@Entity
public class Customer extends BaseEntity 
{
    @Column(name = "first_name")
    private String firstName;

    ...
}

@Entity
public class Invoice extends BaseEntity {
    @Column(name = "invoice_no")
    private String invoiceNo;

    ...
}


In the above code snippet BaseEntity is the MappedSuperclass which contains the mapping information of the common properties. Customer and Invoice are two Entities extending the BaseEntity. In this scenario only CUSTOMER and INVOICE tables will be created in the database not the BASEENTITY. "created_by" and "creation_date" columns will be present in both CUSTOMER and INVOICE tables.


Limitations of using Mapped Superclass :
-Mapped Superclasses are not queryable, and can’t be used in EntityManager or Query operations.
-Mapped Superclasses can’t be targets of entity relationships.

Protect Your Java Application by reCAPTCHA

4 months gone since I have post my last blog. Got a very encouraging feedback from my readers in this period but can't manage to write anything. Now feeling glad to start writing again. Hope java developers will find this tutorial useful to protect their application using reCaptcha, a widely used CAPTCHA system in the industry.

First go to the reCAPTCHA website and create your reCAPTCHA key by providing the domain name of your application. You will get two keys one is Private and another is Public. Public key will be used in the JavaScript code that is served to your users. Private key is required to communicate between your server and the reCAPTCHA server. Be sure to keep the Private key secret.

Now download the recaptcha4j library from here. And place the jar file in WEB-INF/lib/ directory. It will make your life easy to display the reCAPTCHA widget, send the user request to reCAPTCHA server and get response from there.

You are now ready to use reCAPTCHA in your application. First import the required classes in your JSP page.

<%@ page import="net.tanesha.recaptcha.ReCaptcha" %>
<%@ page import="net.tanesha.recaptcha.ReCaptchaFactory" %>
Now add the following code in the web page, where you want to put the reCAPTCHA box. Target of using reCAPTCHA is to protect form submission so place this between the form beginning and ending tags.
<%
ReCaptcha c = ReCaptchaFactory.newReCaptcha("your_public_key", "your_private_key", false);
          out.print(c.createRecaptchaHtml(null, null));
%>

First line of the code will create an instance of reCAPTCHA. Second line will generate and display a reCAPTCHA widget in your page.

Now come to the server side where you have to validate the submitted form with the reCAPTCHA server.


Here is a simple servlet which is used to do the validation job.
import net.tanesha.recaptcha.ReCaptchaImpl;
import net.tanesha.recaptcha.ReCaptchaResponse;

public class GreetingServlet extends HttpServlet 
{
    public void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws IOException {

        String challenge = req.getParameter("recaptcha_challenge_field");
        String response = req.getParameter("recaptcha_response_field");
        
        String remoteAddr = req.getRemoteAddr();

        ReCaptchaImpl reCaptcha = new ReCaptchaImpl();
        reCaptcha.setPrivateKey("[write your privatekey here]");

        ReCaptchaResponse reCaptchaResponse =
                reCaptcha.checkAnswer(remoteAddr, challenge, response);

        if (reCaptchaResponse.isValid()) {
            //valid do something whatever you want to do
        } 
        else
        {
            //not valid do something like send error message to user
        }
    }
}

remoteAddr is the user's IP address which is passed to the reCAPTCHA servers. response contains the user's answer to the reCAPTCHA challenge.

You are done. Visit this link to get an example of how it works.
Reference link.

How to call a method dynamically using Java Reflection

In my previous post i have shown you how to create an instance dynamically using java reflection. Here i will show you how to call a method dynamically using reflection.

Let us start with a simple example. Assume that the method name is refreshForm and it has no argument. You can get the method using class.getMethod(methodName) method and then call the method using method.invoke(instance of the class) method.

 
String className = "com.commlink.cbs.appclient.gl.ChartsOfAccount"
String methodName = "refreshForm";

//get the Class
Class class = Class.forName(className);

// get the instance
Object obj = class.newInstance();

// get the method
Method method = class.getMethod(methodName );

//call the method
method.invoke(obj);


Things will be little complex if the method has some arguments. Suppose the refreshForm method takes two String values. To call this method using reflection first create an array of Class and then an array of Object. Use the class array in getMethod method and the Object array in invoke method in the following way.


String className = "com.commlink.cbs.appclient.gl.ChartsOfAccount"
String methodName = "refreshForm";
Class class = Class.forName(className );

Object obj = class.newInstance();

//create the class array
Class[] types = new Class[] { String.class,String.class};

//get the method
Method method = class.getMethod(methodName ,types);

//create the object array
Object[] args = new Object[]{new String("Hello"), new String("World")};

//call the method
method.invoke(obj,args);

How to create an instance of a class at runtime using Java Reflection

Java Reflection gives us the facility of creating an instance of any class at run time. In our ERP project it helps us a lot to solve some critical problems.

First create a class using the class name then use the class.newInstance method
to create an instance of that class.


javax.swing.JPanel newPanel = null;

String className= "com.commlinkinfotech.cbs.appclient.gl.ChartsOfAccount";

Class class = Class.forName(className);

//we know that the ChartsOfAccount is a JPanel class so cast this to JPanel
newPanel = (JPanel) class.newInstance();


But if the constructor of your class takes some parameters then what will you do?

You have to create an array of your argument class. Use this to create a constructor of your class using the class.getConstructor method. Now call the constructor.newInstance method with the value of the arguments and it gives you an instance of the class.


javax.swing.JPanel newPanel = null;

String className= "com.commlinkinfotech.cbs.appclient.gl.ChartsOfAccount";

//create an array of parameter classes
Class[] types = new Class[] { String.class };

Class class = Class.forName(className);
//create a constructor with the types array
Constructor constructor = class.getConstructor(types);

//create an array of argument values
Object[] args = new Object[] {new String("Hello")};

//now use ther args array to create an instance
newPanel = (JPanel) constructor .newInstance(args);

Understanding GroupLayout in Java

GroupLayout is one of the most effective layout managers in Java to place the GUI elements in a very organized way. Here I show you how to use Group Layout to build your GUI.

GroupLayout works with the horizontal and vertical layouts separately. The layout is defined for each dimension independently and it uses two types of arrangements -- sequential and parallel, combined with hierarchical composition. Usually, components placed in parallel in one dimension are in a sequence in the other, so that they do not overlap.

Let’s start with a very simple example to understand this layout.

Suppose you have to put one JLabel and one JTextField component in a row within a container named jpTestGroupLayout


You have to put these comonents both in a Horizontal sequential group and in a Vertical sequential group. But how?

To add the components in a horizontal sequential group at first you need to create two parallel groups. Add the JLable and the JTextField in the parallel groups then add these groups sequentially in the Horizontal sequential group.

And to add the components in a Vertical sequential group, create one parallel group and add the components in the group. Then add this parallel group to your vertical sequential group.

Now let’s look at the code to create the layout described above.


//declare the two component
JLabel label = new javax.swing.JLabel();
label.setText("JLabel");
label.setBorder(null);
JTextField jtfValue = new javax.swing.JTextField();
jtfValue.setText("JTextField");

//create a GroupLayout object associate with the panel
GroupLayout grpLayout = new GroupLayout(jpTestGroupLayout); jpTestGroupLayout.setLayout(grpLayout);
grpLayout.setAutoCreateGaps(true); // specify automatic gap insertion
grpLayout.setAutoCreateContainerGaps(true);

//create the Horizontal and Vertical and sequential group
GroupLayout.SequentialGroup horizontalSeqGrp = grpLayout.createSequentialGroup();
GroupLayout.SequentialGroup verticalSeqGrp = grpLayout.createSequentialGroup();

//create two parallel group for adding the components in the horizontal sequential group
GroupLayout.ParallelGroup hParallelGroup1 = grpLayout.createParallelGroup(GroupLayout.Alignment.LEADING);
GroupLayout.ParallelGroup hParallelGroup2 = grpLayout.createParallelGroup(GroupLayout.Alignment.LEADING);

//add the components
hParallelGroup1.addComponent(label);
hParallelGroup2.addComponent(textField);

//add two parallel groups sequentially in the horizontal sequential group
horizontalSeqGrp.addGroup(hParallelGroup1);
horizontalSeqGrp.addGroup(hParallelGroup2);

//create one parallel group for adding the components in the vertical sequential group
GroupLayout.ParallelGroup vparallelGroup1 = grpLayout.createParallelGroup(GroupLayout.Alignment.BASELINE);

//add the components
vparallelGroup1.addComponent(label);
vparallelGroup1.addComponent(textField);

//add this parallel group in the vertical sequential group
verticalSeqGrp.addGroup(vparallelGroup1);

//finally set the both sequential group to the grpLayout object
grpLayout.setHorizontalGroup(horizontalSeqGrp);
grpLayout.setVerticalGroup(verticalSeqGrp);


If you want to add another JLabel in the same row then what will you do?


It is very simple now. Just create another parallel group to add the new JLable in the Horizontal sequential group and to add this to the Vertical sequential group add this in the existing vertical parallel group.


JLabel label2 = new javax.swing.JLabel();
label2.setText("JLabel2");
label2.setBorder(null);
GroupLayout.ParallelGroup hParallelGroup3 = lout.createParallelGroup(GroupLayout.Alignment.LEADING);
hParallelGroup3.addComponent(label2);

//add the new parallel group to the horizontal sequential group
horizontalSeqGrp.addGroup(hParallelGroup3);
vparallelGroup1.addComponent(labe2l);


Now I describe another scenario. Suppose you want to add the second JLable in the following way.


The code will be like this


//add the new component in the hParallelGroup1
hParallelGroup1.addComponent(label2);

//create a new parallel group to add the new component in the vertical Sequential group
GroupLayout.ParallelGroup vparallelGroup2 = grpLayout.createParallelGroup(GroupLayout.Alignment.BASELINE);

//add the component to the new group
vparallelGroup2.addComponent(label2);

//add the new parallel group to the vertical sequential group
verticalSeqGrp.addGroup(vparallelGroup2);


Try the above examples yourself and definitely you will find this layout very easy to manage. For more information visit this link.

Filter a JTable row with input in a text field

In an enterprise application when there is huge amount data in a table
users feel comfortable if you provide them a option for filtering the
table. Here I show you an example of how to filter a JTable row with
input in a JTextField.

Declare a JTable and your own table model


private MyTableModel tableModel;
private javax.swing.JTable jtblSampleTable;


Now declare a table row sorter for that table model


private TableRowSorter sorter ;
//


Initialize all the above three declared variables


jtblSampleTable = new javax.swing.JTable();
tableModel = new MyTableModel();
sorter = new TableRowSorter(tableModel);
//


Bind the model with the table


jtblSampleTable.setModel(tableModel);


Set the sorter as the row sorter for the table


jtblSampleTable.setRowSorter(sorter);


Now declare a JTextField


jtfSearch = new javax.swing.JTextField();


Add a document listener for the search text field.


jtfSearch.getDocument().addDocumentListener(
new DocumentListener()
{
public void changedUpdate(DocumentEvent e)
{
newFilter();
}
public void insertUpdate(DocumentEvent e)
{
newFilter();
}
public void removeUpdate(DocumentEvent e)
{
newFilter();
}
}
);



Here is the newFilter method


private void newFilter()
{
RowFilter< MyTableModel , Object> rf = null;
//declare a row filter for your table model
Try
{
rf = RowFilter.regexFilter("^" + jtfSearch.getText(), 0);
//initialize with a regular expression
}
catch (java.util.regex.PatternSyntaxException e)
{
return;
}
sorter.setRowFilter(rf);
}



The above example is able to filter JTable for its first column.

Showing your own custom dialog box in java

While developing our ERP application we need to show a list of
all accounts in a dialog box and upon selecting an account the
base form will be updated. For this we need our custom dialog
box to show the list of accounts. Here i give an example of how
can you show your own custom dialog box and get desired value on
closing the dialog.

At first i like to describe the custom dialog class.



import javax.swing.JDialog;
import javax.swing.JFrame;

/**
* @author ratul
*/
public class CustomDialog extends JDialog {

private javax.swing.JLabel jLabel1;
private javax.swing.JButton jbtOK;
private javax.swing.JTextField jtfInput;
private String inputString = "";

public CustomDialog(JFrame frame, boolean modal) {
super(frame, modal);
initComponents();
pack();
setLocationRelativeTo(frame);
setVisible(true);
}

private void initComponents() {

jbtOK = new javax.swing.JButton();
jtfInput = new javax.swing.JTextField();
jLabel1 = new javax.swing.JLabel();

setLayout(new org.netbeans.lib.awtextra.AbsoluteLayout());

jbtOK.setText("OK");
jbtOK.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jbtOKActionPerformed(evt);
}
});
add(jbtOK, new org.netbeans.lib.awtextra.AbsoluteConstraints(160, 190,
-1,-1));

jtfInput.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyReleased(java.awt.event.KeyEvent evt) {
jtfInputKeyReleased(evt);
}
});
add(jtfInput, new org.netbeans.lib.awtextra.AbsoluteConstraints(180, 120,
160, 20));

jLabel1.setText("Input some text here:");
add(jLabel1, new org.netbeans.lib.awtextra.AbsoluteConstraints(70, 120,
-1, -1));
}

private void jbtOKActionPerformed(java.awt.event.ActionEvent evt)
{
this.dispose();
}

private void jtfInputKeyReleased(java.awt.event.KeyEvent evt)
{
inputString += evt.getKeyChar();
}

public String getInputText()
{
return inputString;
}

}



The CustomDialog class extends the JDialog class. The first
parameter of the constructor is the parent frame, second parameter
determines whether the parent frame is disabled or enabled when
the dialog box will be shown.

In the key released action of the text field i populate the inputString.
The dialog box can be closed either by clicking the 'OK' button or close
button of the top right corner. You can get the value of the input
field from the parent from by calling the public String getInputText() method.

Now i describe how to open your custom dialog box:
In the action handler of a button in the parent frame write the following code



CustomDialog cDialog = new CustomDialog(this, true);
this.jtfShowText.setText(cDialog.getInputText());



This will show the dialog box. Now Input some text on the text field
and close the dialog box. The input text will be shown in the text
field of the parent frame.

NB: use null or absolute layout to design the custom dialog box.

Total Pageviews

Tags

Twitter Updates
    follow me on Twitter

    Followers