Sunday, September 18, 2011

How to create custom JLabel using java graphics

The first step is to extend the JLabel. We may have our own constructor to initialize variables which will impact the custom jlabel to be created. CalendarDateLabel.java source code provided below is the custom JLabel which will display a round corner JLabel with border and with a dark background:

Source: test.CalendarDateLabel.java


/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/

package test;

import java.awt.AlphaComposite;
import java.awt.event.MouseEvent;
import org.jps.ui.customcomponent.*;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.color.ColorSpace;
import java.awt.event.MouseListener;
import javax.swing.JComponent;
import javax.swing.JLabel;

/**
* Custom JLabel which displayes gray background with round corners.
* @author JoyP
*/
public class CalendarDateLabel extends JLabel implements MouseListener{

private String lblText = ""; //default text
private Color color_bg = Color.BLACK; //default bg color
private Color color_fg = Color.WHITE; //default text color
//private Color color_border = Color.BLUE; //default border color
private Color color_border = Color.LIGHT_GRAY; //default border color
private int arc = 3; //default to arc - 0 means sharp edges
private int x = 0; //x where label starts getting painted
private int y = 0; //y where label starts getting painted
private int w = 0; //width of the label
private int h = 0; //height of the label
private float border = 0f; //border of the label
private float alpha = 1.0f;
private boolean isMouseEntered = false;



public CalendarDateLabel(){
super();
super.setOpaque(false);

addMouseListener(this);


}

public CalendarDateLabel(String _text){
super();
super.setOpaque(false);

this.lblText = _text;

addMouseListener(this);


}


@Override
protected void paintComponent(Graphics g){
x = 3;
y = 3;
w = getWidth()-6;
h = getHeight()-6;
arc = 5;

Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setComposite(AlphaComposite.SrcOver.derive(alpha));

if(isMouseEntered){
//fill the label with color_bg
g2.setColor(color_bg);
g2.fillRoundRect(x, y, w, h, arc, arc);

//draw a round rectangle at the edge of the label with the arc value
g2.setStroke(new BasicStroke(border));
g2.setColor(color_border);
g2.drawRoundRect(x, y, w, h, arc, arc);
}




g2.setStroke(new BasicStroke(3f));
g2.setColor(color_fg);
g2.drawString(lblText, x+(Math.abs(w/4)), y+(Math.abs(h/2)));

g2.dispose();
}

@Override
public void mouseClicked(MouseEvent e) {
throw new UnsupportedOperationException("Not supported yet.");
}

@Override
public void mousePressed(MouseEvent e) {
throw new UnsupportedOperationException("Not supported yet.");
}

@Override
public void mouseReleased(MouseEvent e) {
throw new UnsupportedOperationException("Not supported yet.");
}

@Override
public void mouseEntered(MouseEvent e) {
isMouseEntered = true;


System.out.println("mouse entered");
color_bg = Color.GRAY;
border = 2f;

updateUI();


}

@Override
public void mouseExited(MouseEvent e) {
isMouseEntered = false;


System.out.println("mouse exited");
color_bg = Color.BLACK;

updateUI();


}


}




The above class may be instantiated in a JFrame as provided in source code below:

Source: test.TestFrame.java




/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/

/*
* TestFrame.java
*
* Created on Apr 27, 2010, 9:53:16 PM
*/

package test;



/**
* JFrame creating instances of custom JLabel
* @author JoyP
*/
public class TestFrame extends javax.swing.JFrame {

/** Creates new form TestFrame */
public TestFrame() {
initComponents();
}

/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
//
private void initComponents() {

jPanel1 = new javax.swing.JPanel();
jLabel2 = new test.CalendarDateLabel("TESTING");
jLabel1 = new test.CalendarDateLabel("TESTING");
jLabel3 = new test.CalendarDateLabel("TESTING");

setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setBackground(new java.awt.Color(255, 255, 255));

jPanel1.setBackground(new java.awt.Color(89, 89, 89));

jLabel2.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
jLabel2.setText("1");

jLabel1.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
jLabel1.setText("2");

jLabel3.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
jLabel3.setText("3");

javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
jPanel1.setLayout(jPanel1Layout);
jPanel1Layout.setHorizontalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addGap(20, 20, 20)
.addComponent(jLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, 102, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(18, 18, 18)
.addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 102, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 28, Short.MAX_VALUE)
.addComponent(jLabel3, javax.swing.GroupLayout.PREFERRED_SIZE, 102, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(28, 28, 28))
);
jPanel1Layout.setVerticalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addGap(41, 41, 41)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, 76, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jLabel3, javax.swing.GroupLayout.PREFERRED_SIZE, 76, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 76, javax.swing.GroupLayout.PREFERRED_SIZE))
.addContainerGap(121, Short.MAX_VALUE))
);

javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(62, Short.MAX_VALUE))
);

pack();
}//


/**
* @param args the command line arguments
*/
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new TestFrame().setVisible(true);
}
});
}

// Variables declaration - do not modify
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
private javax.swing.JLabel jLabel3;
private javax.swing.JPanel jPanel1;
// End of variables declaration

}





Running TestFrame.java will result in three custom JLabel which is highlighted on mouseover.

Ensuring Software Quality through effective Software Testing

Today I am going to speak more about best practices and process being followed in some of the well established software organizations. I will discuss on the pros and cons of such process. I will walk you through a detailed gap analysis of the situation where the processes lack the fine tuning. To help you kick start such best practices in your working environment – I’ll provide you with simple bullet points which you can adhere to all the time. This document is not a step by step tutorial document rather a confluence of thoughts on various processes which will require you to do some googling. As a result this documentation expects you to be aware of a very high level idea about software testing and software packaging process.

So let’s start with software testing. Software testing is the only process which ensures software quality. Let me put it in a question and answer format.

HOW TO PLAN SOFTWARE TESTING?

The best person to test the application should be the developer. Why a developer and not a tester? First reason being the developer will know in the first place what all minor bugs are there which he couldn’t take care of due to time limits or due to other reasons. Another reason, this also helps in creating a competitive and clean environment. The idea is keeping the resource overheads low, making sure egos are not built up, eliminating the have-to-find-bug attitude (which is important as a tester is concerned – else its assumed he has not done any job!!) and creating more friendly atmosphere where testers ‘n’ developers work in confluence towards a common achievable target. The problem to this kind of approach is that a developer may take testing for granted (For instance – One of my brilliant and highly expert resource, John, may think since that he has developed the module he knows exactly if there exists a bug or not hence can give away with certain testing!!). A proper test case needs to be put in place by the testing people/or someone who has no intellect regarding the implementation of the application logic. This will ensure that while writing the test cases no assumptions are made about the implementation side rather the concentration in on the user’s functional requirement. Such person while preparing the test case should think from clients’ perspective while writing the test cases to facilitate negative testing.

WHAT IS THE MOST DIFFICULT PHASE IN THE TESTING AND CORRECTION PROCESS?

Developers often find it difficult to accept that their implementation is having a bug. This is more apparent where the organizations have more of fresh graduates as resources. Moving the testing responsibility of actual testing from a tester to a developer goes a long way in tackling this kind of situation. Automating the testing process is another important step to ensure that all the tests are carried out. Automation saves lots of time spent in doing manual testing.

WHO SHOULD TEST THE APPLICATION AND ITS MODULE?

Automated test suite should be written by the developers as they proceed with their implementation. To ensure the implementation of test suits as the application implementation proceeds, we must ensure that the test cases are complete and have been reviewed. There are many tools available in the market for example JUnit is a fairly simple testing framework which fits well with java desktop application. We can create JUnit test suits which can be automatically called periodically or every time the code is changes.



WHAT CAN BE DONE TO AUTOMATE TESTING PROCESS?

Almost any process can be automated using a simple but highly powerful script tool called ANT. If you are not aware of ANT, you’re right I’d suggest that it’s again time for you to do some googling.

Apart from JUnit combined with ANT, you can also make use of LUNTBUILD an open source tool which helps manage the build and patch releases through ant build script. I’ll discuss about build automation in a separate thread.

TESTING ENVIRONMENT

Testing environment should always be clean and separate from the development environment. Key things to be considered:

· Never carry out testing in a high-end workstation or server machine. Even though one may argue that these days even the laptops are having the processing power of a server – still there are people in huge numbers who are comfortable with their old PIII with Windows 98 running on them. Hence testing should be done in a machine ideally with 1-1.5 GHz processor speed and 512 MB RAM. The answer to this is use VMWARE. VMWARE will also help in cost cutting which otherwise needs to be spent in buying high end servers and workstations for testing purpose.

· Testing machine should have a clean OS. Enterprise level application should be tested in clean OS. This ensures that application shall run on an environment independent of the development environment. For example: A clean system may not have the class-path set for the application to run – hence running it on a clean system will eventually help to find the application-environment dependencies.



WHAT TO TEST?

Various aspects need to be tested viz.:

Functionality (Positive Testing)

Test cases should first concentrate on testing the core and detailed level functionality of the application. User Requirement Document and Software Technical Specifications should be closely referenced while preparing the test cases and carrying out the tests not covered in the test case (One must ensure that the test cases are periodically updated).

Negative Testing

Following the positive testing – we must move on to carry out negative testing of our application. Negative testing ensures the user a highly qualitative product.



GUI Testing

User interfaces should be well planned out. Implementation should be such that the components can be re-arranged easily. Different layouts and combinations should be debated to enhance user experience. One such tool is swingunit. Swingunit is a unit test automation toolkit for Java Swing Application.



Load Testing

Enterprise level application sometimes needs to process a huge number of records within minutes or even seconds. Such application need to be subject to extensive load testing. During load testing the upper and lower cut-off limit (efficiency limit) needs to be constantly checked rather than the performance of each module separately. For example: JMeter from Apache

Eclipse's exported jar fails to include the entry for "SplashScreen-Image" in the exported MANIFEST.MF file.

For exporting my project as jar - i've built a custom MANIFEST.MF file in my project which can be selected for creating the jar. The MANIFEST.MF file in the project appears as below:

Manifest-Version: 1.0
Class-Path: lib/external1.jar lib/external2.jar
Main-Class: main.Main
SplashScreen-Image: MySplashImage.jpg

After the jar has been fully exported. On checking the MANIFEST.MF file in the exported jar - only the following entries appear:

Manifest-Version: 1.0
Class-Path: lib/external1.jar lib/external2.jar
Main-Class: main.Main

Solution:

Re-arrange the projects MANIFEST.MF entries such that the Main-Class entry appears at the very end. For example:

Manifest-Version: 1.0
Class-Path: lib/external1.jar lib/external2.jar
SplashScreen-Image: MySplashImage.jpg
Main-Class: main.Main

Now exporting the jar using the modified MANIFEST.MF jar will have proper MANIFEST.MF file with all its entries.

JMenuItem not getting focus

All components have the method show() and setVisible(true) which can be used to display the component. The same is true with JPopupMenu also. But one problem faced while using these two methods is that JMenuItem added to the popup menu may not get the focus and hence will not show as selected when moving the mouse over it.

To resolve this we can use the following method:

show(Component invoker, int x, int y)