Using JRE 5.0.0, simulator device is an 8520.
On a screen I am using a FlowFieldManager(Manager.VERTICAL_SCROLL) and adding Fields to it to show data.
When I do
this.flowManager = new FlowFieldManager(Manager.VERTICAL_SCROLL);
Field field = new Field()
{
protected void paint(Graphics graphics)
{
graphics.drawTest("Test", 0, 0);
}
protected void layout(int width, int height)
{
this.setExtend(300, 300); // just testing
}
}
this.flowManager.add(field);
The screen renders correctly and 'Test' appears on the screen.
If, on the other hand, I try and abstract this into a class called CustomField with the same properties and add it to the flow manager the render will not happen. Debugging shows that the device enters into the Object, into the layout function, but not the paint function.
I can't figure out why the paint function is not called when I extend Field. The 4.5 API says that layout and paint are the only functions that I really need to extend. (getPreferredWidth and getPreferredHeight will be used to calculate screen sizes etc.)
Thanks in advance.
If at the time of paint a Field is outside the clipping region, it will not be instructed to paint. That's really the only thing that I can see wrong with this.
So make sure you don't have this Field scrolled off the screen somewhere.
Related
I'm working on project, which uses custom Layout Manager. My goal is rotate all components by 180°.
I have some screen which consists of JFrame. I also have some LayoutHandler, which defines some layers of layout. Each layer is instance of LayerLayout which implements LayerManager2 from java.awt
The flow works probably like this:
I have JFrame, which represents the display. This JFrame has some default contentpane. The application set to this contentpane Layout which is represented by LayerHandler:
graphicalDisplayJFrame.getContentPane().setLayout(new LayerLayout(layerHandler));//graphicalDisplayJFrame is JFrame which represents the display
The layerHandler just somehow manage the layers which are LayerLayouts which implemetns LayerLayout2 from java.awt. So it looks like layout of layouts or whatever it is. I'm not much experienced with creating custom layouts.
There I have a situation which shows creating of JFrame.
graphicalDisplayJPanel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g2d = (Graphics2D) g;
g2d.rotate(Math.PI, anchorx, anchory); //rotation 180°
}
#Override
public void paintChildren(Graphics g) {
super.paintChildren(g);
Graphics2D g2d2 = (Graphics2D) g;
g2d2.rotate(Math.PI, anchorx, anchory);
}
};
graphicalDisplayJFrame = new JFrame(); //creation of JFrame
graphicalDisplayJFrame.setContentPane(graphicalDisplayJPanel); //setting JFrame to apply rotation
The first part should make the rotation 180°, but it does not, even when i call repaint on graphicalDisplayJFrame. BUT when I add this:
JLabel hwLabel = new JLabel("Hello world.");
hwLabel.setVisible(true);
graphicalDisplayJFrame.add(hwLabel);
I cause strange thing. The JFrame and all of the components on it is accidentaly rotated by 180°. But its only static behaviour, because there are some text components on display and when there is changed the text on them its again rendered in non rotated way.
So the question is why this could happens?
If i divide it in two parts:
a) Why the Graphics2D on JFrame does not affect the children components on its content pane. Why it only works when I add the JLabel which has no sense here but it was just experiment which caused what I wanted (= repaint with right rotation).
b) I should probably somehow apply the rotation => something like overriding the paint method on each components which are added on the contentPane of JFrame. But how should can I do it? Becouse upper described layout handler just manage a bunch of layouts (layers which are probably custom layouts implementig LayoutManager2 from java.awt) and it is just feeding the components which are put on the layouts and put them on content pane. So the question should probably be where could be the place where I want to implement my custom paining which means apply the rotation (which is this part of code g2d.rotate(Math.PI, anchorx, anchory); //rotation 180°).
I hope it understandable, I made pretty bit effort to understand where could be problem and trying find out the solution, but its behave really strange. So I hope someone with more experience with this could help me out off this struggling and show me the way.
You are applying the rotation at very strange points. Graphics2D.rotate() applies only to things painted after the rotate call, but your paint-overides rotate after calling super.
As for why adding a label causes rotation, hard to tell without seeing the entire code. Probably an effect of partial repaint.
You should not modify essentials like the graphics translation or rotation of the graphics passed to your paint methods. It has the potential to affect the parent components drawing in unexpected way and the effect can easily change depending on JRE version. Instead create a new graphics to pass down to your child components:
#Override
public void paintChildren(Graphics g) {
Graphics2D g2d = (Graphics2D) g.create();
try {
g2d.rotate(Math.PI, anchorx, anchory);
super.paintChildren(g2d);
} finally {
g2d.dispose();
}
}
This method leaves the original Graphics untouched, at least allowing the parent component to render normally. Rotating the graphics is still tricky and will probably have unintended side effects in the rendering process, but at least these effects are now carefully limited to the children of the rotating component.
I don't want to be too specific because this could have many applications but if required I can post some code. For simplicity let's say I have an RCP view with a Canvas on and I want to draw a circle on that canvas in the centre. Not with every re-draw, I just want it to start in the centre.
I have tried to do this in the constructor of my extended canvas but the getSize() method doesn't yet return the correct size. I have tried to pack() and layout() the parent composite of the View and then get the canvas size, still nothing.
So is there somewhere to catch the initial size of the View and components being set?
Listen to the SWT.Resize event. You will get a resize when the control is created.
I'm not sure what you mean "not with every redraw," but usually, to paint items (and have them continue to be painted, you have to actually "paint" in a control's PaintListener's paintControl() method. This may be what you are looking for:
canvas.addPaintListener(new PaintListener() {
#Override
public void paintControl (PaintEvent event) {
Rectangle clientRect = canvas.getClientArea();
event.gc.drawOval(0, 0, clientRect.width - 1, clientRect.height - 1);
});
So you can get the "size" via the control's (canvas's) client-area, and then paint accordingly. You'd need to change the params in the drawOval method to make your circle the appropriate size.
That's how to "paint" and maintain the drawing. Otherwise, it will disappear.
I'll start off by telling you what Im trying to do if thats OK, as Im not certain the route Im struggling with is even the best way of achieving my ends.
I have a JFrame containing two JPanels. One contains a number of buttons (buttonPanel), the other is, initially, blank (displayPane). When buttons are pressed the stuff shown in displayPanel changes. The way this is working is each press of a button creates a new object that extends JPanel and then adds that to displayPane
So all the above is working fine and dandy (although I freely admit it may not be the best way of doing it) except for one particular case.
In this particular case I need to create a JLayeredPanel and then draw a clipped image on it. JLayeredPanel because I want to draw some stuff on top of it, clipped because I only want to show part of the area (which exact part is passed to the constructor).
Now, the problem Im having is this. The only way I know to draw a clipped image is through g=thingie.getGraphics(), g.setClip(Shape shape), g.drawImage(various). However, all of that relies on being able to get graphics. But because I am assembling the object first there is no graphics object associated with the JLayeredPane (because its not displayed) so getGraphics is returning null and g.setClip() is throwing a Null Pointer Exception.
Obviously I am doing this wrong somehow and somewhere. Any help would be appreciated, sorry if the question is confusing. I tried to include as much detail as possible and now I am a little concerned I've muddied the issue. I'll keep an eye on this and clarify if required.
Warning!: Wrong answer, see below the line
Why don't you just create a new Graphics object, paint on it and then use it with the update() method?
Graphics g = new Graphics();
g.drawStuff();
thingie.update(g);
This showd be correct
As stated on the comments the previous solution was wrong but it can be done with an Double buffer, create a buffered image and draw on it, then override the paint method of the jLayeredPane pane to draw the image.
private void addStuff() {
BufferedImage bi =
new BufferedImage(100, 100, BufferedImage.TYPE_4BYTE_ABGR);
Graphics bufferedGraphics = bi.getGraphics();
//Paint stuff
bufferedGraphics.drawLine(0, 0, 50, 50);
javax.swing.JLayeredPane layered;
layered = new JLayeredPane() {
#Override
public void paint(Graphics g) {
g.drawImage(bi, 0, 0, null);
}
};
this.add(layered);
this.validate();
this.repaint();
}
I am trying to create virtual desktop. I complete successfully.But i am not able to set background image for jdesktoppane. I want to set background image and After adding image also the desktop pane work normally.Is anyone know means just tell me
Thanks
From this thread at coderanch, a possible solution is to paint in the paintComponent method of your subclass of the JDesktopPane (or in your renderer for this class, which could be better).
You can extend JDeskTopPane class with another member as image and then in constructor set the background to that image.
public ExtendedJDesktopPane(Image image) {
super();
this.image = image;
}
protected void paintComponent(Graphics g) {
g.drawImage(scaledImage, 0, 0, this);
}
EDIT:
This is similar to the link provided below by Riduidel.. i just got late writing it.
I am developing a simple platform game using Java using BlueJ as the IDE. Right now I have player/enemy sprites, platforms and other items in the game drawn using polygons and simple shapes. Eventually I hope to replace them with actual images.
For now I would like to know what is the simplest solution to setting an image (either URL or from local source) as the 'background' of my game window/canvas?
I would appreciate it if it isn't something long or complex as my programming skills aren't very good and I want to keep my program as simple as possible. Kindly provide example codes with comments to elaborate on their function, and also if it's in its own class, how to call on relevant methods used by it on other classes.
Thank you very much.
The answer will vary slightly depending on whether the application or applet is using AWT or Swing.
(Basically, classes that start with J such as JApplet and JFrame are Swing, and Applet and Frame are AWT.)
In either case, the basic steps would be:
Draw or load an image into a Image object.
Draw the background image in the painting event of the Component you want to draw the background in.
Step 1. Loading the image can be either by using the Toolkit class or by the ImageIO class.
The Toolkit.createImage method can be used to load an Image from a location specified in a String:
Image img = Toolkit.getDefaultToolkit().createImage("background.jpg");
Similarly, ImageIO can be used:
Image img = ImageIO.read(new File("background.jpg");
Step 2. The painting method for the Component that should get the background will need to be overridden and paint the Image onto the component.
For AWT, the method to override is the paint method, and use the drawImage method of the Graphics object that is handed into the paint method:
public void paint(Graphics g)
{
// Draw the previously loaded image to Component.
g.drawImage(img, 0, 0, null);
// Draw sprites, and other things.
// ....
}
For Swing, the method to override is the paintComponent method of the JComponent, and draw the Image as with what was done in AWT.
public void paintComponent(Graphics g)
{
// Draw the previously loaded image to Component.
g.drawImage(img, 0, 0, null);
// Draw sprites, and other things.
// ....
}
Simple Component Example
Here's a Panel which loads an image file when instantiated, and draws that image on itself:
class BackgroundPanel extends Panel
{
// The Image to store the background image in.
Image img;
public BackgroundPanel()
{
// Loads the background image and stores in img object.
img = Toolkit.getDefaultToolkit().createImage("background.jpg");
}
public void paint(Graphics g)
{
// Draws the img to the BackgroundPanel.
g.drawImage(img, 0, 0, null);
}
}
For more information on painting:
Painting in AWT and Swing
Lesson: Performing Custom Painting from The Java Tutorials may be of help.
Firstly create a new class that extends the WorldView class. I called my new class Background. So in this new class import all the Java packages you will need in order to override the paintBackground method. This should be:
import city.soi.platform.*;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.ImageObserver;
import javax.swing.ImageIcon;
import java.awt.geom.AffineTransform;
Next after the class name make sure that it says extends WorldView. Something like this:
public class Background extends WorldView
Then declare the variables game of type Game and an image variable of type Image something like this:
private Game game;
private Image image;
Then in the constructor of this class make sure the game of type Game is in the signature of the constructor and that in the call to super you will have to initialise the WorldView, initialise the game and initialise the image variables, something like this:
super(game.getCurrentLevel().getWorld(), game.getWidth(), game.getHeight());
this.game = game;
bg = (new ImageIcon("lol.png")).getImage();
Then you just override the paintBackground method in exactly the same way as you did when overriding the paint method in the Player class. Just like this:
public void paintBackground(Graphics2D g)
{
float x = getX();
float y = getY();
AffineTransform transform = AffineTransform.getTranslateInstance(x,y);
g.drawImage(bg, transform, game.getView());
}
Now finally you have to declare a class level reference to the new class you just made in the Game class and initialise this in the Game constructor, something like this:
private Background image;
And in the Game constructor:
image = new Background(this);
Lastly all you have to do is add the background to the frame! That's the thing I'm sure we were all missing. To do that you have to do something like this after the variable frame has been declared:
frame.add(image);
Make sure you add this code just before frame.pack();.
Also make sure you use a background image that isn't too big!
Now that's it! Ive noticed that the game engines can handle JPEG and PNG image formats but could also support others. Even though this helps include a background image in your game, it is not perfect! Because once you go to the next level all your platforms and sprites are invisible and all you can see is your background image and any JLabels/Jbuttons you have included in the game.
Or try this ;)
try {
this.setContentPane(
new JLabel(new ImageIcon(ImageIO.read(new File("your_file.jpeg")))));
} catch (IOException e) {};
The Path is the only thing you really have to worry about if you are really new to Java.
You need to drag your image into the main project file, and it will show up at the very bottom of the list.
Then the file path is pretty straight forward. This code goes into the constructor for the class.
img = Toolkit.getDefaultToolkit().createImage("/home/ben/workspace/CS2/Background.jpg");
CS2 is the name of my project, and everything before that is leading to the workspace.
<script>
function SetBack(dir) {
document.getElementById('body').style.backgroundImage=dir;
}
SetBack('url(myniftybg.gif)');
</script>