I want to add a java.awt.Panel to my JavaFX8 application. Unfortunately it seems that the Panel doesn't get rendered when attached to a SwingNode.
I have a simple testapplication:
import java.awt.Dimension;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Application;
import javafx.embed.swing.SwingNode;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class AWTInJFX extends Application {
#Override
public void start(Stage stage) {
final AwtInitializerTask awtInitializerTask = new AwtInitializerTask(() -> {
AWTPanel panel = new AWTPanel();
return panel;
});
SwingNode swingNode = new SwingNode();
SwingUtilities.invokeLater(awtInitializerTask);
try {
swingNode.setContent(awtInitializerTask.get());
} catch (InterruptedException | ExecutionException ex) {
Logger.getLogger(AWTInJFX.class.getName()).log(Level.SEVERE, null, ex);
}
stage.setScene(new Scene(new Group(swingNode), 600, 600));
stage.setResizable(false);
stage.show();
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame();
frame.setSize(new Dimension(600, 400));
frame.add(new AWTPanel());
frame.setVisible(true);
});
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
private class AwtInitializerTask extends FutureTask<JPanel> {
public AwtInitializerTask(Callable<JPanel> callable) {
super(callable);
}
}
}
My JPanel containing the java.awt.Panel
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Panel;
import javax.swing.JPanel;
public class AWTPanel extends JPanel{
public AWTPanel()
{
Dimension d = new Dimension(600, 400);
setPreferredSize(d);
Panel p = new Panel();
p.setSize(d);
p.setPreferredSize(d);
p.setBackground(Color.red);
this.add(p);
this.setBackground(Color.green);
}
}
Other AWT components doesn't show up either when I add my AWTPanel to a SwingNode.
Can somebody explain me why this isn't working?
I need a AWT Panel to get a hWnd used in additonal C++ libraries.
From the SwingNode Javadocs:
The hierarchy of components contained in the JComponent instance
should not contain any heavyweight components, otherwise SwingNode may
fail to paint it.
As far as I know, there is no way to embed a heavyweight component, such as an AWT component, in JavaFX.
Depending on your requirements, you could consider reversing things around, so that you have a Swing/AWT frame as your main window, and embed the JavaFX part of your application in a JFXPanel.
Related
I am here to ask if it is possible to use JavaFX for the main menu of my game and then switch over to JFrame for the game itself.
The reason I want to do this is because I know how to make pretty fancy game menus in JavaFX and not in JFrame and JavaFX to me also looks alot more fancy then JFrame..
I will truly appreciate any help you give me.
This can be done: you just need to make sure you use the correct threads for everything. In particular, ensure you launch the Swing application on the AWT Event Dispatch Thread.
Here is a simple example.
SwingApp:
import java.awt.BorderLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class SwingApp extends JFrame {
public SwingApp() {
setLayout(new BorderLayout());
add(new JLabel("This is the Swing App", JLabel.CENTER), BorderLayout.CENTER);
JButton quitButton = new JButton("Exit");
quitButton.addActionListener(e -> System.exit(0));
add(quitButton, BorderLayout.SOUTH);
setSize(600, 600);
setLocationRelativeTo(null);
setVisible(true);
}
}
and then
import javax.swing.SwingUtilities;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class LaunchSwingFromFX extends Application {
#Override
public void start(Stage primaryStage) {
Platform.setImplicitExit(false);
Button launch = new Button("Launch");
launch.setOnAction(e -> {
SwingUtilities.invokeLater(SwingApp::new);
primaryStage.hide();
});
StackPane root = new StackPane(launch);
Scene scene = new Scene(root, 400, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
How can I embed a custom label I created using JAVAFX into an existing swing's JPanel?
E.g.
Custom JavaFX Label:
public class CustomJavaFXLabel extends Label{
public CustomJavaFXLabel(){
super();
setFont("blah blah blah");
setText("blah blah blah");
/*
*and so on...
*/
}
}
Existing JPanel in swing
public class SwingApp(){
private JPanel jpanel;
public SwingApp(){
jpanel = new JPanel();
jpanel.add(new CustomJavaFXLabel()); //this line does not work
}
}
Error I got is:
The method add(Component) in the type Container is not applicable for argument (CustomJavaFXLabel)
I understand that to for this, I am better off using JLabel to create the custom label. However, due to certain constraints I was required to use FX for the custom Label.
Thanks.
As shown in JavaFX: Interoperability, ยง3 Integrating JavaFX into Swing Applications, add your custom javafx.scene.control.Label to a javafx.embed.swing.JFXPanel. Because a JFXPanel is a java.awt.Container, it can be added to your Swing layout. Several examples may be found here and below.
import java.awt.Dimension;
import java.awt.EventQueue;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javax.swing.JFrame;
/**
* #see https://stackoverflow.com/q/41159015/230513
*/
public class LabelTest {
private void display() {
JFrame f = new JFrame("LabelTest");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JFXPanel jfxPanel = new JFXPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(320, 240);
}
};
initJFXPanel(jfxPanel);
f.add(jfxPanel);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private void initJFXPanel(JFXPanel jfxPanel) {
Platform.runLater(() -> {
Label label = new Label(
System.getProperty("os.name") + " v"
+ System.getProperty("os.version") + "; Java v"
+ System.getProperty("java.version"));
label.setBackground(new Background(new BackgroundFill(
Color.ALICEBLUE, CornerRadii.EMPTY, Insets.EMPTY)));
StackPane root = new StackPane();
root.getChildren().add(label);
Scene scene = new Scene(root);
jfxPanel.setScene(scene);
});
}
public static void main(String[] args) {
EventQueue.invokeLater(new LabelTest()::display);
}
}
I'm creating a small Game of Life application. I'm using a 'dynamic universe' for all my cells (named Tiles in my project). But for some reason my JScrollPane and JButtons aren't rendering into the frame. I just get a empty JFrame. The controller is returning values and the buttons are getting constructed and added to the panel. It's just that jsp.setViewportView(p); doesn't seem to update the UI.
Main:
GOLController controller = new GOLController();
controller.run();
SwingUtilities.invokeLater(() -> {
GameOfLifeFrame frame = new GameOfLifeFrame(controller);
frame.init();
});
UI class:
package org.gameoflife.ui;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.HeadlessException;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import org.gameoflife.controller.GOLController;
import org.gameoflife.model.Tile;
public class GameOfLifeFrame extends JFrame {
private final GOLController controller;
private JScrollPane jsp;
public GameOfLifeFrame(GOLController controller) throws HeadlessException {
super("Game of Life");
this.controller = controller;
}
public void init() {
jsp = new JScrollPane();
add(jsp);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setExtendedState(JFrame.MAXIMIZED_BOTH);
setVisible(true);
controller.setLock();
this.draw();
controller.releaseLock();
}
public void draw(){
List<List<Tile>> currentState = controller.getTiles();
GridLayout layout = new GridLayout(currentState.size(), currentState.get(0).size());
JPanel p = new JPanel(layout);
currentState.stream().forEach((currentTiles) -> {
currentTiles.stream().map((t) -> {
JButton b=new JButton(" ");
b.setBackground(t.isHasLife() ? Color.GREEN : Color.BLACK);
return b;
}).forEach((b) -> {
p.add(b);
});
});
jsp.removeAll();
jsp.setViewportView(p);
}
}
I'm probably overlooking something really stupid, any help is appreciated.
This: jsp.removeAll() is going to be problematic, as it's likely removed the viewport AND the JScrollBars, it's also no required, as setting the viewportView will do the same thing anyway
Remember, JScrollPane is a specailsed component, that consists of a JViewPort and two JScrollBars, the actually content lives on the JViewport, not the JScrollPane
The following code, as you see below:
public class app extends javax.swing.JFrame implements Runnable {
extends JFrame. But I also need it to extend JPanel, in order to make a transparent JPanel. The problem is that I can't extend both, java throws a mistake:
If I extend JPanel I'm able to make a transparent JPanel, but the program can't run because there's a mistake in a few lines of code (mistake that disappears if I extend JFrame).
However, if I extend JFrame the program will run just fine, but it keeps me away from doing a transparent JPanel. How can I solve this?
Basically, create your custom class extending from a JPanel, use setOpaque to false to make it transparent.
Create an instance of JFrame, set it to undecorated and adjust it's opacity separately.
Add the custom panel to the frame...
Example
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.LayoutManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TransparentPanel {
public static void main(String[] args) {
new TransparentPanel();
}
public TransparentPanel() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new BorderLayout());
try {
BufferedImage img = ImageIO.read(new File("/Users/swhitehead/Dropbox/MegaTokyo/issue459.jpg"));
final JLabel label = new JLabel(new ImageIcon(img.getScaledInstance(-1, 200, Image.SCALE_SMOOTH)));
label.setLayout(new CardLayout());
JPanel menu = new JPanel(new GridBagLayout());
JButton button = new JButton("Show");
menu.add(button);
JPanel transparent = new JPanel(new GridBagLayout());
transparent.setOpaque(false);
transparent.add(new JLabel("Look, I'm see through"));
label.add(menu, "menu");
label.add(transparent, "transparent");
CardLayout layout = (CardLayout) label.getLayout();
layout.show(label, "menu");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
CardLayout layout = (CardLayout) label.getLayout();
layout.show(label, "transparent");
}
});
add(label);
} catch (IOException exp) {
exp.printStackTrace();
}
}
}
}
A class can only ever extend one other class, that's why it won't allow you to extend more than 1 class. here is an explanation why that is the case. Perhaps you should try reading this for more information about such window modifications (window transparency and shapes)
If you want specifically a transparent JPanel, perhaps you should look at this answer as it could explain it better than I could.
I have created a appointment calendar which essentially is a JPanel which contains other movable and resizable JPanels all surrounded by a JScrollpane, this all works well and I am able to scroll around the JPanel using the scrollbars correctly. I close to finishing my application but would like to achieve one more thing.
What I would like to do is when a user is moving the appointment (JPanel), when you reach the edge of scrollpane it automatically will scroll at a desired speed. I am confused which existing method or class can do this (if there is one) or if anyone knows of a jar library available out there that will suit my needs?
Is that being lazy? Yeah probably, I guess I should code it myself, if you do agree could someone suggest where I would start? I'm still learning Java and I might need a gentle nudge to keep my code clean and tidy.
If I can provide anymore detail to help with an answer, let me know.
Ok, it's actually not much complicated. You need to call setAutoscroll(true); on your "scrollable" component and add a MouseMotionListener which invokes scrollRectToVisible.
Here is a small example code:
import java.awt.BorderLayout;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class TestImageResize {
protected void initUI() throws MalformedURLException, IOException {
final JFrame frame = new JFrame(TestImageResize.class.getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
BufferedImage bi = ImageIO.read(new URL(
"http://www.desktopwallpaperhd.net/wallpapers/19/5/islands-paradise-maldive-nature-background-image-landscape-194469.jpg"));
JPanel panel = new JPanel(new BorderLayout());
JLabel label = new JLabel(new ImageIcon(bi));
panel.add(label);
MouseMotionListener doScrollRectToVisible = new MouseMotionAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
Rectangle r = new Rectangle(e.getX(), e.getY(), 1, 1);
((JPanel) e.getSource()).scrollRectToVisible(r);
}
};
panel.addMouseMotionListener(doScrollRectToVisible);
panel.setAutoscrolls(true);
frame.add(new JScrollPane(panel));
frame.pack();
frame.setSize(frame.getWidth() / 2, frame.getHeight() / 2);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
try {
new TestImageResize().initUI();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
}