Custom Swing Component Development Tip: Not Everything is Transparent

The previous article in this series, titled Insets Matter, introduced us to a new Swing developer named Toni and documented his efforts to create a custom swing component named the Orb. The purpose of the Orb is to draw a simple blue circle within the bounds of the component.

 

Toni's current code and output can be seem below.

 

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);		
	}
}

 

Everything has been going really well for Toni, everyone in the company was impressed by the recent demo of his Orb. After a few more days of flawless testing the Orb was distributed to the company's web site, whereby the orders for the Orb flooded in.

 

After a few weeks, customers who purchased the Orb started complaining of two serious problems. Firstly they are unable to change the background color of the Orb, and secondly after they attempted to change the background color, strange rendering artifacts started appearing.

 

Upon reading the bug reports Toni immediately realises that his code does not take into account the component's opacity and background color. Toni's understanding of a components opacity is that it is the opposite of transparency. When a component has opaque = false, it will be transparent, and not paint its background. However, when a component has opaque = true, it will not be transparent and will then use its background color to paint the background of the component.

 

In order to reproduce the defect Toni writes some code to create a new instance of the Orb, sets its opacity to true and set its background color to red.

 

Orb orb = new Orb();				
orb.setBackground(Color.RED);
orb.setOpaque(true);

 

Upon running the test Toni can clearly see that the Orb does not cater for a component's opacity. Toni now adjust his code to the following.

 

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;

		//this will fill the component's background
		//based on the component's opacity and 
		//the component's border and insets
		if (isOpaque()) {
			g2.setPaint(getBackground());
			g2.fillRect(x, y, w, h);		
		}
		
		g2.setPaint(Color.BLUE);
		g2.fillOval(x, y, w, h);		
	}
}

 

Toni again runs his test program and is glad to see that the Orb's background is turning red in his test. As for the rendering artifacts, Toni's quick tests were unable to reproduce them in any form and he quickly (and naively) put them down to some quirk on the customer's machine.

 

Everyone is pleased with Toni's changes and the an update is subsequently sent down to all the customers.

 

A few days pass, and Toni receives some disturbing feedback, although the customers are now happy that the Orb caters for its background color, however the original customers are still reporting visual artifacts around the component's border. To make matters worse, the rendering artifacts are no longer confined to the original customers but are now occurring at nearly all of the company's customers. Toni is now starting to panic as he is still not able to reproduce the artifacts in a single test.

 

Lets leave Toni for a moment and discuss the problem that he is now facing. The problem actually lies with Toni's understanding of a component's opacity. Toni's understanding of a component's opacity is about 85% correct. Yes, a component's opacity does determine if a component is transparent and whether or not it should have its background filled with its background color. However this is slightly more to it.

 

A component's opacity is also a contract with the underlying swing framework. Opacity more correctly relates to whether or not the component will paint all the pixels within the confines (bounds) of the component.

 

When a component's opacity is set to false, swing paint the component in such a way that it appears to be transparent. It does so by first painting the parent container and then painting the component over the parent, so as to make the component appear to be transparent.

 

When a component's opacity is set to true, the component has declared that it is not transparent, and that it will fill all of the pixels in the component's bounds. Swing expects the component to abide by this contract and will therefore not paint the components that are currently behind the opaque component.

 

If one violates this contract and does not draw over all of the component's pixels, rendering artifacts appear, most commonly in the form of other components appearing in the background of your component. To make matters worse these artifacts are not common on simple screens and only manifest after a variable amount of time. A simple test will in most cases not be able to reproduce them.

 

Revisiting Toni's code, we can see that by taking the component's border into account by using insets, he is leaving the border area of the component unpainted. This is what is causing Toni's rendering artifacts. One may argue that it should be the responsibility of the border to paint those pixels, however this can not be guaranteed, as the border may be an EmptyBorder or a border that is not fully opaque.

 

In order to correctly handle a component's opacity, the background area filled should ignore the component's insets and fill the entire bounds of the component.

 

After stressing himself to the point that he is convinced the Orb has taken at least 2 years off his life, Toni discovers an article detailing the contract between swing and a component's opacity. He immediately updates his code to the following:

 

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;

			//this will fill the component's background
			//based on the component's opacity and 
			//fill the entire bounds of the component.
			if (isOpaque()) {
				g2.setPaint(getBackground());
				g2.fillRect(0, 0, getWidth(), getHeight());		
			}
			
			g2.setPaint(Color.BLUE);
			g2.fillOval(x, y, w, h);			
		}
	}

After changing his code, Toni runs his test again.

 

 

Although the output of the test is not exactly visually appealing, it displays the correct behaviour, and abides by the rules laid down by the swing framework.

 

The moral of the story, if your component is opaque, it must fill all of its pixels. Failing to do so will cause your developers to grow grey hairs while they spend hours trying to reproduce a real problem, that simply never seems to show up in simple test cases.

Reply to comment | Custom Swing Components for the Java™

Hi to every body, it's my first pay a quick visit of this weblog; this blog consists of remarkable and in fact good material in favor of readers.

Reply to comment | Custom Swing Components for the Java™

Thanks for a marvelous posting! I definitely enjoyed reading it, you can be a great author. I will remember to bookmark your blog and will come back down the road. I want to encourage continue your great posts, have a nice afternoon!

Reply to comment | Custom Swing Components for the Java™

I loved as much as you'll receive carried out right here. The sketch is attractive, your authored material stylish. nonetheless, you command get got an impatience over that you wish be delivering the following. unwell unquestionably come more formerly again as exactly the same nearly a lot often inside case you shield this increase.

Reply to comment | Custom Swing Components for the Java™

I really like looking through an article that can make men and women think. Also, many thanks for permitting me to comment!

Reply to comment | Custom Swing Components for the Java™

I needed to thank you for this good read!! I certainly loved every little bit of it. I have got you bookmarked to look at new things you post…

Reply to comment | Custom Swing Components for the Java™

These herbal products are responsible for growing height in a person as it contains the herbs which stimulate the production of the human growth hormone and that too in a natural way. Height is of utmost concern for maximum individuals and thus they always try to seek ways to grow taller. You can find useful tips on how to grow taller naturally and a list of frequently asked questions on growing taller at now.

Reply to comment | Custom Swing Components for the Java™

Hello are using Wordpress for your site platform? I'm new to the blog world but I'm trying to get started and create my own. Do you need any coding expertise to make your own blog? Any help would be greatly appreciated!

The LATEST chatter

  • Halted all development on the twitter client. The application in its incomplete state is available at: http://tinyurl.com/6ktd8xw 6 years 13 weeks ago
  • Java Swing Components is currently undergoing a rebranding exercise to Custom Swing Components. The url however will remain the same. 6 years 36 weeks ago
  • Java Swing Components is proud to announce the release of our rater component. http://www.javaswingcomponents.com/product/rater 6 years 37 weeks ago
  • Java Swing Components is proud to announce the release of our first bundle including a fun demo. http://www.javaswingcomponents.com/products 6 years 42 weeks ago
  • New post: New Component Teaser http://tinyurl.com/35hxfnn 6 years 42 weeks ago

User login

Syndicate

Syndicate content