I am relatively new to Java Graphics. I want to draw 20 x 80 rectangle at (X,Y) coordinates in JPanel when user clicks a JButton. (where 'X' and 'Y' are coming from 2 JTextFields) .
I have read many questions and tutorial, but could not solve a problem. In some cases, I can draw rectangle but cannot draw new rectangle without emptying JPanel.
Here is my code :
public class CustomPanel extends JPanel {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g); // first draw a clear/empty panel
g.draw3DRect(Integer.parseInt(x.getText()),Integer.parseInt(y.getText()), 20, 80, true);
// then draw using your custom logic.
}
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
//Code for frame
//Code for JTextfields x and y
JButton btnDraw = new JButton("Draw");
btnDraw.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
panel= new CustomPanel();
panel.setBounds(406, 59, 407, 297);
frame.getContentPane().add(panel);
frame.revalidate();
}
});
btnDraw.setBounds(286, 339, 89, 23);
frame.getContentPane().add(btnDraw);
}
You ActionListener code is wrong. You don't want to create a new panel, you want to add a Rectangle to the existing panel.
When you create the GUI you should add two panels to the GUI:
The first panel will be an empty panel that will do your custom painting. You would generally add this to the CENTER of the frame
The second panel will contain the "Draw" button. You would generally add this panel to the PAGE_END. Then when you click the Draw button you invoke a method like addRectangle(...) in your custom painting panel so the panel can paint the Rectangle.
Check out Custom Painting Approaches for the two common ways to do custom painting:
Keep a List of Object to paint and then in the paintComponent() method you iterate the LIst an paint each object.
Create a BufferedImage and then just paint the Rectangle onto the BufferedImage, then you can just paint the BufferedImage either in a JLabel or in your paintComponent() method.
Related
I create this class to draw the line and extend it as a component.
class MyCanvas extends JComponent {
public void paint(Graphics g)
{
g.drawLine(30, 20, 80, 90);
}
}
...
frame.getContentPane().add(new MyCanvas());
After drawing, when adding text fields to frame, it disappears.
frstVectorField = new JTextField("");
frstVectorField.setBounds(600, 50, 160, 30);
frame.add(frstVectorField);
frame.setLayout(null);.
The default content pane is a JPanel with BorderLayout layout manager. When you call method add(Component), of class JPanel, the Component gets placed in the CENTER area of the JPanel. Hence a subsequent call to method add(Component) will replace the Component that was previously added, since the CENTER area can only hold one Component.
I recommend the tutorial Creating a GUI With JFC/Swing
I created a separate class for JFrame and JPanel, then draw (fillOval in a JFrame class) and draw (fillOval in a JPanel class), and a button that will just animate the JPanel components. But the problem is, whenever i repaint the JPanel class; ---- The JFrame components disappeared. I don't understand why is this happening. I want the JFrame component be permanent for every animation done in JPanel class.
Sample Code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class TryRepaintIssue extends JFrame
{
public TryRepaintIssue(){
thePanel panel = new thePanel();
add(panel);
setSize(1000,1000);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public void paint(Graphics g){
super.paint(g);
g.fillOval(100,500,100,100);
}
public static void main(String[] args){
new TryRepaintIssue();
}
public static class thePanel extends JPanel{
private int y = 100, vector = 1;
public thePanel(){
JButton button = new JButton("Play");
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent ae){
y += vector;
repaint();
}
});
add(button);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.red);
g2.fillOval(100,y,100,100);
}
}
}
The JFrame components disappeared.
The components do not disappear. The button and panel are still displayed.
I assume you mean the custom painting of the black circle disappears.
I don't understand why is this happening
The paint() method of the frame is responsible for painting all the child components of the frame. So it repaints the JPanel you add to the frame, which in turn paints the JButton you add to the panel.
It then paints the black circle on top of the panel.
When you click the button you repaint only the "panel" which causes the JButton and the red circle to be painted.
You lose the painting of the black circle because you no longer invoke the code to paint that circle.
If you want the black circle to remain you have a couple of options:
The best solution is to NOT override paint() on the frame. Instead do all the custom painting in your panel. So paint both the black and red circles.
repaint the entire frame in your ActionListener code:
//repaint();
SwingUtilities.windowForComponent(button).repaint();
use the Glass Pane as suggested in the answer by Tom.
You shouldn't override JFrame.paint, particularly without calling the super. Usually drawing in these situations is done on a glass pane.
I'm making a game and I want to add a JTextField to a JPanel that has Paint Component. I repaint the JPanel every 16 milliseconds.
I add() the textfield to the panel but it show up only for a single frame when i click on it.
Then I tried to repaint() the textfield but now it is flashing.
public class Screen extends JPanel {
public Screen() {
JTextField txt = new JTextField();
txt.setBounds(10, 10, 300, 50);
this.add(txt);
}
#Override
public void paint(Graphics g) {
Graphics2D g2D = (Graphics2D) g;
g2D.setColor(Color.BLACK);
g2D.fillRect(0, 0, this.getWidth(), this.getHeight());
g2D.setColor(Color.WHITE);
g2D.fillRect(0, 0, this.getWidth(), 20);
txt.repaint();
}
}
I want to show the textfield on the top of the panel
JTextField txt = new JTextField();
When you create a JTextField you should use code like:
JTextField txt = new JTextField(10);
Now the text field can calculate its own preferred size.
//txt.setBounds(10, 10, 300, 50);
Don't use setBounds() to give a component a size. Again each Swing component is responsible for determining its own preferred size. Then the layout manager will set the size/location of the component on the panel.
//public void paint(Graphics g) {
public void paintComponent(Graphics g)
{
super.paintComponent(g);
// add custom painting here
}
Don't override paint(). Custom painting is done by overriding the paintComponent() method. And the first statement in the method should be super.paintComopnent(g)
//g2D.setColor(Color.BLACK);
//g2D.fillRect(0, 0, this.getWidth(), this.getHeight());
Don't paint the background of the panel. That is the job of the panel and that is why you need to super.paintComponent(), to make sure the background is painted.
Then in the constructor of your JPanel class you simply use setBackground( Color.BLACK )
//txt.repaint();
Don't ever invoke repaint() on any component in a painting method.
Read the section from the Swing tutorial on Custom Painting for working examples to get you started. Use the demo code as the starting point for you program. Then you simply add a JTextField to the panel, so it will be a single line of code that is needed to display the text field.
It seems like you want to have a JTextField on a black panel. You don't need to set the colour of the panel every time in paint() method. Instead add this to the constructor:
public Screen() {
setOpaque(true);
setBackground(Color.BLACK);
//...
}
and remove paint() method.
Also, if you want to use absolute positioning with setBounds() method then you should set the layout to null setLayout(null) in constructor. If you use absolute positioning you will also need to specify the size of the panel explicitly. However, I would still suggest you use a layout manager that takes care of panel sizing as well.
See this post for more information about absolute positioning.
I have a board game (think Monopoly) where multiple game pieces can be located on a single tile. I want to be able to arbitrarily place game pieces on the any given tile. I want the tile to have a background (image or just flat color) and be able to place up to 4 game pieces on the tile in a grid. I am currently using this code but the circles do not display.
tank.png is a 135 x 135 pixel background.
GraphicsTile:
public class GraphicsTile extends JPanel {
public static final Dimension SIZE = new Dimension(135, 135);
public static final GridLayout MGR = new GridLayout(4, 4);
public GraphicsTile() {
super();
setLayout(MGR);
initGraphics();
setSize(SIZE);
add(new CirclePanel());
}
private void initGraphics() {
JLabel panel = null;
try {
Image image = ImageIO.read(new File("tank.png"));
panel = new JLabel(new ImageIcon(image));
panel.setSize(SIZE);
} catch (IOException e) {
e.printStackTrace();
}
add(panel);
}
}
CirclePanel:
public class CirclePanel extends JPanel {
public CirclePanel() {
setSize(33, 33);
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D)g;
g2d.setColor(Color.RED);
Ellipse2D.Float circle = new Ellipse2D.Float(50, 50, 0, 0);
g2d.draw(circle);
g2d.fill(circle);
}
}
public class GraphicsTile {
I don't know how your code compiles since your GraphicsTile doesn't extend any Swing component yet you use methods like setLayout(...) and setSize(...) which implies you are trying to use it like a JPanel.
You should not be using setSize(...). A Swing component should have a preferred size. Then the layout manager will set the size and location of the component based on the rules of the layout manager. I'm guessing you have a problem because the preferred size is (0, 0).
I also have no idea how you add the GraphicsTile to the parent component. Again it looks like you are using setSize() when you should let the layout manager position the tiles on the game board.
Also, if you want to have a background image with circles on top then you need a hierarchical structure. That is you need something like:
panel
background image
circle component.
So my suggestions are:
CirclePanel needs to implement the getPreferredSize(...) method to return the size of your custom painting.
Your GraphicsTile class needs to extend JPanel. You would then override the paintComponent(...) method to draw your background image. Now you can add the CirclePanel instances to the this panel which will use the GridLayout.
I have a JSlider in a JPanel that return me a value of R-G-B .
I create it, in the Costructor of JPanel. I draw in same Panel (using paintComponent) a little circle, and I change his color using the Slider. I want that the color change in contemporany of slider shift.
So, i use the method repaint.. Next to Panel there is another Panel, with two button.. If I use method repaint in first panel , the buttons of second panel duplicated in the topLeft of First Panel. Why? Thank's you.
First Panel:
public class OptionsPanel extends JPanel {
static JSlider RBG = new JSlider(0,255);
OptionsPanel(){
this.setVisible(false);
this.setSize(350,1000);
this.setLayout(null);
this.setBackground(new Color(200,200,0));
Main.f1.add(this);
RBG.setVisible(true);
RBG.setSize(255,50);
RBG.setLocation(30,240);
this.add(RBG);
LotL lotl = new LotL();
Button save = new Button("Save");
save.setVisible(true);
save.setSize(100,40);
save.setLayout(null);
save.setLocation(60,300);
save.addActionListener(lotl);
save.setBackground(Color.yellow);
save.identificatore=3;
this.add(save);
}
boolean draw=false;
#Override
public void paintComponent(Graphics g){
g.drawOval(50,100,70,70);
g.setColor(new Color(RBG.getValue(),180,200));
g.fillOval(50,100,70,70);
repaint();
}
}
Second Panel:
public class FirstPanel extends JPanel{
FirstPanel(){
this.setVisible(true);
this.setSize(1000,1000);
this.setLayout(null);
this.setBackground(new Color(255,200,180));
Main.f1.add(this);
Button start = new Button("Start Game!");
Button options = new Button("Options");
LotL LotL = new LotL();
start.setVisible(true);
start.setSize(200,80);
start.setLayout(null);
start.setLocation(400,450);
start.addActionListener(LotL);
start.setBackground(Color.green);
start.identificatore=1;
this.add(start);
options.setVisible(true);
options.setSize(200,70);
options.setLayout(null);
options.setLocation(400,550);
options.addActionListener(LotL);
options.setBackground(Color.green);
options.identificatore=2;
this.add(options);
}
}
You've broken the paint chain...
#Override
public void paintComponent(Graphics g){
g.drawOval(50,100,70,70);
g.setColor(new Color(RBG.getValue(),180,200));
g.fillOval(50,100,70,70);
repaint();
}
Graphics is a shared resource, which gets passed to ALL the components that are painted during a given paint cycle.
One of the jobs of paintComponent is to prepare the Graphics context for painting, but filling with the components background color.
You MUST call super.paintComponent before performing any custom painting.
#Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
g.drawOval(50,100,70,70);
g.setColor(new Color(RBG.getValue(),180,200));
g.fillOval(50,100,70,70);
}
Also, there is never any need for paintComponent to be public, no one should ever be calling directly and NEVER modify the state of a component from within any paint method which may trigger a repaint, you will get yourself into a infinite loop which will eventually consume your CPU and make you computer unusable.
Take a look at Painting in AWT and Swing and Performing Custom Painting for more details
You should also avoid using null layouts, pixel perfect layouts are an illusion within modern ui design. There are too many factors which affect the individual size of components, none of which you can control. Swing was designed to work with layout managers at the core, discarding these will lead to no end of issues and problems that you will spend more and more time trying to rectify