10

I have a JPanel added to a JViewport, and the panel has several other panels added to it. I'm trying to implement a dragging selection, where you can select more than one component by dragging the mouse. The only problem I'm facing is that the selection rectangle is being painted behind the components added to the main JPanel. How can I paint over the top of them?

My structure is as follows:
JFrame -> ContentPane -> JLayeredPane -> JScrollPane -> JPanel -> JPanel [].

Design draft for college assignment:
As you can see, the rectangle is behind the other panels.

Design draft for college assignment.

Matthias Braun
  • 32,039
  • 22
  • 142
  • 171
rtheunissen
  • 7,347
  • 5
  • 34
  • 65
  • 2
    +1: Looks very nice! What OS is it running on? Or what look and feel is used? The Font looks like "Ubuntu". – Martijn Courteaux Jan 08 '12 at 09:58
  • At the moment on Windows, but when I'm done it'll look the same on Windows and Mac. I've created all the components from scratch, which is probably a naive way to go about it but I like the design freedom it allows. – rtheunissen Jan 08 '12 at 10:01
  • Font is Gotham, but I'm not sure if I will keep to it. :p – rtheunissen Jan 08 '12 at 10:01
  • 1
    All components from scratch!?! That looks amazing!!! You should consider publishing it either free or non-free (the look 'n' feel I mean). – Martijn Courteaux Jan 08 '12 at 10:07
  • Haha thanks for the compliment!! :) When I'm finished with it I'll consider creating an LnF - thanks for the idea. – rtheunissen Jan 08 '12 at 10:10

6 Answers6

14

This is what I'm already doing (on a much simpler level obviously), and Swing paints the rectangle underneath the components added to it.

This is one case where you should override the paint() method of the panel and not the paintComponent() method. Then the custom painting will be done AFTER all the child components have been painted.

camickr
  • 321,443
  • 19
  • 166
  • 288
5

Use a Layered Pane:

http://docs.oracle.com/javase/tutorial/uiswing/components/layeredpane.html

This allows you to create overlapping components.

Use a glass pane to handle the drag painting, and possibly events as well:

http://docs.oracle.com/javase/tutorial/uiswing/components/rootpane.html#glasspane

The Nail
  • 8,355
  • 2
  • 35
  • 48
  • Okay, so my structure is as follows: JFrame -> ContentPane -> LayeredPane -> JScrollPane -> JPanel -> JPanel []. I've added a screenshot to the question. – rtheunissen Jan 08 '12 at 09:51
  • You will have to place the LayeredPane inside the JScrollPane to be able to scroll the overlay (if you want that). – The Nail Jan 08 '12 at 09:54
  • I think I see what you mean. For example: `JFrame` -> `ContentPane` -> `JLayeredPane` -> `JScrollPane` -> **JLayeredPane** -> `JPanel` -> `JPanel []` – rtheunissen Jan 08 '12 at 09:56
  • What are the `JPanel -> JPanel []` exactly? You can add the original calendar-drawing component as the first layer, and then the glass pane drawing the drag details on top of it. – The Nail Jan 08 '12 at 10:00
  • The first is the `JPanel` that paints the grid etc. with a `JPanel []` containing appointment objects (coloured blocks). The first is added to the `JViewport` of a `JScrollPane`, which is added to the main `JLayeredPane` of the `JFrame`'s `ContentPane`. Flip, if that makes sense? – rtheunissen Jan 08 '12 at 10:06
  • My bet would be `JFrame -> ContentPane -> JLayeredPane -> JScrollPane -> JViewport -> JLayeredPane -> JPanel []` where the first (bottom) `JPanel` in the `JLayeredPane` is the one drawing the grid and the last (top) one is a Glass Pane – The Nail Jan 08 '12 at 10:27
  • See http://rabbit-hole.blogspot.com/2006/04/decoratingoverpainting-swing.html for an example of arbitrary decorations which may be applied over your main content. – technomage Feb 17 '12 at 18:29
1

Without seeing your actual code, it is difficult to say what you are doing wrong. However, I can still say what I would do:

Create a JPanel that represents the whole area where you want to draw, which — of course — contains every component.
Override that panel its paintComponents(Graphics) like this (EDITED, notice the s is now the last character from the method name):

@Override
public void paintComponents(Graphics g)
{ //                      ^
    super.paintComponents(g);

    // Draw your selection rectangle:
    g.setColor(Color.RED);
    g.drawRectangle(selectionRectangle); 
}
Martijn Courteaux
  • 67,591
  • 47
  • 198
  • 287
1

hot really sure what do you really needed and final effect, maybe is there two another ways painting to

1) GlassPane

2) Viewport

you can put that together, carrefully Insets to the visible Rectanle

Community
  • 1
  • 1
mKorbel
  • 109,525
  • 20
  • 134
  • 319
0

Custom painting on top of Swing components is facilitated by JLayeredPane. This article describes an abstract base class that facilitates overpainting specific areas (like selection rectangles or component bounds).

technomage
  • 9,861
  • 2
  • 26
  • 40
0

Okay, this is what I've decided to do in the end:
I'm not sure if this is the best way to do it, but it seems to work okay.
Note: Using MigLayout.

In the constructor of the JPanel lying underneath the colored blocks.

 ...
 this.add(new JPanel() {

     @Override
     public boolean isOpaque() {
        return false;
     }

     @Override
     public void paintComponent(Graphics g) {
        if (dragShape != null) {
           g.setColor(Colors.SECONDARY);
           g.setStroke(new BasicStroke(2));
           g.draw(dragShape);
        }
     }
  }, "pos 0 0, width 100%, height 100%", 0);
  ...
rtheunissen
  • 7,347
  • 5
  • 34
  • 65