How to repaint/call again paintComponent? - java

So I have this code:
public class myPanel extends JPanel implements ActionListener{
int x = 0;
JButton myButton = new JButton("Click me");
public myPanel(){
super().setLayout(null);
myButton.setBounds(50,50,50,50);
super().add(myButton);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
if(x==1)
g.drawString("hi",10,10);
}
public void actionPerformed(ActionEvent e){
if(e.getSource()==myButton){
x=1;
//Do something here
}
}
}
How do I call paintComponent again? Say when I press the button, it calls paintComponent again and draw the string, "Hi", after checking if the integer,x, is equal to one? Thank you in advance!!! Still very new to Java here, so can you guys explain this like you will to a 10 year old?

Call repaint(), it will paint it again.

You would call repaint() after any change in state that should change the GUI's view. For instance, if the button changes a variable, and if this should be reflected in a change in the view, call repaint() in the button's ActionListener. If a mouse drag changes the view of an ImageIcon sprite, then you would call repaint in the MouseMotionListener's mouseDragged method. If a Swing Timer drives an animation, then you would call repaint() from within the Swing Timer's ActionListener.
One thing you never want to do is to call repaint() from within a paint(Graphics g) or paintComponent(Graphics g) method as this will lead to looping that is completely out of your control.
On a side note, in general you will want to avoid using null layouts and setBounds as this makes for very inflexible GUI's that while they might look good on one platform look terrible on most other platforms or screen resolutions and that are very difficult to update and maintain.

Related

how to call a graphical method in actionperformed?

I am kinda new to java and would like to invoke a graphical method in ActionEvent, for instance let's say I would like a square to be drawn when button b is pressed? Will appreciate any help thanks:
package Mst;
import java.awt.*;
import java.applet.Applet;
import java.awt.event.*;
public class Cours2_2 extends Applet implements ActionListener {
Button a,b,c;
public void init(){
setBackground(Color.pink);
a= new Button("KIRMIZI");
a.addActionListener(this);
add(a);
b= new Button("BEYAZ");
b.addActionListener(this);
add(b);
c= new Button("SARI");
c.addActionListener(this);
add(c);
}
public void paint(Graphics g){
g.drawString("s", 5, 5);
}
public void actionPerformed(ActionEvent e){
String s= e.getActionCommand();
if(s.equals("KIRMIZI")){
setBackground(Color.red);
}
if(s.equals("BEYAZ")){
setBackground(Color.white);
}
if(s.equals("SARI")){
setBackground(Color.yellow);
}
drawStrings(t);
}
public void drawStrings(Graphics t) {
t.setColor(Color.yellow);
t.fillRect(0, 0, 75 ,75);
}
}
I would like to know if I should create this square which I want drawn when a button is pressed as a method or a function. Thanks
Avoid Applet, if you "really" have to, use JApplet instead. Having said that, you should start with JPanel and override it's paintComponent method instead (and make sure you call super.paintComponent before doing any custom painting. Take a look at Painting in AWT and Swing and Performing Custom Painting for more details.
Generally speaking, painting in AWT/Swing is passive, that is, when the system "decides" something needs to be updated, it will then be painted. This means that you (generally) have little control over when something will be painted. You make suggestions, but it's update to the system to decide what and when something is painted.
You paint methods should paint the current state of the component. This means that you will need to provide some information and logic that the paint methods can use to make decisions about what to paint. For example, you could have a flag, which is changed by the ActionListener, which calls repaint on your component and when the component is painted, you would test the state of this flag and make decisions on what should be done (like drawing a square for example).
A more complicated approach might use a List and take advantage of the Shape API, adding or removing shapes to the List which the paint method would then be able to iterate over and paint
Have a look at Collections Trail and
2D Graphics for more details

Overriding paintComponent() Method within a custom JButton

So my ultimate goal is to change the design of a JButton from the basic looking blue button to whatever I want, like a circle.
So I create a class called "Button" and made it extend JButton
public class Button extends JButton {
public Button(String text) {
super(text);
this.setContentAreaFilled(false);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("hello");
//Paint Stuff Will Happen Here
}
#Override
public Dimension getPreferredSize() {
return (new Dimension(120, 120));
}
}
My first goal was just to make sure that the paintComponent method was being called, so I put in a debug message. That debug message has never shown.
Basically the paintComponent() method is never called, even though I'm manually calling the "repaint" method for my JFrame.
Despite the fact that the method is not being called, a regular button still shows up on my JFrame, which is really confusing to me.
Here is my JPanel code
public class Scene extends JPanel {
public Scene() {
//Initialize Listeners
Button button = new Button("Hello");
button.setBounds(400, 400, 50, 25);
this.setLayout(null);
this.add(button);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
//Paint Stuff Below
for (int xI = 0; xI < Sprite.allSprites.size(); xI++) {
Sprite sprite = Sprite.allSprites.get(xI);
if (sprite.isVisible) {
g2.drawImage(sprite.image, sprite.rawLocation.x.intValue(), sprite.rawLocation.y.intValue(), null);
}
}
g2.dispose();
}
}
Basically in my JPanel I override the paintComponent method as well so as to paint my various sprites onto the screen, which has worked just fine and is probably irrelevant to the issue.
And finally, this is my JFrame code
public class GameWindow extends JFrame {
private Scene currentScene;
public void initialize(Scene scene) {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(Settings.DEFAULT_WINDOW_SIZE);
this.setResizable(false);
this.setLocation(this.getLocationToCenterScreen());
this.setScene(scene);
}
//Gets the center of the screen with the given window
public Point getLocationToCenterScreen() {
return new Point(Settings.SCREEN_CENTER.x - (this.getSize().width / 2), Settings.SCREEN_CENTER.y - (this.getSize().height / 2));
}
public void setScene(Scene scene) {
this.currentScene = scene;
this.setContentPane(scene);
}
public Scene getCurrentScene() {
return currentScene;
}
}
Nothing really fancy in this code as far as I can tell.
I've set the content pane.
I've made sure each paintComponent() method also includes super.paintComponent(g).
I've set the LayoutManager to null for testing purposes.
I've set the Button's bounds.
As I said, the button actually does show up on the screen. But the debug message never shows.
Also, the button that shows up on the screen looks like the really old Windows buttons from 10 years ago. It's all grey with a black border.
This old button only shows up if I'm using a class that extends JButton.
Anyways, thanks guys! I hope I can get over this weird problem.
First and foremost, as a few other people have said, don't name your class "Button"; that belongs to Swing's predecessor, AWT (Advanced Windowing Toolkit), and is likely to confuse the compiler at best, and get you the wrong "Button" at worst.
That should solve the paintComponent() problem, but in addition, if all you're trying to do is change the feel of the button, then you're overprogramming this.
There are two ways to accomplish this with a JButton.
The first, and probably easiest (for an image), is AbstractButton.setIcon(Icon defaultIcon) An Icon is a type of image, loadable from a BufferedImage with ImageIcon(Image image) and manipulable in the same way. This is probably what you need.
The other method which comes to mind, which is much more broad in scope, is change the Look and Feel of the application. Most of us have several available to our systems, inclusive of the default Java look and feel, and the platform look and feel. I recommend setting it as early as possible; since it's entirely done through static methods, for small projects you might even get away with slipping it into the main method, before anything is even initialized.
Let me know if this doesn't solve your problem, and I wish you luck with the rest of your project!

Strange repositioning using repaint();

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

Clearing drawings on Jframe

I am making a game in which I move a square with my mouse, but when I move my mouse the old squares do not delete, which results in a trail of squares. I would like it to only have the one square which is following my mouse. This is currently my code. I have read to use paintcomponents but I am not sure how to use it since I am still a beginner.
This is in my "GamePanel" Class
public void mouseMoved(MouseEvent m) {
Graphics g= this.getGraphics();
h.changeX(m.getX());
h.changeY(m.getY());
h.drawHero(g);
}
This is in my "Hero" Class
public void drawHero(Graphics g){
g.drawImage(heroPic,stX,stY,null); //heroPic is a picture I imported
Don't use the this.getGraphics(). That is something you will definitely not want to to do, since it produces artifacts (as you mentioned).
It would be better to store the mouse position as a variable, then handle all the rendering when the paintComponent(Graphics) method has been called. Be sure to also call super.paintComponent(Graphics) to get rid of artifacts.
Generally, you should only handle graphics inside the paintComponent(Graphics) method and in any methods that are called only from the paintComponent(Graphics) method.
Here is a question which touches on why you should avoid Component#getGraphics(): Drawing an object using getGraphics() without extending JFrame
Here is another question I answered revolving around rendering with graphics: Java JFrame draw
Use a seperate class that extends JPanel :
class DrawPane extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(heroPic, x, y, this);
}
}
Then create a variable that will hold this class object :
DrawPane dp = new DrawPane();
after that set the variable to the contence pane. :
JFrame.setContencePane(dp);
Now to repaint this do :
dp.repaint();
Do not worry about the 'Graphics g' you wont have to input anything.

Drawing graphics on top of a JButton

I have a situation wherein I have a bunch of JButtons on a GridLayout. I need each of the JButtons to have:
a background image (but retain the ability to keep the default button look if needed)
custom graphics drawn on top by other classes
I have no trouble with the background image, since I am using setIcon() but I am having problems drawing things on top of the background. At one point I was able to draw on top of the button, but after the button was clicked, the drawings disappeared. How can make the button keep this drawing state?
Basically, I need a way for my JButtons to have public methods that would allow another class to draw anything on it such as:
public void drawSomething() {
Graphics g = this.getGraphics();
g.drawOval(3,2,2,2);
repaint();
}
or
public Graphics getGraphics() {
return this.getGraphics();
}
then another class could do this:
button.getGraphics().drawSomething();
The latter is more what I am looking for but the first is equally useful.
Is there any way to go about this? Also, overriding the parent class method paintComponent() doesn't help since I need each button to have different graphics.
you can subclass JButton and override paintComponent().
you can handle each button having a different graphic by providing an external 'painter' to the subclass. Or just have a different subclass for each different graphic.
public class MyButton extends JButton {
private Painter painter;
public void paintComponent(Graphics g) {
super.paintComponent(g);
painter.paint(g);
}
}
public interface Painter {
public void paint(Graphics g);
}
you cannot just paint on the button as you are doing as the painting will get lost when the button is next repainted.
You can create a BufferedImage and do custom painting on it and then draw the image in your custom paintComponent(...) method.
Look at the DrawOnImage example from Custom Painting Approaches.

Categories

Resources