Jpanel repaint with mouse movement event - java

Ok here is the thing I am making a function grapher and I want when you move your mouse over a line it will show the coordinates. So I set up just a basic drawstring on the panel to show the mouse coords but I can not get to repaint well normally. It seems to be painting just fine but it is not clearing the contents before painting here is the code I have thus far.
public class Grapher extends JPanel implements MouseMotionListener{
private final int BORDER_GAP = 15;
private final int MAX_SCORE = 20;
private final int PREF_WIDTH = 800;
private final int PREF_HEIGHT = 650;
private final int GRAPH_POINT_WIDTH = 12;
private static final int GRAPH_INTERVAL = 15;
private static Point mse;
private List<Point> values;
public Grapher(List<Point> values) {
setMse(new Point(0,0));
this.values = values;
addMouseMotionListener(this);
}
public void paintComponent(Graphics g){
super.paintComponents(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
float xScale = ((float) getWidth() - 2 * BORDER_GAP) / (values.size()-1);
float yScale = ((float) getHeight() - 2 * BORDER_GAP) / (MAX_SCORE-1);
g2d.drawString(xScale+"", 50, 50);
g2d.drawString(yScale+"", 50, 70);
g2d.drawString(getWidth()/2+"", 50, 90);
g2d.drawString(mse.x +" " + mse.y, 50, 30);
//create axis
g2d.setColor(new Color(0x7e7e7e));
//x line
g2d.drawLine(BORDER_GAP, (getHeight() - BORDER_GAP)/2, getWidth() - BORDER_GAP, (getHeight() - BORDER_GAP)/2);
//y line
g2d.drawLine(getWidth()/2, getHeight() - BORDER_GAP, getWidth()/2, BORDER_GAP);
}
public Dimension getPreferredSize(){
return new Dimension(PREF_WIDTH, PREF_HEIGHT);
}
private static void createAndShowGui(){
List<Point> values = new ArrayList<Point>();
int maxDataPoints = 20;
for (int i = -GRAPH_INTERVAL; i <= GRAPH_INTERVAL; i++) {
String val = "";
try {
val = EquationSolver.solveEquation(variableReplace('x', i));
} catch (Exception e) {
val ="0";
e.printStackTrace();
}
System.out.println(i + "= " + val);
values.add(new Point(i, Integer.parseInt(val)));
}
Grapher panel = new Grapher(values);
JFrame frame = new JFrame("Grapher");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(panel);
frame.pack();
//frame.setLocationByPlatform(true);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run(){
createAndShowGui();
}
});
}
#Override
public void mouseMoved(MouseEvent e) {
setMse(new Point(e.getX(), e.getY()));
removeAll();
repaint();
}
#Override
public void mouseDragged(MouseEvent e) {
setMse(new Point(e.getX(), e.getY()));
//repaint();
}
Ok here is some images as to what the code is doing
the top numbers are the mouse position.
A fresh start to program: http://snag.gy/BFrUj.jpg.
After i move the mouse around a little: http://snag.gy/lNqie.jpg
Thanks for any help.

I would suggest the major problem you are having is related to g.dispose()
The graphics context is shared, meaning that if you dispose of the graphics context, nothing else can paint to it. Unless you create the context, you should never dispose it
Your other problem is, you are not actually calling super.paintComponent, which is responsible for preparing the graphics context for painting (by clearing the are to be painted), but instead, you are calling super.paintComponents(g) ... not the s at the end...

For some reason when I draw straight onto the panel it does that overlaying effect but if i add a white rectangle as a background that solves the problem.
...
float xScale = ((float) getWidth() - 2 * BORDER_GAP) / (values.size()-1);
float yScale = ((float) getHeight() - 2 * BORDER_GAP) / (MAX_SCORE-1);
g2d.setColor(Color.white);
g2d.fillRect(0, 0, getWidth(), getHeight());
g2d.setColor(new Color(0x7e7e7e));
g2d.drawString(xScale+"", 50, 50);
g2d.drawString(yScale+"", 50, 70);
g2d.drawString(getWidth()/2+"", 50, 90);
g2d.drawString(mse.x +" " + mse.y, 50, 30);
...
That appears to be a fix for the problem. If anyone can explain why drawing straight to the panel overlays or has a better solution please do answer.

Related

Generate square wave in JFrame

I have inefficient code of a square wave. I have 2 buttons, 1 table and something like a coordinate system where the square appears in. I want the wave to scroll/move in real time until it hits the end of the coordinate system instead of just appearing by selecting both of the buttons. Additionally, if anyone has a better way of drawing a square wave please tell me.
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.drawLine(20, 300, 20, 450);
g2d.drawLine(20, 350, 400, 350);
g2d.drawLine(20, 400, 400, 400);
g2d.drawLine(20, 450, 400, 450);
if (this.jButtonSTART.isSelected() & this.jButtonAND.isSelected()) {
this.draw(g2d);
}
}
public void draw(Graphics2D g2d) {
boolean up = true;
while (x <= 380) {
g2d.setColor(Color.blue);
if (x > 0 && x % 95 == 0) {
up = !up;
g2d.drawLine(20 + x, up ? 315 : 350 + y, 20 + x, up ? 350 : 315 + y);
} else {
if (up) {
g2d.drawLine(20 + x, 315 + y, 21 + x, y + 315);
} else {
g2d.drawLine(20 + x, 350 + y, 21 + x, y + 350);
}
}
x++;
}
x = 0;
}
Simple way to draw your square wave and move it:
Create a BufferedImage that is longer than your GUI. It should have length that matches a the period of your square wave and be at least twice as long as the GUI component that it's displayed in.
Draw within the paintComponent method override of a JPanel, not the paint method.
Call the super's paintComponent method first within your override.
You'll draw the image using g.drawImage(myImage, imageX, imageY, this) where imageX and imageY are private instance fields of the JPanel-extending drawing class.
In a Swing Timer, advance imageX with each tick of the Timer, that is each time its ActionListener's actionPerformed method is called).
Then call repaint() on the drawing JPanel within the same actionPerformed method.
Done.
for example, note that this code does not do exactly what you're trying to do, but does show an example of Swing animation using a Swing Timer and paintComponent.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.*;
#SuppressWarnings("serial")
public class MoveWave extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = 200;
private static final int TIMER_DELAY = 40;
public static final int DELTA_X = 2;
public static final int STARTING_MY_IMAGE_X = -PREF_W;
private static final Color COLOR_1 = Color.RED;
private static final Color COLOR_2 = Color.BLUE;
private static final Color BG = Color.BLACK;
private static final int CIRCLE_COUNT = 10;
private BufferedImage myImage = null;
private int myImageX = STARTING_MY_IMAGE_X;
private int myImageY = 0;
public MoveWave() {
setBackground(BG);
myImage = new BufferedImage(2 * PREF_W, PREF_H, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = myImage.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setPaint(new GradientPaint(0, 0, COLOR_1, 20, 20, COLOR_2, true));
for (int i = 0; i < CIRCLE_COUNT; i++) {
int x = (i * 2 * PREF_W) / CIRCLE_COUNT;
int y = PREF_H / 4;
int width = (2 * PREF_W) / CIRCLE_COUNT;
int height = PREF_H / 2;
g2.fillOval(x, y, width, height);
}
g2.dispose();
new Timer(TIMER_DELAY, new TimerListener()).start();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (myImage != null) {
g.drawImage(myImage, myImageX, myImageY, this);
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
myImageX += DELTA_X;
if (myImageX >= 0) {
myImageX = STARTING_MY_IMAGE_X;
}
repaint();
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("MoveWave");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new MoveWave());
frame.setResizable(false);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}

Swing - irregular shaped border

I'm newbie in the swing and have a question how better to draw this shape:
I thought in two ways
to draw regular rectangle and to write custom border to it?
to draw regular rectangle + compound border(which contains 2 or 3 borders). But here i do not succeed to draw border inside the shape, is is possible at all? Something like this :
figure.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createMatteBor‌​der(outside top,left,bottom, right, Color.WHITE), createMatteBorder(inside top,left,bottom, right, Color.WHITE)), where the inside border is small rectangle, and outside is big rectangle - not sure if it is possible???
Please advise and an examples will be highly appreciated!
Take a look at the Java 2D API. It helps you to draw complex shapes.
E.g.
class IrregularShape extends JComponent {
private int strokeWidth;
IrregularShape(int strokeWidth){
this.strokeWidth = strokeWidth;
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D newGraphics = (Graphics2D) g.create();
Insets borderInsets = new Insets(0, 0, 0, 0);
Border border = getBorder();
if (border != null) {
borderInsets = border.getBorderInsets(this);
}
BasicStroke basicStroke = new BasicStroke(strokeWidth);
newGraphics.setStroke(basicStroke);
int x = getX() + borderInsets.left + strokeWidth;
int y = getY() + borderInsets.top + strokeWidth;
int width = getWidth() - x - borderInsets.right - strokeWidth;
int height = getHeight() - y - borderInsets.bottom - strokeWidth;
Double outterRactangleDouble = new Rectangle2D.Double(x, y, width, height);
Area outterRectangle = new Area(outterRactangleDouble);
Area innerRectangle = new Area(outterRactangleDouble);
AffineTransform affineTransform = new AffineTransform();
affineTransform.scale(0.5, 0.5);
affineTransform.translate(x + width * 0.10, y + height * 1.2);
innerRectangle.transform(affineTransform);
outterRectangle.subtract(innerRectangle);
newGraphics.draw(outterRectangle);
}
}
public class MainFrame {
public static void main(String[] args) {
JFrame frame = new JFrame("Irregular Shape");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
Container contentPane = frame.getContentPane();
contentPane.add(new IrregularShape(3));
frame.setSize(640, 150);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Result
and it's also resizeable
you can use the polygon class (java.awt.Polygon)
int xs = new int[]{1,2,3...7}; //your x-coordinates
int ys = new int[]{1,2,3...7}; //your y-coordinates
Shape irr = new Polygon(xs, ys, xs.length);
if you want to use certain borders you can use Graphics2D
public void paintComponent(Graphics gr){
Graphics2D g2d = (Graphics2D)gr;
GradientPaint redToWhite = new GradientPaint(0,0,color.RED,100, 0,color.WHITE);
g2d.setPaint(redtowhite)
g2d.fill(irr); //fill special color
Stroke customBorder = getCustomBorder();
g2d.setStroke(customBorder);
g2d.draw(irr); //draw 'special' borders
}
have a look at stroke and fill
note that Polygon implements the contains(double x, double y)method which lets you detect if you're inside or not
You could use a Area for example...
public class TestPane extends JPanel {
public TestPane() {
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
Area area = new Area(new Rectangle(10, 10, getWidth() - 20, getHeight() - 20));
area.subtract(new Area(new Rectangle(20, getHeight() / 2, getWidth() / 2, getHeight() - 10)));
g2d.draw(area);
g2d.dispose();
}
}
You define a custom shape...
public class TestPane extends JPanel {
public TestPane() {
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
Path2D path = new Path2D.Float();
path.moveTo(10, 10);
path.lineTo(getWidth() - 20, 10);
path.lineTo(getWidth() - 20, getHeight() - 20);
path.lineTo(getWidth() / 2, getHeight() - 20);
path.lineTo(getWidth() / 2, getHeight() / 2);
path.lineTo(20, getHeight() / 2);
path.lineTo(20, getHeight() - 20);
path.lineTo(10, getHeight() - 20);
path.closePath();
g2d.draw(path);
g2d.dispose();
}
}
Actually writing a custom border would be very, very difficult, because of the irregular style of shape, where would the components actually be contained?
It might be possible to create two or more borders, which could then be laid out so that the appeared as one
See Working with Geometry for more details
Updated with Border example...
Getting a Border to actually work is far more difficult, as the expectation is that the internal area of the border will be rectangular.
Based on the complex shape you've provided, one solution would be to actually create two borders, a left and right borer, which take care of generating a "safe" area for components to be laid out within, for example:
public class LeftBorder implements Border {
private int offset;
public LeftBorder(int offset) {
this.offset = offset;
}
#Override
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
Path2D path = new Path2D.Float();
int xOffset = x + offset;
int yOffset = y + offset;
width -= offset;
height -= offset * 2;
float gap = width * 0.1f;
path.moveTo(xOffset, yOffset);
path.lineTo(xOffset + width, yOffset);
path.moveTo(xOffset, yOffset);
path.lineTo(xOffset, yOffset + height);
path.lineTo(xOffset + gap, yOffset + height);
path.lineTo(xOffset + gap, yOffset + (height - (height / 2)));
path.lineTo(xOffset + width, yOffset + (height - (height / 2)));
((Graphics2D)g).draw(path);
}
#Override
public Insets getBorderInsets(Component c) {
int height = c.getHeight();
height -= (height / 2);
System.out.println(height);
return new Insets(offset + 4, offset + 4, height + 4, 0);
}
#Override
public boolean isBorderOpaque() {
return false;
}
}
public class RightBorder implements Border {
private int offset;
public RightBorder(int offset) {
this.offset = offset;
}
#Override
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
Path2D path = new Path2D.Float();
int xOffset = x;
int yOffset = y + offset;
width -= offset;
height -= offset * 2;
path.moveTo(xOffset, yOffset);
path.lineTo(xOffset + width, yOffset);
path.lineTo(xOffset + width, yOffset + height);
path.lineTo(xOffset, yOffset + height);
path.lineTo(xOffset, yOffset + (height - (height / 2)));
((Graphics2D)g).draw(path);
}
#Override
public Insets getBorderInsets(Component c) {
return new Insets(offset + 4, 0, offset + 4, offset + 4);
}
#Override
public boolean isBorderOpaque() {
return false;
}
}
This would then require you to provide at least two panels of equal height, for example:
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.geom.Path2D;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.Border;
public class Main {
public static void main(String args[]) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridBagLayout());
frame.add(new LeftPane());
frame.add(new RightPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class RightPane extends JPanel {
public RightPane() {
setBorder(new RightBorder(10));
setLayout(new GridBagLayout());
add(new JLabel("Righty"));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
public class LeftPane extends JPanel {
public LeftPane() {
setBorder(new LeftBorder(10));
setLayout(new GridBagLayout());
add(new JLabel("Lefty"));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
}
This will also be relient on the layout manager been able to layout the two components next to each other
In addition to my first answer https://stackoverflow.com/a/34287251/974186
You can also implement it as a Border.
class IrregularBorder implements Border {
private int thickness;
public IrregularBorder(int thickness) {
this.thickness = thickness;
}
#Override
public void paintBorder(Component c, Graphics g, int x, int y, int width,
int height) {
Graphics2D graphics2d = (Graphics2D) g;
BasicStroke basicStroke = new BasicStroke(thickness);
graphics2d.setStroke(basicStroke);
int halfThickness = thickness / 2;
Double outterRactangleDouble = new Rectangle2D.Double(
x + halfThickness, y + halfThickness, width - thickness,
height - thickness);
Area outterRectangle = new Area(outterRactangleDouble);
Area innerRectangle = computeInnerRect(x, y, width, height,
outterRactangleDouble);
outterRectangle.subtract(innerRectangle);
graphics2d.draw(outterRectangle);
}
private Area computeInnerRect(int x, int y, int width, int height,
Double outterRactangleDouble) {
Area innerRectangle = new Area(outterRactangleDouble);
AffineTransform affineTransform = new AffineTransform();
affineTransform.scale(0.5, 0.5);
affineTransform.translate(x + width * 0.10, y + height * 1.2);
innerRectangle.transform(affineTransform);
return innerRectangle;
}
#Override
public Insets getBorderInsets(Component c) {
int left = (int) (thickness + (c.getWidth() * 0.6));
return new Insets(thickness, left, thickness, thickness);
}
#Override
public boolean isBorderOpaque() {
return true;
}
}
and use it as usual
public class MainFrame {
public static void main(String[] args) {
JFrame frame = new JFrame("Irregular Shape");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
Container contentPane = frame.getContentPane();
JPanel mainPanel = new JPanel(new BorderLayout());
mainPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
contentPane.add(mainPanel);
JPanel irregularShapeBorderedPanel = new JPanel(new BorderLayout());
irregularShapeBorderedPanel.add(new JButton("Button"),
BorderLayout.CENTER);
irregularShapeBorderedPanel.setBorder(new IrregularBorder(2));
mainPanel.add(irregularShapeBorderedPanel);
frame.setSize(640, 150);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}

Java Swing Frame is a tad off?

I have a simple animation code that creates a meter type rectangle effect. I would like to create it so that it fills a panel completely. I am so close, but it extends past the frame on the bottom. What am I missing?
public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame("Pong");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridLayout(1,2));
frame.setSize(500, 500);
//MouseTest test = new MouseTest();
Test test2 = new Test(frame.getWidth(), frame.getHeight(), frame.getHeight(), 50);
//frame.add(test);
frame.add(test2);
frame.setVisible(true);
}
}
public class Test extends JPanel implements ActionListener, MouseListener{
int y = 0, width, height, dy=0, maxHeight;
int BOTTOM;
Timer timer;
public Test(int width, int height, int BOTTOM, int SPEED){
setBackground(Color.BLUE);
this.width = width;
maxHeight = height;
this.BOTTOM = BOTTOM;
addMouseListener(this);
timer = new Timer(1000/SPEED, this);
timer.start();
}
public void move(){
if(y>=maxHeight){
dy = -1;
}
if(y<=0)
{
dy = 1;
}
y+=dy;
height+=dy;
//System.out.println(y);
repaint();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
if(y<=maxHeight/2) {
g.setColor(Color.green);
g.fillRect(0, BOTTOM - y, width, height);
}
if(y>=maxHeight/2 && y<(maxHeight/10)*9){
g.setColor(Color.green);
g.fillRect(0, BOTTOM-(maxHeight/2), width, maxHeight/2);
g.setColor(Color.green);
g.fillRect(0, BOTTOM - y, width, height-(maxHeight/2));
}
if(y>=(maxHeight/10)*9){
g.setColor(Color.green);
g.fillRect(0, BOTTOM-(maxHeight/2), width, maxHeight/2);
g.setColor(Color.green);
g.fillRect(0, BOTTOM-(9*(maxHeight/10)), width, (4*maxHeight)/10);
g.setColor(Color.green);
g.fillRect(0, BOTTOM - y, width, height-(9*(maxHeight)/10));
}
for(int i = 1; i<6; i++)
g.fillRect(0, BOTTOM - (i*(maxHeight/5)), width, 10);
System.out.println(y);
}
Your panel takes up less room than your JFrame, because your frame has a title bar and window borders. You can just query in your paint method for the correct width and height used by the 'JPanel' with your JPanel's getWidth() and getHeight() (in other words, your JFrame's width and height is not the same as your JPanel's width and height, even though the JPanel takes up all the space within the frame visually between the borders).
Alternatively, if you did have logic where this was not possible, you could query the size of the insets of the frame, and subtract the left and right inset values from the width, and pass that as the width, and do the same for the height with the top and bottom inset values.
Override getPreferredSize of your JPanel, this will helps the layout manager determine the best way to layout your component
Use JFrame#pack to wrap the frame borders around the view
Use getWidth and getHeight to get the actual size the panel. You should do this whenever you need to know these values, don't store them for long periods, as the values can change
You should also have a read through Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?
This is basic example based on you code...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test1 {
public static void main(String[] args) {
new Test1();
}
public Test1() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private int yPos;
private int dy = 1;
private int bottom = 50;
public TestPane() {
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
move();
}
});
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(500, 500);
}
public void move() {
if (yPos >= getHeight()) {
dy = -1;
}
if (yPos <= 0) {
dy = 1;
}
yPos += dy;
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int maxHeight = getHeight();
int width = getWidth();
int height = maxHeight;
if (yPos <= maxHeight / 2) {
g.setColor(Color.green);
g.fillRect(0, bottom - yPos, width, height);
}
if (yPos >= maxHeight / 2 && yPos < (maxHeight / 10) * 9) {
g.setColor(Color.green);
g.fillRect(0, bottom - (maxHeight / 2), width, maxHeight / 2);
g.setColor(Color.green);
g.fillRect(0, bottom - yPos, width, height - (maxHeight / 2));
}
if (yPos >= (maxHeight / 10) * 9) {
g.setColor(Color.green);
g.fillRect(0, bottom - (maxHeight / 2), width, maxHeight / 2);
g.setColor(Color.green);
g.fillRect(0, bottom - (9 * (maxHeight / 10)), width, (4 * maxHeight) / 10);
g.setColor(Color.green);
g.fillRect(0, bottom - yPos, width, height - (9 * (maxHeight) / 10));
}
for (int i = 1; i < 6; i++) {
g.fillRect(0, bottom - (i * (maxHeight / 5)), width, 10);
}
}
}
}
Another way to go is to use pack(). It sets the size of the frame to be the size of the frame's contents. In your code it would look like this:
frame.add(test2);
frame.pack();
If you do it this way, you don't need the frame.setSize() call. You can add the panel either with .add() as you've done or with:
frame.setContentPane(test2);
So I combined both your comments and got it to work correctly. Here is the code that works.
public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame("Pong");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridLayout(1,2));
Insets inset = frame.getInsets();
Test test2 = new Test(200-(inset.right + inset.left), 200 -(inset.top + inset.bottom), 200, 50);
frame.setContentPane(test2);
frame.pack();
frame.setVisible(true);
}
}
public class Test extends JPanel implements ActionListener, MouseListener{
int y = 0, width, height, dy=0, maxHeight;
int BOTTOM;
Timer timer;
Dimension size;
Insets inset;
public Test(int width, int height, int BOTTOM, int SPEED){
size = new Dimension(width, height);
setBackground(Color.BLUE);
setPreferredSize(size);
inset = this.getInsets();
this.width = width-(inset.right+inset.left);
maxHeight = height;
this.BOTTOM = BOTTOM - (inset.bottom+inset.top);
addMouseListener(this);
timer = new Timer(1000/SPEED, this);
timer.start();
}
public void move(){
if(y>=maxHeight){
dy = -1;
}
if(y<=0)
{
dy = 1;
}
y+=dy;
height+=dy;
//System.out.println(y);
repaint();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
if(y<=maxHeight/2) {
g.setColor(Color.green);
g.fillRect(0, BOTTOM - y, width, height);
}
if(y>=maxHeight/2 && y<(maxHeight/10)*9){
g.setColor(Color.green);
g.fillRect(0, BOTTOM - (maxHeight / 2), width, maxHeight / 2);
g.setColor(Color.green);
g.fillRect(0, BOTTOM - y, width, height-(maxHeight/2));
}
if(y>=(maxHeight/10)*9){
g.setColor(Color.green);
g.fillRect(0, BOTTOM-(maxHeight/2), width, maxHeight/2);
g.setColor(Color.green);
g.fillRect(0, BOTTOM-(9*(maxHeight/10)), width, (4*maxHeight)/10);
g.setColor(Color.green);
g.fillRect(0, BOTTOM - y, width, height-(9*(maxHeight)/10));
}
g.setColor(Color.white);
for(int i = 1; i<6; i++)
g.fillRect(0, BOTTOM - (i*(maxHeight/5)), width, 5);
}

Drawing lines on top of image without using AlphaComposite

I am currently having lots of difficulty in one of my assignments. The task for this assignment is to create an aviation radar, VOR, with java's GUI features. When the user presses either the left/right arrow on their keyboard, the circular radar should rotate, and a needle in the middle of the radar should move left/right.
I am very close to finishing, but I am stuck on one part. I drew an image of the radar, and I attempted to draw a line on top of it. However, I was only successful when I was able to make all JPanels transparent. This causes a problem because it is difficult to see what I drew on top of it.
So, my question is, how would I draw it on top of the radar image without making everything transparent? Below is my code
public class finalVORGUI extends JPanel{
private JPanel rotationPanel;
private JPanel needle;
private JPanel attributes;
private int degrees;
private String CurrentRadial;
private int x;
private int y1;
private int y2;
final int WIDTH = 600;
final int HEIGHT = 600;
private ImageIcon radar = new ImageIcon("image/vor1.png");
/**
* The constructor for the class
* It's going to set the dimension of the program to 600x600, the
* background is going to be white (in order to blend in with the
* vor image), and it is going to add in the VOR radar and a radial
* indicator that will let the user know which radial he/she is on
*/
public finalVORGUI(){
JLayeredPane lp = new JLayeredPane();
lp.setPreferredSize(new Dimension(WIDTH, HEIGHT));
setBackground(Color.white);
lp.setLayout(null);
lp.setFocusable(true);
lp.addKeyListener(new KeyboardListener());
rotationPanel = new JPanel();
rotationPanel = new TurningCanvas();
needle = new JPanel();
needle = new DrawNeedle();
attributes = new JPanel();
attributes = new DrawAttributes();
lp.add(rotationPanel, Integer.valueOf(1));
lp.add(needle, Integer.valueOf(2));
lp.add(attributes, Integer.valueOf(3));
needle.setBounds(100,0, needle.getPreferredSize().width, needle.getPreferredSize().height);
rotationPanel.setBounds(100, 100, rotationPanel.getPreferredSize().width, rotationPanel.getPreferredSize().height);
attributes.setBounds(100, 100, rotationPanel.getPreferredSize().width, rotationPanel.getPreferredSize().height);
add(lp);
degrees = 360; //to edit: this is going to be the radial the radar is currently facing
x = 172; //x is the location of the needle
y1 = 155;
y2 = 330;
CurrentRadial = "Radial: " + degrees; //A string that is always going to be above the radar. it's going to let the user know the current radial
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawString(CurrentRadial, 250, 100);
}
public class DrawAttributes extends JPanel{
public DrawAttributes(){
setOpaque(false);
add(new Attributes());
}
public class Attributes extends JPanel{
int w = 500;
int h = 400;
public Attributes(){
setPreferredSize(new Dimension(w,h));
setBackground(Color.white);
}
public void paintComponent(Graphics g){
Graphics2D g2 = (Graphics2D) g;
g2.drawString("To",300,400);
g2.setComposite(AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, 0.3f));
g2.setStroke(new BasicStroke(3));
super.paintComponent (g);
g2.dispose();
}
}
}
public class DrawNeedle extends JPanel{ //todo: make sure this works and adds correctly to the LayeredPane
public DrawNeedle(){
setOpaque(false);
add(new Needle());
}
public class Needle extends JPanel{
int w = 500;
int h = 400;
public Needle(){
setPreferredSize(new Dimension(w,h));
setBackground(Color.white);
}
private void doDrawing(Graphics g){
Graphics2D g4 = (Graphics2D) g;
g4.drawString("TO", 190, 200);
g4.drawString("FROM",190, 300);
}
public void paintComponent(Graphics g){
Graphics2D g2 = (Graphics2D) g;
RenderingHints hints = new RenderingHints(null);
hints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
hints.put(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
hints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2.setRenderingHints(hints);
g2.setComposite(AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, 0.3f));
g2.setStroke(new BasicStroke(3));
doDrawing(g);
g2.drawLine(x,y1,x,y2);
super.paintComponent (g);
g2.dispose();
}
}
}
public class TurningCanvas extends JPanel{
public TurningCanvas(){
setOpaque(false);
add(new TurningImage());
}
public class TurningImage extends JPanel{
int w = radar.getIconWidth()- 20;
int h = radar.getIconHeight() -20;
public TurningImage(){
setPreferredSize(new Dimension(w,h));
setBackground(Color.white);
}
public void paintComponent(Graphics g){
super.paintComponent (g);
Graphics2D g2 = (Graphics2D) g;
RenderingHints hints = new RenderingHints(null);
hints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
hints.put(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
hints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2.setRenderingHints(hints);
g2.rotate (Math.toRadians(degrees),w/2, h/2);
g2.drawImage(radar.getImage(), 0, 0, this);
//g2.drawLine(171,0,x,300);
g2.dispose();
}
}
}
/**
* This is the keyboard listener that this program will be using
* Depending on what the user wishes, or what type of keyboard they have,
* they will be able to find their desired radial by using the arrow keys
* or the "a" and "d" buttons. Left arrow to minus radial, right arrow to plus radial, etc etc...
*
*/
public class KeyboardListener implements KeyListener{
public void keyPressed (KeyEvent event) {
if(event.getKeyCode() == KeyEvent.VK_LEFT){
degrees--;
x--;
if(degrees <= 0){
degrees = 360;
}
if(x <= 89){
x = 89;
}
CurrentRadial = "Radial: " + degrees;
repaint();
}
if(event.getKeyCode() == KeyEvent.VK_RIGHT){
degrees++;
x++;
if(degrees >= 360){
degrees = 1;
}
if(x >= 250){
x = 250;
}
CurrentRadial = "Radial: " + degrees;
repaint();
}
}
public void keyTyped (KeyEvent event) {}
public void keyReleased (KeyEvent event) {}
}
/**
* The main method of this class
* This is going to make a new JFrame, which will hold the new
* VOR radar
* #param args
*/
public static void main(String[] args){
finalVORGUI test = new finalVORGUI();
JFrame frame = new JFrame("VOR Radar");
frame.setContentPane(test);
frame.pack();
frame.setVisible(true);
}
}

How do i set the size of a panel to the size of a window, even if the window size changes?

This is my code. I would like to set the size of the box the ball bounces in to that of the window size, even if the window is resized by the user, such as making the window restored, or dragging it to a size.
Thanks a lot.
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
/**
* One ball bouncing inside a rectangular box.
* All codes in one file. Poor design!
*/
// Extends JPanel, so as to override the paintComponent() for custom rendering codes.
public class BouncingBallSimple extends JPanel {
// Container box's width and height
private final int BOX_WIDTH = 700;
private final int BOX_HEIGHT = 700;
// Ball's properties
private float ballRadius = 15; // Ball's radius
private float ballX = ballRadius + 50; // Ball's center (x, y)
private float ballY = ballRadius + 20;
private float ballSpeedX = 60; // Ball's speed for x and y
private float ballSpeedY = 60;
private static final int UPDATE_RATE = 30; // Number of refresh per second
/** Constructor to create the UI components and init game objects. */
public BouncingBallSimple() {
this.setPreferredSize(new Dimension(BOX_WIDTH, BOX_HEIGHT));
// Start the ball bouncing (in its own thread)
Thread gameThread;
gameThread = new Thread() {
#Override
public void run() {
while (true) { // Execute one update step
// Calculate the ball's new position
ballX += ballSpeedX;
ballY += ballSpeedY;
// Check if the ball moves over the bounds
// If so, adjust the position and speed.
if (ballX - ballRadius < 0) {
ballSpeedX = -ballSpeedX; // Reflect along normal
ballX = ballRadius; // Re-position the ball at the edge
} else if (ballX + ballRadius > BOX_WIDTH) {
ballSpeedX = -ballSpeedX;
ballX = BOX_WIDTH - ballRadius;
}
// May cross both x and y bounds
if (ballY - ballRadius < 0) {
ballSpeedY = -ballSpeedY;
ballY = ballRadius;
} else if (ballY + ballRadius > BOX_HEIGHT) {
ballSpeedY = -ballSpeedY;
ballY = BOX_HEIGHT - ballRadius;
}
// Refresh the display
repaint(); // Callback paintComponent()
// Delay for timing control and give other threads a chance
try {
Thread.sleep(1000 / UPDATE_RATE); // milliseconds
} catch (InterruptedException ex) { }
}
}
};
gameThread.start(); // Callback run()
}
/** Custom rendering codes for drawing the JPanel */
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g); // Paint background
// Draw the box
g.setColor(Color.CYAN);
g.fillRect(0, 0, getWidth(), getHeight());
// Draw the ball
g.setColor(Color.BLUE);
g.fillOval((int) (ballX - ballRadius), (int) (ballY - ballRadius),
(int)(2 * ballRadius), (int)(2 * ballRadius));
Graphics2D comp2D = (Graphics2D) g;
comp2D.drawRect(0, 645, 1365, 100);
comp2D.setColor(Color.GREEN);
comp2D.fillRect(0, 645, 1365, 100);
Graphics2D stand = (Graphics2D) g;
stand.setColor(Color.BLACK);
stand.fillRect(80, 575, 30, 70);
Graphics2D sling = (Graphics2D) g;
sling.drawArc(15, 570, 90, 50, 50, 250);
}
/** main program (entry point) */
public static void main(String[] args) {
// Run GUI in the Event Dispatcher Thread (EDT) instead of main thread.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
// Set up main window (using Swing's Jframe)
JFrame frame = new JFrame("Angry Birds for Annie May Tion");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(new BouncingBallSimple());
frame.pack();
frame.setVisible(true);
}
});
}
}
Drop this line: this.setPreferredSize(new Dimension(BOX_WIDTH, BOX_HEIGHT));
Wherever you used BOX_WIDTH replace it with getWidth()
Wherever you used BOX_HEIGHT replace it with getHeight()
That should do the trick.
It should be as simple as removing the call to this.setPreferredSize() in your constructor. When the window is resized, it will request the panel to resize itself. In your paint routine, you're getting the current bounds of the panel and bouncing between them, so it should just work.
On an unrelated note: you should replace your aameThread with a javax.swing.Timer. As it is, you're invoking paint requests from outside the event dispatch thread, which is a bad idea.
There is no simple answer here because you have hard coded x,y,w,h values. The not-so-simple answer is to use variables instead of hard coded values and dynamically adjust those values inside the paintComponent() method.

Categories