Saturday, 21 October 2017

Launch Swing GUI always in a dedicated Thread



1. Since Swing is not thread safe, it is not at all a good practice to launch a UI Container like JFrame, JDialog etc in main Thread.
2. Doing so leads to incorrect behavior of java GUI.
3. To avoid this, Swing toolkit has predefined API as part of JFC.
4.    a. SwingUtilities.invokeAndWait(Runnable r);
       b. SwingUtilities.invokeLater(Runnable r);

5. Which part of the code must be in UI Thread?
        a. setVisible(true);
        b. show(); [deprecated]
 and c. pack();
     

6. Call to these methods mentioned in 5(a), 5(b), and 5(c) must happen in one of the methods mentioned in point 4(a) and point 4(b). That's enough. :)
         Example :
             
         public static void main(String[] args){
                         
         JFrame frame = new JFrame();
         frame.setSize(100, 200);
         SwingUtilities.invokeAndWait(new Runnable(){
             public void run(){
                     frame.setVisible(true);
                     frame.pack();
             }//run
        });//
       }//main

  7. Difference between invokeAndWait() and invokeLater():
          a. invokeLater() is non blocking and asynchronous, where as invokeAndWait() is blocking and synchronous.
          b. Since invokeLater() is asynchronous, It is more flexible.
                                 
                                   

Friday, 6 October 2017

File Manager/File Explorer with Swing JTree Component

This post is intended to beginners of java swing toolkit programmers.
It is a simple java program which demonstrates the swing based File explorer GUI.





import java.awt.GridLayout;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;

/**
 * @author NagasharathK
 *
 */
public class FileExplorer extends JFrame {

private JTree fileManagerTree = null;

public FileExplorer() {
initComponents();
}

/**
* Initializes components
*/
private void initComponents() {
this.getContentPane().add(new JScrollPane(createFileManagerTree()));
this.setSize(500, 500);
this.setResizable(true);
this.setTitle("File Manager..");
}

/**
* @return JPanel object which contains other comp...
*/
private JPanel createFileManagerTree() {
JPanel panel = new JPanel();
panel.setLayout(new GridLayout());

fileManagerTree = new JTree();
fileManagerTree.setModel(new FilesContentProvider("C:\\"));
panel.add(fileManagerTree);
return panel;
}

class FilesContentProvider implements TreeModel {

private File node;

public FilesContentProvider(String path) {
node = new File(path);

}

@Override
public void addTreeModelListener(TreeModelListener l) {

}

@Override
public Object getChild(Object parent, int index) {
if (parent == null)
return null;
return ((File) parent).listFiles()[index];
}

@Override
public int getChildCount(Object parent) {
if (parent == null)
return 0;
return (((File) parent).listFiles() != null) ? ((File) parent).listFiles().length : 0;
}

@Override
public int getIndexOfChild(Object parent, Object child) {
List<File> list = Arrays.asList(((File) parent).listFiles());
return list.indexOf(child);
}

@Override
public Object getRoot() {
return node;
}

@Override
public boolean isLeaf(Object node) {
return ((File) node).isFile();
}

@Override
public void removeTreeModelListener(TreeModelListener l) {

}

@Override
public void valueForPathChanged(TreePath path, Object newValue) {

}

}

/**
* @param args
* @throws InvocationTargetException
* @throws InterruptedException
* @throws UnsupportedLookAndFeelException
* @throws IllegalAccessException
* @throws InstantiationException
* @throws ClassNotFoundException
*/
public static void main(String[] args) throws InvocationTargetException, InterruptedException,
ClassNotFoundException, InstantiationException, IllegalAccessException, UnsupportedLookAndFeelException {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
FileExplorer explorerUI = new FileExplorer();
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
explorerUI.setVisible(true);
}
});
}
}
 

The above program has one inner class [FilesContentProvider] which serves as a model to the JTree.

The UI has 4 Components: JFrame, JScrollPane, JPanel and JTree.

To Do:

  1. Add Context menu to node based upon the file type
  2. Add Cell renderer to give proper names to the Nodes
  3. Option to Expand whole tree or selected node etc..  


Friday, 6 January 2017

GridLayout: fill the form with gridlayout

Swing controls are of two types they are Containers and components. components are arranged on a containers. example components are JLabel, JButton etc and example containers are JPanel, JFrame and JDialog etc.
these components are arranged on a container with the help of layout managers. Few layout managers available in swing toolkit are

1. FlowLayout [Jframe's Default layout manager]
2. GridLayout
3. BorderLayout [JPanel's Default layout manager]
4. GridBagLayout.
5. Custom Layout manager

The custom layout amanger is useful to design programmer's own layout manager. Usually this is useful when any of the available layout managers does not give the needy result.
apart of these above all layout managers, few third party libraries are also available they are

1. DesignGridLayout
2. Mig Layout etc

                                          Designgrid Layout

Gridlayout is one of the most simple and flexible layout managers. layout manager is used to arrange the components on a container with proper margins, gap etc.

Gridlayout is suitable when the number of components are even numbered in each row of the container.


Swing program without any layout manager:


import java.awt.GridLayout;
import java.lang.reflect.InvocationTargetException;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

public class GridLayoutExample extends JFrame {



private JLabel label1 = null;
private JLabel label2 = null;
private JLabel label3 = null;
private JTextField tf1 = null;
private JTextField tf2 = null;
private JTextField tf3 = null;
private JButton button1 = null;
private JButton button2 = null;

public GridLayoutExample() {
initComponents();
}

private void initComponents() {

label1 = new JLabel("Name: ");
add(label1);
tf1 = new JTextField();
add(tf1);

label2 = new JLabel("Qualification: ");
add(label2);

tf2 = new JTextField();
add(tf2);
label3 = new JLabel("Profile: ");
add(label3);

tf3 = new JTextField();
add(tf3);

button1 = new JButton("Submit");
add(button1);
button2 = new JButton("Cancel");
add(button2);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       
}

public static void main(String[] args) throws InvocationTargetException, InterruptedException {

GridLayoutExample ex = new GridLayoutExample();

ex.setSize(300, 200);
ex.setLocationRelativeTo(null);
//ex.pack();
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
ex.setVisible(true);
}
});

}
}

 the output




Swing program after adding a Gridlayout. replace the initComponents() method [ Highlighted] of the above program with the below method........


private void initComponents() {
GridLayout gl = new GridLayout();
gl.setColumns(2);
gl.setRows(4);
gl.setHgap(15);
gl.setVgap(15);

this.setLayout(gl);

label1 = new JLabel("Name: ");
add(label1);
tf1 = new JTextField();
add(tf1);

label2 = new JLabel("Qualification: ");
add(label2);

tf2 = new JTextField();
add(tf2);
label3 = new JLabel("Profile: ");
add(label3);

tf3 = new JTextField();
add(tf3);

button1 = new JButton("Submit");
add(button1);
button2 = new JButton("Cancel");
add(button2);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       
}


the output after applying layout manager.....