A quick and simple(?) question I can't seem to find an answer to.
Is it possible to draw a shape (rectangle, oval etc) and add to the JPanel, then add this JPanel to the JFrame? The examples of drawing with Graphics I found online added the shape directly to the JFrame. Example:
public class DShape extends JPanel
{
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.GREEN);
g.drawRect(10,10,100,30);
}
public class Test {
public static void main(String[] args)
{
JFrame frame = new JFrame();
DShape shape = new DShape();
JPanel panel = new JPanel();
panel.add(shape);
frame.add(panel);
frame.setSize(200,200);
frame.setVisible(true);
}
}
This code will simply display a blank JFrame. A green rectangle will be displayed if you add a DShape class object directly to the JFrame. Is it possible to add the shape to JPanel first, then add JPanel to JFrame? Thank you.
The examples of drawing with Graphics I found online added the shape directly to the JFrame.
When you add the panel to the frame directly the default layout of the content pane is a BorderLayout, so the component gets resized to the size of the frame.
Is it possible to draw a shape (rectangle, oval etc) and add to the JPanel, then add this JPanel to the JFrame?
JFrame frame = new JFrame();
DShape shape = new DShape();
JPanel panel = new JPanel();
panel.add(shape);
frame.add(panel);
The default layout manager for a JPanel is the FlowLayout. A FlowLayout respects the preferred size of a component added to it. Your component doesn't have a preferred size so the size is (0, 0) so there is nothing to paint.
You need to override the getPreferredSize() method of your DShape panel to return the appropriate size.
Read the section from the Swing tutorial on Custom Painting for more information and working example.
Related
I have a JFrame, which contains just a JPanel.
I add an mouse event to the JPanel.
But the whole JFrame gets the same mouse event.
Here is my code:
public class TestSwing extends JPanel {
public TestSwing() {
super.setSize(20, 20);
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent me) {
System.out.println(me);
}
});
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.getContentPane().add(new TestSwing());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(200, 200);
frame.setVisible(true);
}
}
I set the size of the JPanel (20, 20), but no matter where I click, the mouse event will always be triggered.
You're adding that JPanel to the JFrame's contentPane, a component that uses BorderLayout, a layout which does not respect size or even for the most part preferred size, and so the JPanel will fill the entire JFrame's contentPane. Give the contentPane a FlowLayout and set the JPanel's preferred size and you'll see a difference. In the future, give the JPanel a Border to see its boundaries. This will make debugging this easy.
If you don't tell it otherwise, your JFrame will have BorderLayout like this:
Now if you furthermore don't tell your Panel where to go, it wil go into CENTER and thus be resized to fill whole content area.
For checking MouseEvent on only one JPanel I suggest you add another JPanel (maybe with different background?) to other area:
frame.getContentPane().add(new TestSwing(), BorderLayout.CENTER);
JPanel left = new JPanel();
left.setBackground(Color.red);
frame.getContentPane().add(left, BorderLayout.LEFT);
Size set by setSize() is only valid until it's recalculated based on Layout and other properties.
I have a custom JPanel. The only thing that is in it, is a drawing of a rectangle, using the drawRect method of the Graphics object. The JPanel is always in a very specific square size, refuses to get any bigger or smaller. Tried overriding the getPreferredSize() method, didn't work.
Tried setting different layout managers for this custom JPanel, and also tried every layout manager for the JPanel that hosts this JPanel. Still, the size of the custom JPanel stays the same.
As I said, the custom JPanel has no components in it, only a drawing of a rectangle.
Any ideas?
Without knowing more about what you're trying to achieve:
As far as your containing panel, you need to know which layout managers respect preferred sizes and which ones don't
Grid Flow Border Box GridBag
Respect PreferredSize NO YES NO YES YES
That being said, if you wrap the painted JPanel in a JPanel with one of the "NOs", the painted JPanel shoud stretch with the resizing of the frame.
Also if you want the drawn rectangle to stretch along with its JPanel, then you need to remember to draw the rectangle with getWidth() and getHeight() of the JPanel and not use hard coded values.
Here is an example using BorderLayout as the containing panel's layout, and making use of getWidth() and getHeight() when performing the painting.
import java.awt.*;
import javax.swing.*;
public class StretchRect {
public StretchRect() {
JPanel panel = new JPanel(new BorderLayout());
panel.add(new RectanglePanel());
JFrame frame = new JFrame();
frame.add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public class RectanglePanel extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.fillRect( (int)(getWidth() * 0.1), (int)(getHeight() * 0.1),
(int)(getWidth() * 0.8), (int)(getHeight() * 0.8) );
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 200);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new StretchRect();
}
});
}
}
I have some Graphics2D graphics displayed in my frame, and then I added a JPanel to the entire frame so that I can add a mouselistener to clicks anywhere in the panel. However, the graphics disappear, I assume blocked out by the frame. I tried setting the panel to visible false, but that didnt do anything. How can I keep my mouselistener listening on the entire window, and still display my graphics?
EDIT:
Heres a bit of code: EDIT:(and some more)
//adding the panel and mouselistener
JPanel allPanel = new JPanel();
allPanel.addMouseListener(this);
frame.add(allPanel);
//...
//drawing some of the graphics
public void draw() {
frame.add(new CustomPaintComponent());
// Display the frame
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setVisible(true);
JPanel allPanel = new JPanel();
allPanel.addMouseListener(this);
frame.add(allPanel);
}
static class CustomPaintComponent extends Component {
private static final long serialVersionUID = 1L;
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D)g;
g2d.fillRoundRect(10, 10, 50, 50, 10,10);
//...
Three problems jump out...
First, JFrame uses a BorderLayout as its default layout manager, this means that only one component can occupy any of its available five positions. By using add(Component) you add each component to the CENTRE position, overriding the first component you added to it...
Second, JPanel is opaque by default, meaning, even if you did get both components to occupy the same space, the top component would block the lower one
Third, you should be using paintComponent instead of paint
Take a look at Performing Custom Painting for more details
The solution could be to add the MouseListener directly to the custom component
Another choice would be to use a BorderLayout on the lower component, make the top component transparent (using setOpaque(false)) and add it to the lower component directly...
I believe your problem is that JFrame can have only one component added to it (by default). You add a CustomPaintComponent, which paints your graphics. Then, you add the JPanel, which automatically removes the CustomPaintComponent
Are you trying to paint the custom drawing on top of the JPanel? If that is the case, simply move that code over to the JPanel (but instead of using a CustomPaintComponent, put it in the paintComponent(Graphics g) method of the JPanel)
Here's my simple code which draws rectangle on frame.How can I add button to this frame? I tried to set FlowLayout but then rectangle is not visible.Help please.
import java.awt.*;
import javax.swing.*;
public class test extends Canvas{
public static JFrame frame;
public static JButton button;
public void paint(Graphics graphics) {
graphics.setColor(Color.yellow);
graphics.fillRect(10, 10, 100, 100);
graphics.setColor(Color.red);
graphics.drawRect(10, 10, 100, 100);
}
public static void main(String args[]){
test x=new test();
frame=new JFrame();
button=new JButton();
button.setSize(20,20);
button.setText("Click");
frame.setSize(500,500);
frame.add(button);
frame.add(x);
frame.setVisible(true);
}
}
The default layout for a JFrame is BorderLayout which can only accept one component per layout constraint. The default when none is specified is CENTER. So change:
frame.add(button);
frame.add(x);
To:
frame.add(button, BorderLayout.PAGE_START);
frame.add(x);
And you should see both components.
Other tips:
Don't set the size of top level containers. Instead layout the content & call pack().
Don't mix Swing & AWT without good reason. As the other poster mentioned, we'd typically use a JPanel for custom rendering in Swing.
The BorderLayout will ignore the size of the button and stretch it to fit. To have it stay a certain size, set a preferred size and add it to a FlowLayout. Add the FlowLayout to the PAGE_START constraint.
Don't paint onto a Canvas. Paint onto a JPanel.
Have your class extend JPanel, and then override paintComponent(Graphics g). Don't forget to call super.paintComponent()!
you must use Container, get Container of the frame then use layouts and add components to it using add() method.
I'm currently trying to draw shapes on a JPanel, which is within another JPanel, within a JFrame.
I've searched Google and Youtube and found out how to draw shapes within a JFrame that has one panel, but have found nothing which can help me with what I'm doing. (maybe I'm not seeing something).
Code I've seen so far:
public class GameScreen
{
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.red);
g.drawRect(100, 10, 30, 40);
}
public static void main(String[] args)
{
GameScreen gs = new GameScreen();
JFrame f = new JFrame();
f.setTitle("");
f.setSize(400,400);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(gs);
}
This is all good for when I'm dealing with just one panel, but I wanna display shapes on a panel which is within the 1'st panel I've created.
Add a JPanel to the JFrame in the same way as you're doing now, but do it with your own subclass of JPanel.
class MyPanel extends JPanel {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.red);
g.drawRect(100, 10, 30, 40);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400,400); // As suggested by camickr
}
}
You can add this to a JPanel which sits within the JFrame
public static void main(String[] args)
{
MyPanel mp = new MyPanel();
JPanel jp = new JPanel();
jp.add(mp);
JFrame f = new JFrame();
f.setTitle("");
f.setSize(400,400);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(jp);
}
This can work for components within components, if you add them as children components. The key is to extend the component and override the methods you wish to change.
This is all good for when I'm dealing with just one panel,
The code you posted works fine because a frame uses a BorderLayout. So, when you add your panel to the frame is will increase in size and your custom painting will be seen.
I wanna display shapes on a panel which is within the 1'st panel I've created.
When you create a panel it uses a FlowLayout by default. When you add a custom painting panel to that panel it will be displayed at its preferred size, which will be (0, 0) since you didn't specify the preferred size.
On the panels that do custom painting you also need to implement the getPreferredSize() method so the layout manager knows how to arrange the panels. For example:
public Dimension getPreferredSize()
{
return new Dimension(200, 200);
}