Solved

transparent for real

Posted on 2004-03-22
7
758 Views
Last Modified: 2012-05-04
in my swing application (with windows L&F) i want to set a gradient paint on my menu bar. so i extend JMenuBar and override the paintComponent method (that's the way, right?). all's ok until i add a JMenu to this menu bar of mine. I can't make the menu button (such as "File") to be transparent. Apparently setOpaque(false) works only with the Metal L&F. So how do i set my JMenu-s to see the menubar through them (both when they are selected and not selected) ??? thanks


p.s: i think the same problem occurs even if you only set the background of the menuBar
0
Comment
Question by:hapciu
  • 3
  • 2
  • 2
7 Comments
 
LVL 86

Expert Comment

by:CEHJ
Comment Utility
Did you call

super.paintComponent();

?
0
 

Author Comment

by:hapciu
Comment Utility
of course.... first thing in the method ...
0
 
LVL 86

Expert Comment

by:CEHJ
Comment Utility
That's just my 2c i'm afraid.
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 9

Expert Comment

by:doronb
Comment Utility
Working on it, but could you post some code? :)
0
 
LVL 9

Accepted Solution

by:
doronb earned 80 total points
Comment Utility
Ok, I've built a GradientPainter object that performs the gradient work.
I also extended JMenuBar, JMenu, JMenuItem into their respective Gradient counter-parts.
I setup the Menus and MenuItems to share the Gradient of the MenuBar so that it looks ok.

However, under Windows for some reason, things don't seem to work right.
The JMenuBar doesn't draw the Gradient background while the other menu components do!
I'm working with JBuilder and inside JBuilder everything works just fine.
However, if I use the SystemLookAndFeel classes (Windows L&F) running my program from the executable JAR, then the JMenuBar doesn't work right.
If I run the JAR with the CrossPlatform L&F, everything works fine.

I think the problem lies in the L&F UI classes themselves because I believe its not entirely up to the Menu components to draw everything by themselves!

I don't know if it'd be any help, but here's my GradientPainter class :)

import java.awt.*;
import javax.swing.*;
import java.awt.image.*;

public class GradientPainter {
      private Image background;
      private Rectangle rect;
      private TransparentColourFilter filter;
      private GradientPaint gradient;
      private Rectangle gradientRect;
      private Color start = Color.black;
      private Color finish = Color.white;
      private JComponent swingComponent;
      private GradientPainter linkedGradient;
      private boolean isMaster = false;

      // Create a GradientPainter for a specific Swing component..
      public GradientPainter(JComponent c) {
            swingComponent = c;
      }

      public void setMasterGradient(GradientPainter gp) {
            linkedGradient = gp;
            linkedGradient.setMaster();
            gradient = null;
      }

      protected void setMaster() {
            isMaster = true;
      }

      protected GradientPaint getGradientPaint() {
            verifyGradientColour();
            return gradient;
      }

      // This is the TransparentColourFilter that will help us put the Gradient as background..
      private class TransparentColourFilter extends RGBImageFilter {
            protected int from;
            protected static final int rgbMask = 0x00ffffff;

            private TransparentColourFilter(Color transparentColour) {
                  super();
                  from = transparentColour.getRGB() & rgbMask;
                  canFilterIndexColorModel = true;
            }

            public int filterRGB(int x, int y, int rgb) {
                  return ((rgb & rgbMask) == from) ? rgbMask : rgb;
            }
      }

      private Rectangle getCurrentBounds() {
            Container current = swingComponent;
            if (isMaster) {
                  while (current.getParent() != null) {
                        current = current.getParent();
                  }
            }
            return current.getBounds();
      }

      // Make sure a GradientColor object is created for our use..
      private void verifyGradientColour() {
            gradientRect = getCurrentBounds();
            if (linkedGradient != null) {
                  gradient = linkedGradient.getGradientPaint();
            } else if ((gradient == null) || ((rect.width != gradientRect.width) || (rect.height != gradientRect.height))) {
                  gradient = new GradientPaint(0, 0, start, gradientRect.width, gradientRect.height, finish, true);
            }
      }

      public void setStartColor(Color colour) {
            start = colour;
      }

      public void setEndColor(Color colour) {
            finish = colour;
      }

      public Color getStartColor() {
            return start;
      }

      public Color getEndColor() {
            return finish;
      }

      // This method is used to prepare the Gradient background on the Component's Graphics..
      public Graphics prepareGraientBackground(Graphics g) {
            // Prepare a TransparentColourFilter object..
            filter = new TransparentColourFilter(swingComponent.getParent().getBackground());
            // Get the rectangle where we'll draw..
            rect = g.getClipBounds();
            // Get the Graphics object color..
            Color c = g.getColor();
            // Cast to Graphics2D..
            Graphics2D g2d = (Graphics2D)g;
            // Make sure we've created the Gradient colour..
            verifyGradientColour();
            // Set the Gradient as the Paint Object..
            g2d.setPaint(gradient);
            // Fill the rectangle with the gradient colour..
            g2d.fillRect(rect.x, rect.y, rect.width, rect.height);
            // Return to the previous paint colour..
            g2d.setPaint(c);
            // Create the background image..
            background = swingComponent.createImage(rect.width, rect.height);
            // Return the Graphics object that belongs to the background image..
            return background.getGraphics();
      }

      // This method is used to paint the transparent image over the Gradient background..
      public void paintComponent(Graphics g) {
            // Create a transparent image based on filtering the background image with the Gradient colour..
            background = swingComponent.createImage(new FilteredImageSource(background.getSource(), filter));
            // Finally, draw the transparent-gradient-background image together with the rest of the component..
            g.drawImage(background, rect.x, rect.y, null);
      }
}

I now of course have a GradientMenuBar:

public class GradientMenuBar extends JMenuBar {
      private GradientPainter tmHelper;

      public GradientMenuBar() {
            super();
            tmHelper = new GradientPainter(this);
      }

      public GradientPainter getGradientPainter() {
            return tmHelper;
      }

      public void setStartColor(Color colour) {
            tmHelper.setStartColor(colour);
      }

      public void setEndColor(Color colour) {
            tmHelper.setEndColor(colour);
      }

      public Color getStartColor() {
            return tmHelper.getStartColor();
      }

      public Color getEndColor() {
            return tmHelper.getEndColor();
      }

      protected void paintComponent(Graphics g) {
            super.paintComponent(tmHelper.prepareGraientBackground(g));
            tmHelper.paintComponent(g);
      }
}

And I also extended JMenu and JMenuItem into their respective GradientMenu and GradientMenuItem using the same template from GradientMenuBar.

The code that creates the Menus in my frame is almost the same as JBuilder's designer created for me:

      private GradientMenuBar jMenuBar1 = new GradientMenuBar();
      private GradientMenu jMenuFile = new GradientMenu();
      private GradientMenuItem jMenuFileExit = new GradientMenuItem();
      private GradientMenuItem jMenuFileStart = new GradientMenuItem();
      private GradientMenu jMenuHelp = new GradientMenu();
      private GradientMenuItem jMenuHelpAbout = new GradientMenuItem();

And I added this code to ensure the Gradient of the MenuBar is shared by its children like this:

      GradientPainter gp = jMenuBar1.getGradientPainter();
      jMenuFile.getGradientPainter().setMasterGradient(gp);
      jMenuHelp.getGradientPainter().setMasterGradient(gp);
      jMenuFileStart.getGradientPainter().setMasterGradient(gp);
      jMenuFileExit.getGradientPainter().setMasterGradient(gp);
      jMenuHelpAbout.getGradientPainter().setMasterGradient(gp);

It works for me, unless I run my JAR file completely from Windows with the Windows L&F, if this is not you current problem, my code may help.
If my code does help, I urge you to reconsider the amount of points you've dedicated to this question because it seems a bit low for the amount of work and knowledge that has to go into this, then again, you may already solved everything, in which case, the reward is the code itself ;)

Hope this helps,
Doron
0
 

Author Comment

by:hapciu
Comment Utility
well thanks a lot for the effort, but i've already solved my problem on my own - unlike you i have  extended the UI classes (BasicMenuBarUI, BasicMenuUI and BasicMenuItemUI) and it works just fine. but as i said, i did that on my own, eventually.
i will give you the points because it doesn't hurt me, but i won't increase them.
0
 
LVL 9

Expert Comment

by:doronb
Comment Utility
No problem, thanks for the points, I was going to suggest working with the UI classes, and do it myself too :)
0

Featured Post

Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

Join & Write a Comment

INTRODUCTION Working with files is a moderately common task in Java.  For most projects hard coding the file names, using parameters in configuration files, or using command-line arguments is sufficient.   However, when your application has vi…
For beginner Java programmers or at least those new to the Eclipse IDE, the following tutorial will show some (four) ways in which you can import your Java projects to your Eclipse workbench. Introduction While learning Java can be done with…
Viewers learn how to read error messages and identify possible mistakes that could cause hours of frustration. Coding is as much about debugging your code as it is about writing it. Define Error Message: Line Numbers: Type of Error: Break Down…
This theoretical tutorial explains exceptions, reasons for exceptions, different categories of exception and exception hierarchy.

744 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now