JavaFX app in System Tray - awt

I am Making a Simple App using JavaFX UI, The app simply just do that:
has a systray icon, which when clicked shows a window, when clicked again hides it, on rightclick shows a menu with 1 "exit" item
I already Made the UI and put the App in the Sys Tray, but i can't show/hide it using Normal Actionlistener method, but i got this error:
Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Not on FX application thread; currentThread = AWT-EventQueue-0
here is the Code:
import java.awt.Image;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.SystemTray;
import java.awt.Toolkit;
import java.awt.TrayIcon;
import java.awt.event.ActionListener;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Main extends Application{
public static void main(String[] args) {
launch(args);
}
#Override
public void start(final Stage primaryStage) {
primaryStage.setTitle("Hello World!");
Button btn = new Button();
btn.setText("Say 'Hello World'");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("Hello World!"); }
});
StackPane root = new StackPane();
root.getChildren().add(btn);
primaryStage.setScene(new Scene(root, 300, 250));
primaryStage.show();
if (SystemTray.isSupported()) {
SystemTray tray = SystemTray.getSystemTray();
Image image = Toolkit.getDefaultToolkit().getImage("Germany-politcal-map.jpg");
PopupMenu popup = new PopupMenu();
MenuItem item = new MenuItem("Exit");
popup.add(item);
TrayIcon trayIcon = new TrayIcon(image, "Amr_Trial", popup);
ActionListener listener = new ActionListener() {
#Override
public void actionPerformed(java.awt.event.ActionEvent arg0) {
// TODO Auto-generated method stub
System.exit(0);
}
};
ActionListener listenerTray = new ActionListener() {
#Override
public void actionPerformed(java.awt.event.ActionEvent arg0) {
// TODO Auto-generated method stub
primaryStage.hide();
}
};
trayIcon.addActionListener(listenerTray);
item.addActionListener(listener);
try{
tray.add(trayIcon);
}catch (Exception e) {
System.err.println("Can't add to tray");
}
} else {
System.err.println("Tray unavailable");
}
//
}
}

Wrap the code in the actionListener which calls back to JavaFX in Platform.runLater. This will execute the code which interfaces with the JavaFX system on the JavaFX application thread rather than trying to do it on the Swing event thread (which is what is causing you issues).
For example:
ActionListener listenerTray = new ActionListener() {
#Override public void actionPerformed(java.awt.event.ActionEvent event) {
Platform.runLater(new Runnable() {
#Override public void run() {
primaryStage.hide();
}
});
}
};
By default the application will shutdown when it's last window is hidden. To override this default behaviour, invoke Platform.setImplicitExit(false) before you show the first application Stage. You will then need to explicitly call Platform.exit() when you need the application to really shutdown.
I created a demo for using the AWT system tray within a JavaFX application.

You should only modify the javafx classes on the javafx thread, the listeners on the tray icon are likely to be running on the swing thread. You can do this by posting a runnable to Platform#runLater like so:
Platform.runLater(new Runnable() {
public void run() {
primaryStage.hide();
}
});

The system tray is not supported in JavaFX yet. You could track the progress on this task under the following JIRA issue: https://bugs.openjdk.java.net/browse/JDK-8090475
The issue also provides a workaround, which could be used in JavaFX 8 to get the basic support.
The feature is not planned for JavaFX 8, so it might be released in one of the following updates or even in JavaFX 9.

Shameless self-plug, but I developed a small wrapper library for JavaFX icons that use the SystemTray called FXTrayIcon.
It abstracts away all of the nasty AWT bits and eliminates having to guess which thread you should be running code on. It's available as a dependency on Maven Central.

I resolved your issue. JavaFX with AWT. I have one example of a application that shows and hides when you make left clic. i really hope works for you
import java.awt.AWTException;
import java.awt.Image;
import java.awt.SystemTray;
import java.awt.Toolkit;
import java.awt.TrayIcon;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.net.URL;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class MainApp2 extends Application {
int stateWindow = 1;
#Override
public void start(final Stage stage) throws Exception {
//Check the SystemTray is supported
if (!SystemTray.isSupported()) {
System.out.println("SystemTray is not supported");
return;
}
URL url = System.class.getResource("/image/yourImage.png");
Image image = Toolkit.getDefaultToolkit().getImage(url);
//image dimensions must be 16x16 on windows, works for me
final TrayIcon trayIcon = new TrayIcon(image, "application name");
final SystemTray tray = SystemTray.getSystemTray();
//Listener left clic XD
trayIcon.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent event) {
if (event.getButton() == MouseEvent.BUTTON1) {
Platform.runLater(new Runnable() {
#Override
public void run() {
if (stateWindow == 1) {
stage.hide();
stateWindow = 0;
} else if (stateWindow == 0) {
stage.show();
stateWindow = 1;
}
}
});
}
}
});
try {
tray.add(trayIcon);
} catch (AWTException e) {
System.out.println("TrayIcon could not be added.");
}
stage.setTitle("Hello man!");
Button btn = new Button();
btn.setText("Say 'Hello man'");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("Hello man!");
}
});
StackPane root = new StackPane();
root.getChildren().add(btn);
stage.setScene(new Scene(root, 300, 250));
Platform.setImplicitExit(false);
stage.show();
}
/**
* The main() method is ignored in correctly deployed JavaFX application.
* main() serves only as fallback in case the application can not be
* launched through deployment artifacts, e.g., in IDEs with limited FX
* support. NetBeans ignores main().
*
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}

Related

Intellij plugin development, how to prevent an action from occuring, like closing a tab

Is this possible?
I need to subscribe to the event somehow and possibly return false or similar, i am guessing. I have no idea how though.
What event is that?
Where do I register it?
Anyone?
EDIT:
I have tried this:
import com.intellij.openapi.components.ApplicationComponent;
import com.intellij.openapi.editor.impl.EditorComponentImpl;
import org.jetbrains.annotations.NotNull;
import java.awt.*;
import java.awt.event.AWTEventListener;
import java.awt.event.KeyEvent;
public class MyPlugin implements ApplicationComponent {
static {
/*MessageBus bus = ApplicationManager.getApplication().get
MessageBusConnection connection = bus.connect();
connection.subscribe(AppTopics.FILE_DOCUMENT_SYNC,
new FileDocumentManagerAdapter() {
#Override
public void beforeDocumentSaving(Document document) {
// create your custom logic here
}
});*/
}
private final AWTEventListener listener;
public MyPlugin() {
System.out.println("111111111111111111");
listener = new AWTEventListener() {
#Override
public void eventDispatched(AWTEvent event) {
if ( event instanceof KeyEvent ) {
KeyEvent kv = (KeyEvent) event;
Component component = kv.getComponent();
if ( component instanceof EditorComponentImpl) {
EditorComponentImpl cp = (EditorComponentImpl) component;
}
System.out.println("3333333" + component.getClass());
}
System.out.println("aaaaaaa" + event.getClass());
}
};
}
#Override
public void initComponent() {
System.out.println("bbbbbbbbbbbbbbbbbbbbbbbbbbb");
Toolkit.getDefaultToolkit().addAWTEventListener(listener, AWTEvent.KEY_EVENT_MASK);
}
#Override
public void disposeComponent() {
Toolkit.getDefaultToolkit().removeAWTEventListener(listener);
}
#NotNull
#Override
public String getComponentName() {
return "temp";
}
}
But it does not work. I get events but the wrong kind.
Two plugins were developed in the end to accomplish this:
https://plugins.jetbrains.com/space/index?pr=idea&lg=opensource%40momomo.com

#EventHandler events not working

I am trying to make a simple addition to my plugin so that when someone joins they receive a message that says "Heyyyyyyy". My plugin has a few commands also.
Here's my Main class:
package me.ben.test;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.Listener;
import org.bukkit.plugin.java.JavaPlugin;
public class Main extends JavaPlugin implements Listener {
#Override
public void onEnable() {
this.getServer().getPluginManager().registerEvents(new Click(), this);
getLogger().info("The Plugin Has Been Enabled!");
}
#Override
public void onDisable() {
getLogger().info("The Plugin Has Been Disabled!");
}
public boolean onCommand(CommandSender sender, Command cmd, String label,
String[] args) {
if (cmd.getName().equalsIgnoreCase("hello") && sender instanceof Player) {
Player player = (Player) sender;
player.sendMessage("Hello, " + player.getName() + "!");
return true;
} else if (cmd.getName().equalsIgnoreCase("isonline")
&& args.length == 1) {
Player target = Bukkit.getServer().getPlayer(args[0]);
if (target == null) {
sender.sendMessage(ChatColor.AQUA + "Player " + args[0]
+ " is not online.");
return true;
} else if (target != null) {
sender.sendMessage(ChatColor.AQUA + "Player " + args[0]
+ " is online.");
return true;
} else {
return false;
}
}
return false;
}
}
and here is my Click class:
package me.ben.test;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.plugin.java.JavaPlugin;
public class Click extends JavaPlugin implements Listener {
#EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
event.getPlayer().sendMessage("Heyyyyyyy");
}
}
All of the #EventHandler things are not working so I quick made this simple one.
You can have only one class that extends JavaPlugin. Remove extends JavaPlugin from your Click Class - only your main class should extend JavaPlugin.
Check out Bukkit's official plugin tutorial for help on coding Bukkit Plugins.
You are using Listener in your Main class but you are not handling any event there, use it only when you want the class to be able to handler bukkit events.
You can use Listener with your Main class if you want, but you'll need to put the methods that handles events in your main class, but it'll become messy in big projects...
You also don't need to extend JavaPlugin everywhere, just in your main class.
If you want to use your main class:
public class Main extends JavaPlugin implements Listener {
#Override
public void onEnable() {
this.getServer().getPluginManager().registerEvents(this, this);
getLogger().info("The Plugin Has Been Enabled!");
}
#EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
event.getPlayer().sendMessage("Heyyyyyyy");
}
}
If you want to use a separated class to handle events:
public class Main extends JavaPlugin {
#Override
public void onEnable() {
this.getServer().getPluginManager().registerEvents(new Click(), this);
getLogger().info("The Plugin Has Been Enabled!");
}
}
public class Click implements Listener {
#EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
event.getPlayer().sendMessage("Heyyyyyyy");
}
}
Don't forget that you need to create a plugin.yml file correctly otherwise nothing will work.

Make a label update while dragging a slider

I'm using a Slider in my javaFX project and I have a Label that updates when I move the slider.
I want the Label to update whilst I'm dragging the Slider and not only when the drag is dropped.
This is my code:
betSlider.valueChangingProperty().addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> source, Boolean oldValue, Boolean newValue) {
betLabel.textProperty().setValue(String.valueOf((int)betSlider.getValue()));
} });
You just need to change the valueChangingProperty() to valueProperty() and TADA, it works as you want !
A small sample is attached here :
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.Slider;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Demo extends Application {
#Override
public void start(Stage primaryStage) {
// Add a scene
VBox root = new VBox();
Scene scene = new Scene(root, 500, 200);
final Label betLabel = new Label("sdsd");
final Slider betSlider = new Slider();
betSlider.valueProperty().addListener(new ChangeListener<Number>() {
#Override
public void changed(
ObservableValue<? extends Number> observableValue,
Number oldValue,
Number newValue) {
betLabel.textProperty().setValue(
String.valueOf(newValue.intValue());
}
}
});
root.getChildren().addAll(betSlider, betLabel);
betLabel.textProperty().setValue("abc");
// show the stage
primaryStage.setTitle("Demo");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Bind the label's textProperty to the slider's valueProperty.
A format conversion is required in the binding to make it work.
Either Itachi's valueProperty() ChangeListener or a binding will work.
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Slide extends Application {
#Override public void start(Stage stage) {
Label label = new Label();
Slider slider = new Slider(1, 11, 5);
label.textProperty().bind(
Bindings.format(
"%.2f",
slider.valueProperty()
)
);
VBox layout = new VBox(10, label, slider);
layout.setStyle("-fx-padding: 10px; -fx-alignment: baseline-right");
stage.setScene(new Scene(layout));
stage.setTitle("Goes to");
stage.show();
}
public static void main(String[] args) { launch(args); }
}
And if you want to do completely in in FXML, you can do this:
<TextField prefWidth="50" text="${speedSlider.value}"/>
<Slider fx:id="speedSlider" orientation="HORIZONTAL" prefWidth="300"
min="60" max="100000" blockIncrement="100"/>
Adding an alternative that seems simpler and easier to me:
Given a slider named slMySlider and a label named lblMySlider
Add a MouseEvent.MOUSE_DRAGGED event handler to the slider and have it call a helper method:
slMySlider.addEventHandler(MouseEvent.MOUSE_DRAGGED, this::changeLabelHandler);
Have the helper method change the label's text:
private void changeLabelHandler(MouseEvent e) {
lblMySlider.setText("Value: " + String.format("%1.2f", slMySlider.getValue()));
}
slider.valueProperty().addListener((observable, oldValue, newValue) ->
label.setText("sliderNameLabel: " + newValue));
If you have a slider in JavaFX 8, you could do this:
slider().addListener(e -> {
// Your code here could be anything.
});

My android application cannot play again when clicking button

I'm new in android programming. My first application is an android mediaplayer.
I built two buttons : one to play a song, and another to stop it.
My application is running correctly ; the problem is that i can play and stop it, but I cant play the song again.
I tried to use setDataSource() but it triggers an error.
Here's the code ; the file is in raw/song.mp3
package com.example.test6;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.app.Activity;
import android.view.View;
import android.widget.Button;
public class MainActivity extends Activity {
MediaPlayer mp;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mp = MediaPlayer.create(this,R.raw.song);
setContentView(R.layout.activity_main);
final Button btnPlay = (Button)this.findViewById(R.id.button1);
final Button btnStop = (Button)this.findViewById(R.id.button2);
btnPlay.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
mp.start();
}
});
btnStop.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
mp.stop();
mp.reset();
if(mp.isPlaying()){
mp.stop();
}else{
mp.setDataSource("res/raw/song.mp3");
mp.prepare();
mp.start();
}
});
}
}
First of all, you don't need to set the data source manually if you're doing the creation like this: MediaPlayer.create(this, R.raw.song); Also, in that case, you don't need to call prepare() because MediaPlayer.create() does that for you.
I would suggest this kind of approach (assuming you don't want the start button to do anything if it's already playing):
Start button listener:
if (mp==null) {
mp = MediaPlayer.create(this, R.raw.song);
}
if (!mp.isPlaying()) {
mp.start();
}
Stop button listener:
if (mp!=null) {
if (mp.isPlaying()) {
mp.stop();
}
mp.release();
mp = null;
}
I didn't test this, so I'm looking forward to your response

multiple Inheritance .. class need to extend abstractHandler as well as Applet

I am trying to make an automation wizard that would take some files from system (via a command handler) and make its relevant applet.
I shall try to explain my senario.
I made a plugin for new command "newModule" which is handled via "newModuleHandler.java". so newModuleHandler extends AbstractHandler.
Now i would like to make a wizard (applet) that helps me with certain selections that i need to make in order to complete that "newModule" command. so
newModuleHandler extends Applet too.
i wrote newModuleHandler something like this.
package archetypedcomponent.commands;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import java.applet.*;// required when you create an applet
import java.awt.Graphics;
public class newModuleHandler extends AbstractHandler {
#Override
public boolean isEnabled() {
// TODO Auto-generated method stub
return true;
}
#Override
public boolean isHandled() {
// TODO Auto-generated method stub
return true;
}
#Override
public Object execute(ExecutionEvent event) throws ExecutionException {
// TODO Auto-generated method stub
return null;
}
public class HelloWorld extends Applet
{
// The method that will be automatically called when the applet is started
public void init()
{
// It is required but does not need anything.
System.out.println("Applet initiated");
}
// This method gets called when the applet is terminated
// That's when the user goes to another page or exits the browser.
public void stop()
{
// no actions needed here now.
System.out.println("Applet Stopped");
}
// The standard method that you have to use to paint things on screen
// This overrides the empty Applet method, you can't called it "display" for example.
public void paint(Graphics g)
{
//method to draw text on screen
// String first, then x and y coordinate.
System.out.println("Applet in paint");
g.drawString("Hey hey hey",20,20);
g.drawString("Hellooow World",20,40);
}
}
}
Now when the command will b given this method will be called
#Override
public Object execute(ExecutionEvent event) throws ExecutionException {
// TODO Auto-generated method stub
return null;
}
and applet will have to be called inside it. my question is how to call it?
========================================================================================
i was able to solve my problem but m replying here so that somebody who is also facing same problem can b guided
this is my new "newModuleHandler.java"
package archetypedcomponent.commands;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import java.applet.*;// required when you create an applet
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
public class newModuleHandler extends AbstractHandler {
#Override
public boolean isEnabled() {
// TODO Auto-generated method stub
return true;
}
#Override
public boolean isHandled() {
// TODO Auto-generated method stub
return true;
}
#Override
public Object execute(ExecutionEvent event) throws ExecutionException {
// TODO Auto-generated method stub
// call applet here
JFrame jp1 = new JFrame();
Loader a=new Loader ();
jp1.getContentPane().add(a, BorderLayout.CENTER);
jp1.setSize(new Dimension(500,500));
jp1.setVisible(true);
return null;
}
}
i made a new Loader.java which extends applet
package archetypedcomponent.commands;
import java.applet.Applet;
import java.awt.Graphics;
public class Loader extends Applet
{
// The method that will be automatically called when the applet is started
public void init()
{
// It is required but does not need anything.
System.out.println("Applet initiated");
// Graphics g=new ;
}
// This method gets called when the applet is terminated
// That's when the user goes to another page or exits the browser.
public void stop()
{
// no actions needed here now.
System.out.println("Applet Stopped");
}
// The standard method that you have to use to paint things on screen
// This overrides the empty Applet method, you can't called it "display" for example.
public void paint(Graphics g)
{
//method to draw text on screen
// String first, then x and y coordinate.
System.out.println("Applet in paint");
g.drawString("Hey hey hey",20,20);
g.drawString("Hellooow World",20,40);
}
}
Now whatever i need applet to do can b done in paint of Loader.
An applet can have more than one Object, so extends AbstractHandler in some other class that the applet has a reference to.