Okay, this seems like a really simple task but I can't seem to get it. All I want is to have an image (jpg) as the background to my breakout game. Here is my code:
Main Class:
import java.awt.BorderLayout;
import java.awt.Color;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Breakout extends JFrame {
public Breakout()
{
add(new BreakBoard());
setTitle("Breakout");
setSize(BreakCommons.WIDTH, BreakCommons.HEIGTH);
setLocationRelativeTo(null);
setIgnoreRepaint(true);
setResizable(false);
setVisible(true);
}
public static void main(String[] args) {
new Breakout();
}
}
Board Class:
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class BreakBoard extends JPanel implements BreakCommons {
ImageIcon icon = new ImageIcon("../pacpix/love.jpg");
Timer timer;
String message = "Game Over";
BreakBall ball;
BreakPaddle paddle;
BreakBrick bricks[];
boolean ingame = true;
int timerId;
public BreakBoard() {
setOpaque(false);
addKeyListener(new TAdapter());
setFocusable(true);
//setBackground(Color.white);
bricks = new BreakBrick[30];
setDoubleBuffered(true);
timer = new Timer();
timer.scheduleAtFixedRate(new ScheduleTask(), 1000, 10);
}
public void paint(Graphics g) {
super.paint(g);
g.drawImage(icon.getImage(), 10, 10, this);
if (ingame) {
g.drawImage(ball.getImage(), ball.getX(), ball.getY(),
ball.getWidth(), ball.getHeight(), this);
g.drawImage(paddle.getImage(), paddle.getX(), paddle.getY(),
paddle.getWidth(), paddle.getHeight(), this);
for (int i = 0; i < 30; i++) {
if (!bricks[i].isDestroyed())
g.drawImage(bricks[i].getImage(), bricks[i].getX(),
bricks[i].getY(), bricks[i].getWidth(),
bricks[i].getHeight(), this);
}
} else {
Font font = new Font("Verdana", Font.BOLD, 18);
FontMetrics metr = this.getFontMetrics(font);
g.setColor(Color.BLACK);
g.setFont(font);
g.drawString(message,
(BreakCommons.WIDTH - metr.stringWidth(message)) / 2,
BreakCommons.WIDTH / 2);
}
Toolkit.getDefaultToolkit().sync();
g.dispose();
}
So the image is stored in variable icon and is located in my source files (along with my classes) so I know that the path is right. I tried setting the frame and panel to setOpaque(false) but that just changed the background to default grey. I can easily set the background color by setBackground(Color.white);, but how do I set an image?
I tried putting the image in a JLabel and then adding it to the JPanel, but that produced no results. I would appreciate any help, and thanks in advance! I can provide more information as needed.
easy way first create a separate class for jpane
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Paint;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
public class JPanelDemo extends JPanel {
/**
*
*/
private static final long serialVersionUID = 1L;
private static final Color BACKGROUND = Color.black;
private static final Color BACKGROUND_2 = Color.WHITE;
String path="/img/background.jpg";
#Override
protected void paintComponent(Graphics g) {
Graphics2D graphics = (Graphics2D) g.create();
int midY = 100;
Paint topPaint = new GradientPaint(0, 0, BACKGROUND,0, midY, BACKGROUND_2);
graphics.setPaint(topPaint);
graphics.fillRect(0, 0, getWidth(), midY);
Paint bottomPaint = new GradientPaint(0, midY + 1, BACKGROUND_2,0, getHeight(), BACKGROUND);
graphics.setPaint(bottomPaint);
graphics.fillRect(0, midY, getWidth(), getHeight());
Image img = new ImageIcon(getClass().getResource(path)).getImage();
int imgX = img.getWidth(null);
int imgY = img.getHeight(null);
graphics.drawImage(img, (getWidth() - imgX) / 2, (getHeight() - imgY) / 2, imgX, imgY, null);
// graphics.dispose();
}
}
how use it
JPanelDemo contentPane = new JPanelDemo();
This is a JPanel with a background image. Use IPanel in place of JPanel in your code. Tweak as necessary to suit your needs.
public class IPanel extends JPanel {
private static final long serialVersionUID = 1L;
private Image imageOrg = null;
private Image image = null;
{
addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(final ComponentEvent e) {
final int w = IPanel.this.getWidth();
final int h = IPanel.this.getHeight();
image = w > 0 && h > 0 ? imageOrg.getScaledInstance(w, h, Image.SCALE_SMOOTH) : imageOrg;
IPanel.this.repaint();
}
});
}
public IPanel(final Image i) {
imageOrg = i;
image = i;
}
#Override
public void paintComponent(final Graphics g) {
super.paintComponent(g);
if (image != null)
g.drawImage(image, 0, 0, null);
}
}
Example:
final JPanel j = new IPanel(image);
j.setLayout(new FlowLayout());
j.add(new JButton("YoYo"));
j.add(new JButton("MaMa"));
j.add(new JLabel(icon));
Produces:
I got it to work finally!
public class BreakBoard extends JPanel implements BreakCommons {
Image love;
public BreakBoard() {
ImageIcon icon = new ImageIcon(this.getClass().getResource("../pacpix/love.jpg"));
love = icon.getImage();
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(love, 10, 10, null);
}
}
For future searches or those that are curious, I used http://zetcode.com/tutorials/javagamestutorial/basics/. Great site for beginners! (Or those that need dumbing-down to understand)
JPanel panel = new JPanel()
{
#Override
public void paintComponent(Graphics g)
{
g.drawImage(ImageObject, 0, 0, null);
}
};
Related
So I want to rotate this Rectangle I made
public void paint (Graphics g)
{
super.paint(g);
Graphics2D g2 = (Graphics2D) g;
g2.fillRect(10, 10, 30, 30);
g2.rotate(Math.toRadians(45)); //I tried this but doesn't seem to work...
}
How do I do that? Rotate as in rotate in 45* angle or 200* angle.
It really isn't that hard to rotate objects. Most of the code below is simply boiler plate to create the frames and panels. Here is a demo that shows two methods that were mentioned in the comments.
the left panel simply rotates the graphics context. This is, imo, the easiest method but it does not alter the object.
the right panel uses the AffineTransform to rotate the object. This actually changes the contents of the shape.
If the desire is to rotate an object in place it is necessary to ensure one is rotating about the middle of the image that is under rotation. In both cases below that would be (125,125) or the center of both the panels and the rectangle.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.border.LineBorder;
public class RotateRectangle extends JPanel {
JFrame frame = new JFrame();
double angle = 0;
MyPanel mypanel = new MyPanel();
public static void main(String[] args) {
SwingUtilities
.invokeLater(() -> new RotateRectangle().start());
}
public void start() {
Timer t = new Timer(0, (ae) -> {mypanel.rotateit(); frame.repaint();});
t.setDelay(30);
t.start();
}
public RotateRectangle() {
frame.setLayout(new FlowLayout());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(this);
frame.add(mypanel);
setBorder(new LineBorder(Color.red,2));
mypanel.setBorder(new LineBorder(Color.red, 2));
frame.pack();
// center on screen
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
// visually smooth the lines
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setPaint(Color.BLACK);
g2d.rotate(angle, 125,125);
g2d.drawRect(75, 75, 100, 100);
// adjust the amount of rotation per timer interval
angle += Math.PI / 200;
g2d.dispose();
}
public Dimension getPreferredSize() {
return new Dimension(250, 250);
}
}
class MyPanel extends JPanel {
Polygon polygon = new Polygon();
// amount to rotate
double angle = Math.PI / 200;
Shape shape = polygon;
AffineTransform af = new AffineTransform();
public MyPanel() {
af.rotate(angle, 125,125);
polygon.addPoint(75,175);
polygon.addPoint(175,175);
polygon.addPoint(175,75);
polygon.addPoint(75,75);
}
public void rotateit() {
shape = af.createTransformedShape(shape);
}
public void paintComponent(Graphics g) {
if (shape == null) {
return;
}
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
// visually smooth the lines
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setPaint(Color.BLACK);
g2d.draw(shape);
}
public Dimension getPreferredSize() {
return new Dimension(250, 250);
}
}
Following up on my comment, I created the following GUI.
I used math to calculate the four endpoints of a rotated rectangle and used the Graphics2D fillPolygon method to draw the rectangle.
The buttons at the bottom of the GUI allow you to rotate the rectangle on the center point or the upper left endpoint.
I created a drawing JPanel to draw the rectangle. All the paintComponent method of the drawing JPanel does is draw the Polygon returned by the application model.
The application model is a key part of this application. I create a plain Java getter / setter class. I start with a java.awt.Rectangle and use polar coordinates to rotate the rectangle. I convert the polar coordinates back to cartesian coordinates to get the four endpoints of the Polygon.
Here's the complete runnable code.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class RotatingRectangle implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new RotatingRectangle());
}
private DrawingPanel drawingPanel;
private JButton centerButton;
private JButton endPointButton;
private RotatedRectangle rotatedRectangle;
public RotatingRectangle() {
this.rotatedRectangle = new RotatedRectangle(Color.BLUE,
new Rectangle(200, 200, 100, 50));
}
#Override
public void run() {
JFrame frame = new JFrame("Rotating Rectangle");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.drawingPanel = new DrawingPanel(rotatedRectangle);
frame.add(drawingPanel, BorderLayout.CENTER);
frame.add(createButtonPanel(), BorderLayout.AFTER_LAST_LINE);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public JPanel createButtonPanel() {
JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 5));
ButtonListener listener = new ButtonListener(this, rotatedRectangle);
centerButton = new JButton("Rotate on center point");
centerButton.addActionListener(listener);
panel.add(centerButton);
endPointButton = new JButton("Rotate on end point");
endPointButton.addActionListener(listener);
endPointButton.setPreferredSize(centerButton.getPreferredSize());
panel.add(endPointButton);
return panel;
}
public void repaint() {
drawingPanel.repaint();
}
public JButton getCenterButton() {
return centerButton;
}
public JButton getEndPointButton() {
return endPointButton;
}
public class DrawingPanel extends JPanel {
private static final long serialVersionUID = 1L;
private RotatedRectangle rotatedRectangle;
public DrawingPanel(RotatedRectangle rotatedRectangle) {
this.rotatedRectangle = rotatedRectangle;
this.setBackground(Color.WHITE);
this.setPreferredSize(new Dimension(400, 400));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Polygon polygon = rotatedRectangle.getRectangle();
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(rotatedRectangle.getColor());
g2d.fillPolygon(polygon);
}
}
public class ButtonListener implements ActionListener {
private final RotatingRectangle frame;
private final RotatedRectangle model;
private Timer timer;
public ButtonListener(RotatingRectangle frame, RotatedRectangle model) {
this.frame = frame;
this.model = model;
}
#Override
public void actionPerformed(ActionEvent event) {
if (timer != null) {
timer.stop();
}
JButton button = (JButton) event.getSource();
if (button.equals(frame.getEndPointButton())) {
model.setCenterPoint(false);
model.setAngle(180);
} else {
model.setCenterPoint(true);
model.setAngle(0);
}
timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
model.incrementAngle(1);
frame.repaint();
}
});
timer.start();
}
}
public class RotatedRectangle {
private boolean centerPoint;
private int angle;
private final Color color;
private final Rectangle rectangle;
public RotatedRectangle(Color color, Rectangle rectangle) {
this.color = color;
this.rectangle = rectangle;
this.angle = 0;
this.centerPoint = true;
}
public int getAngle() {
return angle;
}
public void setAngle(int angle) {
this.angle = angle;
}
public void incrementAngle(int increment) {
this.angle += increment;
this.angle %= 360;
}
public Polygon getRectangle() {
Point rotatePoint = new Point(rectangle.x, rectangle.y);
if (isCenterPoint()) {
int x = rectangle.x + rectangle.width / 2;
int y = rectangle.y + rectangle.height / 2;
rotatePoint = new Point(x, y);
}
Point[] point = new Point[4];
int width = rectangle.x + rectangle.width;
int height = rectangle.y + rectangle.height;
point[0] = new Point(rectangle.x, rectangle.y);
point[1] = new Point(width, rectangle.y);
point[2] = new Point(width, height);
point[3] = new Point(rectangle.x, height);
Polygon polygon = new Polygon();
for (int i = 0; i < point.length; i++) {
point[i] = calculatePoint(rotatePoint, point[i], angle);
polygon.addPoint(point[i].x, point[i].y);
}
return polygon;
}
private Point calculatePoint(Point rotatePoint, Point point, int angle) {
double theta = Math.toRadians(angle);
int xDistance = rotatePoint.x - point.x;
int yDistance = rotatePoint.y - point.y;
double distance = Math.sqrt(xDistance * xDistance + yDistance * yDistance);
double alpha = Math.atan2(yDistance, xDistance);
theta += alpha;
int x = (int) Math.round(Math.cos(theta) * distance) + rotatePoint.x;
int y = (int) Math.round(Math.sin(theta) * distance) + rotatePoint.y;
return new Point(x, y);
}
public Color getColor() {
return color;
}
public boolean isCenterPoint() {
return centerPoint;
}
public void setCenterPoint(boolean centerPoint) {
this.centerPoint = centerPoint;
}
}
}
I am using a JSeparator in my java swing application. The normal implementation makes the separator normal line; but what I need is the separator should be dashed(like we create dashed border). Is there any way we can do that?
Thanks
To create a custom JSeparator, you can override the paint() method of BasicSeparatorUI, discussed here, and draw the line using a dashed Stroke, illustrated here.
Addendum: A more familiar approach overrides paintComponent(), as shown in the accepted answer and encapsulated conveniently in this StrokedSeparator. The variation below replaces drawLine() with draw() using a Line2D, which takes advantage of the stroke's geometry.
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Stroke;
import java.awt.geom.Line2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import static javax.swing.JSeparator.*;
/**
* #see https://stackoverflow.com/a/74657060/230513
*/
public class StrokeSepTest {
private static final int N = 10;
private void display() {
var f = new JFrame("StrokeSepTest");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
var stroke = new BasicStroke(8.0f, BasicStroke.CAP_BUTT,
BasicStroke.JOIN_MITER, 10.0f, new float[]{5.0f}, 0.0f);
var panel = new JPanel(new GridLayout(0, 1)) {
#Override
public Dimension getPreferredSize() {
return new Dimension(320, 240);
}
};
panel.setBackground(Color.white);
for (int i = 0; i < N; i++) {
Color color = Color.getHSBColor((float) i / N, 1, 1);
panel.add(new StrokedSeparator(stroke, HORIZONTAL, color));
}
f.add(panel);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
// #see https://stackoverflow.com/a/74657060/230513 */
private static class StrokedSeparator extends JSeparator {
private Stroke stroke;
public StrokedSeparator() {
this(new BasicStroke(1F), HORIZONTAL);
}
public StrokedSeparator(int orientation) {
this(new BasicStroke(1F), orientation);
}
public StrokedSeparator(Stroke stroke) {
this(stroke, HORIZONTAL);
}
public StrokedSeparator(Stroke stroke, int orientation) {
super(orientation);
this.stroke = stroke;
}
public StrokedSeparator(Stroke stroke, int orientation, Color color) {
super(orientation);
super.setForeground(color);
this.stroke = stroke;
}
#Override
public void paintComponent(Graphics g) {
var graphics = (Graphics2D) g;
var s = getSize();
graphics.setStroke(stroke);
graphics.setColor(getForeground());
if (getOrientation() == JSeparator.VERTICAL) {
graphics.draw(new Line2D.Double(0, 0, 0, s.height));
} else // HORIZONTAL
{
graphics.draw(new Line2D.Double(0, 0, s.width, 0));
}
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new StrokeSepTest()::display);
}
}
You can use the following code snippet to create a dashed line.
import java.awt.Container;
import java.awt.Graphics;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JSeparator;
public class SeparatorSample {
public static void main(String args[]) {
JFrame f = new JFrame("JSeparator Sample");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container content = f.getContentPane();
content.setLayout(new GridLayout(0, 1));
JLabel above = new JLabel("Above Separator");
content.add(above);
JSeparator separator = new JSeparator() {
private static final long serialVersionUID = 1L;
public void paintComponent(Graphics g) {
for (int x = 0; x < 300; x += 15)
g.drawLine(x, 0, x + 10, 0);
}
};
content.add(separator);
JLabel below = new JLabel("Below Separator");
content.add(below);
f.setSize(300, 100);
f.setVisible(true);
}
}
With a slight modification to trashgod's answer, I found that using paintComponent() rather than paint() works very well for me:
Stroke stroke = new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f, new float[] { 5.0f },
0.0f);
JSeparator separator = new StrokedSeparator(stroke);
// Add separator to container
And here's the StrokedSeparator class:
import java.awt.BasicStroke;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Stroke;
import javax.swing.JSeparator;
public class StrokedSeparator extends JSeparator {
private static final long serialVersionUID = 1L;
private Stroke stroke;
public StrokedSeparator() {
this(new BasicStroke(1F), HORIZONTAL);
}
public StrokedSeparator(int orientation) {
this(new BasicStroke(1F), orientation);
}
public StrokedSeparator(Stroke stroke) {
this(stroke, HORIZONTAL);
}
public StrokedSeparator(Stroke stroke, int orientation) {
super(orientation);
this.stroke = stroke;
}
#Override
public void paintComponent(Graphics g) {
Dimension s = getSize();
Graphics2D graphics = (Graphics2D) g;
graphics.setStroke(stroke);
if (getOrientation() == JSeparator.VERTICAL) {
graphics.setColor(getForeground());
graphics.drawLine(0, 0, 0, s.height);
graphics.setColor(getBackground());
graphics.drawLine(1, 0, 1, s.height);
} else // HORIZONTAL
{
graphics.setColor(getForeground());
graphics.drawLine(0, 0, s.width, 0);
graphics.setColor(getBackground());
graphics.drawLine(0, 1, s.width, 1);
}
}
}
I have a very specific question:
I want to be able to, via a method call, popup a tooltip with text(it could say anything) in a given location on the screen for a certain amount of time on method call(say the logic is in a talk method) and fades away. How could I go about that? Is there a way to do it via JTooltip? Or would I have to dive into JNA to get what I want?
I should mention I want the tooltip to popup with text in a given location without the cue of a mouse over, like a popup.
Also, in case a tooltip is not the right way to go about what I want (which I hope I made clear), is there a more effective alternative?
There are few ways this might be achieved. One possible way is through the use of a transparent JWindow and a Swing Timer
Basically, what this does is creates a JWindow, set's it's background color to fully transparent, making a transparent window. It then uses simple BackgroundPane (to render a nice background) and MessagePane to hold the actual message. You can do this in one panel, but I like the flexibility this affords me.
Now, personally, I would create a simpler API which could build the popup window and create a Timer with a variable delay, but you get the idea
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.LinearGradientPaint;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.RoundRectangle2D;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JWindow;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
public class PopupMessageWindow {
public static void main(String[] args) {
new PopupMessageWindow();
}
public PopupMessageWindow() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
final JWindow frame = new JWindow();
frame.setBackground(new Color(0, 0, 0, 0));
BackgroundPane pane = new BackgroundPane();
pane.setMessage("Boo, This is a popup...");
frame.add(pane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.setAlwaysOnTop(true);
Timer timer = new Timer(10000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
frame.dispose();
System.exit(0);
}
});
timer.setRepeats(false);
timer.start();
}
});
}
public class BackgroundPane extends JPanel {
private MessagePane messagePane;
public BackgroundPane() {
setBorder(new EmptyBorder(40, 40, 40, 40));
messagePane = new MessagePane();
setLayout(new BorderLayout());
add(messagePane);
setOpaque(false);
}
public void setMessage(String msg) {
messagePane.setMessage(msg);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
LinearGradientPaint glp = new LinearGradientPaint(
new Point(0, 0),
new Point(0, getHeight()),
new float[]{0f, 1f},
new Color[]{Color.GRAY, Color.BLACK});
RoundRectangle2D frame = new RoundRectangle2D.Float(0, 0, getWidth() - 1, getHeight() - 1, 20, 20);
g2d.setPaint(glp);
g2d.fill(frame);
g2d.setColor(Color.WHITE);
g2d.draw(frame);
}
}
public class MessagePane extends JPanel {
private JLabel label;
public MessagePane() {
setOpaque(false);
label = new JLabel();
label.setForeground(Color.WHITE);
setLayout(new GridBagLayout());
add(label);
}
public void setMessage(String msg) {
label.setText(msg);
}
}
}
You could play with a AlphaComposite on the background panel to create a semi transparent background
Popup window using a 50% AlphaComposite
Updated
You could use a factory or builder pattern to provide a simple API, for example...
new PopupBuilder().at(new Point(100, 100)).withMessage("Hello").withDelay(5000).show();
The builder would collect the properties you want to specify, provide defaults where you didn't set them and then would show the final popup.
The basic idea is when you call show, it would collect the properties and build the window similar to how the constructor works right now...
Updated with a fading popup window
This is (a somewhat over the top) example of how you might be able to produce a fading in/out effect. The example guarantees that the message will be on the screen (full) for at specified delay period
import java.awt.AlphaComposite;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.LinearGradientPaint;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.RoundRectangle2D;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JWindow;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
public class PopupMessageExample {
public static void main(String[] args) {
new PopupMessageExample();
}
public PopupMessageExample() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
new PopupMessageBuilder().withDelay(10000).withMessage("Hello, this is a fading message").show();
}
});
}
public class PopupMessageBuilder {
private int delay;
private Point location;
private String message;
private long startTime;
private Timer fadeTimer;
public PopupMessageBuilder at(Point p) {
this.location = p;
return this;
}
public PopupMessageBuilder withDelay(int delay) {
this.delay = delay;
return this;
}
public PopupMessageBuilder withMessage(String msg) {
this.message = msg;
return this;
}
public PopupMessageBuilder show() {
final JWindow frame = new JWindow();
frame.setOpacity(0f);
frame.setBackground(new Color(0, 0, 0, 0));
BackgroundPane pane = new BackgroundPane();
pane.setMessage(message);
frame.add(pane);
frame.pack();
if (location == null) {
frame.setLocationRelativeTo(null);
} else {
frame.setLocation(location);
}
frame.setVisible(true);
frame.setAlwaysOnTop(true);
new FadeTimer(frame, 1000, 0f, 1f, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Timer timer = new Timer(delay, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
new FadeTimer(frame, 1000, 1f, 0f, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
frame.dispose();
}
}).start();
}
});
timer.setRepeats(false);
timer.start();
}
}).start();
return this;
}
public class FadeTimer extends Timer implements ActionListener {
private final float startAt;
private final float endAt;
private final int duration;
private long startTimer;
private ActionListener endListener;
private Window window;
public FadeTimer(Window window, int duration, float startAt, float endAt, ActionListener endListener) {
super(5, null);
addActionListener(this);
this.duration = duration;
this.startAt = startAt;
this.endAt = endAt;
this.window = window;
this.endListener = endListener;
}
#Override
public void start() {
startTime = System.currentTimeMillis();
super.start();
}
#Override
public void actionPerformed(ActionEvent e) {
long now = System.currentTimeMillis();
long lapsed = now - startTime;
float opacity = startAt;
if (lapsed >= duration) {
opacity = endAt;
((Timer) e.getSource()).stop();
if (endListener != null) {
endListener.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "stopped"));
}
} else {
float progress = (float) lapsed / (float) duration;
float distance = endAt - startAt;
opacity = (float) (distance * progress);
opacity += startAt;
}
window.setOpacity(opacity);
}
}
public class BackgroundPane extends JPanel {
private MessagePane messagePane;
public BackgroundPane() {
setBorder(new EmptyBorder(40, 40, 40, 40));
messagePane = new MessagePane();
setLayout(new BorderLayout());
add(messagePane);
setOpaque(false);
}
public void setMessage(String msg) {
messagePane.setMessage(msg);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
LinearGradientPaint glp = new LinearGradientPaint(
new Point(0, 0),
new Point(0, getHeight()),
new float[]{0f, 1f},
new Color[]{Color.GRAY, Color.BLACK});
RoundRectangle2D frame = new RoundRectangle2D.Float(0, 0, getWidth() - 1, getHeight() - 1, 20, 20);
g2d.setPaint(glp);
g2d.fill(frame);
g2d.setColor(Color.WHITE);
g2d.draw(frame);
}
}
public class MessagePane extends JPanel {
private JLabel label;
public MessagePane() {
setOpaque(false);
label = new JLabel();
label.setForeground(Color.WHITE);
setLayout(new GridBagLayout());
add(label);
}
public void setMessage(String msg) {
label.setText(msg);
}
}
}
}
Now, you probably also do this by changing the maximum opacity level of the frame, but, if you change the paintComponent of the BackgroundPane
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
AlphaComposite alpha = AlphaComposite.SrcOver.derive(0.75f);
g2d.setComposite(alpha);
you can also effect the over opacity of the popup message. This method will only effect the background, not the message text...
I created a background using a relatively bland texture (it repeats well, so that's a bonus). However, on top of that, I am trying to add two images in random positions, each five times. So I tried that out with this -
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Insets;
import java.io.File;
import java.io.IOException;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class RepeatDiagonals {
public static Image whiteOverlayStreak;
public static Image blackOverlayStreak;
public static JFrame framePanel;
public static DiagonalImages diagTest;
public static void createAndInitGUI() {
diagTest = new DiagonalImages();
framePanel = new JFrame("Diagonal Testing");
framePanel.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
framePanel.setPreferredSize(new Dimension(1020, 720));
framePanel.add(diagTest);
framePanel.pack();
framePanel.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndInitGUI();
} // public void run() Closing
}); // SwingUtilities Closing
}
}
// TODO Add in constructor for better image import
class DiagonalImages extends JPanel {
public static final String IMAGE_PATH_WHITESTREAK = "imageFolder/whiteBackgroundStreakOverlay.png";
public static final String IMAGE_PATH_BLACKSTREAK = "imageFolder/blackBackgroundStreakOverlay.png";
public static Image whiteOverlayStreak;
public static Image blackOverlayStreak;
public static Image overlayStreak;
DiagonalImages() {
loadImages();
setVisible(true);
setOpaque(false);
};
public void loadImages() {
try {
whiteOverlayStreak = ImageIO.read(new File(IMAGE_PATH_WHITESTREAK));
blackOverlayStreak = ImageIO.read(new File(IMAGE_PATH_BLACKSTREAK));
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
Dimension size = this.getSize();
Insets insets = this.getInsets();
int w = size.width - insets.left - insets.right;
int h = size.height - insets.top - insets.bottom;
Random randomInteger = new Random();
randomInteger.nextInt(900);
for (int i = 0; i < 3; i++) {
int x = randomInteger.nextInt() % w;
int y = randomInteger.nextInt() % h;
g2d.drawImage(blackOverlayStreak, x, y, null);
}
for (int i2 = 0; i2 < 5; i2++){
int x2 = randomInteger.nextInt() % w;
int y2 = randomInteger.nextInt() % h;
g2d.drawImage(whiteOverlayStreak, x2, y2, null);
}
}
}
The relevant part of the main code:
// Makes the Initial BorderLayout
allContent = new ImagePanel(image);
allContent.setLayout(new BorderLayout());
allContent.add(new DiagonalImages());
allContent.add(tabbedPane, BorderLayout.CENTER);
allContent.add(logoImage, BorderLayout.NORTH);
allContent.setVisible(true);
allContent.setOpaque(false);
// Add ScrollPane
scrollPane = new JScrollPane(allContent);
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
scrollPane.getVerticalScrollBar().setUnitIncrement(10);
scrollPane.setOpaque(false);
scrollPane.getViewport().setOpaque(false);
scrollPane.setBorder(new EmptyBorder(0, 0, 0, 0));
scrollPane.setWheelScrollingEnabled(true);
// JFrame programFrame Constructors
programFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
programFrame.setLayout(new BorderLayout());
programFrame.add(scrollPane);
programFrame.pack();
programFrame.setVisible(true);
programFrame.setResizable(true);
programFrame.setSize(1280, 720);
programFrame.setLocationRelativeTo(null);
And here's the ImagePanel I have:
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.JPanel;
class ImagePanel extends JPanel {
private Image image;
private boolean tile;
ImagePanel(Image image) {
this.image = image;
this.tile = false;
};
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
int iw = image.getWidth(this);
int ih = image.getHeight(this);
if (iw > 0 && ih > 0) {
for (int x = 0; x < getWidth(); x += iw) {
for (int y = 0; y < getHeight(); y += ih) {
g.drawImage(image, x, y, iw, ih, this);
}
}
}
}
}
Thanks for the (future) help!
EDIT: Made a small change based on the answer given, and it's still not working.
Okay, so the problem is that the image that's supposed to be repeated isn't actually even showing up.
EDIT2: Rewrote my entire code for this, and it's still not working. Even setting the background color isn't working, which leads me to believe it's a problem with my paintComponent.
EDIT3: paintComponent is working thanks to help. My final problem is getting it to work correctly in my main method.
First JFrame.setVisible(true); should be done last, after pack() which does layouting.
framePanel.pack();
framePanel.setVisible(true);
The images maybe better reside in the application (jar) itself, then you can use getClass().getResource("...").
They should be loaded outside paint, say in the constructor. I guess, it was test code.
public static Image whiteOverlayStreak;
public static Image blackOverlayStreak;
DiagonalImages() {
loadImages();
}
private void loadImages() {
whiteOverlayStreak = new ImageIcon(
getClass().getResource("/white.jpg")).getImage();
blackOverlayStreak = new ImageIcon(
getClass().getResource("/black.jpg")).getImage();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
int x = r.nextInt(w);
int y = r.nextInt(h);
Your failure was not using #Override because then you would have seen, that you miswrote Graphics2D g instead of Graphics g. The function paintComponent never got called! LoL
Additional question: adding a second panel
framePanel.setLayout(new BorderLayout());
framePanel.add(diagTest, BorderLayout.CENTER);
framePanel.add(otherPanel, BorderLayout.SOUTH);
It wasn't really an SSCCE.
I haven't tested this fully, mainly because I didn't want to have to set up an entire Eclipse project just to point out the obvious mistake.
Separate the image process from the JPanel.
Only extend Swing components when you're modifying a component method.
Here's my version of your code. I had to modify your code to read an image to get it to work. You're going to have to figure out that part of the code yourself.
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Insets;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
class GUIImages {
private Image whiteDiagonal;
// private Image blackDiagonal;
public GUIImages() {
loadImages();
}
private void loadImages() {
try {
whiteDiagonal = ImageIO.read(new File(
"C:/Documents and Settings/BOP00082/" +
"My Documents/My Pictures/Places-icon.png"));
} catch (IOException e) {
e.printStackTrace();
}
// whiteDiagonal = new ImageIcon(this.getClass().getResource(
// "imageFolder/whiteBackgroundStreakOverlay.png")).getImage();
// blackDiagonal = new ImageIcon(this.getClass().getResource(
// "imageFolder/blackBackgroundStreakOverlay.png")).getImage();
}
public void doDrawing(JPanel panel, Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(createDiagonalImage(panel), 0, 0, null);
}
private Image createDiagonalImage(JPanel panel) {
BufferedImage buffImg = new BufferedImage(677, 856,
BufferedImage.TYPE_INT_ARGB);
Graphics2D gbi = buffImg.createGraphics();
Dimension size = panel.getSize();
Insets insets = panel.getInsets();
int w = size.width - insets.left - insets.right;
int h = size.height - insets.top - insets.bottom;
Random r = new Random();
for (int i = 0; i < 5; i++) {
int x = Math.abs(r.nextInt()) % w;
int y = Math.abs(r.nextInt()) % h;
gbi.drawImage(whiteDiagonal, x, y, null);
}
gbi.dispose();
return buffImg;
}
}
class Surface extends JPanel {
GUIImages images;
public Surface(GUIImages images) {
this.images = images;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
images.doDrawing(this, g);
}
}
public class RepeatDiagonals implements Runnable {
JFrame frame;
#Override
public void run() {
frame = new JFrame();
frame.setTitle("Repeat Diagonals");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Surface(new GUIImages()));
frame.setSize(350, 250);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new RepeatDiagonals());
}
}
I am writing a test app. To set Alpha for image I use paintComponent method. Watch next snippet...
public class TestImage extends JLabel{
public void paintComponent( Graphics g ) {
super.paintComponent( g );
Graphics2D g2d=(Graphics2D)g;
g2d.drawImage(this.bImage, rop, 0, 0);
}
public void setRescaleOp(RescaleOp rop){this.rop=rop;}
}
As you can see,
g2d.drawImage(this.bImage, rop, 0, 0);
does not allow to set width and height as if I use g.drawImage(bImage, 0, 0,width,height, null);
So the question is... How to set width and height for bImage in this case?
Any useful comment is appreciated
Andrew
First filter(), as shown here, and then scale using drawImage() or AffineTransformOp, as shown here.
Addendum: Alternatively, you can scale the image first (using either approach above) and then use your RescaleOp in drawImage().
As an aside, RescaleOp scales the image's color bands; it does not change the image's dimensions. To avoid confusion, dimensional scaling is sometimes called resampling.
Addendum: Here's an example of using drawImage() to resample and RescaleOp to adjust the alpha of an image.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.RescaleOp;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
/**
* #see https://stackoverflow.com/questions/5838842
* #see https://stackoverflow.com/questions/5864490
*/
public class AlphaTest {
private static void display() {
JFrame f = new JFrame("AlphaTest");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ImageIcon icon = new ImageIcon("image.jpg");
final AlphaPanel ip = new AlphaPanel(icon, 0.75);
final JSlider slider = new JSlider();
slider.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
int v = slider.getValue();
ip.setAlpha((float) v / slider.getMaximum());
ip.repaint();
}
});
f.add(ip, BorderLayout.CENTER);
f.add(slider, BorderLayout.SOUTH);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
display();
}
});
}
}
class AlphaPanel extends JPanel {
private BufferedImage bi;
private float[] scales = {1f, 1f, 1f, 0.5f};
private float[] offsets = new float[4];
private RescaleOp rop;
public AlphaPanel(ImageIcon icon, double scale) {
int width = (int) (scale * icon.getIconWidth());
int height = (int) (scale * icon.getIconHeight());
this.setPreferredSize(new Dimension(width, height));
this.bi = new BufferedImage(
width, height, BufferedImage.TYPE_INT_ARGB);
this.bi.createGraphics().drawImage(
icon.getImage(), 0, 0, width, height, null);
rop = new RescaleOp(scales, offsets, null);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(bi, rop, 0, 0);
}
public void setAlpha(float alpha) {
this.scales[3] = alpha;
this.rop = new RescaleOp(scales, offsets, null);
}
}