I ran into a problem where no matter what I do my JPanel won't repaint. I was using the following method to create a connect four game board and dynamically change the color of the circles as the play progresses, but I've simplified it into a test class which has the same issue.
I decided to use a state pattern design for each of the circles. The following is the code for the classes so it knows which color to print which are JPanel children classes.
public class GridCircle extends JPanel
{
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillRect(0, 0, 100, 100);
}
}
public class WhiteGridCircle extends GridCircle
{
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.WHITE);
g.fillOval(5, 5, 80, 80);
}
}
public class RedGridCircle extends GridCircle
{
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.RED);
g.fillOval(5, 5, 80, 80);
}
}
The following is a test class where I attempt to change the class of a JPanel in the main method to see if it would change the color that is painted (which fails).
public class test extends JFrame
{
static JPanel testPanel = new WhiteGridCircle();
public static void main(String[] args)
{
new test();
testPanel = new RedGridCircle();
testPanel.revalidate();
testPanel.repaint();
}
test()
{
this.add(testPanel);
this.setSize(150,150);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
}
}
I can't figure out why the panel wouldn't repaint no matter what I've tried. From what I understand repaint() has no guarantee to call a the paint method but I see no reason it shouldn't when theres nothing else going on.
Because instance you created and added this.add(testPanel); is still new WhiteGridCircle().
You changed instance but the original one added to JFrame remains in the frame.
To change call this.getContentPane().add(testPanel); after instantiating RedGridCircle and before revalidate() call.
Related
Hi I have made an actionlistener and I want to call a paintComponent method when you click the button?
I have googled it but with no luck.
Here is the actionlisetener,
graf.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
graf();
}
And here is the method,
public static void paintComponent (Graphics g) {
int width = Integer.parseInt(xinwindow.getText());
int hight = Integer.parseInt(yinwindow.getText());
g.setColor(Color.black);
g.drawLine((width/2)- 1, 0, (width/2) +1 , hight);
}
How to call it?
Any help would be appreciated.
Override the paintComponent method of a JComponent object you want to paint.
JComponent c = new JComponent() {
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int width = Integer.parseInt(xinwindow.getText());
int hight = Integer.parseInt(yinwindow.getText());
g.setColor(Color.black);
g.drawLine((width/2)- 1, 0, (width/2) +1 , hight);
}
}
And add
c.revalidate();
c.repaint();
after handling the click in actionPerformed.
You should start with some examples to construct a GUI.
static is for a global, a once occuring instance; one per class. Try to remove all, just the program's entry point:
public static void main(String args) {
JFrame appWindow = new MyFrame();
SwingUtilities.invokeLater(() -> appWindow->setVisible(true));
}
public class MyFrame extends JFrame {
private MyPanel panel;
public MyFrame() {
panel = new MyPanel();
add(panel);
panel.addClickListener(evt -> panel.repaint(50L));
}
}
public class MyPanel extends JPanel {
#Override
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.RED);
g2.drawRectangle(40, 40, getWidth() - 80, getHeight() - 80);
}
}
The mechanism is as follows:
A click is handled on the event dispatching thread of swing.
Here it says to repaint the panel in 50 ms.
A bit later repaintComponent is called from the swing framework in the conjunction of erasing the background and painting the child components.
In paintComponent the Graphics parameter for all newer java versions actually is a Graphics2D which has many nice methods.
In my application (using java), a button is pushed and then a panel opens up with a graph on it. To create the graph I am using graphics/paint. However, I am unable to get the graphics to show up. For now, I am just trying to paint a circle (instead of the actual graph). It would be much appreciated if someone could explain what I am doing wrong.
public class SeeProgressHandleClass extends JPanel{
public SeeProgressHandleClass(JFrame window) {
this.window = window;
}
public void mouseClicked(MouseEvent e) {
panel = new JPanel();
fillPanel();
window.add(panel);
panel.setBackground(Color.white);
panel.setBounds(50, 40, 1100, 660);
}
public static void fillPanel() {
Graph graph = new Graph();
panel.add(graph);
}
}
public class Graph extends JPanel{
public void paintComponent(Graphics g) {
super.paintComponent(g);
this.setBackground(Color.white);
g.setColor(Color.green);
g.fillOval(50, 50, 50, 50);
}
}
Graph should provide preferredSize hints, which will allow the layout manager to make better determinations about how the component should be displayed. Consider overriding getPreferredSize
Don't call this.setBackground(Color.white); inside paintComponent, each time you do this, it will trigger a potential repaint request, which will eventually consume all your CPU cycles. Set this in the constructor
You're adding Graph into JPanel and then adding this to the screen ... not sure why, but it's making it more confusing
After window.add(panel);, all window.revalidate() and window.repaint() to trigger a new layout and paint pass
public void display() {
pan.repaint();
fen.add(pan);
fen.addKeyListener(this);
fen.setResizable(false);
fen.setTitle("Le Jeu 2D");
img.setText("Coucou");
pan.add(img);
pan.repaint();
pan.setBackground(Color.yellow);
fen.setVisible(true);
fen.setSize(480, 272);
pan.repaint();
fen.revalidate();
}
public void paintComponent(Graphics g) {
System.out.println("zzz");
pan.paint(g);
g.setColor(Color.red);
g.drawRect(10, 10, 10, 10);
}
It doesn't draw anything. Why? I have defined the paint component method, so I don't understand why.
Edit: I edited my code, please take a look
You don't create an instance of your Game class and don't add it to the JFrame.
Here is the Game panel which you are painting on:
Game.java
public class Game extends JPanel {
#Override
public final void paintComponent(final Graphics g) {
super.paintComponent(g);
g.setColor(Color.red);
g.drawRect(10, 10, 10, 10);
}
#Override
public Dimension getMinimumSize() {
return new Dimension(300, 300);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
#Override
public Dimension getMaximumSize() {
return new Dimension(300, 300);
}
}
You then need to create an instance of this Game panel and add it to your JFrame:
GameFrame.java
public class GameFrame extends JFrame {
public GameFrame() {
setLocationRelativeTo(null);
setResizable(false);
setTitle("2D Game");
Game game = new Game();
setContentPane(game);
pack();
setVisible(true);
}
}
Then when you create an instance of the JFrame:
Example.java
public class Example {
public static void main(String[] args) {
new GameFrame();
}
}
The panel will be added, and painted:
You never create an instance of the Game class and you never add the Game class to the frame. Even if you did create an instance the size would still be (0, 0) so there would be nothing to paint.
Basically the whole structure of your code is wrong.
I suggest you start over and start with the demo code found in the Swing tutorial on Custom Painting.
The basic structure of your code seems weird.
You could instantiate a JFrame in your main control class, ie. it should be GAME class in this case. Then you can create a new JPanel class and add its object into the JPanel object. Within the JPanel class, you can create all the elements you need and set corresponding parameters. You could also add the event listener in an inner class or a separate class.
The code that I have now gives me the size of the applet, not the size of the drawing area. How could I fix that?
public void paint(Graphics g)
{
g.setColor(new Color(255,255,255));
g.fillRect(5, 5, getWidth()-5, getHeight()-5);
}
Emm... I guess you are trying to paint right in JApplet so you should have applet and canvas been separated
use code conception like a
class MyCanvas extends JPanel
{
public void paintComponent(Graphics g)
{
g.setColor(new Color(255,255,255));
g.fillRect(5, 5, getWidth()-5, getHeight()-5);
}
}
and applet...
public class MyApplet extends JApplet
{
public void init()
{
this.getContentPane().add(new MyCanvas());
}
}
P.S.
Report if that was helpful
I have the folowing custom JPanel and I have aded it to my frame using Netbeans GUI builder but the background won't change! I can see the circle, drawing with g.fillOval(). What's wrong?
public class Board extends JPanel{
private Player player;
public Board(){
setOpaque(false);
setBackground(Color.BLACK);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.red);
g.fillOval(player.getxCenter(), player.getyCenter(), player.getRadius(), player.getRadius());
}
public void updatePlayer(Player player){
this.player=player;
}
}
If your panel is 'not opaque' (transparent) you wont see your background color.
You have to call the super.paintComponent(); as well, to allow the Java API draw the original background. The super refers to the original JPanel code.
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.red);
g.fillOval(player.getxCenter(), player.getyCenter(), player.getRadius(), player.getRadius());
}
You need to create a new Jpanel object in the Board constructor.
for example
public Board(){
JPanel pane = new JPanel();
pane.setBackground(Color.ORANGE);// sets the background to orange
}
setOpaque(false);
CHANGED to
setOpaque(true);
I just tried a bare-bones implementation and it just works:
public class Test {
public static void main(String[] args) {
JFrame frame = new JFrame("Hello");
frame.setPreferredSize(new Dimension(200, 200));
frame.add(new Board());
frame.pack();
frame.setVisible(true);
}
}
public class Board extends JPanel {
private Player player = new Player();
public Board(){
setBackground(Color.BLACK);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.red);
g.fillOval(player.getCenter().x, player.getCenter().y,
player.getRadius(), player.getRadius());
}
}
public class Player {
private Point center = new Point(50, 50);
public Point getCenter() {
return center;
}
private int radius = 10;
public int getRadius() {
return radius;
}
}
In order to completely set the background to a given color :
1) set first the background color
2) call method "Clear(0,0,this.getWidth(),this.getHeight())" (width and height of the component paint area)
I think it is the basic procedure to set the background...
I've had the same problem.
Another usefull hint : if you want to draw BUT NOT in a specific zone (something like a mask or a "hole"), call the setClip() method of the graphics with the "hole" shape (any shape) and then call the Clear() method (background should previously be set to the "hole" color).
You can make more complicated clip zones by calling method clip() (any times you want) AFTER calling method setClip() to have intersections of clipping shapes.
I didn't find any method for unions or inversions of clip zones, only intersections, too bad...
Hope it helps