• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 772
  • Last Modified:

transparent for real

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
hapciu
Asked:
hapciu
  • 3
  • 2
  • 2
1 Solution
 
CEHJCommented:
Did you call

super.paintComponent();

?
0
 
hapciuAuthor Commented:
of course.... first thing in the method ...
0
 
CEHJCommented:
That's just my 2c i'm afraid.
0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
doronbCommented:
Working on it, but could you post some code? :)
0
 
doronbCommented:
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
 
hapciuAuthor Commented:
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
 
doronbCommented:
No problem, thanks for the points, I was going to suggest working with the UI classes, and do it myself too :)
0

Featured Post

Upgrade your Question Security!

Add Premium security features to your question to ensure its privacy or anonymity. Learn more about your ability to control Question Security today.

  • 3
  • 2
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now