DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations

Custom Swing Component Development Tip: Insets Matter

Rhiannon Liebowitz user avatar by
Rhiannon Liebowitz
·
Oct. 18, 10 · Interview
Like (1)
Save
Tweet
Share
16.30K Views

Join the DZone community and get the full member experience.

Join For Free

This is the first article in a series where I will be detailing a number of tips and common pitfalls I have encountered while developing custom Swing components for Java.

I have decided to start with a discussion around how a component's border and insets affect developing a custom Swing component. To illustrate this concept I am going to ask you to put yourself into the shoes of a young developer called Toni.

Toni is a junior developer who has just joined a new start up company, whose strategy revolves around developing a large number of custom Swing components. On his first day on the job, his technical lead Bob decides to test Toni's mettle and assigns him the task of developing the company's next big custom Swing component named the Orb. The use case for the Orb states that the Orb must render a blue circle to the screen.

Toni is excited to start work on the Orb and immediately dives into the code. After a few hours Toni produces the following code for the Orb.

private class Orb extends JComponent {
	@Override
	protected void paintComponent(Graphics graphics) {
		super.paintComponent(graphics);
		
		//create a new graphics2D instance
		Graphics2D g2 = (Graphics2D) graphics.create();
		
		//determine the x, y, width and height
		int x = 0;
		int y = 0;
		int w = getWidth();
		int h = getHeight();
		
		//draws the blue circle
		g2.setPaint(Color.BLUE);
		g2.fillOval(x, y, w, h);
		
	}
}

Bob is really impressed with Toni's work, the Orb meets all the requirements of the use case and flies through the testing phase without a single issue.

A few days later Bob informs Toni that he is preparing a demo for upper management and would really like to include the Orb in the demo, however as the demo would include a number of new components that the company has been working on, it would be necessary to add a titled border to the Orb to help identify it. Bob asks Toni if he minds quickly adding the Orb to the demo.

Toni gets to work including the Orb in the demo and gives an instance of the Orb a fancy border using the following code:

Orb customComponent = new Orb();
		
Border outterBorder = BorderFactory.createEmptyBorder(10,10,10,10);
Border innerBorder = BorderFactory.createTitledBorder("The Orb");
Border compoundBorder = BorderFactory.createCompoundBorder(outterBorder, innerBorder);
customComponent.setBorder(compoundBorder);

However when Toni runs the demo, he is horrified to discover that the Orb has not rendered correctly. The Orb seems to have totally ignored the borders when rendering. Toni begins to panic as the demo is in a matter of hours!

Stepping out of Toni's shoes it is time to discuss where Toni went wrong. The crux of Toni's problem is that he never knew he needed to cater for borders when rendering his custom Orb component.

When you apply a border to any Swing component, the component's position (x and y coordinate) and dimensions (width and height) remain unchanged. This leads to the question, if applying a border to a component does not change its position or dimensions, then how are you expected to cater for the borders?

The answer to this question lies with the border's Insets. An Insets is a simple class that contains 4 fields: top, left, bottom and right. Insets are used to describe the padding surrounding a component. Every Border in Swing is expected to return an Insets object describing how much padding to add to the component for the Border to render correctly. Below is a simple example of a Border (the code does not do much, but the key point is to notice the getBorderInsets method). The Border below returns an Insets whose top and bottom padding is 10 pixels, and whose left and right padding is 2 pixels. This is the amount of padding the border will require from the component.

(As a side note the constructor for Insets reads in the arguments anti-clockwise starting with top, then left, then bottom, then right).

private class ExampleBorder extends AbstractBorder {
		
@Override
public void paintBorder(Component c,Graphics g,int x,int y,int width,int height) {
		super.paintBorder(c, g, x, y, width, height);
		//code to paint a border goes here
	}

	@Override
	public Insets getBorderInsets(Component c) {
		//returns a new Inset with 
		//top = 10
		//left = 2
		//bottom = 10
		//right = 2
		return new Insets(10,2,10,2);
	}
}

This sounds good, but how does a developer use this information to render his component correctly? The answer is simple, the component may call its own getInsets method which will give the developer an Inset objects describing how much padding exists around the component.

To illustrate the point further, lets assume we are rendering a component whose current width and height is 100 pixels and currently has no borders. The rectangular area where the component should be rendered would be:

x = 0
y = 0
w = 100
h = 100

However if we then applied a border whose Insets had a top and bottom padding of 10 and a left and right padding of 2, the rectangular area where the component should render would be different.

The x coordinate should be equal to the left padding.
The y coordinate should be equal to the top padding.
The renderable width would be the width of the component minus its left and right padding.
The renderable height would be the height of the component minus its top and bottom padding.

They key point to take away is that when a border is applied to a component, its location and dimensions remain the same, however its Insets are change based on the border.

Stepping back into Toni's now rather sweaty shoes... Toni is in a flat panic, Bob wants to demo his Orb with a border, and the component is simply not behaving! Toni decides to consults Google and discovers how borders and their insets affect the Swing components. His new (correct code) looks as follows.

private class Orb extends JComponent {
	@Override
	protected void paintComponent(Graphics graphics) {
		super.paintComponent(graphics);
		
		//create a new graphics2D instance
		Graphics2D g2 = (Graphics2D) graphics.create();
		
		//determine the actual x, y, width and height
		int x = getInsets().left;
		int y = getInsets().top;
		int w = getWidth() - getInsets().left - getInsets().right;
		int h = getHeight() - getInsets().top - getInsets().bottom;
		
		g2.setPaint(Color.BLUE);
		g2.fillOval(x, y, w, h);
		
	}
}
 

Toni's new code fixes the issue a few minutes before the demo was due. Relieved Toni takes a well deserved coffee break, and vows never to forget about catering for borders ever again.

The moral of the story: always render within the Insets of your component and always include a test in your test pack whereby a border is applied to your custom component.

The extremely observant may have noticed more issues with Toni's code, however that will be discussed in the next article. Additional Swing related articles can be found at the Custom Swing Components site under the blogs section.

Orb (software)

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • How To Use Linux Containers
  • Choosing the Right Framework for Your Project
  • DevOps for Developers — Introduction and Version Control
  • 10 Most Popular Frameworks for Building RESTful APIs

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: