|
|
||
Kirill Grouchnikov's BlogMarch 2005 ArchivesYour project has been approved by IDEA's review boardPosted by kirillcool on March 12, 2005 at 09:14 AM | Permalink | Comments (0)As described here, IDEA is granting free licenses to the open-source community. The (incomplete) list of the licensed projects can be found here. As you can see, the project does not have to be under Apache. One of my projects on this site has been granted such license :) How to create custom popup menusPosted by kirillcool on March 12, 2005 at 08:55 AM | Permalink | Comments (10)The popup menus in Swing application are rather standard. Put a few JMenuItems (most probably with icons), spice them up with an assorted selection of JSeparators, and your plain boring popup is ready for the outside world to see. The immediate solution to creating custom menu items is, of course, using some lively look'n'feel scheme. However, you don't have to go that far to bring your popup menu alive. There are two things you can do - use HTML text and create custom background image. The following example illustrates both techniques. First, here is a sample popup menu:
The zoomed-in version shows some interesting details on the underlying visual artifacts:
setText() function) of JMenuItem:
JMenuItem myItem = new JMenuItem("<html><b>Increase</b> font size</html>");
The more interesting part is providing custom rendering for your menu items. The obvious approach is to extend the JMenuItem class and override the paintComponent(Graphics g) function:
@Override
protected final void paintComponent(Graphics g) {
Graphics2D graphics = (Graphics2D) g;
graphics.setColor(Color.red);
graphics.fillRect(0,0,this.getWidth(), this.getHeight());
super.paintComponent(graphics);
}
Of course, the fillRect function can be replaced by drawImage for painting your background image before the super implementation is called. However, this approach fails when the corresponding menu item is selected - the background is filled with grey color (or the color specified in UIDefaults / L&F specific setting). In this case, you may completely override the painting function, using HTMLEditorKit, HTMLDocument and HTML.Attribute classes to correctly display both the background image and the HTML text. Of course, special attention has to be paid to icons and accelerator strings. The code given below goes halfway in this direction - it draws only the background image and simple (non-HTML) text.Let's call our class HeaderMenuItem: public final class HeaderMenuItem extends JMenuItemThe constructor is straightforward, making this item disabled:
public HeaderMenuItem(String text) {
super(text);
this.setEnabled(false);
}
The main functionality lies in the paintComponent overriden function. It sets anti-aliasing hint on the graphics context, paints the background image (with the corresponding dimension) and paints the text with shadow:
@Override
protected final void paintComponent(Graphics g) {
Graphics2D graphics = (Graphics2D) g;
graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
// paint background image
graphics.drawImage(ImageCreator.getGradientCubesImage(
this.getWidth(), this.getHeight(),
ImageCreator.mainMidColor,
ImageCreator.mainUltraDarkColor,
(int) (0.7 * this.getWidth()),
(int) (0.9 * this.getWidth())), 0, 0, null);
graphics.setFont(HEADER_FONT);
// place the text slightly to the left of the center
int x = (this.getWidth() - graphics.getFontMetrics().stringWidth(
this.getText())) / 4;
int y = (int)(graphics.getFontMetrics().getLineMetrics(
this.getText(), graphics).getHeight());
// paint the text with black shadow
graphics.setColor(Color.black);
graphics.drawString(this.getText(), x+1, y+1);
graphics.setColor(Color.white);
graphics.drawString(this.getText(), x, y);
}
Where the default font is
private static final Font HEADER_FONT = new Font("Arial", Font.BOLD, 14);
And the ImageCreator class defines color constants
public static final Color mainMidColor = new Color(0, 64, 196); public static final Color mainUltraDarkColor = new Color(0, 0, 64);and the getGradientCubesImage function. This function is pretty straightforward:
public static BufferedImage getGradientCubesImage(int width,
int height, Color leftColor, Color rightColor,
int transitionStart, int transitionEnd) {
First it fills the image with background. All pixels to the left of the transitionStart column are painted with leftColor, all pixels to the right of the transitionEnd column are painted with rightColor, and the pixels in the transition area are filled with the gradient:
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); Graphics2D graphics = (Graphics2D) image.getGraphics(); graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); GradientPaint gradient = new GradientPaint(transitionStart, 0, leftColor, transitionEnd, 0, rightColor); graphics.setPaint(gradient); graphics.fillRect(transitionStart, 0, transitionEnd - transitionStart, height); graphics.setColor(leftColor); graphics.fillRect(0, 0, transitionStart, height); graphics.setColor(rightColor); graphics.fillRect(transitionEnd, 0, width - transitionEnd, height);Now, the transition area is covered with squares of the predefined size. We compute how many rows and columns of squares we have to paint in order to completely cover the transition area: public static final int CUBE_DIMENSION = 5;The computation itself: int cubeCountY = height / ImageCreator.CUBE_DIMENSION; int cubeCountX = 1 + (transitionEnd - transitionStart) / ImageCreator.CUBE_DIMENSION; int cubeStartY = (height % ImageCreator.CUBE_DIMENSION) / 2; int cubeStartX = transitionStart - (ImageCreator.CUBE_DIMENSION - ((transitionEnd - transitionStart) % ImageCreator.CUBE_DIMENSION));Now, we iterate over cube rows and columns. A random decision is made - if random number is less than 0.5, no cube is drawn at that location:
for (int col = 0; col < cubeCountX; col++) {
for (int row = 0; row < cubeCountY; row++) {
// decide if we should put a cube
if (Math.random() < 0.5)
continue;
Now, a semi-random color is chosen. The base color is interpolated according to the current X position in the transition area. This color is then perturbed using a random number:
// Make semi-random choice of color. It should lie // close to the interpolated color, but still appear // random double coef = 1.0 - (((double) col / (double) cubeCountX) + 0.9 * (Math.random() - 0.5)); coef = Math.max(0.0, coef); coef = Math.min(1.0, coef);The interpolated color is computed: // Compute RGB components int r = (int) (coef * leftColor.getRed() + (1.0 - coef) * rightColor.getRed()); int g = (int) (coef * leftColor.getGreen() + (1.0 - coef) * rightColor.getGreen()); int b = (int) (coef * leftColor.getBlue() + (1.0 - coef) * rightColor.getBlue());And the corresponding square is filled: // fill cube graphics.setColor(new Color(r, g, b)); graphics.fillRect(cubeStartX + col * ImageCreator.CUBE_DIMENSION, cubeStartY + row * ImageCreator.CUBE_DIMENSION, ImageCreator.CUBE_DIMENSION, ImageCreator.CUBE_DIMENSION);The last thing - the border of the square is painted with slightly brighter color (10% closer to the pure white): // draw cube's border in slightly brighter color graphics.setColor(new Color( 255 - (int) (0.95 * (255 - r)), 255 - (int) (0.9 * (255 - g)), 255 - (int) (0.9 * (255 - b)))); graphics.drawRect(cubeStartX + col * ImageCreator.CUBE_DIMENSION, cubeStartY + row * ImageCreator.CUBE_DIMENSION, ImageCreator.CUBE_DIMENSION, ImageCreator.CUBE_DIMENSION);The last thing you can do with your regular menu item - draw it in anti-aliased text. All you have to do is extend the JMenuItem class and override the paintComponent function:
@Override
protected final void paintComponent(Graphics g) {
Graphics2D graphics = (Graphics2D) g;
Object oldHint = graphics.getRenderingHint(
RenderingHints.KEY_TEXT_ANTIALIASING);
graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
super.paintComponent(graphics);
graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
oldHint);
}
Don't forget to restore the state of the graphics context.
What is keeping me from switching to LinuxPosted by kirillcool on March 03, 2005 at 09:30 AM | Permalink | Comments (23)Lately I have been thinking a lot about my complete lack of intention to install Linux at home. It may appear that I am a perfect target for another successful conversion of tech-savvy Windows user to the free new world. Most certainly I can follow all steps in the installation guide (if I don't fall asleep following all the instructions in a 140-page PDF guide). I might even enjoy the (reported) two weeks it takes to completely configure my new OS. I guess I will not have any problem installing kernel patches, security patches, drivers, modem, graphic card, speakers and USB drive. From time to time I might feel the urge to write a missing driver to share it with the community. I would install all the cross-platform open-source software, my own web and mail servers. In general, life could be very good. So, why am I not there? Why am I not a part of the free new world? Why I am still tied to the old leaky raft that has been called by so many nicknames that all end in soft? Well, the answer is simple - why should I? The opponents of Windows give me two seemingly good reasons to abandon it. First, it's closed source. Second, it's full of bugs. All I can say is - so? Indeed it is closed source. But what real value do I get installing an open-source operating system? I am not going to read its code, I am not going to contribute to its development, all I am going to do is download patches and hope they come in time. I get the same thing from Windows. You may say - it takes ages to fix bugs in Windows, while some are never fixed at all. It is true, and it may be very damaging to average Joe the plumber at home. Well, I am not a plumber. I have an anti-virus and firewall installed, I use web mail account and most importantly, I use Firefox. I had never have (known to me) attack on my computer, the anti-spyware and anti-adware programs find nothing except cookies when I run them, the only time I have seen a blue screen in the last 7 years was when I got defect RAM sticks and it takes 30 seconds to reboot my computer six months after I bought it. It can be completely different thing for average Joe the plumber, but I am not him. And now about the bugs. I can proudly say that I have never written a function longer than 5 lines that was free of bugs in its initial version. Why proudly? Because it's an integral part of the profession. Java has 22764 listed bugs on its site, with 1158 being Swing related (good luck, Joshua). Firefox lists 6783 open bugs, Eclipse lists 13793 open bugs, Oracle's JDeveloper is strewn with fixes and workarounds, a study by a single firm has discovered 985 bugs in Linux kernel and packages. Bugs in Linux and other open source projects are found on daily basis. It gets even worse when the bugs are security related. Mozilla line has 19083 reported problems, Apache's "secure" alternative to IIS was not so secure in 1.3 version, and it didn't get better in 2.0. Linus keeps his security bugs a secret and security flaws in various Linux distributions are found on daily basis. A free new world, they promised. Well, it is free, I guess. According to Secunia reports, not so new. And now the real answer to the question. Why am I not moving to Linux? It's really simple - I don't want the OS to stand in my way. I immensely enjoy new "bleeding edge" Java-related technologies and try to use them in my home projects. Do I really need to install the kernel patches for that one? I am perfectly at ease with Windows Update Manager. Whatever it brings to me, let it install the stuff. Do I really need the source code for them? Couldn't care less. All I need is to bring up the Eclipse or IntelliJ and start working. New JDK? Give me an installer that asks as little information as possible. Why? Because I know that the default options are fine; I rely on Sun's engineers. Bought a new USB drive? I just want to plug it in and start working. I will most certainly not enjoy hunting the web for the drivers. I get my excitement developing applications, not installing drivers. Those who prefer Mac because of the icons or Linux because it gives them full control over the operating system - nice try, but Windows will have to get much worse before I join you. | ||
|
|