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:
Related
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.
I have a JButton in a JPanel that has graphics, but the button won't show as it is in the layer BELOW the graphics.
I've already read this : Put JLabel in front of Graphics 2D Rectangle in JPanel
But the answers tell me not to use the NullLayoutManager.
Is there any way to do it with the NullLayoutManager, because I need to specifically position my JButton in my JPanel?
If this is not possible, are there any other ways I can position a JComponent at a position x, y? I've also googled that and NullLayoutManager is what the world wide web gives me.
Code:
JPanel p = new JPanel(){
#Override
public void paintComponent(Graphics gr){
Graphics2D g = (Graphics2D) gr;
g.setColor(Color.BLACK);
g.fillRect(0, 0, 800, 800);
g.setFont(titlefont);
g.setColor(Color.WHITE);
g.drawString("dont steal my game idea plz", 25, 100);
g.drawImage(bi, 138, 70, null);
repaint();
}
};
p.setLayout(null);
JButton b = new JButton("PLAY");
b.setLocation(100, 200);
b.setFont(ufont);
f.add(p);
p.add(b);
Is there any way to do it with the NullLayoutManager, because I need to specifically position my JButton in my JPanel?
The answer is "yes", but do you understand what the layout managers actually do? How they work and the role they fill in order to replace them and take over the requirements of their functionality?
null layouts are just a bad idea, there are so many things that can wrong with them it's mind numbing just trying to think about it. If none of the stock layout managers do what you want, maybe consider using MigLayout or some other layout manager, possibly even writing your own, at least this way, you will still be able to work within the API, which has been designed to work around layout managers.
There are a couple of other issues, first, you're painting your image AFTER the paint the text, this could cause some issues if the two overlap. Second, you're breaking the paint chain by not calling super.paintComponent, this could result in some unexpected and unwanted results. Third, you don't need to fill the component, use setBackground and let the super.paintComponent deal with it.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class DownWithNullLayouts {
public static void main(String[] args) {
new DownWithNullLayouts();
}
public DownWithNullLayouts() {
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 Font titlefont;
private BufferedImage bi;
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(30, 0, 0, 0);
add(new JButton("Play"), gbc);
try {
bi = ImageIO.read(...);
} catch (IOException ex) {
ex.printStackTrace();
}
titlefont = UIManager.getFont("Label.font");
setBackground(Color.BLACK);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int x = (getWidth() - bi.getWidth()) / 2;
int y = (getHeight()- bi.getHeight()) / 2;
g2d.drawImage(bi, x, y, this);
g2d.setFont(titlefont);
g2d.setColor(Color.WHITE);
g2d.drawString("dont steal my game idea plz", 25, 100);
g2d.dispose();
}
}
}
Take a closer look at Painting in AWT and Swing and Performing Custom Painting for more details
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());
Consider this small runnable example:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Test2 extends JFrame implements MouseWheelListener{
ArrayList<JLabel> lista = new ArrayList<JLabel>();
JPanel p;
double d = 0.1;
Test2(){
p=new JPanel();
_JLabel j = new _JLabel("Hello");
j.setOpaque(true);
j.setBackground(Color.yellow);
p.add(j);
p.setBackground(Color.blue);
add(p);
this.setVisible(true);
this.setSize(400,400);
addMouseWheelListener(this);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static void main(String args[]){
new Test2();
}
private class _JLabel extends JLabel{
_JLabel(String s){
super(s);
}
protected void paintComponent(Graphics g) {
d+=0.01;
Graphics2D g2d = (Graphics2D) g;
g2d.scale(d, d);
setMaximumSize(null);
setPreferredSize(null);
setMinimumSize(null);
super.paintComponent(g2d);
System.out.println("d= " +d);
}
}
public void mouseWheelMoved(MouseWheelEvent e) {
this.repaint();
}
}
When I scroll the mousewheel the JLabel increases in size and the variable d is printed out. However, when it reaches the actual size (d=1) only the text continues zooming. How can I make the background continue to zoom?
You shouldn't be modifying the preferred/min/max sizes in the paint method, this coud have unexpected results (cause another repaint).
The problem is that the parent layout has no reference from which to determine size of the component. That is, the preferred/in/max size is actually calculated based on the font information & this information is not been changed.
So, while it "appears" that the component is being resized, it's actual size has not changed.
Try instead to scale against the original font size.
AffineTransformation af = AffineTranfrmation.getScaleInstance(scale, scale);
Font font = originalFont.deriveFont(af);
setFont(font);
invalidate();
repaint();
Of course you run into the problem of what happens if the user changes the font, but with a little bit of flagging, you should be able to over come that