I have this code:
public class SomeNewLayer extends JLayeredPane{
public void paintGraphics(Graphics g){
super.paintComponent(g);
g.setColor(Color.RED);
g.fillRect(0, 0, 25, 250);
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.RED);
g.fillRect(0, 0, 25, 250);
}
}
The first method, if called, draws the rectangle and in a blink of an eye it just disapears.
The second method, if called, draws the rectangle and it will then remain. Why?
I know it is supposed to override the paintComponent, but I was unable to find a hint as why the first method drawing won't remain.
Related
how can I implement water 2D wave effect in JavaFX, I have image and want to when click on image a wave(or more) start expanding from that point, just like when we drop a piece rock into the calm water and we see the wave expanding.
This is a conversion of parts of old sun JavaFX 1 ripple generator to JavaFX 2.
It's not the most realistic water ripple effect, but maybe it's enough to get you started creating your own. You could add in a DisplacementMap effect to distort your image as a result of the "waves".
The code uses JavaFX animation timelines to generate expanding concentric circles that gradually fade away of time.
import javafx.animation.*;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.collections.*;
import javafx.event.*;
import javafx.scene.*;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.*;
import javafx.scene.shape.Circle;
import javafx.stage.*;
import javafx.util.Duration;
public class FishSim extends Application {
private static final Paint SCENE_FILL = new RadialGradient(
0, 0, 300, 300, 500, false, CycleMethod.NO_CYCLE,
FXCollections.observableArrayList(new Stop(0, Color.BLACK), new Stop(1, Color.BLUE))
);
#Override public void start(Stage stage) {
final RippleGenerator rippler = new RippleGenerator();
final Scene scene = new Scene(rippler, 600, 400, SCENE_FILL);
scene.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent event) {
rippler.setGeneratorCenterX(event.getSceneX());
rippler.setGeneratorCenterY(event.getSceneY());
rippler.createRipple();
rippler.startGenerating();
}
});
scene.setOnMouseDragged(new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent event) {
rippler.setGeneratorCenterX(event.getSceneX());
rippler.setGeneratorCenterY(event.getSceneY());
}
});
scene.setOnMouseReleased(new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent event) {
rippler.stopGenerating();
}
});
stage.setTitle("Click, hold mouse button down and move around to create ripples");
stage.setScene(scene);
stage.setResizable(false);
stage.show();
}
public static void main(String[] args) { launch(args); }
}
/**
* Generates ripples on the screen every 0.5 seconds or whenever
* the createRipple method is called. Ripples grow and fade out
* over 3 seconds
*/
class RippleGenerator extends Group {
private class Ripple extends Circle {
Timeline animation = new Timeline(
new KeyFrame(Duration.ZERO, new KeyValue(radiusProperty(), 0)),
new KeyFrame(Duration.seconds(1), new KeyValue(opacityProperty(), 1)),
new KeyFrame(Duration.seconds(3), new KeyValue(radiusProperty(), 100)),
new KeyFrame(Duration.seconds(3), new KeyValue(opacityProperty(), 0))
);
private Ripple(double centerX, double centerY) {
super(centerX, centerY, 0, null);
setStroke(Color.rgb(200, 200, 255));
}
}
private double generatorCenterX = 100.0;
private double generatorCenterY = 100.0;
private Timeline generate = new Timeline(
new KeyFrame(Duration.seconds(0.5), new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent event) {
createRipple();
}
}
)
);
public RippleGenerator() {
generate.setCycleCount(Timeline.INDEFINITE);
}
public void createRipple() {
final Ripple ripple = new Ripple(generatorCenterX, generatorCenterY);
getChildren().add(ripple);
ripple.animation.play();
Timeline remover = new Timeline(
new KeyFrame(Duration.seconds(3), new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent event) {
getChildren().remove(ripple);
ripple.animation.stop();
}
})
);
remover.play();
}
public void startGenerating() {
generate.play();
}
public void stopGenerating() {
generate.stop();
}
public void setGeneratorCenterX(double generatorCenterX) {
this.generatorCenterX = generatorCenterX;
}
public void setGeneratorCenterY(double generatorCenterY) {
this.generatorCenterY = generatorCenterY;
}
}
The original JavaFX 1 fish simulator code that the conversion is based on came from a jfrog repository (which might no longer exist if you click it).
Robert Ladstätter created a 2D water effect sample animation for JavaFX 2 (using Scala). Roberts animation is like viewing the water from the side rather than above, but perhaps some of the concepts might help you.
In this tutorial you can find how to use custom GLSL/HLSL pixel shaders for JavaFX.
And the code for a simple distortion procedural wave in screenSpace in HLSL form:
uniform extern texture ScreenTexture;
sampler ScreenS = sampler_state
{
Texture = <ScreenTexture>;
};
float wave; // pi/.75 is a good default
float distortion; // 1 is a good default
float2 centerCoord; // 0.5,0.5 is the screen center
float4 PixelShader(float2 texCoord: TEXCOORD0) : COLOR
{
float2 distance = abs(texCoord - centerCoord);
float scalar = length(distance);
// invert the scale so 1 is centerpoint
scalar = abs(1 - scalar);
// calculate how far to distort for this pixel
float sinoffset = sin(wave / scalar);
sinoffset = clamp(sinoffset, 0, 1);
// calculate which direction to distort
float sinsign = cos(wave / scalar);
// reduce the distortion effect
sinoffset = sinoffset * distortion/32;
// pick a pixel on the screen for this pixel, based on
// the calculated offset and direction
float4 color = tex2D(ScreenS, texCoord+(sinoffset*sinsign));
return color;
}
technique
{
pass P0
{
PixelShader = compile ps_2_0 PixelShader();
}
}
I hope it helps.
Imagine that we have an AnchorPane, it has child Pane and there we have Button, for example.
I want this Button to be shown only inside this Pane.
In other words, it whould be cut by the Pane edges if it is not completely within Pane. Now the Button can be visible even if it is out of Pane rectangle.
this is what the clip of a node is made for.
Example:
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class ClipTest extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
Group root = new Group();
StackPane pane = new StackPane();
pane.setMaxWidth(100);
pane.setMaxHeight(100);
pane.setLayoutX(50);
pane.setLayoutY(50);
Rectangle rect = new Rectangle(100, 100);
rect.setFill(null);
rect.setStroke(Color.RED);
Rectangle rect2 = new Rectangle(150, 150);
rect2.setFill(Color.BLUE);
pane.getChildren().addAll(rect2, rect);
root.getChildren().add(pane);
// Rectangle clip = new Rectangle(100, 100);
// clip.setLayoutX(25);
// clip.setLayoutY(25);
// pane.setClip(clip);
Scene scene = new Scene(root, 250, 250);
primaryStage.setScene(scene);
primaryStage.show();
}
}
This produces:
Uncommenting the lines regarding the clip produces:
You can use clipping functionality to achieve this.
public class ClipPane extends Application {
#Override
public void start(Stage stage) throws Exception {
Pane clipPane = new Pane();
clipPane.setStyle("-fx-border-color: red;");
clipPane.setPrefSize(200, 200);
Rectangle rect = new Rectangle(200, 200);
clipPane.setClip(rect);
Button btn = new Button("Hello, world!");
btn.relocate(120, 0);
clipPane.getChildren().add(btn);
AnchorPane root = new AnchorPane();
root.getChildren().add(clipPane);
AnchorPane.setTopAnchor(clipPane, 50.);
AnchorPane.setLeftAnchor(clipPane, 50.);
stage.setScene(new Scene(root, 300, 300));
stage.show();
}
public static void main(String[] args) { launch(); }
}
Another approach, with using of observables. To clip items outside pane bounds (like css oveflow:hidden):
// create rectangle with sizes of pane,
// dont need to set x and y explictly
// as positions of clip node are relative to parent node
// (to pane in our case)
Rectangle clipRect = new Rectangle(pane.getWidth(), pane.getHeight());
// bind properties so height and width of rect
// changes according pane's width and height
clipRect.heightProperty().bind(pane.heightProperty());
clipRect.widthProperty().bind(pane.widthProperty());
// set rect as clip rect
pane.setClip(clipRect);
I'm trying to change the color of bar in ProgressBar with
pBar.setStyle("-fx-accent: green");
but I have encountered a problem: that doesn't seem to work right for me! (Or I just don't understand something)
here is the code:
public class JavaFXApplication36 extends Application {
#Override
public void start(Stage primaryStage) {
AnchorPane root = new AnchorPane();
ProgressBar pbRed = new ProgressBar(0.4);
ProgressBar pbGreen = new ProgressBar(0.6);
pbRed.setLayoutY(10);
pbGreen.setLayoutY(30);
pbRed.setStyle("-fx-accent: red;"); // line (1)
pbGreen.setStyle("-fx-accent: green;"); // line (2)
root.getChildren().addAll(pbRed, pbGreen);
Scene scene = new Scene(root, 150, 50);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
}
I always get 2 red progressbars with it! It seems that code in line (1) changes the style of ProgressBar class, not the instance.
Another strange moment is that deleting line (1) don't result in 2 green progress bars. So I can figure that line (2) is completely useless!! WHY?! That's definitely getting odd.
Is there any way to set separate colors for separate progressbars?
Answer updated to add a simple non-animated example with multiple progress bars
The code in your question should display two different colored progress bars, the fact that it doesn't is a bug in the JavaFX css processing system. Log the bug against the runtime project here: http://javafx-jira.kenai.com.
As a workaround, instead of calling setStyle on the progress bars, define the accent colors used to color progress bars within a stylesheet and add a style class to the progress bars. Then, you can create multiple progress bars within the same application, all with different colors.
As Uluk points out, you can use JavaFX 2.2 caspian.css in conjunction with the JavaFX 2 css reference guide and the JavaFX 2 css tutorial to determine how to style things.
Here is some sample code which customizes a progress bar based upon the information in those references.
Sample css:
/** progress.css
place in same directory as
ColoredProgressBarStyleSheet.java or SimpleColoredProgressBar.java
ensure build system copies the css file to the build output path */
.root { -fx-background-color: cornsilk; -fx-padding: 15; }
.progress-bar { -fx-box-border: goldenrod; }
.green-bar { -fx-accent: green; }
.yellow-bar { -fx-accent: yellow; }
.orange-bar { -fx-accent: orange; }
.red-bar { -fx-accent: red; }
Simple sample program:
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
// shows multiple progress bars drawn in different colors.
public class SimpleColoredProgressBar extends Application {
public static void main(String[] args) { launch(args); }
#Override public void start(Stage stage) {
final VBox layout = new VBox(10);
layout.setAlignment(Pos.CENTER);
layout.getChildren().setAll(
new ColoredProgressBar("red-bar", 0.2),
new ColoredProgressBar("orange-bar", 0.4),
new ColoredProgressBar("yellow-bar", 0.6),
new ColoredProgressBar("green-bar", 0.8)
);
layout.getStylesheets().add(getClass().getResource("progress.css").toExternalForm());
stage.setScene(new Scene(layout));
stage.show();
}
class ColoredProgressBar extends ProgressBar {
ColoredProgressBar(String styleClass, double progress) {
super(progress);
getStyleClass().add(styleClass);
}
}
}
Simple sample program output:
More complicated sample program with a single animated progress bar which changes color dynamically depending on the amount of progress made:
import javafx.animation.*;
import javafx.application.Application;
import javafx.beans.value.*;
import javafx.event.*;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;
// shows a progress bar whose bar changes color depending on the amount of progress.
public class ColoredProgressBarStyleSheet extends Application {
public static void main(String[] args) { launch(args); }
private static final String RED_BAR = "red-bar";
private static final String YELLOW_BAR = "yellow-bar";
private static final String ORANGE_BAR = "orange-bar";
private static final String GREEN_BAR = "green-bar";
private static final String[] barColorStyleClasses = { RED_BAR, ORANGE_BAR, YELLOW_BAR, GREEN_BAR };
#Override public void start(Stage stage) {
final ProgressBar bar = new ProgressBar();
final Timeline timeline = new Timeline(
new KeyFrame(Duration.millis(0), new KeyValue(bar.progressProperty(), 0)),
new KeyFrame(Duration.millis(3000), new KeyValue(bar.progressProperty(), 1))
);
Button reset = new Button("Reset");
reset.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent event) {
timeline.playFromStart();
}
});
bar.progressProperty().addListener(new ChangeListener<Number>() {
#Override public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
double progress = newValue == null ? 0 : newValue.doubleValue();
if (progress < 0.2) {
setBarStyleClass(bar, RED_BAR);
} else if (progress < 0.4) {
setBarStyleClass(bar, ORANGE_BAR);
} else if (progress < 0.6) {
setBarStyleClass(bar, YELLOW_BAR);
} else {
setBarStyleClass(bar, GREEN_BAR);
}
}
private void setBarStyleClass(ProgressBar bar, String barStyleClass) {
bar.getStyleClass().removeAll(barColorStyleClasses);
bar.getStyleClass().add(barStyleClass);
}
});
final VBox layout = new VBox(10);
layout.setAlignment(Pos.CENTER);
layout.getChildren().setAll(bar, reset);
layout.getStylesheets().add(getClass().getResource("progress.css").toExternalForm());
stage.setScene(new Scene(layout));
stage.show();
timeline.play();
}
}
More complicated sample program output:
You should to override (or customize) the style with JavaFX CSS selectors. See caspian.css for more information. In your own stylesheet define:
.progress-bar .bar {
-fx-background-color:
-fx-box-border,
linear-gradient(to bottom, derive(-fx-accent,95%), derive(-fx-accent,10%)),
red; /* this line is the background color of the bar */
-fx-background-insets: 0, 1, 2;
-fx-padding: 0.416667em; /* 5 */
}
For those who want a simple answer (and without needing to add CSS files):
ProgressBar pbGreen = new ProgressBar(0.6);
pbGreen.setStyle("-fx-accent: green");
I am trying to paint only one part of Image. The image human is 159x22 length.
In that image there is 8 human bodies (2 left, 2 right and etc.). If i try to set the Frame to humanSprite.setFrame(1); I will get an error since I specified in the Sprite constructor the size of an Image so there is only one frame.
Well I have tried to divide it by 8 and Ill getjava.lang.IllegalArgumentException`.
Here is the class :
package org.pack.rhynn;
import java.io.IOException;
import javax.microedition.lcdui.game.GameCanvas;
import javax.microedition.lcdui.game.Sprite;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import java.util.Random;
public class play extends GameCanvas implements Runnable{
int sleep = 30;
private Image map;
private Sprite mapSprite;
private Image human;
private Sprite humanSprite;
private int humanX = getWidth() /2;
private int humanY = getHeight() /2;
public play(){
super(false);
}
public void start(){
try {
map = Image.createImage("/mapas.png");
human = Image.createImage("/human.PNG");
} catch (IOException ioex) {
System.out.println(ioex);
}
mapSprite = new Sprite(map);
mapSprite.defineReferencePixel(100, 150);
mapSprite.setRefPixelPosition(0, 0);
humanSprite = new Sprite(human,159,22);
humanSprite.defineReferencePixel(1, 10);
humanSprite.setRefPixelPosition(humanX, humanY);
Thread thr = new Thread(this);
thr.start();
}
public void run(){
while(true){
updateScreen(getGraphics());
try{
Thread.sleep(sleep);
}catch(Exception e){}
}
}
private void createBackground(Graphics g){
g.setColor(0x000000);
g.fillRect(0, 0, getWidth(), getHeight());
}
private void updateScreen(Graphics g){
createBackground(g);
mapSprite.setRefPixelPosition(0, 0);
mapSprite.paint(g);
humanSprite.setRefPixelPosition(humanX, humanY);
humanSprite.setFrame(0);
humanSprite.setPosition(50,50);
humanSprite.paint(g);
flushGraphics();
}
}
The problem seems to be with your image. All frames must have the same width and height and the image final width and hight must be a multiple of them.
For example, let's say all your frames are in a single row. If the frame width is 19 and you have 8 frames, the final image width must be 152.
On a canvas there is an image and on touch at certain part of the image, I am looking to launch a new Canvas from within pointerPressed() method.
Is it possible? So far I have done the following:
protected void pointerPressed(int x, int y){
if ((x>=164 && x<=173)&&(y>=24 && y<=36)){
disp.setCurrent(new elementDetails());
}
}
and the class is as follows:
//class to show detailed information of elements
class elementDetails extends Canvas{
private Image elmDtlImg;
public elementDetails(){
try{
elmDtlImg = Image.createImage("/details.jpg");
}
catch(IOException e){
System.out.println("Couldn't load Detailed Info image" + e.getMessage());
}
}
public void paint(Graphics g){
//set the drawing color to white
g.setGrayScale(255);
//draw a big white rectangle over the whole screen (over the previous screen)
g.fillRect(0, 0, getWidth(), getHeight());
g.drawImage(elmDtlImg, 0, 0, 20);
}
}
When I run the above code nothing happens. I mean to say that the current image does not change to the new one which I am trying to show in the canvas.
My application keeps on running after the pointer pressed event. It does not crashes. It shows me the coords of other parts of the image correctly. What I am trying to achieve is that; when I click/touch at some particular points of the image it should load a new canvas in place of the old one.
A canvas is made visible by calling the Display.setCurrent() method.You would to retrieve Display from your MIDlet and pass it to your canvas,then use it.I hope this snippet code help you:
//MIDlet:
public class MyMIDlet extends MIDlet{
...
final Canvas1 c1;
final elementDetails c2;
...
public MyMIDlet(){
c1 = new Canvas1(this);
c2 = new elementDetails();
}
...
}
//canvas1:
public class Canvas1 extends Canvas{
MyMIDlet myMidlet;
Display disp;
...
/**
*constructor
*/
public Canvas1(MyMIDlet myMidlet){
this.MyMIDlet = myMidlet;
disp = myMidlet.getDisplay();
}
...
public void paint(Graphics g){
g.setColor(255,255,255);
g.drawString("canvas1", 0, 0, 0);
}
...
protected void pointerPressed(int x, int y){
if ((x>=164 && x<=173)&&(y>=24 && y<=36)){
disp.setCurrent(myMidlet.c2);
}
}
//class to show detailed information of elements
class elementDetails extends Canvas{
private Image elmDtlImg;
public elementDetails(){
try{
elmDtlImg = Image.createImage("/details.jpg");
}
catch(IOException e){
System.out.println("Couldn't load Detailed Info image" + e.getMessage());
}
}
public void paint(Graphics g){
//set the drawing color to white
g.setGrayScale(255);
//draw a big white rectangle over the whole screen (over the previous screen)
g.fillRect(0, 0, getWidth(), getHeight());
g.drawImage(elmDtlImg, 0, 0, 20);
}
}