I try to add JPanel in an ArrayList and in another JPanel. Then repaint () the JFrame which JPanel is located in. After several hours of attempts, I start to get tired and find it difficult to think. I changed the program so many times that there may have been some simple mistakes that I no longer see.(Errors may also be found in my English I write here).
I apologize in advance if this is not understandable.
JFrame
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
public class JFrameClassen extends JFrame{
ArrayList <Bild> somePictures= new <Bild> ArrayList();
JPanel p;
public JFrameClassen(){
super("Window with pictures");
p = new JPanel();
p.setBackground(Color.GREEN);
add(p);
setBounds(1300, 500, 400, 400);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public void addPhoto(String s){
somePictures.add(new Bild(s));
p.add(somePictures.get(somePictures.size()-1));
getContentPane().repaint();
}
public void addPhoto(String [] arr){
for(String s : arr){
somePictures.add(new Bild(s));
p.add(somePictures.get(somePictures.size()-1));
}
getContentPane().repaint();
}
public static void main(String[] args) {
JFrameClassen j = new JFrameClassen();
String oneArray[] = {"blab.gif", "peli.gif"};
j.addPhoto(oneArray);
j.addPhoto("stef.gif");
j.addPhoto("pear.gif");
}
}
JPanel
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
public class Bild extends JPanel{
ImageIcon myImage;
int posX = 50;
int posY = 50;
Muslyssnare m = new Muslyssnare(this);
public Bild(String name){
myImage= new ImageIcon(name);
addMouseListener(m);
addMouseMotionListener(m);
}
public void move(int x, int y){
posX = x;
posY = y;
super.repaint();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(myImage.getImage(), posX, posY, this);
}
}
MouseAdapter
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
public class Muslyssnare extends MouseAdapter implements MouseMotionListene{
Bild oneImage;
public Muslyssnare(Bild b){
oneImage = b;
}
public void mouseClicked (MouseEvent e) {
System.out.println("(" + e.getX() + "," + e.getY() + ")");
}
public void mouseDragged (MouseEvent e) {
int x = e.getX();
int y = e.getY();
oneImage.move(x, y);
}
}
You need to set a Layout on your main JPanel.
public JFrameClassen(){
super("Window with pictures");
p = new JPanel();
p.setBackground(Color.GREEN);
// This will stack your newly created panels.
p.setLayout(new BoxLayout(p, BoxLayout.PAGE_AXIS));
// This will generate a scroll bar. You may need it
JScrollPane pane = new JScrollPane(p);
add(pane);
setBounds(1300, 500, 400, 400);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
Also follow MadProgrammer's advice and invoke revalidate / repaint
public void addPhoto(String s){
somePictures.add(new Bild(s));
p.add(somePictures.get(somePictures.size()-1));
getContentPane().revalidate();
getContentPane().repaint();
}
// Simplify your code. Reuse
public void addPhoto(String [] arr){
for(String s : arr){
addPhoto(s);
}
}
NOTE: BorderLayout will resize your inner panels to occupy all width available. You can user other layouts.
More info: https://docs.oracle.com/javase/tutorial/uiswing/layout/visual.html
http://www.oracle.com/technetwork/java/tablelayout-141489.html
NOTE II: Next problem you'll face is image loading.
ImageIcon Loading in Java
How to add an image to a JPanel?
Related
I'm doing my final project for my college. And I don't have much Java knowledge to debug the code. The bug is in question. I am to drop 3 classes Java code here, Drawing Panel, the Jframe and main() one.
main() code:
package test;
public class main {
public static void main(String[] agrs) {
Aaa a = new Aaa();
}
}
Aaa code (IDK what to name):
package test;
import java.awt.*;
import javax.swing.*;
public class Aaa extends JFrame{
JPanel panel = new JPanel();
JLabel text = new JLabel("please try click on the button first, then drawing, then click and draw again.");
JButton button = new JButton("bug here");
DrawingPanel drawingPanel = new DrawingPanel();
public Aaa() {
this.add(panel, BorderLayout.NORTH);
panel.setBackground(Color.WHITE);
panel.add(text);
panel.add(button);
this.add(drawingPanel, BorderLayout.CENTER);
this.setSize(700,500);
this.setTitle("Submit to StackOverFlow");
this.setLocationRelativeTo(null);
this.setVisible(true);
this.setResizable(false);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
}
}
DrawingPanel() Class (Personally suspect this is where the bug is. I have been using this in different projects and it got the same bug too):
package test;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class DrawingPanel extends JPanel implements MouseListener, MouseMotionListener{
boolean mouse = false;
private int x1,y1,x2,y2;
protected int resetCount = 0;
public DrawingPanel() {
this.addMouseListener(this);
this.addMouseMotionListener(this);
}
protected void paintComponent(Graphics g) {
if (mouse) {
if (resetCount == 0 ) {
super.paintComponent(g);
resetCount++;
}
g.setColor(Color.black);
g.drawLine(x1, y1, x2, y2);
}
}
public void mouseClicked(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {
mouse = false;
}
public void mousePressed(MouseEvent e) {
mouse= true;
x2 = (int) e.getPoint().getX();
y2 = (int) e.getPoint().getY();
}
public void mouseMoved(MouseEvent e) {
}
public void mouseDragged(MouseEvent e) {
x1 = x2;
y1 = y2;
x2 = (int) e.getPoint().getX();
y2 = (int) e.getPoint().getY();
repaint();
}
}
With these 3 codes run together, DrawingPanel drawingPanel will copy JButton button onto the top left of its panel. If there's 2 or more button it will copy the lasted one. the 1st clicked button will not be duplicate onto its panel. Sometimes this bug applies to JTextField too. Also, we can paint over the panel! This is the picture of
this
If anyone knows how to debug this I'm all ears to fix them, Thank you so much!
I am trying to use Swing components to manipulate the elements i am painting, with swing stuff in a jpanel on the right of the screen, and my painting stuff in a jpanel on the left of the screen. I have a JButton named btn1 which when pressed, repaints my jpanel with a black rectangle moved over ten pixels. However when i repaint the gui, the entire gui seems to be shifted about 5 px down and 5 px to the right when the black rect moves 10 px to the right. Then eventually, the black rect stops appearing after moving half way across the jpanel. Is there something i am doing wrong with using painting and swing stufff? i went through the custom painting documentation as well as this article article tut here but when i tried to implement these concepts myself, i still had weird problems like this.
Thanks for your help! i am new to this so any clarification / links to other resources would help me a lot. :)
Main.java
package p3p4;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
public class Main extends JFrame{
private GamePanel gPnl;
private JPanel contentPane;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Main frame = new Main();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public Main() {
gPnl = new GamePanel();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(0, 0, 500, 500);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout());
JPanel rightPnl = new JPanel();
rightPnl.setBackground(Color.LIGHT_GRAY);
contentPane.add(rightPnl, BorderLayout.EAST);
JButton btn1 = new JButton("THIS IS A BUTTON");
rightPnl.add(btn1);
btn1.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
gPnl.setX(gPnl.getX() + 10);
gPnl.repaint();
}
});
// JPanel centerPnl = new JPanel();
// centerPnl.setBackground(Color.gray);
// contentPane.add(centerPnl);
contentPane.add(gPnl, BorderLayout.CENTER);
setContentPane(contentPane);
}
}
GamePanel.java
package p3p4;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
public class GamePanel extends JPanel{
private int x = 0, y = 0;
public GamePanel() {
setBackground(Color.gray);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.fillRect(x, y, 50, 50);
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
Your issue is the methods getX and getY are used by swing to manage layout. So you're essentially confusing swing.
You could just change the names of those methods, maybe getRectangleX or something along those lines.
I prefer to use composition over inheritance these days. Although, you might actually want to extend JPanel for layout purposes etc.
public class GamePanel{
private int x = 0, y = 0;
JPanel panel;
public GamePanel() {
panel = new JPanel(){
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.fillRect(x, y, 50, 50);
}
};
panel.setBackground(Color.gray);
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public JPanel getJPanel(){
return panel;
}
}
Then when you add it, contentPane.add(gPnl.getJPanel(), BorderLayout.CENTER);
In a similar manner, I would stop extending JFrame, and just create a JFrame instance.
This is quite bizarre, I have a gui program that allows user to update a J panel by detecting mouseclick
every time the mouse click is detected, the JPanel repaints itself. for some reason the repaint is off by like 30-40 pixels even though through testings,it shows that they are painting at the exact same coordinates. This problem is solved however after I minimize and then re-maximize the window .
the repaint is called in the after detecting mouse click in the same method
Edit: below is a minimum reproduction of that error
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;
public class CenterPanel extends JPanel{
private int sideLength = 50;
private int x = 10;
private int y = 10;
public CenterPanel() {
setPreferredSize(new Dimension(x*sideLength,y*sideLength));
addMouseListener(new Mouse());
}
public void paintComponent (Graphics g) {
super.paintComponent(g);
this.setBackground(Color.WHITE);
this.setBorder(new LineBorder(Color.BLACK,3));
try {
createCanvas(x,y,g,sideLength);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void createCanvas(int x, int y, Graphics g, int sideLength) throws InterruptedException {
int coordX=0;
int coordY=0;
for(int i=0; i<x;i++) {
for(int j=0; j<x;j++) {
paintRectangle(g,Color.LIGHT_GRAY,coordX,coordY,sideLength-1,sideLength-1);
coordX=coordX+sideLength;
}
coordX=0;
coordY=coordY+sideLength;
}
}
private static void paintRectangle(Graphics g,Color color,int x, int y,int width,int height) throws InterruptedException {
g.setColor(color);
g.fillRect(x, y, width, height);
}
class Mouse extends MouseAdapter{
public void mouseClicked (MouseEvent e) {
repaint();
}
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
import javax.swing.*;
import javax.swing.border.LineBorder;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
public class TestFrame extends JFrame implements MouseMotionListener, ActionListener{
private static Color currentColor = Color.lightGray;
private static Color defaultColor = Color.lightGray;
private CenterPanel centerPanel;
JButton red, yellow, white, pink, orange, magenta, light_gray, green, gray, dark_gray, cyan, blue, black;
public TestFrame() {
centerPanel=new CenterPanel();
gui();
}
private void gui() {
JPanel topPanel = new JPanel ();
topPanel.setBackground(Color.GREEN);
topPanel.setPreferredSize(new Dimension(50,50));
JPanel bottomPanel = new JPanel ();
bottomPanel.setBackground(Color.YELLOW);
bottomPanel.setPreferredSize(new Dimension(50,50));
JPanel leftPanel = new JPanel ();
leftPanel.setBackground(Color.RED);
leftPanel.setPreferredSize(new Dimension(50,50));
JPanel rightPanel = new JPanel ();
rightPanel.setBackground(Color.PINK);
rightPanel.setPreferredSize(new Dimension(50,50));
Container c = this.getContentPane();
c.setLayout(new BorderLayout());
c.add(centerPanel, BorderLayout.CENTER);
c.add(topPanel, BorderLayout.NORTH);
c.add(bottomPanel, BorderLayout.SOUTH);
c.add(leftPanel, BorderLayout.WEST);
c.add(rightPanel, BorderLayout.EAST);
this.setVisible(true);
pack();
}
public void actionPerformed(ActionEvent e) {
}
public static void main(String[] args) {
TestFrame t=new TestFrame();
}
#Override
public void mouseDragged(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseMoved(MouseEvent e) {
// TODO Auto-generated method stub
}
}
Edit2: I performed another test by adding Jpanels to North South and West borderlayout locations and find out that the center borderlayout location (the one canvas is in) is misaligned and was overlapping with other Jpanels and was fixed after repaint. Which seems to be whats causing the change in Canvas location.
Edit3: photo of said experiment
Update: I changed setSize() of the CenterPanel Jpanel to setPreferredSize(). now the overlapping shows up without having to call repaint (mouse click).
**UPDATE!!! I have narrowed the problem down to the getter function in the CenterPanel **
public int getX() {
return x;
}
public int getY() {
return y;
}
these two. if I remove them the problem disappears. The problem is I still dont understand why the two getter function could cause this issue when they aren't even called???
You are overriding JComponents (the superclass of JPanel) getX() and getY().
When the position of your panel is determined, it will call those two getters and use them as the coordinates - in pixels.
Name your getters in a different way.
And enable your IDE's warning WRT missing #Override annotations.
Could you please provide a MyFrame class?
I tried with this code and it worked well:
import javax.swing.JFrame;
import java.awt.Color;
public class App extends JFrame {
public static void main(String[] args) {
App app = new App();
app.start();
}
public static Color getCurrentColor() {
return Color.GREEN.darker();
}
public void start() {
setSize(400, 400);
setVisible(true);
add(new Canvas());
}
public static Color getDefaultColor() {
return Color.BLUE;
}
}
Replace
super.paintComponents(g);
with
super.paintComponent(g);
import javax.swing.*;
import java.awt.*;
public class Test1 {
int x = 70;
int y = 70;
public static void main (String[] args) {
Test1 gui = new Test1 ();
gui.go();
}
public void go() {
JFrame frame = new JFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MyDrawPanel drawPanel = new MyDrawPanel();
frame.getContentPane().add(drawPanel);
frame.setSize(300,300);
frame.setVisible(true);
for (int i = 0; i < 130; i++) {
x++; y++;
drawPanel.repaint();
try { Thread.sleep(50);
} catch(Exception ex) { } }
}// close go() method
class MyDrawPanel extends JPanel {
public void paintComponent(Graphics g) {
g.setColor(Color.green);
g.fillOval(x,y,40,40);
}
} // close inner class
} // close outer class
page1page2
According to the page 2, the circle should be smeared in the frame... but actually, when I ran it, it just moved without smearing. Why was that?
btw, if these codes were not able to make a smearing circle, how could I make a smearing one?
cheers
As shown here, "If you do not honor the opaque property you will likely† see visual artifacts." Indeed, running your example on Mac OS X with Java 6 produces a series of circles that appear "smeared."
How could I make a smearing one?
Do not rely on painting artifacts to get the desired result; instead, render a List<Shape> as shown below.
Use javax.swing.Timer to pace animation.
Construct and manipulate Swing GUI objects only on the event dispatch thread.
Override getPreferredSize() to establish a drawing panel's initial geometry.
Code:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Test2 {
public static void main(String[] args) {
EventQueue.invokeLater(new Test2()::display);
}
public void display() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final MyDrawPanel drawPanel = new MyDrawPanel();
frame.add(drawPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
class MyDrawPanel extends JPanel {
private int x = 30;
private int y = 30;
private final List<Shape> list = new ArrayList<>();
public MyDrawPanel() {
new Timer(50, (new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
x++;
y++;
list.add(new Ellipse2D.Double(x, y, 40, 40));
repaint();
}
})).start();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g.setColor(Color.green);
for (Shape s : list) {
g2d.fill(s);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
}
}
†Emphasis mine.
I write a program to draw 50 rectangles after clicking OK button. But I don't uderstand why it disappears after resizing window, using scrollbar or clicking on OK again.
Here's my code (I have two classes: drawingPanel and Main)
drawingPanel.java:
import javax.swing.*;
import java.awt.*;
public class drawingPanel extends JPanel
{
public boolean drawIt = false;
public int x = 140,y = 0;
public void paintIt()
{
drawIt = true;
repaint();
}
public void paintComponent(Graphics g)
{
if (drawIt == true)
{
super.paintComponent(g);
for (int i = 1; i <= 50; i++)
{
g.fillRect(x, y, 50, 50);
y += 70;
}
}
}
}
Main.java:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Main extends JFrame
{
private drawingPanel draw = new drawingPanel();
private JPanel controlPanel = new JPanel();
private JButton ok = new JButton("OK");
private JScrollPane scroll = new JScrollPane(draw);
public Main()
{
setSize(500,500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("Demo");
setLayout(new BorderLayout());
controlPanel.setLayout(new FlowLayout());
controlPanel.add(ok);
ok.addActionListener(new okListener());
draw.setPreferredSize(new Dimension(100,1000));
add(controlPanel, BorderLayout.NORTH);
add(scroll,BorderLayout.CENTER);
setVisible(true);
}
private class okListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
draw.paintIt();
}
}
public static void main(String[] args)
{
new Main();
}
}
Please help me, thanks in advance.
Re-initialize x and y fields within your paint component method like so that they won't keep increasing out of view each time the JPanel is drawn:
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); // move this here
if (drawIt) {
x = 140; // add these guys
y = 0;
for (int i = 1; i <= 50; i++) {
// .... etc....
and things should draw OK.
Other minor issues not related to your question:
The super's painting method should always be called, so pull that out of the if block.
Rename your drawingPanel class to be DrawingPanel so that it conforms to Java conventions.
Better to change if (drawIt == true) { to the more simple if (drawIt) {
Minor quibble: paintComponent should be protected, not public.