I am currently making a version of the board-game Khet and was planning on displaying the laser fired between turns using a Glass Pane, but for the life of me I can't get the drawings to show up at all. To save posting all of the code for the game I've posted the code only related to the glass pane as it's own separate application below. Can anyone tell me why the graphics aren't showing up?
package glasspane;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.Line2D;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class GlassPane {
JPanel panel, glass;
GlassPane() {
JFrame f = new JFrame("GlassPane");
panel = new JPanel();
JButton show = new JButton("Show glass");
JButton hide = new JButton("Hide glass");
show.addActionListener(e -> changeVisibility());
hide.addActionListener(e -> changeVisibility());
panel.add(show);
panel.add(hide);
glass = (JPanel) f.getGlassPane();
glass.add(new line());
glass.setVisible(false);
f.add(panel);
f.setSize(300, 300);
f.setVisible(true);
}
private void changeVisibility() {
glass.setVisible(!glass.isVisible());
panel.repaint();
}
#SuppressWarnings("serial")
private class line extends JComponent {
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
Shape s = new Line2D.Float(0, 0, 300, 300);
g2.setColor(Color.GREEN);
g2.setStroke(new BasicStroke(20));
g2.draw(s);
System.out.println("doing something...");
}
}
public static void main(String[] args) {
new GlassPane();
}
}
Your line Component has zero size. Thats because JFrame.getGlassPane() returns a java.awt.Component that has no default layoutManager. So set a layoutManager for your glassPane should solve your problem.
glass = (JPanel) f.getGlassPane();
glass.setLayout(new BorderLayout());
glass.add(new line(), BorderLayout.CENTER);
glass.setVisible(false);
Now your line Compnent should be as big as glassPane
I did this and the line get showed up:
glass = (JPanel) f.getGlassPane();
glass.setLayout(new BorderLayout());
glass.add(new line());
Related
I am creating a word search GUI using Swing for a club project. I want the answers "hidden" by making them upside down in the GUI. I've seen a post where a person put a negative Integer as font size but it was 9 years ago and it doesn't seem to work anymore, instead the text simply does not appear
Font FontUpsideDown = new Font("Sans_Serif", Font.PLAIN, -50);
JTextArea upsideDown = new JTextArea("Hello");
upsideDown.setFont(FontUpsideDown);
upsideDown.setEditable(false);
...
JPanel.add(upsideDown, gbc);
I've seen a post where a person put a negative Integer as font size but it was 9 years ago
If you are referring to this question then this answer, to that question, worked for me. Simply override method paintComponent of the relevant JComponent (which appears, from your question, to be JTextArea). Below code demonstrates.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class Inverted {
private static JScrollPane createTextArea() {
JTextArea textArea = new JTextArea(10, 50) {
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.scale( -1.0, -1.0 );
g2.translate( -getWidth(), -getHeight() );
super.paintComponent(g2);
}
};
textArea.append("Is this upside down?");
JScrollPane scrollPane = new JScrollPane(textArea);
return scrollPane;
}
private static void gui() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel label = new JLabel("Inverted") {
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.scale( -1.0, -1.0 );
g2.translate( -getWidth(), -getHeight() );
super.paintComponent(g2);
}
};
JPanel inverted = new JPanel();
inverted.add(label);
frame.add(inverted, BorderLayout.PAGE_START);
frame.add(createTextArea(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(Inverted::gui);
}
}
When I run the above code, using Java 19 on Windows 10, I get the following GUI:
I'm writing the UI for the pet project I've been doing and I'm experimenting with java Graphics, drawing lines, shapes, and stuff. And, I've been trying all day to insert a simple line in a Jpanel but still haven't figured out what went wrong.
package thuake;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Menu;
import java.awt.MenuBar;
import java.awt.Paint;
import java.awt.Polygon;
import java.awt.geom.Line2D;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class Main extends JFrame{
static Dimension DEFAULT_SIZE = new Dimension(530, 320);
static JFrame Frame1 = new JFrame();
static JScrollPane spanel = new JScrollPane();
static JPanel Panel1 = new JPanel();
static MenuBar menu = new MenuBar();
static Menu menusub1 = new Menu("Open");
public static void main(String[] args)
{
start();
}
public static void start (){
Frame1.setLayout(new FlowLayout(FlowLayout.CENTER,5,10));
spanel.add(new draw());
Frame1.add(spanel);
spanel.setBorder(BorderFactory.createLineBorder(Color.black));
spanel.setPreferredSize(new Dimension(500, 500));
Frame1.add(new JButton("ad"));
Frame1.add(new JButton("ad"));
Frame1.add(new JButton("ad"));
Frame1.add(new draw());
Frame1.setMenuBar(menu);
menu.add(menusub1);
Frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Frame1.pack();
spanel.setVisible(true);
Frame1.setVisible(true);
System.out.println();
}
static class draw extends Component {
public void paint(Graphics g) {
Graphics2D line = (Graphics2D)g;
line.drawLine(0, 0, 120, 120);
}
}
}
Here is a basic framework you should follow when you are doing graphics.
Key points are:
Don't extend JFrame, use a separate instance.
Override paintComponent() and not paint()
Start the process in the EDT. Do all swing stuff in the EDT.
Do not paint outside the EDT or with a graphics context that you retrieved yourself. Always use the one from paintComponent()
Set the width and height (dimension) for the panel and not the JFrame. The reason being that those dimensions on the JFrame include the thick borders. For the JPanel you get the full width.
At some point you can modify this and add additional components to the JFrame and/or JPanel. For now this should provde a basis for experimenting.
You should also read up on this and anything I omitted shown below. Check out the Java Tutorials for more on information on graphics and painting.
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Template extends JPanel {
final static int height = 500;
final static int width = 500;
final static String title = "title";
JFrame frame = new JFrame(title);
public static void main(String[] args) {
// start on the EDT
SwingUtilities.invokeLater(() -> new Template().start());
}
public Template() {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(this); // add the panel
setPreferredSize(new Dimension(width, height));
frame.pack();
// center on screen
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public void paintComponent(Graphics g) {
super.paintComponent(g); // always do this
Graphics2D g2d = (Graphics2D) g.create();
// Optional. It averages the edges of a figure to give a smoothing effect
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
// do something here.
g2d.setColor(Color.red);
g2d.fillRect(200,200,100,100);
g2d.dispose();
}
}
I made a simple draw rectangle application with JFrame and JPanel
Graphics2D g2d = (Graphics2D)jPanel1.getGraphics();
g2d.setColor(Color.red);
g2d.drawRect(x,y,w,h);
Whenever I draw something and click on menu, the overlapped part disappears
How to fix it?
As I already said in my comment, never use jPanel1.getGraphics(), but overridie the method paintComponent instead. This method will always be called when panel is repainted. Here is a small example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JPanel;
import javax.swing.WindowConstants;
/**
* <code>PaintExample</code>.
*/
public class PaintExample extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// correct approach
g.setColor(Color.RED);
g.fillRect(20, 20, Math.max(getWidth() - 200, 0), Math.max(getHeight() - 100, 0));
}
#Override
public Dimension getPreferredSize() {
// required for correct work of JFrame.pack method
return new Dimension(500, 400);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(PaintExample::createAndShowGUI);
}
private static void createAndShowGUI() {
JFrame frm = new JFrame();
JMenuBar menuBar = new JMenuBar();
JMenu m = new JMenu("File");
m.add("Test menu item 1");
m.add("Test menu item 2");
m.add("Test menu item 3");
menuBar.add(m);
frm.setJMenuBar(menuBar);
frm.add(new PaintExample());
frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frm.pack();
frm.setLocationRelativeTo(null);
frm.setVisible(true);
}
}
The program works fine, but when I add the setUndecorated code, the panel does not appear. Problem is solving when I minimize and reopen the program. I tried repaint() , but It's not working.
package testing;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class test extends JFrame{
static int width = 900;
static int height = 520;
JFrame frame;
JPanel panel;
JButton selectKey = new JButton("Select KeyIMG");
static BufferedImage bg;
class MyCanvas extends JComponent{
public void paint(Graphics g) {
try {
bg = ImageIO.read(new File("BGFILE"));
} catch (IOException e) {
e.printStackTrace();
}
g.setClip(0, 0, width, height);
g.drawImage(bg,0,0,width,height, this);
g.dispose();panel.repaint();
}
}
public test(){
super("Test");
setBounds(250, 100, width, height);
selectKey.setBounds(width/9,height/2,width/45*8,height/13);
getContentPane().add(new MyCanvas());setUndecorated(true);setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel = new JPanel();
panel.setBackground( new Color(0, 0, 0, 0));
panel.setLayout(null);
panel.add(selectKey);
add(panel);
}
public static void main(String...Args){
new test();
}
}
What's wrong ?
Issues
Overriding paint. It's highly discouraged to override paint, painting is a complex series of compounding methods which work together to produce a the final result. It's highly recommended that you override paintComponent instead
Not calling super.paint, see the previous comment. Unless you know exactly what you're doing and are prepared to take over the responsibility of the paint method, call it's super method, there only a very few use cases I'd consider it safe not to do this.
Using a alpha based color on an opaque component; panel.setBackground(new Color(0, 0, 0, 0));. This is bad idea. Swing only knows how to deal with opaque and transparent components, it doesn't know how it should paint components with alpha based colors. The API will simply ignore any components beneath it, which is likely one of the major causes of your problem
g.dispose(); don't ever dispose of a Graphics context you did not create or copy. Doing so can prevent other components from been painted
Don't call panel.repaint(); from within any paint method, painting paints the current state, it should never do anything to change it, doing so well put you into a spiral of CPU death as it begins to chew up all the CPU cycles, in fact, MyCanvas has no right to be modifying panel anyway and the way your code is set up, it could generate a NullPointerException
"Other" concerns
static BufferedImage bg; is worrisome. No body else has any need to deal with this variable, the only class which should be dealing with it is the MyCanvas class
g.setClip(0, 0, width, height); is pointless (and potentially dangerous), this has already been done before the paint method was called. This is made worse by the fact that you are not relying on the components actual size, which could cause the painting to overrun the visible bounds of the component
Extending from JFrame. You should avoid extending from top level containers, they are complex components to which you rarely add any new/reusable functionality to and they lock you into a single use case, much better to start with a JPanel and add that to whatever container you need
An example...
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Test {
class Background extends JComponent {
private BufferedImage bg;
public Background() {
try {
bg = ImageIO.read(new File("/path/to/your/image"));
} catch (IOException e) {
e.printStackTrace();
}
setLayout(new BorderLayout());
}
#Override
public Dimension getPreferredSize() {
return bg == null ? super.getPreferredSize() : new Dimension(bg.getWidth(), bg.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (bg != null) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawImage(bg, 0, 0, getWidth(), getHeight(), this);
g2d.dispose();
}
}
}
public Test() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.setContentPane(new Background());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setUndecorated(true);
JPanel panel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
panel.add(new JLabel("This is a label, don't I look pretty"), gbc);
JButton selectKey = new JButton("Select KeyIMG");
panel.add(selectKey, gbc);
panel.setOpaque(false);
frame.add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static void main(String... Args) {
new Test();
}
}
Hi I'm new to java GUI Programming. I created Jframe(MainFrame) and add JPanel(OutPanel) Which has another Jpanel(InnerPanel). I try to achieve drawing Image in InnerPanel, not drawing OutPanel. I want OutPanel used to be just Container. So as you see TestA. I get Graphics from InnerPanel in OutPanel's paintComponent() which is overided method.
So finally I can draw using InnerPanel's Graphics in OutPanel's paintComponent() method. but It couldn't work well. It couldn't draw Image one time when program starts. when I hided window and shown again, the program shows image. Even though that is part of Image, not all Image.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class TestA{
private static Image image = GUI.loadImage("PlayerBoard.jpg");
public static void main(String[] args) {
TestA testA = new TestA();
}
public TestA() {
JFrame mainFrame = new JFrame("Main Frame");
mainFrame.setLayout(null);
mainFrame.setSize(500, 500);
mainFrame.setVisible(true);
mainFrame.setBackground(Color.black);
mainFrame.setLocation(800, 400);
OutPanel outPanel = new OutPanel();
mainFrame.getContentPane().add(outPanel);
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
outPanel.repaint();
}
private class OutPanel extends JPanel {
JPanel innerPanel;
public OutPanel() {
this.setLayout(null);
this.setLocation(0, 0);
this.setSize(500, 50);
this.setBackground(Color.red);
innerPanel = new JPanel();
this.innerPanel.setSize(400, 50);
this.innerPanel.setVisible(true);
this.add(innerPanel);
}
#Override
protected void paintComponent(Graphics g) {
// TODO Auto-generated method stub
super.paintComponent(g);
int width = 500;
int height = 50;
BufferedImage resized = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE);
Graphics gBuffer = resized.createGraphics();
gBuffer.drawImage(TestA.image, 0, 0, width, height, this);
Graphics gPanel = innerPanel.getGraphics();
gPanel.drawImage(resized, 0, 0, width, height, this);
}
}
}
So I try diffrerent way(TestB). Only different thing is I just moved drawImage() method and getGraphics() thing to InnerPanel's paintComponent() from OutPanel's paintComponent(). Here's another Code TestB. and It works well.
Why this happens. Is it relates to context?. What is Context. and could I draw InnerPanel's Image in OutPanel?
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class TestB {
private static Image image = GUI.loadImage("PlayerBoard.jpg");
public static void main(String[] args) {
TestB testB = new TestB();
}
public TestB() {
JFrame mainFrame = new JFrame("Main Frame");
mainFrame.setLayout(null);
mainFrame.setSize(500, 500);
mainFrame.setVisible(true);
mainFrame.setBackground(Color.black);
mainFrame.setLocation(800, 400);
OutPanel outPanel = new OutPanel();
mainFrame.add(outPanel);
outPanel.repaint();
}
private class OutPanel extends JPanel {
JPanel innerPanel;
public OutPanel() {
this.setLayout(null);
this.setLocation(0, 0);
this.setSize(500, 50);
this.setBackground(Color.red);
innerPanel = new InnerPanel(this);
this.innerPanel.setSize(500, 50);
this.innerPanel.setVisible(true);
this.add(innerPanel);
this.repaint();
}
}
private class InnerPanel extends JPanel {
OutPanel outPanel;
public InnerPanel(OutPanel outPanel) {
this.outPanel = outPanel;
}
#Override
protected void paintComponent(Graphics g) {
// TODO Auto-generated method stub
super.paintComponent(g);
int width = 500;
int height = 50;
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.drawImage(TestB.image, 0, 0, width, height, this);
}
}
}
The paintComponent() method of a component is responsible for painting itself only. It should never know or care about any other component.
I want OutPanel used to be just Container.
Then do just that. Create the panel and set the layout manager for the outer panel and then add the outer panel to the JFrame.
Then create your inner panel and add it to the outer panel. Make sure you override the getPreferredSize() method of the inner panel so the layout manager of the outer panel can do its job.
Read the section from the Swing tutorial on Custom Painting for more information and working examples to start with.