Java Swing, scrollable HBox - java

I'm writing a program where I'm trying to implement a scrollable HBox. Sadly the JSCrollPane doesn't seem to function at all and when the window gets too small the images just start to clip each other.
The pane with the images has the following code:
public class Caller extends JPanel {
public Caller() {
initPanel();
}
private void initPanel() {
this.setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
}
public void addBall(Ball ball) {
this.add(ball);
}
}
And the main frame:
public class GUI extends JFrame {
public GUI() throws HeadlessException {
super();
initMainFrame();
initCaller();
}
private void initCaller() {
Caller caller = new Caller();
JScrollPane scrollPane = new JScrollPane(caller, JScrollPane.VERTICAL_SCROLLBAR_NEVER, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
caller.addBall(new Ball(5));
caller.addBall(new Ball(16));
caller.addBall(new Ball(34));
caller.addBall(new Ball(34));
caller.addBall(new Ball(34));
this.add(scrollPane);
}
private void initMainFrame() {
this.setTitle("Main");
this.setSize(new Dimension(500,200));
}
}
Ball Draw Code:
#Override
public void paint(Graphics g) {
super.paint(g);
g.drawImage(ballImage, 0,0, this);
g.setFont(new Font("Arial Black", Font.BOLD, 20));
g.setColor(Color.WHITE);
g.drawString(designation, 20,ballImage.getHeight()/2);
}
Am I implementing the scroller in the wrong way?

It looks like your Ball JComponent is missing informations about its preferred/min/max sizes, so the Caller panel with the BoxLayout doesn't know what they are and when you reduce the width, your components will have their size reduced rather than the scrollpane reflecting the need for scrolling.
You will have to override the relevant methods of your Ball class e.g :
#Override
public Dimension getPreferredSize() {
return new Dimension(ballImage.width, ballImage.height);
}
#Override
public Dimension getMaximumSize() {
return new Dimension(ballImage.width, ballImage.height);
}
#Override
public Dimension getMinimumSize() {
return new Dimension(ballImage.width, ballImage.height);
}

Related

Gui graphic does not appear in Panel

I am trying to make a drawOval moving by using the two buttons that I set to be North and East so the ball will move between the JButtons, at the center.
Why does not appear at the panel?
Also I am thinking using a function that make this x=x+; and y=y+1 when I pressed left or right.
I do not figure out what can I do.
So this is the code I made:
public class Main extends JFrame implements ActionListener {
JButton left;
JButton right;
JPanel p;
Main(){
JButton left = new JButton("left");
left.addActionListener(this);
left.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
//The first way I think is better to make it move.
}
});
JButton right = new JButton("right");
right.addActionListener(this);
Panel p = new Panel();
p.setLayout(new BorderLayout());
p.add("West",left);// to the left
p.add("East",right);//to the right
Container c = getContentPane();
c.add(p);
}
public static void main(String[] args) {
Main f=new Main();
f.setTitle("Heracles");
f.setSize(500, 500);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true); //this is the window
}
public void paintComponent (Graphics g) {
super.paintComponents(g);
Graphics2D g1=(Graphics2D) g;
g.drawOval(3, 5, 45, 46); // The ball
g.fillOval(20, 30, 40, 40);
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
}
To understand why it's not working, you need to understand how the paint system actually works
Just by looking at this snippet it should be obvious something is wrong.
public class Main extends JFrame implements ActionListener {
//...
public void paintComponent (Graphics g) {
super.paintComponents(g);
//...
}
}
You've declare a method called paintComponent but are calling the super method paintComponents (note the s at the end).
Further, when ever you "think" you're overriding a method, you should make use of the #Override attribute, this will cause a compiler error when you've done something wrong
public class Main extends JFrame implements ActionListener {
//...
#Overrride
public void paintComponent (Graphics g) {
super.paintComponents(g);
//...
}
}
The above code will now fail to compile, as JFrame doesn't declare a paintComponent method.
As a general rule, you should avoid extending directly from JFrame (or other top level containers), they are compound components and have a complex hierarchy and functionality.
A better place to start might be with a JPanel
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
JButton left;
JButton right;
JPanel paintPane;
public TestPane() {
JButton left = new JButton("left");
left.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
}
});
JButton right = new JButton("right");
right.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
}
});
paintPane = new PaintPane();
setLayout(new BorderLayout());
add(left, BorderLayout.WEST);
add(right, BorderLayout.EAST);
add(paintPane);
}
}
public class PaintPane extends JPanel {
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
public void paintComponent(Graphics g) {
super.paintComponents(g);
Graphics2D g1 = (Graphics2D) g;
g1.drawOval(3, 5, 45, 46); // The ball
g1.fillOval(20, 30, 40, 40);
}
}
}
You should take the time to have a look at Painting in Swing and Performing Custom Painting for more details.
Some other concepts you might like to take the time to learn:
Single Responsibility Principle - a class should do one thing and do it well
Observer Pattern - This typically represent in Swing as the listener API
Model-View-Controller - this encompasses the above and defines different layers of responsibility for different parts of the program, it will helper you understand the basic structure of Swing as well
Also I am thinking using a function that make this x=x+; and y=y+1 when I pressed left or right.
Ok, so this is where the "model" part of the MVC will play it's part.
So lets start by defining the basic properties we expect the model to support...
public interface ShapeModel {
public Point getPoint();
public void addChangeListener(ChangeListener listener);
public void removeChangeListener(ChangeListener listener);
}
Here is supports a Point to act as the location and a ChangeListener to act as the observer pattern, which will notify interested parties that the state of the model has changed.
Why start with a interface? As a general concept, you should always prefer to code to interface instead of implementation. In this case, one aspect of the interface which hasn't been defined is, how does the Point get updated? That's of little interest to most parties who want to work with the model, they just want to know when it changes, the mutation of the model can be expressed either directly via the implementation or a "mutable" interface which extends from the this interface
Next, we define a default implementation...
public class DefaultShapeModel implements ShapeModel {
private Point point = new Point(40, 40);
private List<ChangeListener> listeners = new ArrayList<>(25);
#Override
public Point getPoint() {
return point;
}
public void setPoint(Point point) {
this.point = point;
fireStateChanged();
}
protected void fireStateChanged() {
ChangeEvent evt = new ChangeEvent(this);
for (ChangeListener listener : listeners) {
listener.stateChanged(evt);
}
}
#Override
public void addChangeListener(ChangeListener listener) {
listeners.add(listener);
}
#Override
public void removeChangeListener(ChangeListener listener) {
listeners.remove(listener);
}
}
This does define how the paint is to be updated.
Finally, we update the TestPane and PaintPane to support the model...
public class TestPane extends JPanel {
JButton left;
JButton right;
JPanel paintPane;
private DefaultShapeModel model;
public TestPane() {
model = new DefaultShapeModel();
JButton left = new JButton("left");
left.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
Point p = model.getPoint();
p.x--;
if (p.x > 0) {
p.x = 0;
}
model.setPoint(p);
}
});
JButton right = new JButton("right");
right.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Point p = model.getPoint();
p.x++;
if (p.x + 40 > paintPane.getWidth()) {
p.x = paintPane.getWidth() - 40;
}
model.setPoint(p);
}
});
paintPane = new PaintPane(model);
setLayout(new BorderLayout());
add(left, BorderLayout.WEST);
add(right, BorderLayout.EAST);
add(paintPane);
}
}
public class PaintPane extends JPanel {
private ShapeModel model;
public PaintPane(ShapeModel model) {
this.model = model;
this.model.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
repaint();
}
});
}
public ShapeModel getModel() {
return model;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
public void paintComponent(Graphics g) {
super.paintComponents(g);
Graphics2D g1 = (Graphics2D) g;
Point p = getModel().getPoint();
g1.fillOval(p.x, p.y, 40, 40);
g1.setColor(Color.WHITE);
g1.drawOval(p.x, p.y, 40, 40);
}
}
Why does not appear at the panel?
To display graphic you created, use follow these steps,
Remove paintComponent method and replace it with below code..
public JComponent createOvel() {
return new JComponent() {
#Override
protected void paintComponent(Graphics g) {
Graphics2D g1 = (Graphics2D) g;
g.drawOval(3, 5, 45, 46); // The ball
g.fillOval(20, 30, 40, 40);
}
};
}
Then call it in Main() constructor,
p.add("Center", createOvel());
This will display the graphic you created.

Java Drawing to a JPanel (debugging)

I'm trying to draw a basic object to a JPanel
although it doesn't seem to be working.
I'm certain I am doing something wrong with where the paint method
is being called
import javax.swing.*;
import java.awt.*;
import java.awt.image.*;
public class testGui {
static colors gc_colors;
static gui gc_gui;
public static void main(String[] args) {
gc_colors = new colors();
gc_gui = new gui();
gc_gui.cv_frame.setVisible(true);
}
public static class colors {
Color cv_ltGrey;
Color cv_mdGrey;
Color cv_dkGrey;
public colors() {
cv_ltGrey = Color.decode("#DDDDDD");
cv_mdGrey = Color.decode("#CCCCCC");
cv_dkGrey = Color.decode("#111111");
}
}
public static class gui {
JFrame cv_frame;
JPanel cv_panel;
JPanel cv_content;
public gui() {
cv_frame = new JFrame();
cv_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
cv_frame.setTitle("Test GUI");
cv_frame.setSize(600, 400);
cv_frame.setLayout(new FlowLayout());
cv_panel = new JPanel();
cv_panel.setBackground(gc_colors.cv_ltGrey);
cv_panel.setPreferredSize(new Dimension(500, 300));
cv_frame.add(cv_panel);
cv_content = new content();
cv_panel.add(cv_content);
}
}
public static class content extends JPanel {
public void paint(Graphics graphic) {
super.paint(graphic);
draw(graphic);
}
public void update() {
repaint();
}
public void draw(Graphics graphic) {
Graphics2D graphic2D = (Graphics2D) graphic;
graphic2D.setPaint(gc_colors.cv_ltGrey);
graphic2D.fillRect(10, 10, 100, 100);
}
}
}
I have a class for my gui which I am adding a JPanel to (a light grey one).
Which I am then trying to add my drawing to using a JPanel extended class
called content.
When I run it though it seems to create the grey JPanel which I want but
the drawing is just a tiny white square and I'm not sure why.
So, you content panel has a default preferred size of 0x0, FlowLayout honours the preferredSize of its components (with a little margin), hence the reason why you have a nice little small white rectangle.
What you need to do is override the getPreferredSize method of the content panel and return a suitable size, for example
public static class content extends JPanel {
#Override
public Dimension getPreferredSize() {
return new Dimension(120, 120);
}
public void paint(Graphics graphic) {
super.paint(graphic);
draw(graphic);
}
public void update() {
repaint();
}
public void draw(Graphics graphic) {
Graphics2D graphic2D = (Graphics2D) graphic;
graphic2D.setPaint(gc_colors.cv_ltGrey);
graphic2D.fillRect(10, 10, 100, 100);
}
}
I've decided to just leave out the second JPanel altogether.
It was too much of a hassle to put the JPanel inside of another JPanel
so instead I am only going to use a single JPanel
public static class gui {
JFrame cv_frame;
JPanel cv_panel;
JPanel cv_content;
public gui() {
cv_frame = new JFrame();
cv_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
cv_frame.setTitle("Test GUI");
cv_frame.setSize(600, 400);
cv_frame.setLayout(new FlowLayout());
cv_content = new content();
cv_content.setBackground(gc_colors.cv_ltGrey);
cv_content.setPreferredSize(new Dimension(500, 300));
cv_frame.add(cv_content);
}
}

Paint new things on JPanel

Ok, so I have a JPanel with the paintComponent method overrided.
it's simple, looks like this:
public class Panel1 extends JPanel {
public void paintComponent (Graphics g) {
super.paintComponent (g);
g.fillOval (0, 0, getWidth (), getHeight ());
}
}
Now, I add this JPanel as an attribute to another JPanel class, like:
public class Panel2 extends JPanel {
Panel1 panel;
public Panel2 (Panel1 panel) {
this.panel = panel;
}
protected void paintComponent (Graphics g) {
super.paintComponent (g);
panel.paint (g); //This isn't working.
// panel.paintComponent (g); //Tried this too
g.drawOval (100, 100, getWidth () - 200, getHeight () - 200);
}
}
What I want is Panel2 to be painted exactly the same as Panel1 (without hard-coding it) and maybe add other stuff (like a triangle or sth, I don't know).
Is this even possible? I looked into it but didn't find any way to do it. Thanks in advance for your help!!
The MAIN in case it helps:
public class Main {
public static void main (String[] args) {
JFrame frame = new JFrame ();
frame.setSize (500, 500);
frame.add (new Panel2 (new Panel1 ()));
frame.setVisible (true);
}
}
EDIT: just in case, I don't want to do it with inheritance; that's why I add it as an attribute, but if there is other way just let me now.
You could try to make paintComponent of Panel1 public and then call it in paintComponent of Panel2:
protected void paintComponent (Graphics g) {
panel1.paintComponent(g);
}
You could also create a method inside your Panel1 class that handles the painting for you
public void yourPainting(Graphics g){
//whatever you want to paint
}
and then call this method in the paintComponent methods of both your Panel1 and your Panel2
The reason it does not work the way seen in the question is that Panel1 has a size of 0x0. To get a sensible size, return a size from getPreferredSize(), then set the panel size to the preferred size.
import java.awt.*;
import javax.swing.*;
public class PaintUnrealized {
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception useDefault) {
}
JFrame f = new JFrame("Paint Unrealized Component");
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLocationByPlatform(true);
f.setContentPane(new Panel2(new Panel1()));
f.pack();
f.setMinimumSize(f.getSize());
f.setVisible(true);
}
};
SwingUtilities.invokeLater(r);
}
}
class Panel1 extends JPanel {
public Panel1() {
setBackground(Color.RED);
setSize(getPreferredSize());
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.fillOval(0, 0, getWidth(), getHeight());
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
class Panel2 extends JPanel {
Panel1 panel;
public Panel2(Panel1 panel) {
this.panel = panel;
setBackground(Color.YELLOW);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
panel.paintComponent(g); // This works
int pad = 25;
g.drawOval(pad, pad, getWidth()-(2*pad), getHeight()-(2*pad));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(500, 300);
}
}
public class Panel2 extends JPanel {
private Panel1 panel1;
public Panel2 (Panel1 panel) {
this.panel1 = panel;
}
protected void paintComponent (Graphics g) {
panel1.paint(g);
}
}
I believe that should work

How can I move my JButton to the right side of my JPanel?

For a programming class, I was asked to create a replica of an iCalendar app. I'm using JAVA to code it, and JFrame and JPanel to draw it. Here is a SSCCEE of my problem:
import java.awt.*;
import javax.swing.*;
public class Mainie extends JFrame {
private JButton back = new TriangleButton(true),
front = new TriangleButton(false);
public Mainie(){
super();
setSize(800, 400);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JPanel months = new JPanel();
final JPanel days = new JPanel();
JLabel one = new JLabel("Hallo");
one.setHorizontalAlignment(JLabel.CENTER);
back.setHorizontalAlignment(SwingConstants.LEFT);
front.setHorizontalAlignment(SwingConstants.RIGHT);
months.setLayout(new BorderLayout());
months.add(back, BorderLayout.WEST);
months.add(one, BorderLayout.CENTER);
months.add(front, BorderLayout.EAST);
days.setLayout(new GridLayout(1,1));
days.add(new JButton("Meister Camickr"));
months.setAlignmentX(CENTER_ALIGNMENT);
add(months, BorderLayout.NORTH);
add(days, BorderLayout.CENTER);
setVisible(true);
}
public static void main(String[] args){
new Mainie();
}
}
class TriangleButton extends JButton {
private Shape triangle = createTriangle();
public void paintBorder(Graphics g) {
((Graphics2D) g).draw(triangle);
}
public void paintComponent(Graphics g) {
((Graphics2D) g).fill(triangle);
}
public Dimension getPreferredSize() {
return new Dimension(200, 100);
}
public boolean contains(int x, int y) {
return triangle.contains(x, y);
}
public TriangleButton(boolean pointLeft) {
super();
if (!pointLeft)
this.triangle = createRTriangle();
}
private Shape createTriangle() {
Polygon p = new Polygon();
p.addPoint(0, 20);
p.addPoint(20, 0);
p.addPoint(20, 40);
return p;
}
private Shape createRTriangle() {
Polygon p = new Polygon();
p.addPoint(20, 20);
p.addPoint(0, 0);
p.addPoint(0, 40);
return p;
}
}
If you compile this, you can see that my JButton is too far to the left. How can I move it to the right?
The basic problem with those buttons is that the button is very wide and the visual indicator is to the left. Put a border around them and it becomes obvious.
OTOH I would use an entirely different approach, using text for the buttons and a factory method to make them look as expected.
import java.awt.*;
import javax.swing.*;
public class CustomPointerButtons {
JPanel ui;
CustomPointerButtons() {
initUI();
}
private final void initUI() {
ui = new JPanel(new BorderLayout(4, 4));
JPanel topPanel = new JPanel(new BorderLayout(4, 4));
ui.add(topPanel, BorderLayout.PAGE_START);
ui.add(new JButton("Mister Mix")); //will default to CENTER
topPanel.add(new JLabel("Blah, Blah.."));
JButton back = getMinimalButton(new String(Character.toChars(9668)));
topPanel.add(back, BorderLayout.LINE_START);
JButton forward = getMinimalButton(new String(Character.toChars(9658)));
topPanel.add(forward, BorderLayout.LINE_END);
}
public JButton getMinimalButton(String text) {
JButton b = new JButton(text);
b.setFont(b.getFont().deriveFont(40f));
b.setMargin(new Insets(0,0,0,0));
b.setContentAreaFilled(false);
b.setBorder(null);
return b;
}
public final JComponent getUI() {
return ui;
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
JFrame f = new JFrame("Custom Pointer Buttons");
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setContentPane(new CustomPointerButtons().getUI());
f.pack();
f.setLocationByPlatform(true);
f.setVisible(true);
}
};
SwingUtilities.invokeLater(r);
}
}
The problem is your random preferred size doesn't represent the real size of the triangle.
You can do something like:
public Dimension getPreferredSize() {
//return new Dimension(200, 100);
Rectangle bounds = triangle.getBounds();
return new Dimension(bounds.width, bounds.height);
}
You still have other problems because you will still have painting artifacts. You should always invoke super.paintComponent() when you override the method:
public void paintComponent(Graphics g) {
super.paintComponent(g);
((Graphics2D) g).fill(triangle);
}
However, this still doesn't really work because the button does other painting as well. So the real problem is that you should not be trying to do custom painting of the button. What you really want to do is custom painting of an Icon. Then you can just add the Icon to the button.
You may want to check out Playing With Shapes. You can use the ShapeIcon class to create your icons. This will provide a more flexible solution since I'm guess all shapes are not represented by an ascii character.

Drawing a static image over the viewport of a JScrollPane

I am trying to draw a red square over a JScrollPane. The code I have below does an okay job of this, but sometimes when I scroll the viewport too fast, the red square jumps up or down.
This struck me as odd since the JScrollPane itself is stationary, so I assumed Swing would not try to move around the components painted within it. I'm guessing that what's actually happening is that the the red square gets associated with viewport, which display graphics that do move.
Anyway, how do I prevent the red square from jumping around and successfully draw a red square over the list? Maybe I'm taking the wrong approach altogether.
package components;
import java.awt.*;
import java.util.Vector;
import javax.swing.*;
import javax.swing.event.*;
#SuppressWarnings("serial")
public class DialogWithScrollPane extends JFrame {
public DialogWithScrollPane() {
super();
setResizable(false);
Container pane = getContentPane();
Vector<Object> listOfStuff = new Vector<Object>();
for (int i = 0; i < 100; i++) {
listOfStuff.add(Integer.toString(i));
}
final JScrollPane scrollPane = new JScrollPane() {
public void paint(Graphics g) {
System.out.println("JScrollPane.paint() called.");
super.paint(g);
g.setColor(Color.red);
g.fillRect(20, 50, 100, 200);
}
};
JList list = new JList(listOfStuff) {
public void paint(Graphics g) {
System.out.println("JList.paint() called.");
super.paint(g);
// Well, I could do this...
//
// scrollPane.repaint();
//
// ...and it would solve the problem, but it would also result in an
// infinite recursion since JScrollPane.paint() would call this
// function again.
}
};
// Repaint the JScrollPane any time the viewport is moved or an item in the
// list is selected.
scrollPane.getViewport().addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
scrollPane.repaint();
}
});
list.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
scrollPane.repaint();
}
});
scrollPane.setViewportView(list);
pane.add(scrollPane);
setMinimumSize(new Dimension(300, 300));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocation(500, 250);
setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
new DialogWithScrollPane();
}
});
}
}
The JScrollPane should be painting behind the JViewport which should be painting behind the list. I'm guessing that this is only working because you're overriding paint and not paintComponent and calling repaint on the JScrollPane all the time so that it paints itself again after its components are painted.
Perhaps you want to use a JLayeredPane and have it hold the JScrollPane, and paint on it.
edit: or the glasspane as I now see that mre suggests, but I'm afraid if you do that, and set the glasspane visible, you'll lose the ability to interact with the underlying scrollpane.
Edit 2
For e.g.,
import java.awt.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.Vector;
import javax.swing.*;
#SuppressWarnings("serial")
public class DialogWithScrollPane2 extends JFrame {
public DialogWithScrollPane2() {
super();
//setResizable(false);
final JPanel pane = (JPanel) getContentPane();
Vector<Object> listOfStuff = new Vector<Object>();
for (int i = 0; i < 100; i++) {
listOfStuff.add(Integer.toString(i));
}
final JScrollPane scrollPane = new JScrollPane();
JList list = new JList(listOfStuff);
scrollPane.setViewportView(list);
final JPanel blueRectPanel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.blue);
g.fillRect(20, 50, 100, 200);
}
};
blueRectPanel.setOpaque(false);
final JLayeredPane layeredPane = new JLayeredPane();
layeredPane.add(scrollPane, JLayeredPane.DEFAULT_LAYER);
layeredPane.add(blueRectPanel, JLayeredPane.PALETTE_LAYER);
layeredPane.addComponentListener(new ComponentAdapter() {
private void resizeLayers() {
final JViewport viewport = scrollPane.getViewport();
scrollPane.setBounds(layeredPane.getBounds());
blueRectPanel.setBounds(viewport.getBounds());
SwingUtilities.invokeLater(new Runnable() {
public void run() {
blueRectPanel.setBounds(viewport.getBounds());
}
});
}
#Override
public void componentShown(ComponentEvent e) {
resizeLayers();
}
#Override
public void componentResized(ComponentEvent e) {
resizeLayers();
}
});
pane.add(layeredPane);
setPreferredSize(new Dimension(300, 300));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setLocation(500, 250);
setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
new DialogWithScrollPane2();
}
});
}
}

Categories