If I paint directly on the frame, it shows up fine but the ship will not show up on top of the panel...
package MoonBlast;
import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.JFrame;
public class Frame extends JFrame{
PlaySpace p;
Ship s;
public Frame(String title){
this.setTitle(title);
this.setSize(800, 800);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
p = new PlaySpace();
s = new Ship();
p.add(s);
this.add(p, BorderLayout.CENTER);
this.setVisible(true);
}
}
package MoonBlast;
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.JPanel;
public class PlaySpace extends JPanel {
public PlaySpace(){
super();
this.setPreferredSize(new Dimension(800, 800));
this.setBackground(Color.BLACK);
}
}
package MoonBlast;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Polygon;
import javax.swing.JComponent;
public class Ship extends JComponent{
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
Polygon p = new Polygon();
p.addPoint(350, 750);
p.addPoint(450, 750);
p.addPoint(400, 700);
g.setColor(Color.YELLOW);
g.fillPolygon(p);
}
}
The only class I left out was the 1 line viewer class. I have tried everything I could think of and a few more people have looked at it too. Thanks in advance.
You need to override the getPreferredSize() method of your Ship class to return the size of the component. Every Swing component is responsible for knowing its preferred size since it is the component that is doing the custom painting.
but the ship will not show up on top of the panel...
Your PlaySpace class using a FlowLayout by default which respects the preferred size of any component added to it. By default the preferred size of the Ship is (0, 0) so there is nothing to paint.
If I paint directly on the frame, it shows up fine
The default layout manager of the content pane of the frame is a BorderLayout. When you add a component to the CENTER of a BorderLayout, the layout ignores the preferred size of the component and just makes the component take up all the available space in the frame.
Read the section from the Swing tutorial on Layout Managers for more information and working examples of each layout manager.
Related
I'm new to Java and I'm playing around with a simple GUI example:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;
public class DrawTest {
class DrawingPanel extends JPanel {
private Rectangle2D shape;
public DrawingPanel(Rectangle2D shape) {
this.shape = shape;
}
public void paintComponent(Graphics g) {
Graphics2D g2D = (Graphics2D) g;
super.paintComponent(g2D);
g2D.setColor(new Color(31, 21, 1));
g2D.fill(shape);
}
}
public void draw() {
JFrame frame = new JFrame();
Rectangle2D shape = new Rectangle2D.Float();
final DrawingPanel drawing = new DrawingPanel(shape);
shape.setRect(0, 0, 400, 400);
frame.getContentPane().add(BorderLayout.NORTH, new JButton("TestN"));
frame.getContentPane().add(BorderLayout.SOUTH, new JButton("TestS"));
frame.getContentPane().add(BorderLayout.EAST, new JButton("TestE"));
frame.getContentPane().add(BorderLayout.WEST, new JButton("TestW"));
frame.getContentPane().add(BorderLayout.CENTER, drawing);
frame.pack();
frame.setSize(500,500);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
public class DrawMain {
public static void main(String[] args) {
DrawTest test = new DrawTest();
test.draw();
}
}
As expected, this code produces a frame with the rectangle at the centre and buttons around it. However, if I change the code like this:
frame.getContentPane().add(BorderLayout.NORTH, drawing);
frame.getContentPane().add(BorderLayout.SOUTH, new JButton("TestS"));
frame.getContentPane().add(BorderLayout.EAST, new JButton("TestE"));
frame.getContentPane().add(BorderLayout.WEST, new JButton("TestW"));
frame.getContentPane().add(BorderLayout.CENTER, new JButton("TestC"));
the "TestC" button gets a huge area in the middle while the rectangle doesn't get enough space. This is even true if I remove the other buttons (TestS, TestE, TestW): I get a huge TestC button and a tiny part of the rectangle (even not the scaled rectangle) at the top.
Why doesn't the rectangle get enough space when it's drawn at the top (NORTH) but does get it when it's drawn at the CENTER?
The DrawingPanel should #Override getPreferredSize() to return an appropriate size.
The layout manager will then take that preferred size as a hint. Some layout managers will expand a component's height or width according to the logic of the layout and constraint. E.G. a BorderLayout will stretch components in the PAGE_START / PAGE_END to the width of the content pane, and LINE_START / LINE_END to the height of the tallest of either of those, or the CENTER. A GridBagLayout OTOH will completely hide / remove a component for which there is not enough space to display it at the preferred size, and that's where 'pack' comes in.
So change frame.setSize(500,500); (which is no better than a guess) to frame.pack();, which will make frame the minimum size it needs to be, in order to display the components it contains.
I decided to write a small Java program to experiment around with BorderLayout, because I'm developing a Java game and I need to have 2 objects placed in a single JFrame at the same time, and everyone I asked said I need BorderLayout to do that.
So the Java program I wrote is supposed to place a JButton on the JFrame and ALSO place a graphic component (a rectangle in this case). The problem is, only the button shows up, as can be seen in the image link below:
http://prntscr.com/3m5ek6
I can't post actual images due to my low reputation statistic.
Here is the code:
main.java --> The main method class + JFrame/JPanel/JButton constructor
import java.awt.BorderLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class main {
public static void main(String[] args) {
Infout m = new Infout();
JFrame f = new JFrame();
JPanel start = new JPanel();
JPanel start2 = new JPanel();
start.add(m);
start2.add(new JButton("Hi"));
f.add(start,BorderLayout.LINE_START);
f.add(start2, BorderLayout.LINE_END);
f.setVisible(true);
f.setSize(300, 400);
}
}
Infout.java --> Rectangle constructor class
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JPanel;
public class Infout extends JPanel{
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.fill(new Rectangle2D.Double(140, 270, 5, 300));
}
}
Can someone tell me what's wrong? Also, is using BorderLayout the best option for adding multiple static and/or dynamic objects to a JFrame?
Thanks!
Ab
You need to override the getPreferredSize() method so the layout manager can determine the proper size for the component.
How do I do that?
Read the section from the Swing tutorial on Custom Painting for more information on custom painting, including a working example that shows how to override the getPreferredSize() method.
I have a JScrollPane that fills a JPanel (which is the content pane for my JFrame). The JPanel performs custom drawing - however, it doesn't appear over top of the JScrollPane. Should I override something other than paintComponent?
Here is a demo:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.LayoutManager;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class Test {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
// Create the frame.
JFrame frame = new JFrame();
frame.setPreferredSize(new Dimension(1024, 768));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel custom = new CustomPanel(new BorderLayout());
// Add the scroll pane.
JScrollPane scroll = new JScrollPane();
scroll.setBorder(BorderFactory.createLineBorder(Color.blue));
custom.add(scroll, BorderLayout.CENTER);
// Display the frame.
frame.setContentPane(custom);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
#SuppressWarnings("serial")
class CustomPanel extends JPanel {
public CustomPanel(LayoutManager lm) {
super(lm);
}
#Override
public void paintComponent(Graphics g) {
g.setColor(Color.red);
g.drawRect(200, 200, 200, 200);
}
}
I'd like for the paint on the JPanel to go over top of the paint on
the JScrollPane
you can to paint to the
JViewport as you can to see here and here
use JLayer(Java7) based on JXlayer(Java6)
very similair (as todays JLayer) is painting to GlassPane, notice GlassPane to consume()(by default) MouseEvent in the case there is(are) added some JComponent(s), GlassPane can to covers whole RootPane or only part of available Rectangle, depends of used LayoutManager and Dimension returns from layed JComponent(s)
Just a simple problem. You are adding the scrollpane to the custompanel which is hiding what your are drawing. Instead, consider intializing your scrollpane with the cutsompanel as its content.
Example:
JScrollPane scrlPane = new JScrollPane(customPanel);
when you add a single component to a BorderLayout and specify BorderLayout.CENTER, the component will expand to completely fill its parent. If the component is opaque, you won't be able to see any custom painting you are doing in the parent.
The way that worked (as #mKorbel suggested) is to play with the JViewport:
scroll.setViewport(new CustomViewPort());
where CustomViewPort is a class extending JViewport that overrides the paintComponent method.
I am trying to re-position the button so that it is in the bottom right corner of the frame, but everything I try such as setLocation and setBounds, don't seem to do anything. Also, how would I change the button to an image? So that it is still a button, but an image is displayed.
package TrainCounselor;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Start extends JPanel {
public Start() {
// Game Properties
setOpaque(false);
setLayout(new FlowLayout());
}
public void paint(Graphics g) {
Image a = Toolkit
.getDefaultToolkit()
.getImage(
"C:/Users/Mel/workspace/camptycoon/javagame/src/javagame/background1.png");
g.drawImage(a, 0, 0, this);
super.paint(g);
}
public static void main(String[] args) {
JFrame myFrame = new JFrame("Put Image");
JButton startButton = new JButton("Start");
startButton.setLayout(null);
startButton.setLocation(50, 50);
Start c = new Start();
c.add(startButton);
myFrame.add(c);
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myFrame.setTitle("Counselor Training");
myFrame.setSize(755, 600);
myFrame.setResizable(false);
myFrame.setVisible(true);
}
}
I am trying to re-position the button so that it is in the bottom right corner of the frame
Use the appropriate Layout Managers.
I would start by using a JPanel with a FlowLayout that is right aligned. Then you add this panel to the "SOUTH" of the BoderLayout which is used by the JFrame.
See A Visual Guide to Layout Managers for more information.
Note when you add the Start class to the frame you are adding it to the "CENTER", not the south. Also, custom painting is done by override the paintComponent() method, not the paint() method and don't forget to invoke super.paintComponent() before you draw the image, not after.
Also, how would I change the button to an image? So that it is still a button, but an image is displayed.
Read the section from the Swing tutorial on How to Use Buttons.
I have a java class that extends from JPanel. The basic purpose of extending this class from JPanel is that i want to draw some graphical figures inside this JPanel. The code of this class is as follow:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.JPanel;
public class ObjectViewer extends JPanel {
public void paintComponent(Graphics g) {
//just for testing
g.drawRect(0, 0, 100, 10);
g.drawLine(150, 150, 250, 150);
}
}
Now i am loading this JPanel in JScrollPane, by using the following code.
JPanel jpnl = new ObjectViewer();
jScrollPane2.add(jpnl);//Note: I drag and drop this JScrollPanel at desired location from NetBeans gui.
But i am unable to see any graphics (Rect and Line) in that JScrollPane, any suggestions for what i am doing wrong?
You never add your JPanel directly to a JScrollPane but rather to its viewport. So for instance, not
jScrollPane2.add(jpnl);
but rather something like:
jScrollPane2.setViewportView(jpnl);
or
jScrollPane2.getViewport().add(jpnl);
alternatively, you could add the JPanel as a parameter in the scrollpane's constructor.