As you can see from the code I am expecting to see a rectangle on DrawingPanel but I am not sure why repaint() method is not working. Any help will be much appreciated. I also tried revalidate method but that is not working either.
Here are my Classes:
import javax.swing.*;
import java.awt.*;
public class Designer extends JFrame {
static JFrame f = new Designer();
JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
DrawingPanel drawingPanel = new DrawingPanel();
PropertyPanel propertyPanel = new PropertyPanel();
public Designer(){
Rectangle bounds = GraphicsEnvironment
.getLocalGraphicsEnvironment()
.getMaximumWindowBounds();
splitPane.setTopComponent(propertyPanel);
splitPane.setBottomComponent(drawingPanel);
add(splitPane, BorderLayout.CENTER);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(bounds);
setVisible(true);
}
public static void main(String[] args) {
System.out.println("App started...");
}
}
Class for first Jpanel: PropertyPanel.Java
import javax.swing.*;
import java.awt.event.*;
public class PropertyPanel extends JPanel {
private DrawingPanel drawingPanel = new DrawingPanel();
public PropertyPanel(){
JButton addShapesBtn = new JButton("Add");
addShapesBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
drawingPanel.addRectangle();
}
});
add(addShapesBtn);
}
}
Class for second Jpanel: DrawingPanel.Java
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
public class DrawingPanel extends JPanel{
private List<Rectangle> squares = new ArrayList<Rectangle>();
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
System.out.println("painting");
for (Rectangle rect : squares) {
g2.draw(rect);
}
}
public void addRectangle() {
Rectangle rectx = new Rectangle(10, 10, 100, 100);
squares.add(rectx);
repaint(); <-- this is not working
}
}
Your repaint works fine. Your problem is that you're calling addRectangle() to the wrong DrawingPanel instance, not the one that is currently displayed in the GUI. To solve this, pass a reference from the displayed one to the code that needs to call the method.
To see that this is correct, simply search this page for new DrawingPanel(). You should see this only once in your own code (and your code posted). You see it twice meaning you've created two instances of this.
e.g., change this:
public class PropertyPanel extends JPanel {
private DrawingPanel drawingPanel = new DrawingPanel();
public PropertyPanel(){
to this:
public class PropertyPanel extends JPanel {
private DrawingPanel drawingPanel; // don't create new
public PropertyPanel(DrawingPanel drawingPanel){
this.drawingPanel = drawingPanel;
and then pass in the true DrawingPanel into this object on creation:
DrawingPanel drawingPanel = new DrawingPanel();
PropertyPanel propertyPanel = new PropertyPanel(drawingPanel);
Better still: structure your code in a M-V-C way, and use dependency injection to make connections -- but this may be overkill for your simple GUI.
Related
To provide some background info that might help, I am creating the game pong and I decided to add an escape/pause menu (when you press escape on the keyboard a menu pops up with some settings), I looked around and found that the best way to do this is to use JLayeredPane and add another JPanel on top. However, when I added my 'painter' class to the JLayeredPane, the paint(Graphics g) method stopped getting called (it worked fine when I just added it to the JFrame).
import javax.swing.*;
public class Game extends JFrame {
public static Painter painter;
public Game() {
setSize(500, 500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLayeredPane lp = getLayeredPane();
painter = new Painter();
add(lp);
}
public static void main(String[] args) {
Game frame = new Game();
frame.setVisible(true);
painter.repaint();
}
}
And here is my Painter class
import java.awt.*;
import javax.swing.*;
public class Painter extends JPanel {
public void paint(Graphics g) {
System.out.println("Working");
super.paint(g);
}
}
Instead of add(lp);, I originally tried lp.add(painter); in which case the paint method never got called. By doing add(lp) I get an IllegalArgumentException for adding container's parent to itself.
Here is mcve of using LayeredPane :
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
public class Game extends JFrame {
public Game() {
setSize(250, 150);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLayeredPane lp = getLayeredPane();
//assign layout manager. otherwise you need to set content
//bounds (not recommended)
lp.setLayout(new BorderLayout());
Painter painter = new Painter();
lp.add(painter,1);
}
public static void main(String[] args) {
Game frame = new Game();
frame.setVisible(true);;
}
}
class Painter extends JPanel {
#Override
protected void paintComponent(Graphics g) { //do not override paint
super.paintComponent(g);
g.drawString("Working",50,50);
}
}
I'm using paintComponent to make a GUI for a class assignment and it's just not affecting the appearance of the GUI at all. To start, I'm just setting the background to white. The following code works:
import javax.swing.*;
import java.awt.*;
public class PA05a extends JPanel {
public static void main(String[] args) {
JFrame window = new JFrame("MouseDrawDemo");
JPanel content = new JPanel();
content.setBackground(Color.WHITE);
window.setContentPane(content);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setLocation(120,70);
window.setSize(400,300);
window.setVisible(true);
}
}
but this does not:
import javax.swing.*;
import java.awt.*;
public class PA05a extends JPanel {
public static void main(String[] args) {
JFrame window = new JFrame("MouseDrawDemo");
JPanel content = new JPanel();
window.setContentPane(content);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setLocation(120,70);
window.setSize(400,300);
window.setVisible(true);
}
#Override
public void paintComponent(Graphics g) {
//add backdrop
super.paintComponent(g);
g.setColor(Color.WHITE);
g.fillRect(0,0,getWidth(),getHeight());
}
}
I can't just not use paintComponent because I'll later be adding things that will change from frame to frame. Can someone pinpoint where I'm missing something?
JPanel content = new PA05a();
You did not create an object of PA05a. ;)
You just forgot to create your object. Change your code to:
import javax.swing.*;
import java.awt.*;
public class PA05a extends JPanel {
public static void main(String[] args) {
JFrame window = new JFrame("MouseDrawDemo");
JPanel content = new PA05a();
window.setContentPane(content);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setLocation(120,70);
window.setSize(400,300);
window.setVisible(true);
}
#Override
public void paintComponent(Graphics g) {
//add backdrop
super.paintComponent(g);
g.setColor(Color.WHITE);
g.fillRect(0,0,getWidth(),getHeight());
}
}
Im trying to add a JScrollpane to my JPanel. The problem is that the scrollpane doesn't recognize that my drawing is outside the frame. So how do I add the JScrollpane correctly?
Main class:
public MainFrame() extends JFrame{
public MainFrame() {
Container container = getContentPane();
container(new BorderLayout());
container.add(new JScrollPane(new Drawing()));
setSize(1280,720);
setVisible(true);
}
Drawing class:
public class Drawing() extends JPanel {
#Override
protected void paintComponent(Graphics g) {
g.drawLine(10, 100, 30000, 10);
}
}
There are a couple of errors in your code, let's step through each of them:
You're extending JFrame, and you should avoid it, see: Extends JFrame vs. creating it inside the program for more information about it. You're actually not changing its behavior so it's not needed to extend it.
For your JScrollPane to show the whole line, you need to change your window's size to be the same size of your line (as shown in this answer by #MadProgrammer).
Related to point 2, avoid the use of setSize(...) and instead override getPreferredSize(): See Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing? for more information
You forgot to call super.paintComponent(...) method in your paintComponent() method.
Related to points 2, 3, you need to call pack() so Swing calculates the best preferred size for your component.
See this example:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class LongDraw {
private JFrame frame;
private Drawing drawing;
public static void main(String[] args) {
SwingUtilities.invokeLater(new LongDraw()::createAndShowGui);
}
private void createAndShowGui() {
frame = new JFrame(getClass().getSimpleName());
drawing = new Drawing();
JScrollPane scroll = new JScrollPane(drawing);
frame.add(scroll);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
class Drawing extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.drawLine(10, 100, 3000, 10);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(3000, 500);
}
}
}
Which produces something similar to this:
I'm trying to remake Snake to improve my programming, Ive been reading about other people having the same problem for hours but none of them seem to be similar to my own code. Here is my relevant code:
package snake;
import java.awt.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class PlayGame extends JPanel implements Runnable{
private JFrame jfr;
private JPanel jpn;
PickupBall b = new PickupBall();
Snake bob = new Snake();
public PlayGame(){
jfr = new JFrame("Snake");
jfr.setSize(640,640);
jfr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jpn = new JPanel();
jpn.setBackground(Color.WHITE);
jfr.add(jpn);
jfr.setVisible(true);
}
#Override
public void run(){
while(true){
repaint();
}
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
b.draw(g);
}
public static void main(String[] args) {
PlayGame p = new PlayGame();
Thread t = new Thread(p);
t.start();
}
}
Everything works, the while(true) loop is initiated, but nothing happens.
package snake;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
public class PickupBall {
//constructor
public PickupBall(){
xPos = (int) (((Math.random()*31)+1)*20);
yPos = (int) (((Math.random()*31)+1)*20);
}
//constants
public final int balletjeSides = 20;
//variables
public int xPos;
public int yPos;
//methods
public void draw(Graphics g){
g.setColor(Color.RED);
g.fillRoundRect(this.xPos, this.yPos, balletjeSides, balletjeSides, 5, 5);
}
}
What am I missing?
just add jfr.setContentPane(this); within your onstructor, as what #Berger said, you actually have a JPanel, PlayGame instance here, but the JFrame you´re creating doesn´t use this JPanel instance, but instead simply adds an empty JPanel, called jpn in your code, to your jfr which doesn´t have any content.
The new constructor could look like this:
private JFrame jfr;
//private JPanel jpn;
PickupBall b = new PickupBall();
//Snake bob = new Snake();
public PlayGame() {
jfr = new JFrame("Snake");
jfr.setSize(640, 640);
jfr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//jpn = new JPanel();
this.setBackground(Color.WHITE);
//jfr.add(jpn);
jfr.setContentPane(this);
jfr.setVisible(true);
}
As you see, i commented out the jpn variable, as the actual JPanel you´d like to work with (my guess) is the PlayGame class itself, and not an JPanel defined within this class.
I create a JPanel and added a few simple buttons with listeners attached to them. Then I decided to add an Image to the background of my panel, so I switched my JPanel to an ImagePanel. The buttons were working on JPanel, but now that I added a bunch of code for the background image to be displayed, the buttons no longer show. I did not change of any of the button adding code so I'm very confused as to why the buttons no longer show. This also happened in my separate GameFrame class. I added 2 rectangle components to a panel, then 3 buttons. For that panel, only the buttons show, despite the rectangles working before the buttons were added. Can I only have one type of JComponent per panel or something? I really do not understand why it's doing this. Thank you for your time.
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class TitleFrame extends JFrame
{
private ImagePanel panel;
private JButton mage;
private JButton rogue;
private JButton warrior;
private Image image;
public TitleFrame()
{
JFrame frame = new JFrame();
frame.setSize(1024, 768);
frame.setTitle("Title Screen");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
createMageButton();
createRogueButton();
createWarriorButton();
ImagePanel panel = new ImagePanel(new ImageIcon("C:/Users/Derek Reitz/Documents/Eclipse Projects/GameApp/src/background.jpg").getImage());
panel.add(mage);
panel.add(rogue);
panel.add(warrior);
panel.paintComponent(frame.getGraphics());
frame.getContentPane().add(panel);
}
private void createRogueButton() {
rogue = new JButton("Select Rogue");
class AddButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
moveToNextFrame('r');
}
}
ActionListener listener = new AddButtonListener();
rogue.addActionListener(listener);
}
private void createWarriorButton() {
warrior = new JButton("Select Warrior");
class AddButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
moveToNextFrame('w');
}
}
ActionListener listener = new AddButtonListener();
warrior.addActionListener(listener);
}
private void createMageButton() {
mage = new JButton("Select Mage");
class AddButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
moveToNextFrame('m');
}
}
ActionListener listener = new AddButtonListener();
mage.addActionListener(listener);
}
public void moveToNextFrame(char c)
{
GameFrame game = new GameFrame(c);
}
class ImagePanel extends JPanel
{
private Image img;
public ImagePanel(Image img) {
this.img = img;
Dimension size = new Dimension(img.getWidth(null), img.getHeight(null));
setPreferredSize(size);
setMinimumSize(size);
setMaximumSize(size);
setSize(size);
setLayout(null);
}
public void paintComponent(Graphics g) {
g.drawImage(img, 0, 0, null);
}
}
}
You need to use a LayoutManager.
You should then be able to add your ImagePanel and buttons to the contentPane and have them all layed out and visible.
Try the follwoing:
JFrame frame = new JFrame();
frame.setTitle("Title Screen");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
createMageButton();
createRogueButton();
createWarriorButton();
ImagePanel panel = new ImagePanel(new ImageIcon(".../background.jpg").getImage());
panel.setLayout(new FlowLayout());
panel.add(mage);
panel.add(rogue);
panel.add(warrior);
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
You set as layout null. That is a special case where absolute positions of the components are accepted. So use `setBounds(x, y, width, height). Better still use a real layout.
Another remark, you can take the image from the class path, say from out of the resulting .jar file):
URL url = getClass().getResource("/background.jpg");
... new ImageIcon(url);