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.
Related
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.
So I've been trying for the last two hours to get this program to draw a simple rectangle in a frame but nothing gets displayed in the frame when i run the program. I've looked through textbooks and old notebooks and everything in my program seems to be fine, yet nothing is displayed. Help?
This is the class that creates the frame and is supposed to draw the rectangle.
import javax.swing.JFrame;
public class FrameViewer {
public static void main(String[] args) {
//creates an empty frame.
JFrame frame = new JFrame();
frame.setSize(300,400);
frame.setTitle("Empty Frame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//draws the rectangle within the frame.
RectangleComponent component = new RectangleComponent();
frame.add(component);
frame.setVisible(true);
}
}
And here is the RectangleComponent
import javax.swing.JComponent;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
public class RectangleComponent extends JComponent{
public void paintCOmponent(Graphics g){
Graphics2D g2 = (Graphics2D) g;
Rectangle box = new Rectangle(5,10,20,30);
g2.draw(box);
}
}
Java is case sensitive, instead of
paintCOmponent
You want
paintComponent
You should use the #Override annotation to mark methods you think you are overriding as it will highlight problems like this.
The method should also remain protected, as there is no reason any one should be calling from outside the class
You may also want to take a look at Initial Threads
As the title says I'm trying to make add a keylistener to a JPanel. So far the only way I got it working was by adding an empty textfield and clicking on it. Now I don't want an empty textfield in my JPanel so I want to add the keylistener to the panel itself.
Here is the class I'm talking about:
package cookieClicker;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.KeyListener;
import java.awt.event.MouseListener;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class CookieView extends JPanel
{
private CookieModel cm;
private ImageIcon cookie;
public Rectangle rect;
public CookieView(CookieModel cm)
{
this.cm = cm;
this.setFocusable(true);
this.requestFocusInWindow();
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
cookie = new ImageIcon("Untitled-1.png");
g.setColor(Color.ORANGE);
g.drawImage(cookie.getImage(), this.getWidth() / 2 - 100, this.getHeight() / 2 - 100, 200, 200, this);
rect = new Rectangle(this.getWidth() / 2 - 100, this.getHeight() / 2 - 100, 200, 200);
}
public void addListener(MouseListener m, KeyListener k)
{
this.addMouseListener(m);
this.addKeyListener(k);
}
}
Does anyone know how to make this work?
panel is focused
How do you know the panel is focused?
The requestFocusInWindow() method only works when the frame is already visible at the time the method is invoked. So invoking the method in your constructor won't do anything.
The basic code should be:
CookieView panel = new CookieView();
JFrame frame = new JFrame();
frame.add(panel);
frame.pack();
frame.setVisible(true);
panel.requestFocusInWindow();
Also you should make sure all the code is execute on the Event Dispatch Thread.
However, you should probably not even be using a KeyListener. In most cases Swing was designed to be used with Key Bindings. Read the tutorial to see if key bindings will work for you.
Finally, you should NOT be reading an Image file in the paintComponent() method. The painting methods are called whenever Swing determines a component needs to be repainted so it is inefficient to keep reading the image over and over.
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.
I have been coding up Java with Netbeans for about a year now, and have written a lot of data manipulation code which plots graphs on-screen. I generally plant a JPanel object in my main window, write custom painting code, and call the repaint() method as needed.
But today, for the first time, I tried to invoke a repaint on a panel from a class (object) other than the one that contained the panel. Although the compiler found nothing wrong with this, and in debugging mode, it single-stepped properly to the exterior call to the repaint, no repaint actually occurred, and the code did not actually step into the repaint method.
I wrote a minimalist program to demonstrate the problem, as shown below (Main is ommitted, since it only contains code to set up the two on-screen panels.)
--- Description of classes, first contains the drawing surface, other the repaint call ---
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Panel1 extends JComponent
{
GraphPnl graphPnl;
boolean colorFlag;
public Panel1()
{
setLayout(null);
colorFlag = true;
graphPnl = new GraphPnl();
graphPnl.setBounds(10, 10, 110, 110);
graphPnl.setBackground(Color.black);
add(graphPnl);
}//Panel1()
public class GraphPnl extends JPanel
{
//just draws a line segment, toggling color
#Override
public void paint(Graphics g)
{
super.paint(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
if (colorFlag) {g2.setColor(Color.red);} else {g2.setColor(Color.green);}
g2.drawLine(10, 10, 50, 50);
}//paint
}//GraphPnl
}//Panel1
import javax.swing.*;
import java.awt.event.*;
public class Panel2 extends JComponent
{
JButton testBtn;
TestAction testAction;
Panel1 p1;
public Panel2()
{
p1 = new Panel1();
testBtn = new JButton("Click");
testBtn.setBounds(10, 10, 80, 30);
add(testBtn);
testAction = new TestAction();
testBtn.addActionListener(testAction);
}//Panel2()
public class TestAction implements ActionListener
{
public void actionPerformed(ActionEvent evt)
{
p1.colorFlag = ! p1.colorFlag;
p1.graphPnl.repaint();
}
}//TestAction
}//Panel2
If anyone has any insights into this, or knows of a workaround, I'd be very happy to hear
from you.
Thanks in advance for any insights.
John Doner
Main is ommitted, since it only contains code to set up the two on-screen panels.)
Well, by definition when you have a problem you don't know what code is or isn't relative until the problem is solved. So a complete SSCCE should be posted.
As a wild guess I would say your component has a size of 0 so there is nothing to paint.
I generally plant a JPanel object in my main window, write custom painting code, and call the repaint() method as needed
You probably got lucky because you added the panel to the center of a BorderLayout which automatically gives the panel all the space available to the frame.
trashgod's example shows one way to set the preferred size of a custom component. Another way is to override the getPreferredSize() method to return the proper value.
You really should learn how to use layout manager rather than using null layouts and you will avoid problems like this in the future. There is no need to use a null layout unless you have a drag/drop type of application.
"Swing programs should override paintComponent() instead of overriding paint()."—Painting in AWT and Swing: The Paint Methods.
main is ommitted, since it only contains code to set up the two on-screen panels.
Verify that you construct your GUI on the EDT, as shown in the article Initial Threads.
Addendum: Here's an example showing both principles:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
/** #see http://stackoverflow.com/questions/4282159 */
public class GraphPanel extends JPanel {
private boolean colorFlag;
public GraphPanel() {
this.setPreferredSize(new Dimension(640, 480));
}
public void toggle() {
colorFlag = !colorFlag;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
if (colorFlag) {
g2.setColor(Color.red);
} else {
g2.setColor(Color.blue);
}
g2.drawLine(0, 0, getWidth(), getHeight());
}
private void display() {
JFrame f = new JFrame("GraphPanel");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this, BorderLayout.CENTER);
f.add(new ControlPanel(this), BorderLayout.SOUTH);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new GraphPanel().display();
}
});
}
}
class ControlPanel extends JPanel {
public ControlPanel(final GraphPanel gp) {
this.add(new JButton(new AbstractAction("Click") {
#Override
public void actionPerformed(ActionEvent e) {
gp.toggle();
gp.repaint();
}
}));
}
}
Addendum: As noted in #camickr's comment, A Visual Guide to Layout Managers may help guide your layout selection.
I believe that when you are painting a JComponent, the clip region is set to that JComponent. So if other components try to paint (or if you call their repaint), they won't, because of the clipping.