Canvas repaint should be called by itself - swing

I have an application with jTabbedPane. There are two tab (JPanel) in jTabbedPane. First tab includes canvas and second one includes simple JLabel. Button draws rectangle into canvas.
Every thing is fine until then. However, when switching tabs, canvas would lose everything. It should be repainted by itself.
Rectangle should exist after changing tabs. Do you have any idea about the problem?
My button code is here:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
Graphics g = canvas1.getGraphics();
g.drawRect(10, 10, 100, 100);
}
Thanks in advance.

First of all, you shouldn't put AWT components inside Swing components. Use JComponent or JPanel instead of Canvas.
Second, no, it shouldn't repaint itself. When the button is clicked, you should simply store what should be painted in some variable, and the paintComponent() method should be overridden in order to paint what is stored in this variable. This way, every time the component is repainted, it will repaint what has been stored last in this variable.
For example:
public class RectangleComponent extends JComponent {
private boolean shouldPaintRectangle = false;
public void setShouldPaintRectangle(boolean b) {
this.shouldPaintRectangle = b;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (shouldPaintRectangle) {
g.drawRect(10, 10, 100, 100);
}
}
}
In general, you should never ask the Graphics of a component and paint on it. Instead, you should override paintComponent() and paint the component using the Graphics passed as argument.

Related

Libgdx: Draw a Sprite on touchdown

I want to draw A Sprite when touchDown event occurs and disposed when touchUp occurs. I tried following code:
public class Connect4Screen implements Screen {
SpriteBatch batch;
Connect4Screen(){
batch = new SpriteBatch();
camera = new OrthographicCamera(30, 20);
camera.update();
batch.setProjectionMatrix(camera.combined);
Gdx.input.setInputProcessor(new InputAdapter(){
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
drawChip();
}
}
}
public void drawChip(){
batch.begin();
batch.draw(new Texture("Images/yellow.png"), 0, 5, 1.4f,1.4f);
batch.end();
}
}
I scrapped off unnecessary code.
What is wrong here?
If you simply draw something as a one-time event, it will only be visible for 1/60 of a second. Games redraw the screen over and over in a loop, so to cause something to appear and stay on the screen, you need to set a member Boolean that indicates it should be drawn, and then in your render method you draw that item if the Boolean is true.
That's a very simplified explanation. Games tend to have many different items to draw that come and go, and keeping separate Booleans for each of them is impractical. So typically you'll have a list of items to draw, and you can add and remove items from the list based on events in the game. In your render method, you would loop through the list and draw everything in it.
Also, you must not create a new Texture without keeping a member reference to it so you can dispose() it later. Textures use native memory on the GPU and must be disposed of or they will leak memory. In LibGDX, any object that can leak memory implements Disposable, and must be disposed before you lose track of the reference.

Post overriding the paint method of the components in java

In java awt or swing when you want to change painting of some component you usually have to override the method paint(Graphics g) (in awt) or paintComponent(Graphics g) (in swing).
This is usually (maybe allways - I'm not sure) done when you are creating the component for example:
JPanel jPanel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
//... my implementation of paint, some transfromations, rotation, etc
}
};
Imagine that you have container of components which could for example consists of some JLabels, some JTextFields, some image. Which will be all put on one component.
By container I mean you have some list or map with ids or some similar structure in which are all components you will put on one JFrame.
The question is if I can change the painting method after creating with all of the components which are in this list in the moment when all of them are already created. For example I want do the rotation action (rotate), which is defined in Graphisc2D, with all of them.
So basicaly what I want is that I throught the list of componets I have and say:
"All of you (components) which are in the list will be rotated by some angle". Is that possible? If yes how?
Edit:
This is my not correctly working solution:
graphicalDisplayPanel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g2d = (Graphics2D) g;
g2d.rotate(Math.PI, anchorx, anchory);
}
#Override
public void paintChildren(Graphics g) {
super.paintChildren(g);
Graphics2D g2d2 = (Graphics2D) g;
g2d2.rotate(Math.PI, anchorx, anchory);
}
};
JFrame jFrame = JFrame();
// ... setting dimension, position, visible etc for JFrame, it works correctly nonrotated
jFrame.setContentPane(graphicalDisplayPanel);
I have not tested this, but it seems like it would work. A JComponent's paint() method calls:
paintComponent(co);
paintBorder(co);
paintChildren(co);
where co is a Graphics object. In theory you create an image, retrieve the graphics object and then pass that into paintChildren(). you will have to call paintComponent() and paintBorder() yourself, if you do this. Then, just rotate the image and draw it into your component. You may have to crop the image or resize your component accordingly for this to work. It might look something like this:
BufferedImage myImage;
#Override
public void paint(Graphics g){
myImage = new BufferedImage(getWidth(), getHeight(), BufferedImage.TRANSLUCENT);
//using a transparent BufferedImage might not be efficient in your case
Graphics myGraphics = myImage.getGraphics();
super.paintComponent(g);
super.paintBorder(g);
super.paintChildren(myGraphics);
//rotation code here
// ...
//draw children onto your component
g.drawImage(myImage, 0, 0,getWidth(), getHeight(), null);
}
I hope I didn't make any mistakes, please let me know if this works.
So basicaly what I want is that I throught the list of componets I have and say: "All of you (components) which are in the list will be rotated by some angle".
If you want to rotate panel and therefore all the components on the panel as a single using then you need to do the custom painting in the paintComponent() method.
If you want to rotate, for example, individual images that each have a different angle of rotation then you can again do this in the paintComponent(...) method and change the angle for each component.
Or, in this second case you can use the Rotated Icon class. In this case the Icon is just added to a JLabel. Then you can change the degrees of rotation and repaint the label, so there is no custom painting (except in the Icon itself).

How to finish animation with libgdx

I am trying to implement a simple animation with libGDX and I am currently stuck on one thing. Lets say I have a bunch of sprites which take some time to finish. For example, around 30 sprites like this link: https://github.com/libgdx/libgdx/wiki/2D-Animation
However, before the animation completes some key is pressed. For smooth animation I want the 30 frames to be completed before I start the next set of animation, to prevent an abrupt stop.
So my question is how do I achieve it this in libGDX? My current idea is to extend the Animation class, which would keep track of how frames I have and how many have been rendered and then display the rest. Or use the isAnimationFinished(float stateTime) function (though I haven't had luck using that).
The examples I have seen like superjumper have very few animations and don't really change that much.
Also, is there a way to hold the list of sprites from a TextureAtlas.createSprites method and use those with the Animation class? If not, whats the purpose of providing this function?
Thanks
You can use
animation.isAnimationFinished(stateTime);
To see if your animation is finished.
For the sprites : personnaly I use TextureRegion from a TextureAtlas and I store them in an array for my animation
I create a class AnimatedImage that extends Image to automate spriting in Image. My code will be like this:
public class AnimatedImage extends Image{
private Array<Array<Sprite>> spriteCollection;
private TextureRegionDrawable drawableSprite;
private Animation _animation;
private boolean isLooping;
private float stateTime;
private float currentTime;
public AnimatedImage(Array<Array<Sprite>> _sprites, float animTime, boolean _looping){
// set the first sprite as the initial drawable
super(_sprites.first().first());
spriteCollection = _sprites;
// set first collection of sprite to be the animation
stateTime = animTime;
currentTime = 0;
_animation = new Animation(stateTime, spriteCollection.first());
// set if the anmation needs looping
isLooping = _looping;
drawableSprite = new TextureRegionDrawable(_animation.getKeyFrame(currentTime));
this.setDrawable(drawableSprite);
}
public void update(float delta){
currentTime += delta;
TextureRegion currentSprite = _animation.getKeyFrame(currentTime, isLooping);
drawableSprite.setRegion(currentSprite);
}
public void changeToSequence(int seq){
// reset current animation time
resetTime();
_animation = new Animation(stateTime, spriteCollection.get(seq));
}
public void changeToSequence(float newseqTime, int seq){
_animation = new Animation(newseqTime, spriteCollection.get(seq));
}
public void setRepeated(boolean _repeat){
isLooping = _repeat;
}
public boolean isAnimationFinished(){
return _animation.isAnimationFinished(currentTime);
}
public void resetTime(){
currentTime = 0;
}
}
changetosequence method will make new Animation that will be used to update the current TextureRegionDrawable at the update method. resetTime will reset the total time for the animation when you call changeToSequence. You could add the event listener to call changeToSequence method.
Here is the example:
private AnimatedImage _img;
then I add the InputListener like this:
_img.addListener(new InputListener(){
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button){
_img.changeToSequence(1);
return true;
}
});
Hope it helps.
Use tween engine for this kind of animation. Its well documented and libgdx supports it .. Google about it , and you can find bunch of examples using libgdx .. Hope it will help you !!

Graphics plain 2D objects are not rendered while an action occurred

I am designing a game in Swing. Currently I am designing the maze for this game. The maze is generated by using Depth First Search algorithm. In my main JFrame, I have some JPanel. One JPanel, named mazePanel contains the maze. There are some other JPanel also, which contains the JButton for controlling. Following is the mazePanel code.
import java.awt.Graphics;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
public class MazePanel extends JPanel {
private MazeGenerator mazeGenerator;
private boolean startNewMaze = false;
public MazePanel() {
setBorder(BorderFactory.createTitledBorder("Maze"));
setToolTipText("This is the maze");
}
public void addNewMaze() {
startNewMaze = true;
mazeGenerator = new MazeGenerator();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (startNewMaze) {
mazeGenerator.generate(g);
startNewMaze = false;
}
}
}
There is one JButton, which calls the method mazePanel.addNewMaze() and set the Boolean startNewMaze to true. After setting the startNewMaze, maze should be generated. i.e. mazeGenerator.generate(g) is inside if() condition. Method mazeGenerator.generate(g) recursively draw the random maze. That is why I don’t want to run this method not more than once.
Up to this everything is looking fine. But while I am running the main JFrame and clicks on the JButton, maze is not rendered in the mazePanel. Sometimes when I minimize and maximize the JFrame, maze rendered (might be because of repaint() occur). Even if I comment mazeGenerator.generate(g) inside if() condition and put some g.drawString(). The string is not rendered while action performed (i.e.Pressing JButton).
Where is the problem? Please help.
Thank you.
So basically you have a JPanel which contains nothing, you call a method unknown to Swing and expects the paintComponent method is magically called when you change the state of a private field.
You already discovered that minimizing and maximizing again solves your problem due to a repaint. That should be sufficient information to know you have to trigger a repaint yourself when you press that button.
If you would have followed the suggestion from #kleopatra to, and I quote,
change the state and then trigger the revalidation/painting
you would already have solved your problem

Better choice: TextLayout or JTextComponent for an "ellipse with editable text" component?

If you've ever used Visio or a UML class diagram editor, you have an idea of what I'm trying to accomplish: Within a JFrame, users can add ellipses that enclose a small editable text field. These ellipses can be repositioned within the frame when the user drags them. Clicking on an ellipse causes the text to become editable: a carat appears, highlighting a substring is possible, etc.
I've got the basic structure set up: the 'ellipse' is a self-contained component, with methods called on it from the containing JFrame and its listeners. I've tried two approaches:
in the component's draw() method, use a TextLayout to find bounds, position the contained text within the ellipse, and draw it to the frame using TextLayout's draw(). This is fast. Dragging the components around in the JFrame, mouse-over and mouse-click behavior are all straightforward. However for the editing functionality it looks like I will need to write a lot of custom code to handle hit testing, carat positioning, text highlighting, line wrapping, etc.
having the component contain a reference to the containing JFrame, and adding or repositioning a TextComponent in that JFrame after drawing the ellipse. This has the advantage of all the built-in TextComponent behavior for editing and line wrapping. But the logistics are really sloppy, and positioning the TextComponent becomes messy too - especially when the user drags the component around.
I'm quite possibly thinking about this all wrong. Can anyone suggest a simple way to do this that I haven't yet stumbled across?
Why don't you combine both your approaches. As long as you are editing, display the text component, otherwise paint all text using a TextLayout. The following example code shows such an approach extending a simple JComponent. It draws a rectangular shape with some text in it and if you click inside it shows an editing possibility. As soon as you click outside again, the component vanished. Note that all the edit-handling functionality is missing in this basic example.
class TestComponent extends JComponent {
JTextArea jta = new JTextArea("12345");
public TestComponent() {
setPreferredSize(new Dimension(400, 400));
setLayout(null);
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(final MouseEvent e) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
if (e.getX() >= 40 && e.getX() <= 200 && e.getY() >= 40 && e.getY() <= 80) {
TestComponent.this.add(jta);
jta.setBounds(42, 42, 156, 36);
} else {
TestComponent.this.remove(jta);
}
repaint();
}
});
}
});
}
#Override
public void paintComponent(Graphics _g) {
Graphics2D g = (Graphics2D) _g;
g.drawRect(40, 40, 160, 40);
TextLayout layout = new TextLayout("12345", g.getFont(), g.getFontRenderContext());
layout.draw(g, 42, 42 + layout.getAscent());
}
}