简体   繁体   中英

How do you draw a JPanel on top of another?

So I have 2 JPanels, StopWatchDial, which are basically just circles with their constructor being (topleftX, topleftY, diameter, and last parameter doesn't affect the dimensions). I'm trying to have it so there's a large outer circle drawn with a smaller inner circle drawn inside of it, but I'm having issues with that. I had assumed the process was suppose to be pretty simple with just overwriting the paintComponent method, but am I just overlooking something?

import java.awt.Graphics;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class Stopwatch extends JPanel
{
    private StopWatchDial innerDial;
    private StopWatchDial outerDial;
    public Stopwatch(int x1, int y1, int width1, int x2, int y2, int width2)
    {
        innerDial = new StopWatchDial(x1, y1, width1, 60);
        outerDial = new StopWatchDial(x2, y2, width2, 1);
        this.add(outerDial);
        this.add(innerDial);
    }
    public void paintComponent(Graphics g)
    {
        outerDial.paintComponents(g);
        innerDial.paintComponents(g);
    }
    public static void main(String[] args) 
    {
        JFrame starter = new JFrame("test");
        starter.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        Stopwatch test = new Stopwatch( 150, 20, 300, 0, 0, 600);
        starter.add(test);
        starter.setSize(1000, 1000);
        starter.setVisible(true);
    }
}

The issue I'm currently having is instead of being created on top of each other it produces this:

https://i.imgur.com/RGZbGtq.png

When StopWatchDial is a Component, one can stack them using a JLayeredPane .

public class Stopwatch extends JLayeredPane
{
    private StopWatchDial innerDial;
    private StopWatchDial outerDial;
    public Stopwatch(int x1, int y1, int width1, int x2, int y2, int width2)
    {
        innerDial = new StopWatchDial(x1, y1, width1, 60);
        outerDial = new StopWatchDial(x2, y2, width2, 1);
        add(outerDial, JLayeredPane.DEFAULT_LAYER);
        add(innerDial, Integer.valueOf(10));
    }

    public static void main(String[] args) 
    {
        final JFrame starter = new JFrame("test");
        starter.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        Stopwatch test = new Stopwatch( 150, 20, 300, 0, 0, 600);
        starter.add(test);
        starter.setSize(1000, 1000);
        starter.pack(); // Could be used to do optimal layouting.
        EventQueue.invokeLater(() -> starter.setVisible(true));
    }
}

The issue I'm currently having is instead of being created on top of each other it produces this:

A JPanel uses a FlowLayout by default. So your Stopwatch panel uses a FlowLayout. When you add two components to the panel they are displayed on a single line.

If you want the components on top of one another (using the Z axis) then you need to:

  1. make the top panel non-opaque, by using innerDial.setOpaque(false).
  2. Use a layout manager that displays component on the Z axis, like the OverlayLayout . I think you will need to set the alignmentX/Y values to 0.5f to make sure the components are centered on one another. Swing paints components in the reverse order they are added to a panel, so you would add the innerDial and then the outerDial to the stopwatch panel, so the outerDial gets painted before the innerDial.

The above answer is for information only. It should not be your final solution. Having 3 components is not the best design approach. You should only have a single Stopwatch component that is created so the programmer doesn't have to deal with layout issues every time they want to use the component.

I had assumed the process was suppose to be pretty simple with just overwriting the paintComponent method,

The paintComponent() method is used for painting the Graphics of a component. It is NOT used to paint other components. You should not invoke paintComponents() on another component.

So instead of having 3 components, you can add all the painting code to the paintComponent(...) method of the StopWatch class. This would be a better design as all the logic related to displaying a stopwatch is in one class and is not dependent on the other classes being added to the stopwatch with a proper layout.

Read the section from the Swing tutorial on Custom Painting for more information and examples.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM