How to draw something over all components of a Panel?
In the code below I tried to do this overriding the paintComponent method, I call super.paintComponent(g) hoping this will draw all components added as part of the constructor, but still my X stays below the image.
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Stack extends JPanel {
private final JLabel some_text = new JLabel("Some very long text that will be covered", JLabel.LEFT);
private final JLabel some_icon = new JLabel((Icon)null, JLabel.CENTER);
public static final String COMPASS_URL = "https://upload.wikimedia.org/wikipedia/commons/thumb/f/f8/Compass_Rose_English_North.svg/240px-Compass_Rose_English_North.svg.png";
public Stack() throws IOException {
super(new GridBagLayout());
URL compassUrl = new URL(COMPASS_URL);
BufferedImage compassImage = ImageIO.read(compassUrl);
ImageIcon compassIcon = new ImageIcon(compassImage);
some_icon.setIcon(compassIcon);
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 0;
c.gridy = 0;
add(some_icon, c);
c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 0;
c.gridy = 1;
add(some_text, c);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
g2.setColor(Color.RED);
g2.setStroke(new BasicStroke(15));
g2.drawLine(0, 0, this.getWidth(), this.getHeight());
g2.drawLine(this.getWidth(), 0, 0, this.getHeight());
g2.dispose();
}
private static void createAndShowUI() throws IOException {
JFrame frame = new JFrame("MyFrame");
frame.getContentPane().add(new Stack());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
try {
createAndShowUI();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
}
Is there a way to bring my X to the foreground or to wait for super.paintComponent(g) to paint everything, and then run the code that draws the X?
Thanks,
Roberto
Override the paint(…) method of your JPanel:
protected void paint(Graphics g)
{
super.paint(g);
// add custom painting code here
}
The paint(…) method invokes the paintChildren(…) method so your custom code will be executed after all the components on the panel are painted.
See A Closer Look at the Painting Mechanism for more information.
Try this. I made the following changes.
Drew the image in paintComponent as opposed to setIcon.
positioned the image to center it.
used setPreferredSize for real panel size (setting frame size includes borders which is probably not what you wanted).
used RenderingHints in paintComponent to smooth out edges of cross.
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Stack2 extends JPanel {
private final JLabel some_text = new JLabel(
"Some very long text that will be covered", JLabel.LEFT);
private final JLabel some_icon =
new JLabel((Icon) null, JLabel.CENTER);
public static final String COMPASS_URL =
"https://upload.wikimedia.org/wikipedia/commons/thumb/f/f8/Compass_Rose_English_North.svg/240px-Compass_Rose_English_North.svg.png";
BufferedImage compassImage;
public Stack2() throws IOException {
super(new GridBagLayout());
URL compassUrl = new URL(COMPASS_URL);
compassImage = ImageIO.read(compassUrl);
// ImageIcon compassIcon = new ImageIcon(compassImage);
// some_icon.setIcon(compassIcon);
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 0;
c.gridy = 0;
add(some_icon, c);
c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 0;
c.gridy = 1;
add(some_text, c);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.drawImage(compassImage,
(400 - compassImage.getWidth()) / 2,
(400 - compassImage.getHeight()) / 2, null);
g2.setColor(Color.RED);
g2.setStroke(new BasicStroke(15));
g2.drawLine(0, 0, this.getWidth(), this.getHeight());
g2.drawLine(this.getWidth(), 0, 0, this.getHeight());
g2.dispose();
}
private static void createAndShowUI() throws IOException {
JFrame frame = new JFrame("MyFrame");
Stack2 panel = new Stack2();
frame.getContentPane().add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel.setPreferredSize(new Dimension(400, 400));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
try {
createAndShowUI();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
}
Related
This question already exists:
How to set size for custom-made panel that will work with gridbaglayout?
Closed 6 years ago.
I have one panel whit gridBagLayout and second with null gridlayout. When I add that to main panel, and main panel to frame one panel disappears. Why is that? And how to add two panels with different layouts setings in one frame?
Here is the code main #Beowolve:
import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class PrikazGUI {
JFrame frejm;
JPanel k;
JButton b1,b2;
public PrikazGUI(){
frejm = new JFrame("Lala");
k = new JPanel();
KvadratPravi p = new KvadratPravi();
JPanel grid = new JPanel();
grid.setLayout(new GridBagLayout());
grid.add(p);
// Kvadrat l = new Kvadrat();
JosJedanKvadrat jos = new JosJedanKvadrat();
// k.setLayout(null);
// k.setBounds(0, 444,444, 445);
k.add(jos);
k.add(grid);
JPanel main = new JPanel();
main.setLayout(null);
k.setBounds(0, 0,1000, 1900);
main.setBounds(0, 0,1000, 1900);
main.add(k);
frejm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frejm.setSize(1900, 1000);
frejm.getContentPane().add(main);
// frejm.getContentPane().add(k);
// frejm.pack();
frejm.setVisible(true);
}
public static void main(String[] args) {
PrikazGUI a = new PrikazGUI();
}
}
Second class:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JPanel;
public class KvadratPravi extends JPanel {
int sizeH = 60;
int sizeW = 60;
public GridBagConstraints cst = new GridBagConstraints();
public KvadratPravi() {
JPanel j = new JPanel();
j.setLayout(new GridBagLayout());
cst.gridx = 0;
cst.gridy = 0;
add(j,cst);
}
#Override
protected void paintComponent(Graphics g) {
// TODO Auto-generated method stub
super.paintComponent(g);
g.setColor(Color.PINK);
g.drawRect(0, 0, sizeH, sizeW);
g.fillRect(0, 0, sizeH, sizeW);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(sizeH,sizeW);
}
}
Third class:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.JPanel;
public class JosJedanKvadrat extends JPanel {
int sizeH = 60;
int sizeW = 60;
int x,y;
public JosJedanKvadrat() {
setBounds(33, 44,444, 445);
JPanel j = new JPanel();
setLayout(null);
add(j);
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
if(!e.isMetaDown()){
x = e.getX();
y = e.getY();
}
}
});
addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent e) {
if(!e.isMetaDown()){
Point p = getLocation();
setLocation(p.x + e.getX() - x,
p.y + e.getY() - y);
}
}
});
}
#Override
protected void paintComponent(Graphics g) {
// TODO Auto-generated method stub
super.paintComponent(g);
g.setColor(Color.BLUE);
g.drawOval(0, 0, sizeH, sizeW);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(sizeH,sizeW);
}
}
So I whant second class be in center of panel,and to have gridBagLayout, and third class I whant to move around the objects,so that class dont have gridlayout...when I and that two panels to main pane its seems that second class whit gridBagLayout does not working.
You are currently adding two JPanel into a JFrame.
JFrame f = new JFrame();
This frame, by default, use a BorderLayout. So if you call f.add(new Panel()); multiple time only the last one will be visible since the center area of this layout can only show one JComponent. You need to use a different layout.
this is my problem, I hope you will help me somehow. I have one class that extends JPanel, and that class is creating a rectangle with a paintComponent method. When I add that class to JPanel who has gridBagLayout,first is not appearing. But, when I set Dimension.getPreferredSize() in that class, I can see the rectangle...and the problem is when I call MouseListener and see that rectangle is only moving in little square in the frame. So I think that somehow that method getPreferredSize() is controlling the place where will rectangle move and be.
Here is pic of my problem:
move3
limitet showing/moving4
Here is code:
Main:
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class PrikazGUI {
JFrame frejm;
JPanel k;
JButton b1,b2;
public PrikazGUI(){
frejm = new JFrame("Lala");
k = new JPanel();
k.setLayout(new GridBagLayout());
Kvadrat l = new Kvadrat();
JPanel a = new JPanel();
a.add(l);
k.add(a);
frejm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frejm.setSize(1900, 1000);
frejm.getContentPane().add(k);
frejm.setVisible(true);
}
public static void main(String[] args) {
PrikazGUI a = new PrikazGUI();
}
Second class:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JPanel;
public class KvadratPravi extends JPanel {
int sizeH = 60;
int sizeW = 60;
#Override
protected void paintComponent(Graphics g) {
// TODO Auto-generated method stub
super.paintComponent(g);
g.setColor(Color.PINK);
g.drawRect(0, 0, sizeH, sizeW);
g.fillRect(0, 0, sizeH, sizeW);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(sizeH,sizeW);
}
}
Third class:
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.JButton;
import javax.swing.JPanel;
public class Kvadrat extends JPanel {
JButton b1,b2;
JPanel panel;
KvadratPravi s1 = new KvadratPravi();
int x,y;
public Kvadrat(){
GridBagConstraints cst = new GridBagConstraints();
panel = new JPanel();
panel.setLayout(new GridBagLayout());
final KvadratPravi s = new KvadratPravi();
cst.gridx = 0;
cst.gridy = 0;
s.setPreferredSize(new Dimension(40,40));
s.setBounds(0, 0, 400, 400);
panel.add(s,cst);
JosJedanKvadrat j = new JosJedanKvadrat();
j.setPreferredSize(new Dimension(40,40));
j.setBounds(0, 0, 400, 400);
cst.gridx = 0;
cst.gridy = 4;
panel.add(j,cst);
s.setPreferredSize(new Dimension(400,400));
s.setBounds(400, 400, 400, 1000);
s.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
if(!e.isMetaDown()){
x = e.getX();
y = e.getY();
}
}
});
s.addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent e) {
if(!e.isMetaDown()){
Point p = s.getLocation();
s.setLocation(p.x + e.getX() - x,
p.y + e.getY() - y);
}
}
});
cst.gridx = 2;
cst.gridy =4;
panel.add(s1,cst);
JPanel k = new JPanel();
k.add(panel);
add(k);
}
}
Fourth class:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JPanel;
public class JosJedanKvadrat extends JPanel {
int sizeH = 60;
int sizeW = 60;
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.drawOval(0, 0, sizeH, sizeW);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(sizeH,sizeW);
}
}
The intention of my code is to create a rectangle when the button is clicked. The button works fine but the rectangle itself is not showing up on the screen, and there are no errors. Thank you for helping btw.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Tester {
static JButton button;
static JFrame frame;
static JPanel panel;
static Rectangle rec;
static void init(){
button = new JButton();
frame = new JFrame();
panel = new JPanel();
rec = new Rectangle(30,30,30,30);
button.setVisible(true);
panel.add(button);
frame.add(panel);
frame.setVisible(true);
panel.setVisible(true);
frame.setSize(200, 200);
button.setBackground(Color.GREEN);
button.setBounds(30, 30, 20, 20);
}
public static void main(String[] args) {
init();
ActionListener listener = new RectangleMover();
button.addActionListener(listener);
}
static class RectangleMover implements ActionListener{
#Override
public void actionPerformed(ActionEvent arg0) {
RectanglePainter r = new RectanglePainter();
r.add(rec);
}
}
static class RectanglePainter extends JPanel{
void add(Rectangle r){
rec = r;
repaint();
}
protected void paintComponent(Graphics g){
Graphics2D g2 = (Graphics2D) g;
Random r = new Random();
int i =r.nextInt(2);
if (i==1)
g2.setColor(Color.BLUE);
else
g2.setColor(Color.RED);
g2.fill(rec);
g2.draw(rec);
}
}
}
Your generally approach is slightly skewed, rather than using another JComponent to "act" as the shape, you should be using it to paint all the shapes through it's paintComponent method
From my "red rectangle" period...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Tester {
public static void main(String[] args) {
new Tester();
}
public Tester() {
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 JPanel panel;
private JButton button;
private JLabel label;
private ShapePane shapePane;
public TestPane() {
setLayout(new BorderLayout());
button = new JButton("Rectangle");
panel = new JPanel();
label = new JLabel();
button.setVisible(true);
panel.add(button);
panel.add(label);
shapePane = new ShapePane();
add(shapePane);
add(panel, BorderLayout.SOUTH);
class ClickListener implements ActionListener {
private int X = 20;
private int Y = 20;
#Override
public void actionPerformed(ActionEvent arg0) {
int width = shapePane.getWidth();
int height = shapePane.getHeight();
int x = (int)(Math.random() * (width - 20)) + 10;
int y = (int)(Math.random() * (height - 20)) + 10;
int w = (int)(Math.random() * (width - x));
int h = (int)(Math.random() * (height - y));
shapePane.add(new Rectangle(x, y, w, h));
}
}
ActionListener listener = new ClickListener();
button.addActionListener(listener);
}
}
public class ShapePane extends JPanel {
private List<Shape> shapes;
public ShapePane() {
shapes = new ArrayList<>(25);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
public void add(Rectangle rectangle) {
shapes.add(rectangle);
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.RED);
for (Shape shape : shapes) {
g2.draw(shape);
}
}
}
}
As to answer your basic question, you could have tried calling revalidate and repaint, but because of the BorderLayout I doubt it would have worked as you would have basically been trying to replace the panel with your ShapeChanger component, and there are better ways to do that
In my application, there are things marked on an image by clicking on the image. That is done by setting the image as an Icon to a JLabel and adding a MousePressed method
I want to add a feature for the users to redo the last step now and need a backupimage for that.
The following is a code example:
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import java.awt.Color;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class BuffImgTest {
private BufferedImage buffimg, scaledimg, backupscaledimg;
private Image img;
private JFrame frame;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
BuffImgTest window = new BuffImgTest();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public BuffImgTest() {
initialize();
}
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
final JLabel label = new JLabel("");
label.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent arg0) {
Graphics graphics = scaledimg.getGraphics();
graphics.setColor(Color.RED);
graphics.drawString("Test", arg0.getX(), arg0.getY());
Image img = Toolkit.getDefaultToolkit().createImage(
scaledimg.getSource());
label.setIcon(new ImageIcon(img));
}
});
label.setBounds(10, 34, 414, 201);
try {
buffimg = ImageIO.read(new File("test.jpg"));
scaledimg = getScaledImage(buffimg, label.getWidth(),
label.getHeight());
backupscaledimg = scaledimg;
// backupscaledimg=getScaledImage(buffimg,label.getWidth(),label.getHeight());
Image img = Toolkit.getDefaultToolkit().createImage(
scaledimg.getSource());
label.setIcon(new ImageIcon(img));
} catch (Exception e) {
System.out.println(e);
}
frame.getContentPane().add(label);
JButton btnNewButton = new JButton("Restart Step");
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
scaledimg = backupscaledimg;
Image img = Toolkit.getDefaultToolkit().createImage(
scaledimg.getSource());
label.setIcon(new ImageIcon(img));
}
});
btnNewButton.setBounds(111, 238, 89, 23);
frame.getContentPane().add(btnNewButton);
}
public static BufferedImage getScaledImage(BufferedImage image, int width,
int height) throws IOException {
int imageWidth = image.getWidth();
int imageHeight = image.getHeight();
double scaleX = (double) width / imageWidth;
double scaleY = (double) height / imageHeight;
AffineTransform scaleTransform = AffineTransform.getScaleInstance(
scaleX, scaleY);
AffineTransformOp bilinearScaleOp = new AffineTransformOp(
scaleTransform, AffineTransformOp.TYPE_BILINEAR);
return bilinearScaleOp.filter(image, new BufferedImage(width, height,
image.getType()));
}
}
It is not working as intended.
If I use the commented line backupscaledimg = getScaledImage(buffimg,label.getWidth(),label.getHeight()); instead of backupscaledimg = scaledimg;, it is working as expected.
The problem is that I want to do several steps of drawing things on the image, and it can only be redone the first time like that. From what I know the problem might be, that the command backupscaledimg = scaledimg is only creating a pointer for backupscaledimg pointing to scaledimg which results in both of them altering.
I don't want to save a new imagefile on each step though.
Is there any way around this? (found the scaling function on here by the way thanks for that anonymous)
Made some changes
Using GridBagLayout
Able to reset back to original image by pressing "Restart Step"
Able to undo last action with the use of an image stack (i.e. a Stack of BufferedImage)
Example code:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Stack;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import java.awt.Color;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class BuffImgTest {
private BufferedImage scaledImg, originalScaledImg;
private JFrame frame;
private Stack<BufferedImage> imageStack = new Stack<>();
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
BuffImgTest window = new BuffImgTest();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public BuffImgTest() {
initialize();
}
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new BorderLayout());
JPanel panel = new JPanel(new GridBagLayout());
final JLabel imgLabel = new JLabel("");
imgLabel.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent arg0) {
// Add current image to the image stack
imageStack.add(copyImage(scaledImg));
// Change the image
Graphics graphics = scaledImg.getGraphics();
graphics.setColor(Color.BLACK);
graphics.setFont(new Font("Arial", Font.BOLD, 32));
graphics.drawString("TEST", arg0.getX(), arg0.getY());
// Update label
Image img = Toolkit.getDefaultToolkit().createImage(
scaledImg.getSource());
imgLabel.setIcon(new ImageIcon(img));
}
});
imgLabel.setSize(500, 500);
imgLabel.setPreferredSize(new Dimension(500, 500));
try {
BufferedImage buffImg = ImageIO.read(new File("test.jpg"));
scaledImg = getScaledImage(buffImg, imgLabel.getWidth(),
imgLabel.getHeight());
// Clone it first
originalScaledImg = copyImage(scaledImg);
Image img = Toolkit.getDefaultToolkit().createImage(
scaledImg.getSource());
imgLabel.setIcon(new ImageIcon(img));
} catch (Exception e) {
System.out.println(e);
}
GridBagConstraints c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 0;
c.insets = new Insets(20, 10, 10, 10);
panel.add(imgLabel, c);
JButton restartBtn = new JButton("Restart Step");
restartBtn.setFont(new Font("Arial", Font.ITALIC, 20));
restartBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
// Clear the image stack
imageStack.clear();
// Reset the image
scaledImg = copyImage(originalScaledImg);
Image img = Toolkit.getDefaultToolkit().createImage(
scaledImg.getSource());
imgLabel.setIcon(new ImageIcon(img));
}
});
c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 1;
c.anchor = GridBagConstraints.CENTER;
c.insets = new Insets(10, 10, 5, 10);
panel.add(restartBtn, c);
JButton undoBtn = new JButton("Undo Last");
undoBtn.setFont(new Font("Arial", Font.ITALIC, 20));
undoBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
if(imageStack.isEmpty()) {
JOptionPane.showMessageDialog(frame, "Cannot undo anymore!");
return;
}
// Get the previous image
scaledImg = copyImage(imageStack.pop());
Image img = Toolkit.getDefaultToolkit().createImage(
scaledImg.getSource());
imgLabel.setIcon(new ImageIcon(img));
}
});
c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 2;
c.anchor = GridBagConstraints.CENTER;
c.insets = new Insets(5, 10, 20, 10);
panel.add(undoBtn, c);
frame.getContentPane().add(panel, BorderLayout.CENTER);
frame.setSize(800, 800);
}
/** For copying image */
public static BufferedImage copyImage(BufferedImage source){
BufferedImage b = new BufferedImage(
source.getWidth(), source.getHeight(), source.getType());
Graphics g = b.getGraphics();
g.drawImage(source, 0, 0, null);
g.dispose();
return b;
}
public static BufferedImage getScaledImage(BufferedImage image, int width,
int height) throws IOException {
int imageWidth = image.getWidth();
int imageHeight = image.getHeight();
double scaleX = (double) width / imageWidth;
double scaleY = (double) height / imageHeight;
AffineTransform scaleTransform = AffineTransform.getScaleInstance(
scaleX, scaleY);
AffineTransformOp bilinearScaleOp = new AffineTransformOp(
scaleTransform, AffineTransformOp.TYPE_BILINEAR);
return bilinearScaleOp.filter(image, new BufferedImage(width, height,
image.getType()));
}
}
Edited Image:
Image after pressing "Restart step":
Pressing "Undo Last" when image stack is empty:
Note:
Code for copying image is from this answer by APerson
I've been trying to add Java form elements such as a textField and a passwordField to a fullscreen exclusive mode frame. The issue i've been having is that when I run the code, my form elements don't show up fully or not at all until I actually click on them.
Here's my code:
Master.java
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.net.URL;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
public class Master extends JFrame {
private static final long serialVersionUID = -4927941474660261348L;
static GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
static GraphicsDevice gd = ge.getDefaultScreenDevice();
static int WIDTH = gd.getDisplayMode().getWidth();
static int HEIGHT = gd.getDisplayMode().getHeight();
static Toolkit toolkit = Toolkit.getDefaultToolkit();
static Graphics2D g2d = null;
static FontMetrics metrics = null;
static URL vignetteURL = null;
static Image vignette = null;
static Rectangle red = new Rectangle(WIDTH - 35, 0, 35, 35);
public Master() {
super("Project Zenith");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
getContentPane().setLayout(null);
setUndecorated(true);
setResizable(false);
gd.setFullScreenWindow(this);
repaint();
setIconImage(new ImageIcon(getClass().getResource("images/hex.png")).getImage());
vignetteURL = getClass().getResource("images/vignette2.png");
addMouseListener(new MouseListener() {
#Override
public void mouseClicked(MouseEvent e) {
if(e.getX() >= red.getX() && e.getY() <= red.getHeight()) {
closeClicked();
}
}
#Override
public void mouseEntered(MouseEvent arg0) {
}
#Override
public void mouseExited(MouseEvent arg0) {
}
#Override
public void mousePressed(MouseEvent arg0) {
}
#Override
public void mouseReleased(MouseEvent arg0) {
}
});
}
public void update(Graphics g) {
paint(g);
}
public void paint(Graphics g) {
g2d = (Graphics2D) g;
vignette = toolkit.getImage(vignetteURL);
g2d.clearRect(0, 0, getWidth(), getHeight());
g2d.setFont(new Font("Bebas Neue", Font.PLAIN, 25));
metrics = g2d.getFontMetrics();
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2d.setColor(new Color(168, 168, 168, 200));
g2d.drawString("Project Zenith", 10, HEIGHT - 10);
g2d.setColor(new Color(0xFFA6A6));
g2d.fill(red);
g2d.drawImage(vignette, 0, 0, WIDTH, HEIGHT, this);
}
public void closeClicked() {
System.exit(0);
}
}
Login.java
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.RoundRectangle2D;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
public class Login extends Master {
private static final long serialVersionUID = 1L;
static Master l;
static JTextField username;
static JTextField password;
static Graphics2D g2d = null;
static FontMetrics metrics = null;
static RoundRectangle2D loginRect = new RoundRectangle2D.Float((WIDTH / 2) - ((WIDTH / 4) / 2), (HEIGHT / 2) - ((HEIGHT / 4) / 2), (WIDTH / 4), (HEIGHT / 4), 20, 20);
Login() {
l = this;
Font inputFont = new Font("Calibri", Font.PLAIN, 15);
username = new JTextField();
username.setBounds((WIDTH / 2) - (((int) loginRect.getY() - 10) / 2), (int) loginRect.getY() + 60, (int) loginRect.getY() - 10, 18);
username.setFont(inputFont);
username.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
username.setEditable(true);
username.setBackground(new Color(0xE6E6E6));
//username.setVisible(true);
getContentPane().add(username);
password = new JPasswordField();
password.setBounds((WIDTH / 2) - (((int) loginRect.getY() - 10) / 2), (int) loginRect.getY() + 110, (int) loginRect.getY() - 10, 18);
password.setFont(inputFont);
password.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
password.setEditable(true);
password.setBackground(new Color(0xE6E6E6));
//password.setVisible(true);
getContentPane().add(password);
JButton loginButton = new JButton("Login");
loginButton.setBounds((WIDTH / 2) - 40, (int) loginRect.getY() + 155, 80, 20);
loginButton.setFont(inputFont);
loginButton.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
loginButton.setBackground(new Color(0xE6E6E6));
//loginButton.setVisible(true);
loginButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println(username.getText());
}
});
getContentPane().add(loginButton);
repaint();
setVisible(true);
}
public void paint(Graphics g) {
super.paint(g);
g2d = (Graphics2D) g;
metrics = g2d.getFontMetrics();
g2d.setColor(Color.WHITE);
g2d.fill(loginRect);
g2d.setColor(new Color(0xA8A8A8));
g2d.drawString("Access Terminal", (Master.WIDTH / 2) - (metrics.stringWidth("Access Terminal") / 2), (int) loginRect.getY() + metrics.getHeight() + 2);
}
public static void main(String [] args) {
new Login();
}
}
Start by taking a look at Painting in AWT and Swing and Performing Custom Painting for an explanation of how painting works in Swing.
The basic problem is:
You're breaking the painting chain
You're painting over child components
This is one (of many reasons) why you shouldn't override paint of top level containers. Instead, start by using a JPanel and overriding it's paintComponent (calling super.paintComponent before you perform any custom painting)
You should also make use of appropriate layout manager to better handle the differences in resolutions and font rendering requirements.
Have a look at Laying Out Components Within a Container for more details
With a little clever planning, you can do some pretty advance things
Now, obviously this isn't in full screen, but that's kind of the point, you can now uncomment the line gd.setFullScreenWindow(frame); and it will auto-magically realign itself, through the power of layout managers.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.RoundRectangle2D;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gd = ge.getDefaultScreenDevice();
Login login = new Login();
JFrame frame = new JFrame("Project Zenith");
frame.setUndecorated(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(login);
frame.pack();
frame.setLocationRelativeTo(null);
// gd.setFullScreenWindow(frame);
frame.setVisible(true);
}
});
}
public static class Master extends JPanel {
private static final long serialVersionUID = -4927941474660261348L;
private Rectangle closeRect;
public Master() {
addMouseListener(new MouseListener() {
#Override
public void mouseClicked(MouseEvent e) {
if (e.getX() >= closeRect.getX() && e.getY() <= closeRect.getHeight()) {
closeClicked();
}
}
#Override
public void mouseEntered(MouseEvent arg0) {
}
#Override
public void mouseExited(MouseEvent arg0) {
}
#Override
public void mousePressed(MouseEvent arg0) {
}
#Override
public void mouseReleased(MouseEvent arg0) {
}
});
}
#Override
public void invalidate() {
super.invalidate();
closeRect = new Rectangle(getWidth() - 35, 0, 35, 35);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setFont(new Font("Bebas Neue", Font.PLAIN, 25));
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2d.setColor(new Color(168, 168, 168, 200));
FontMetrics fm = g2d.getFontMetrics();
int y = (getHeight() - fm.getHeight()) + fm.getAscent();
g2d.drawString("Project Zenith", 10, y);
g2d.setColor(new Color(0xFFA6A6));
g2d.fill(closeRect);
}
public void closeClicked() {
System.exit(0);
}
}
public static class Login extends Master {
private static final long serialVersionUID = 1L;
private JTextField username;
private JTextField password;
Login() {
Font inputFont = new Font("Calibri", Font.PLAIN, 15);
setLayout(new GridBagLayout());
JPanel content = new JPanel(new GridBagLayout()) {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
RoundRectangle2D loginRect = new RoundRectangle2D.Float(0, 0, getWidth() - 1, getHeight() - 1, 20, 20);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.WHITE);
g2d.fill(loginRect);
g2d.setColor(new Color(0xA8A8A8));
g2d.draw(loginRect);
}
};
content.setBorder(new EmptyBorder(20, 20, 20, 20));
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.insets = new Insets(0, 0, 25, 0);
gbc.gridx = 0;
gbc.gridy = 0;
JLabel label = new JLabel("Access Terminal");
label.setFont(new Font("Bebas Neue", Font.PLAIN, 25));
label.setForeground(new Color(0xA8A8A8));
content.add(label, gbc);
gbc.gridy++;
username = new JTextField(25);
username.setFont(inputFont);
username.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
username.setEditable(true);
username.setBackground(new Color(0xE6E6E6));
//username.setVisible(true);
content.add(username, gbc);
gbc.gridy++;
password = new JPasswordField(25);
password.setFont(inputFont);
password.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
password.setEditable(true);
password.setBackground(new Color(0xE6E6E6));
//password.setVisible(true);
content.add(password, gbc);
gbc.gridy++;
JButton loginButton = new JButton("Login");
loginButton.setFont(inputFont);
loginButton.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
loginButton.setBackground(new Color(0xE6E6E6));
loginButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println(username.getText());
}
});
content.add(loginButton, gbc);
add(content);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
}
}
Basically, in your Login view, I've used compounding components to generate the "rounded border" effect, creating a JPanel and overriding it's paintComponent method to paint the effect. This provides me with layout information from the child components in order to make determinations about how big the effect should be. This is then added into a Login panel itself and through the use of layout managers, it all gets centered