This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
paintComponent () never executes on a JFrame
I am using the following code to dispaly two strings and i'm drawing them directly on jfame instead of adding them as component or to a jpanel.But Why am i getting a blank window instead of getting Strings.Where am i wrong?
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class SimpleAttributes extends JFrame{
SimpleAttributes()
{
super("Simple Attributes");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(300, 200);
//setUndecorated(true);
Container cp=this.getContentPane();
cp.setBackground(new Color(0,200,0,0));
setVisible(true);
}
public void paintComponent(Graphics g)
{
Graphics2D g2=(Graphics2D)g.create();
g2.setColor(Color.RED);
g2.drawString("One", 10, 10);
g.drawString("Two", 10,40);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
SwingUtilities.invokeLater(new Runnable(){public void run(){new SimpleAttributes();}});
}
}
JFrame is not a component, therefor there's no paintComponent() function for it. See the API documentation.
As mentioned the above is incorrect there is no such method, (I was to fast at typing) and thinking about JPanels.
what you can do is create your own Container and override the paint() method then use that as your ContentPane by frame.setContentPane(Container con):
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class SimpleAttributes extends JFrame {
SimpleAttributes() {
super("Simple Attributes");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(300, 200);
//setUndecorated(true);
setContentPane(new MyContainer());
getContentPane().setBackground(new Color(0, 200, 0, 0));
setVisible(true);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new SimpleAttributes();
}
});
}
}
class MyContainer extends Container {
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2 = (Graphics2D) g.create();
g2.setColor(Color.RED);
g2.drawString("One", 10, 10);
g.drawString("Two", 10, 40);
}
}
as noted in a comment on one answer you can use the paint() of the JFrame just compensate for the offset of the dialog's header :
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class SimpleAttributes extends JFrame {
SimpleAttributes() {
super("Simple Attributes");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(300, 200);
//setUndecorated(true);
getContentPane().setBackground(new Color(0, 200, 0, 0));
setVisible(true);
}
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2 = (Graphics2D) g.create();
g2.setColor(Color.RED);
g2.drawString("One", 10, 10);//wont show
g2.drawString("One", 50, 50);//will show
g.drawString("Two", 40, 40);//will show
}
public static void main(String[] args) {
// TODO Auto-generated method stub
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new SimpleAttributes();
}
});
}
}
but all of thats just going to give you more headaches why not just do it the preferred way? A JPanel and override paintComponent(Graphics g);
Related
I am trying to make a simple game in Java, All i need to do is draw an im onto the screen and then wait for 5 seconds then 'undraw it'.
Code (this class draws the image on the screen):
package com.mainwindow.draw;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class MainWindow extends JPanel{
Image Menu;
String LogoSource = "Logo.png";
public MainWindow() {
ImageIcon ii = new ImageIcon(this.getClass().getResource(LogoSource));
Menu = ii.getImage();
Timer timer = new Timer(5, new ActionListener() {
public void actionPerformed(ActionEvent e) {
repaint();
}
});
timer.start();
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2 = (Graphics2D) g;
g2.drawImage(Menu, 0, 0, getWidth(), getHeight(), null);
}
}
Code #2 (this creates the JFrame)
package com.mainwindow.draw;
import javax.swing.JFrame;
#SuppressWarnings("serial")
public class Frame extends JFrame {
public Frame() {
add(new MainWindow());
setTitle("Game Inviroment Graphics Test");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(640, 480);
setLocationRelativeTo(null);
setVisible(true);
setResizable(false);
}
public static void main(String[] args) {
new Frame();
}
}
Use some kind of flag to determine if the image should be drawn or not and simply change it's state as needed...
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
if (draw) {
g2.drawImage(Menu, 0, 0, getWidth(), getHeight(), null);
}
}
Then change the state of the flag when you need to...
Timer timer = new Timer(5, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
draw = false;
repaint();
}
});
Note: It's not recommended to to override paint, paint is at the top of the paint change and can easily break how the paint process works, causing no end of issues. Instead, it's normally recommended to use paintComponent instead. See Performing Custom Painting for more details
Also note: javax.swing.Timer expects the delay in milliseconds...5 is kind of fast...
I am making a custom button in with Swing in Java.
This is how my buttons look like:
I want a lightgray button with rounded corners, I want to add a little image later.
The problem is when I override paintComponent(), the gray rounded will be drawn, but you see the old blue Swing background after it.
The corners of the button must be transparent.
This is my code
package game;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JButton;
public class ItemButton extends JButton {
public ItemButton(String text) {
super(text);
this.setBorderPainted(false);
this.setBorder(null);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(new Color(220, 220, 220));
g2.fillRoundRect(0, 0, this.getWidth() - 10, this.getHeight() - 10, 10, 10);
}
}
I'm not sure why you want to do this this way, as JButton allows you to supply an Icon image, but anyway...
There is a way to do this using JButton, but it's not the right thing to do, instead, you should start by using an AbstractButton as it has no UI delegate painting to it to begin with, for example...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.AbstractButton;
import javax.swing.DefaultButtonModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class CustomButton {
public static void main(String[] args) {
new CustomButton();
}
public CustomButton() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridBagLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends AbstractButton {
public TestPane() {
setModel(new DefaultButtonModel());
MouseHandler mh = new MouseHandler();
addMouseListener(mh);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(40, 20);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics g2d = (Graphics2D) g.create();
g2d.setColor(new Color(220, 220, 220));
g2d.fillRoundRect(0, 0, this.getWidth() - 1, this.getHeight() - 1, 10, 10);
if (getModel().isRollover()) {
g2d.setColor(new Color(128, 128, 128));
g2d.drawRoundRect(0, 0, this.getWidth() - 1, this.getHeight() - 1, 10, 10);
}
g2d.dispose();
}
public class MouseHandler extends MouseAdapter {
#Override
public void mouseEntered(MouseEvent e) {
getModel().setRollover(true);
}
#Override
public void mouseExited(MouseEvent e) {
getModel().setRollover(false);
}
#Override
public void mousePressed(MouseEvent e) {
getModel().setArmed(true);
getModel().setPressed(true);
}
#Override
public void mouseReleased(MouseEvent e) {
getModel().setPressed(false);
getModel().setArmed(false);
}
}
}
}
there are two ways
override getPrefferedSize inside class ItemButton
use proper LayoutManager, I'd be start with GridLayout
First coord in this case should be 0,0 and not 8,30. What am i doing wrong(i am using NetBeans)
import java.awt.Color;
import java.awt.Graphics;
public class TEST extends javax.swing.JFrame {
#Override
public void paint(Graphics g){
super.paint(g);
g.setColor(Color.blue);
g.drawRect(8, 30, 200, 200);
repaint();
}}
Add a JPanel to the frame and paint in that. The frame's coordinates include the decorations (title bar, borders, etc.). It would look something like this:
public class Test extends JFrame {
public static void main(String[] args) {
new Test();
}
private Test() {
add(new MyPanel());
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(600, 600);
setVisible(true);
}
private class MyPanel extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.blue);
g.drawRect(8, 30, 200, 200);
}
}
}
Also, don't call repaint(); in paint();. That will cause an infinite loop and will freeze the entire program.
The problem is your paint(..) method is not taking into account the JFrame Insets by calling getInsets which as docs state:
If a border has been set on this component, returns the border's
insets.
this code works fine:
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class Test {
public Test() {
createAndShowGui();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Test();
}
});
}
private void createAndShowGui() {
JFrame frame = new JFrame() {
#Override
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.blue);
g.drawRect(0 + getInsets().left, 0 + getInsets().top, 200, 200);
}
};
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
however this is not best practice.
Rather add JPanel to JFrame and override paintComponent(Graphics g) of JPanel dont forget call to super.paintComponent(g) as first call in the overridden method and than draw there (dont forget to override getPreferredSize() and return correct Dimensions so the JPanel will fit its drawing/graphic content) this problem will no longer persist as JPanel is added at correct co-ordinates on contentPane like so:
import java.awt.Color;
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 Test {
public Test() {
createAndShowGui();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Test();
}
});
}
private void createAndShowGui() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.addRenderingHints(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));
g2d.setColor(Color.blue);
g2d.drawRect(0, 0, 200, 200);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
};
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
}
The above includes Graphics2D and RenderingHints i.e anti-aliasing. Just for some better looking drawings :)
I'm trying to build a simple paint tool. The mouseDrag events creates a new ellipse and causes my JPanel to repaint().
This works fine so far.
However, if I press any button (or any other UI component) before firing the mouseDrag event for the first time, the button is painted in the upper left corner of my panel.
I have isolated the code into this test application:
import java.awt.BasicStroke;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Test extends JFrame
{
public Test()
{
final JPanel paintPanel = new JPanel(){
#Override
protected void paintComponent(Graphics g)
{
Graphics2D g2d = (Graphics2D)g;
g2d.setPaintMode();
g2d.setStroke(new BasicStroke(1));
g2d.fillRect(100, 100, 10, 10);
}
};
paintPanel.setPreferredSize(new Dimension(300,300));
paintPanel.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e)
{
paintPanel.repaint();
}
});
this.setLayout(new FlowLayout());
this.add(paintPanel);
this.add(new JButton("Dummy"));
this.pack();
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
public static void main(String... args)
{
new Test();
}
}
A Screenshot for "seeing" the problem in my Main application
+1 to #MadProgrammer's answers.
You should have super.paintComponent(..) as the first call in your overriden paintComponent()
Do not extend JFrame unnecessarily
Create and minipulate Swing components via EDT
Dont call setPrefferedSize() rather override getPrefferedSize()
Here is an example which incorporates my advice's and #MadProgrammer's:
import java.awt.BasicStroke;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Test {
JFrame frame;
public Test() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final PaintPanel paintPanel = new PaintPanel();
paintPanel.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
paintPanel.addRect(e.getX(), e.getY());
}
});
frame.setLayout(new FlowLayout());
frame.add(paintPanel);
frame.add(new JButton("Dummy"));
frame.pack();
frame.setVisible(true);
}
public static void main(String... args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Test();
}
});
}
}
class PaintPanel extends JPanel {
public PaintPanel() {
addRect(100, 100);
}
ArrayList<Rectangle> rects = new ArrayList<>();
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setPaintMode();
for (Rectangle r : rects) {
g2d.setStroke(new BasicStroke(1));
g2d.fillRect(r.x, r.y, r.width, r.height);
}
}
public void addRect(int x, int y) {
rects.add(new Rectangle(x, y, 10, 10));
repaint();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
}
You're not calling super.paintComponent.
The graphics context used for a paint cycle is shared between all the components begin painted, this means if you don't take care to clear it before painting onto, you will end up with what ever was painted before you.
One of the jobs of paintComponent is to prepare the graphics for painting
I am trying to use Graphics2d to generate german unlauts and http://en.wikipedia.org/wiki/%C3%9F.
The output that I always see is two question marks. Any ideas about how to solve this?
Below is some code to print out the characters you want. My guess is that the font you are using may not have those characters if you are getting question marks. The font being reported when I run the example is LucidaGrande.
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
public class DrawStringUmlaut extends JPanel {
public DrawStringUmlaut() {
setPreferredSize(new Dimension(getPreferredSize().width, 200));
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawString("\u00f6", 10, 20);
g.drawString("\u00df", 40, 20);
g.drawString(g.getFont().getFontName(), 10, 40);
g.drawString(Integer.toString(g.getFont().getSize()) + " pt", 10, 60);
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new DrawStringUmlaut(), BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
});
}
}
If your system uses a font which can display these characters (ü and ß) , it should work out of the box.
Try the following example:
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class Graphics2dUmlaut extends Frame {
public void paint(Graphics g) {
Graphics2D g1 = (Graphics2D) g;
g1.drawString("\u00fc\u00df", 100, 100);
}
public static void main(String args[]) {
Frame frame = new Graphics2dUmlaut();
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
System.exit(0);
}
});
frame.setSize(200, 200);
frame.setVisible(true);
}
}