Post overriding the paint method of the components in java - swing

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).

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.

libgdx - ClickListener not affected by actor scale?

Here's a constructor for a card class I was making. When I create one that is scaled and click on it, only clicks within the 1.0x scaled area are actually registered. i.e. if I pass in 1.5 for the scale, clicks on the borders don't work. Why not? I've scaled the actor itself.
public Card(float x, float y, float scale)
{
this.setPosition(x, y);
faceSprite = new Sprite(MyResources.getInstance().cardTextureRegion);
faceSprite.setPosition(x, y);
faceSprite.setScale(scale);
borderSprite = new Sprite(MyResources.getInstance().cardBorderTextureRegion);
borderSprite.setPosition(x, y);
borderSprite.setScale(scale);
// Set boundaries for ourselves (the actor). Note that we have to match the scale of the sprites.
setSize(borderSprite.getWidth(), borderSprite.getHeight());
setScale(scale);
// Add ClickListener
final Card thisCard = this;
addListener(new ClickListener() {
public void clicked(InputEvent event, float x, float y) {
((MyStage)(thisCard.getStage())).cardClicked(thisCard);
}
});
}
Basic Actor class might be missing some functionalities, including proper scale handling. If all you want is displaying some images (judging by the Sprite objects you use), I'd suggest using the existing classes rather than making custom actors - especially since you might have trouble rendering Sprites with exact Actor parameters if you use a lot of custom actions.
Image allows you to display "sprites" - although somewhat simplified, it should be enough. To store the images, you can use a Table (more flexible) or a Stack (will work with multiple images of the same size).
If you really want to stick with the custom actor approach, try this instead of changing the scale:
setSize(borderSprite.getWidth() * scale, borderSprite.getHeight() * scale);
If you don't change Card scale manually in runtime (only set it up during creation), it should just work.
You Can use image Class to display Images.
Texture texture=new Texture("test.jpg");
Image image=new Image(texture);
//you can use setsize() or setBounds() as per your requirement.
image.setScale(scale);
image.addListener(new ClickListener(){
#Override
public void clicked(InputEvent event, float x, float y) {
((MyStage)(thisCard.getStage())).cardClicked(event.getTarget());
}
});

android Libgdx particle editor special line

As we all know that the particle editor give us a explosive particle line . However , what I need is a particle move from around point to the point I clicked . How can I realize this?
Just take a "Point particle" and change the position over time to the clicked point while the ParticleEffectis running. Thats all you need todo. A simple approach would be to create a class which holds the component ParticleEffect, an target position and extends Actor. Inside of the act(float delta) you update the position of the Actor into the direction of the target by an speedvalue multiplied with the delta time. Don't forget to update the postion of the ParticleEffect. Something like this:
#Override
public void act2(float delta) {
direction = this.pos - this.target; //both are vector2
direction.nor();
this.setPosition(direction.x*delta*velocity, direction.y*delta*velocity);
}
#Override
public void draw2(Batch batch, float alpha) {
emitter.setPosition(getX(), getY());
emitter.draw(batch);
}

Canvas repaint should be called by itself

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.

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());
}
}