I want to create a simple GUI application that displays a map of a city.
I then want to programatically add items (assets) such as hotels, restaurants to this map as images.
Pseudo-Code would be as follows
[set up background object with map image covering entire form]
[create hotel1 object (image, label with icon or whatever]
hotel1.image = "hotel.png";
hotel1.size-x = 30;
hotel1.size-y = 30;
hotel1.location-x = 450; (pixels)
hotel1.location-y = 300;
background-object.add(hotel1);
[create restaurant1 object (image, label with icon or whatever]
restaurant1 .image = "hotel.png";
restaurant1 .size-x = 30;
restaurant1 .size-y = 30;
restaurant1 .location-x = 600; (pixels)
restaurant1 .location-y = 400;
background-object.add(restaurant1);
[repeat for hotel2, hotel3, restaurant2 etc...]
This way I could add any number of Assets to the map. The other functions I would require are
change the image of an asset (e.g. to show different image for an asset)
hotel1.image = "hotel_closed.png";
overlap assets (if they are close together)
register a click event handler for each asset
change visibility of asset
hotel1.visible = false;
I am an experienced .Net programmer. This task would be a simple one in .Net, however I am not clear on the best way to accomplish the above in Java. Please could someone suggest the best approach to achieving the above. I am happy to Google if a concept is suggested (I don't need a full coded solution!!)
Many thanks, Ian
There's a lot of places you could start, without knowing the entire requirements (ie if you need to download the maps, tile the maps etc), I can only give you a few overview suggestions
I'd start by having a read through (in no particular order)
Creating a GUI With JFC/Swing
Concurrency in Swing
Custom Painting in Swing
2D Graphics
Basic I/O
I'd also make my self familiar with The Java Tutorials
While most of the above are GUI specific, I'd be reading through things like
Essential classes
Learning the Java Language
Simply because it doesn't matter where you code in Java, these will always be useful.
Happy readings :)
UPDATE
Oh, and of course, the all important API docs (AKA JavaDocs)
UPDATE
When you're reasonable comfortable with all that, you might like to check out SwingX WS, it has a great example of pulling Google & OpenStreet Maps
I am assuming that you want your application to be desktop rather than web based. In which case I have done something similar (though rather more complicated) before using a third party mapping solution. Unfortunately that solution required a licence and is no longer available anyway.
If you just want a simple non-scrollable map in a desktop application I suggest you start with a Swing solution. Look at extending the JComponent object and override the method
public void paintComponent(Graphics g){
// use g to draw things
}
Use the graphics object to paint your map image and your icons. Add this Component to your Swing JFrame and set up the correct sizes and layouts.
If you want this in a webpage then someone else would be better placed to help you.
Edit:
From the feedback given here and in the other post I think you may benefit from a slice of code so here goes:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class SwingPaintDemo extends JPanel {
private BufferedImage map = null;
private BufferedImage pointer = null;
public SwingPaintDemo() {
this.setPreferredSize(new Dimension(200, 200));
loadImagesFromFile();
}
private void loadImagesFromFile() {
// load your images form file - these are fakes:
map = new BufferedImage(200, 200, BufferedImage.TYPE_3BYTE_BGR);
pointer = new BufferedImage(10, 10, BufferedImage.TYPE_4BYTE_ABGR);
Graphics g = map.getGraphics();
g.setColor(Color.GREEN);
g.fillRect(0, 0, 200, 200);
g = pointer.getGraphics();
g.setColor(Color.BLUE);
g.fillOval(0, 0, 10, 10);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// paint map
g.drawImage(map, 0, 0, this);
// paint pointers
g.drawImage(pointer, 50, 75, this);
}
// this main is for testing the class but can be used as a reference
public static void main(String... args) {
JFrame jf = new JFrame();
SwingPaintDemo mapper = new SwingPaintDemo();
jf.getContentPane().setLayout(new BorderLayout());
jf.getContentPane().add(mapper, BorderLayout.CENTER);
jf.setVisible(true);
jf.pack();
}
}
You will need to edit this to load in your images from your file - I wanted to make this self contained and easily runnable so I have just created the images inline.
An answer has not been accepted, yet. So, using your pseudo code as an example, I coded up a quick overlay example using JavaFX 2. The WebView can easily be replaced with an ImageView using the JPG file you mentioned.
Here is the code:
package simple.map.overlay;
import java.io.InputStream;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
public class SimpleMapOverlay extends Application
{
#Override
public void start(Stage primaryStage)
{
WebView mapView = new WebView();
WebEngine webEngine = mapView.getEngine();
String url = "http://maps.google.com/maps?q=Baramerica,+South+Alamo+Street,+San+Antonio,+TX&hl=en&ll=29.416647,-98.488655&spn=0.025196,0.035233&sll=29.416423,-98.489814&sspn=0.006299,0.008808&hq=Baramerica,&hnear=S+Alamo+St,+San+Antonio,+Texas&t=m&z=15";
url += "&output=embed";
webEngine.load(url);
VBox vBox = new VBox(5);
vBox.getChildren().add(mapView);
InputStream instream = SimpleMapOverlay.class.getResourceAsStream("beer.png");
Image beerImage = new Image(instream);
instream = SimpleMapOverlay.class.getResourceAsStream("food.jpg");
Image foodImage = new Image(instream);
Marker laTunaMarker = new Marker(beerImage, "La Tuna");
laTunaMarker.setLayoutX(210);
laTunaMarker.setLayoutY(480);
Marker rosariosMarker = new Marker(foodImage, "Rosarios");
rosariosMarker.setLayoutX(360);
rosariosMarker.setLayoutY(300);
Group root = new Group();
root.getChildren().add(vBox);
root.getChildren().add(laTunaMarker);
root.getChildren().add(rosariosMarker);
Scene scene = new Scene(root);
primaryStage.setTitle("Hello Map World with Markers!");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args)
{
launch(args);
}
class Marker extends Group
{
public Marker(Image image, String text)
{
ImageView imageView = new ImageView(image);
Label label = new Label(text);
VBox vbox = new VBox(5);
vbox.getChildren().add(imageView);
vbox.getChildren().add(label);
getChildren().add(vbox);
}
}
}
Related
I'm new at working with JFrames. So I dont really know how to draw/paint/display everything in a JFrame. Im working on a memory game. Currently im working at the first form, this form must display a background image, a welcome text, a dropdown list with the amount of cards for the memory game and a button which should start the game. I succesfully displayed the background image and the welcome text. After adding the JButton and combobox my form got messed up (I only see a blue background). I have no idea what im doing wrong, also I dont know how I can place the button and dropdown on the right x and y position. I want to place the dropdown box under the welcome text and the button to the right of the dropdownbox.
This is my code:
Main:
package Memory;
public class Main {
public static Memory memory;
public static void main(String[] args) {
memory = new Memory();
}
}
Renderer:
package Memory;
import javax.swing.*;
import java.awt.*;
public class Renderer extends JPanel {
private static final long serialVersionUID = 1L;
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Memory.backImage = new ImageIcon("Memory/memoryGame.jpg");
Main.memory.repaint(g);
}
}
Memory:
package Memory;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;
import java.io.*;
import javax.imageio.*;
import java.awt.FlowLayout;
public class Memory implements ActionListener {
public String[] amountOfCards = {"8","16","32"};
private JButton startButton;
public Renderer renderer;
public static ImageIcon backImage;
public boolean screen1;
public static final int WORLD_WIDTH=1250, WORLD_HEIGHT=800;
public Memory() {
JComboBox comboBox = new JComboBox(amountOfCards);
comboBox.setSelectedIndex(1);
startButton = new JButton("Start game");
JFrame jframe = new JFrame();
Timer timer = new Timer(20,this);
renderer = new Renderer();
jframe.add(renderer);
jframe.setTitle("Memory game");
jframe.setSize(WORLD_WIDTH,WORLD_HEIGHT);
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jframe.setResizable(false);jframe.add(startButton);
jframe.add(comboBox);
jframe.setVisible(true);
screen1=true;
timer.start();
}
#Override
public void actionPerformed(ActionEvent e) {
renderer.repaint();
}
public void repaint(Graphics g) {
//welcome screen
if(screen1) {
BufferedImage scaledImage = getScaledImage();
g.drawImage(scaledImage, 0, 0, null);
g.setColor(new Color(150, 196, 100));
g.setFont(new Font("TimesRoman", Font.PLAIN, 75));
g.drawString("MEMORY GAME", WORLD_WIDTH / 2 - 275, 100);
g.setFont(new Font("TimesRoman", Font.PLAIN, 25));
g.drawString("Please select the amount of cards u want to play with and start the game!", WORLD_WIDTH / 2 -400, 200);
}
}
public BufferedImage getScaledImage() {
BufferedImage image = new BufferedImage(WORLD_WIDTH,WORLD_HEIGHT, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D) image.createGraphics();
g2d.addRenderingHints(new RenderingHints(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY));
g2d.drawImage(backImage.getImage(), 0, 0,WORLD_WIDTH,WORLD_HEIGHT, null);
return image;
}
}
Alright, multiple errors in a first view of your code
public static Memory memory; : That line, having static and being a public member of class will harm you a lot! Why? Because your memory variable is the same for all the instances you create, because it's a "Class variable" not an "instance variable", and being public is going against the convention and security reasons. For reference see: What does the 'static' keyword do in a class? and Why use getters and setters?
From the above point, static is not a "magic cross method / class" word that allows you to use variables through classes or with main and other methods... and thus this line public static ImageIcon backImage; and this one: Memory.backImage = new ImageIcon("Memory/memoryGame.jpg"); shouldn't exist. And the same for this one: Main.memory.repaint(g);
That being said, you should NEVER NEVER NEVER EVER!!! override repaint() method, all of that code should be into the paintComponent(...) mehtod!
Also it is wise to treat images as embedded resources, because, once you export your program as a JAR file, they will become embedded resources, it's better to treat them like if they already were, here you can find information about how to change your program accordingly.
Try and set your ImageIcon BackImage from public static, to public. Also, try and write the jframe.setVisible(true); command after timer.start()
note that setting your JFrame to visible, before completing every initialisation, might lead to unwanted behaviour of your program.
To set the position of your button on the screen, after adding your JButton to your JFrame, you can use: startButton.setLocation(x,y);
After you play a little bit with the coordinates of your window, you'll get the spot you want for your JButton. Keep in mind that (0,0) is usually the upper left corner of your JFrame.
Be careful when using static variables in your program. There seems to be no reason in setting your Memory class, your width and height variables as static.
For more information regarding this, check out this post: Why are static variables considered evil?
I'm completely clueless and lost. I recently started programming on Java. I wanted to make a program that displayed an image that the user could click (a button with an image) and in return play a sound. I've watched many tutorials and they don't work when I follow them. Also I don't know whether I should use swing or javaFX or awt, or if I need to make a new file for the images and buttons only. Please help.
Here is a sample using JavaFX. Your question is tagged Swing, but the question text mentions you are considering JavaFX, so I thought I'd provide this solution so that you could see what a JavaFX style implementation would look like.
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.image.*;
import javafx.scene.layout.StackPane;
import javafx.scene.media.AudioClip;
import javafx.stage.Stage;
public class ImageAudioPlayer extends Application {
private static final String BUTTON_ICON_LOC =
"http://icons.iconarchive.com/icons/mirella-gabriele/fantasy-mediaeval/128/Poison-red-icon.png";
private static final String AUDIO_FILE_LOC =
"http://soundbible.com/mp3/Power_Up_Ray-Mike_Koenig-800933783.mp3";
#Override
public void start(Stage stage) throws Exception {
final AudioClip audioClip = new AudioClip(AUDIO_FILE_LOC);
final ImageView graphic = new ImageView(new Image(BUTTON_ICON_LOC));
Button button = new Button(null, graphic);
button.setStyle("-fx-base: mistyrose;");
button.setOnAction(event -> audioClip.play());
StackPane layout = new StackPane(button);
layout.setPadding(new Insets(10));
stage.setScene(new Scene(layout));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
I don't really know Swing, so I won't provide a solution for that. Library recommendations are off-topic for StackOverflow, so I won't provide a library recommendation here and encourage you to do your own research into potential technologies and decide on the best match that suits your application requirements and skill set.
Search more: it has an answer here:
Icon img = new ImageIcon("/class/path/to/image.png");
JButton btn = new JButton(img);
Make sure /class/path/to/image.png is in the classpath. If it's an image from your hard drive you'll have to load it first, as described in the answer I linked.
Edit: #jewelsea example in JavaFX into Swing:
public class ImageAudioPlayer extends JFrame {
private static final String BUTTON_ICON_LOC =
"http://icons.iconarchive.com/icons/mirella-gabriele/fantasy-mediaeval/128/Poison-red-icon.png";
private static final String AUDIO_FILE_LOC =
"http://soundbible.com/grab.php?id=1019&type=wav";
public ImageAudioPlayer() throws MalformedURLException {
super("Audion button");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container cp = getContentPane();
Icon icon = new ImageIcon(new URL(BUTTON_ICON_LOC));
JButton button = new JButton(icon);
cp.add(button, BorderLayout.CENTER);
button.addActionListener(new ActionListener() {
#Override public void actionPerformed(ActionEvent e) {
playAudio();
}
});
}
private void playAudio() {
// Not nearly as easy as JavaFX, and cannot play MP3
try {
URL url = new URL(AUDIO_FILE_LOC);
final Clip clip = AudioSystem.getClip();
AudioInputStream ais = AudioSystem.getAudioInputStream(url);
clip.open(ais);
clip.start();
clip.addLineListener(new LineListener() {
#Override public void update(LineEvent event) {
if (event.getType() == LineEvent.Type.STOP)
clip.close();
}
});
} catch (UnsupportedAudioFileException | IOException | LineUnavailableException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws MalformedURLException {
ImageAudioPlayer iap = new ImageAudioPlayer();
iap.pack();
iap.setVisible(true);
}
Personally I've been experimenting with Swing lately and I think it's rather intuitive, at least at the base level.
What you want is something along the lines of an image object with an added listener for reactions for clicks/whatever it is you wish to react to.
Something like this:
Adding a mouse listener to image or image Icon in java
alternatively you could use the built in button objects in the swing libraries and set an image to it. You would still need to configure the listener to do whatever it you wish it to do.
Along these lines:
How do I add an image to a JButton
Setting up an action listener.
I think if you are a beginner you can start with swing and netbeans: here are a simple tutorial how to handle images in swing :
Other good tutorials:
text : here
video: here
You should either use Swing or JavaFX...
AWT is very old and should not be used unless there is no other way (I heard that sometimes on OSX there are some issues with Swing...).
Swing is the most common GUI-Toolkit in java, but Oracle announced, that JavaFX will completely replace Swing.
In my opinion Swing is easier to start, because there are tools like the eclipse window builder, which enables you to create your application in a graphical interface, but JavaFX is more likely to be used in the future, because it has some great improvements over Swing (like CSS skins etc.).
So you'll basically have to decide what you like more:
JavaFX will be the Toolkit in the Future - Swing is - still - the mostly used one, with more support etc.
And if you are using Swing, I think a JLabel can contain an image - if you add an mouseClicked listener that's probably the way to go...
You can wrap an image object inside of an anchor tag:
<img src="pic_mountain.jpg" alt="Mountain View" style="width:304px;height:228px;">
I want to make a JavaFX application that basically overlays the entire user screen with a Canvas object, so basically I can draw anything on the user's screen.
Making a window that covers the whole screen is simple. Making it essentially transparent can be achieved with this tutorial: https://assylias.wordpress.com/2013/12/08/383/
So the one and only thing stopping me is the fact that obviously, the window, albeit being transparent it will still capture user mouse and key events.
Is there a way I can achieve this? For a more concrete example, imagine I want to make a red circle surround the user's mouse cursor wherever it goes, but the user input will not be interrupted.
What you want isn't possible in plain JavaFX.
You can check out my answer here, that's the closest thing. But you can't overlay a transparent canvas over the entire desktop and forward the mouse events to the underlying windows.
Having the Canvas semi-transparent would catch all events, but you could see the underlying windows. But when you have the Canvas fully transparent, your application wouldn't catch any events.
However, your "concrete example" could be solved in a different way. Here's the code:
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.PointerInfo;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class CircleAroundCursor extends Application {
double radius = 50;
#Override
public void start(Stage primaryStage) {
Group root = new Group();
Circle circle = new Circle( radius * 2,radius * 2,radius);
circle.setStroke(Color.RED);
circle.setFill(Color.TRANSPARENT);
root.getChildren().add(circle);
Scene scene = new Scene(root, Color.TRANSPARENT);
scene.getRoot().setStyle("-fx-background-color: transparent");
primaryStage.initStyle(StageStyle.TRANSPARENT);
primaryStage.setScene(scene);
primaryStage.show();
primaryStage.setAlwaysOnTop(true);
AnimationTimer loop = new AnimationTimer() {
#Override
public void handle(long now) {
PointerInfo info = MouseInfo.getPointerInfo();
Point p = info.getLocation();
primaryStage.setX(p.getX() - radius * 2);
primaryStage.setY(p.getY() - radius * 2);
}
};
loop.start();
}
public static void main(String[] args) {
launch(args);
}
}
This at least solves "I want to make a red circle surround the user's mouse cursor wherever it goes, but the user input will not be interrupted"
Note: Here AWT classes are mixed with FX classes. You may need to use an EDT & FX thread handling. It does work without though.
Screenshot:
You may have a look at the Robot class. I have abused its powers many times, although I consider most solutions I used that class for as hacky.
Maybe you could do it like this:
intercept MouseEvent and save its properties
do your things like drawing
make the Window invisible
invoke the same MouseEvent with the help of Robot
make the Windows visible again
Sorry about my English, and my ignorance in programming, its because I'm new at this , and I'm having problem with Buttons and JFrame, please help me ;)
I'll post the print of the problem, and the codes of my the two classes I have so far, Game and Menu, hope you guys can solve it, I want the buttons to paint inside the gray panel.
Thanks.
Print of my Problem
Print
(GAME CLASS)
package br.com.lexo.dagame;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import javax.swing.JFrame;
import br.com.lexo.dagame.menu.Menu;
public class Game extends Canvas implements Runnable {
private static final long serialVersionUID = 1L;
private static int width = 300;
private static int height = width / 16 * 9;
private static int scale = 3;
private static String title = "Da Game";
private Thread thread;
public JFrame janela;
private Menu menu;
private boolean running = false;
public Game() {
Dimension size = new Dimension(width * scale, height * scale);
setPreferredSize(size);
janela = new JFrame();
menu = new Menu(janela, this);
}
private synchronized void start() {
if (running) return;
running = true;
thread = new Thread(this, "Thread_01");
thread.start();
}
private synchronized void stop() {
if (!running) return;
running = false;
try {
thread.join();
} catch (Exception e) {
e.printStackTrace();
}
}
public void render() {
BufferStrategy bs = getBufferStrategy();
if (bs == null){
createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.LIGHT_GRAY);
g.fillRect(0, 0, getWidth(), getHeight());
g.dispose();
bs.show();
}
public void update() {
}
public void run() {
while (running){
render();
update();
}
stop();
}
public static void main(String[] args) {
Game game = new Game();
game.janela.add(game);
game.janela.setTitle(title);
game.janela.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
game.janela.pack();
game.janela.setLocationRelativeTo(null);
game.janela.setResizable(false);
game.janela.setVisible(true);
game.start();
}
}
(MENU CLASS)
package br.com.lexo.dagame.menu;
import java.awt.Canvas;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import br.com.lexo.dagame.Game;
public class Menu extends Canvas {
private static final long serialVersionUID = 1L;
public boolean inMenu = false;
JButton startGame = new JButton("Começar Jogo");
JButton exitGame = new JButton("Sair do Jogo");
JButton howToPlay = new JButton("Como Jogar");
private Game game;
public Menu(JFrame janela, Game game){
this.inMenu = true;
this.game = game;
game.janela.setLayout(new GridBagLayout());
game.janela.add(startGame);
game.janela.add(exitGame);
game.janela.add(howToPlay);
howToPlay.setEnabled(false);
}
#Override
public void paint(Graphics g) {
super.paint(g);
}
}
I don't know what are you trying to accomplish but you are not adding the components correctly:
Look at:
game.janela.setLayout(new GridBagLayout());
game.janela.add(startGame);
game.janela.add(exitGame);
game.janela.add(howToPlay);
This is incorrect, the add method has two arguments, like this: container.add(component, constraints); your error is not specifying the constraints. The constraints contains all the details to know where in the panel you want to add that component.
For each LayoutManager the Object constraints is diferent. For the GridBagLayout the constraints is a GridBagConstraints object.
However GridBagLayout is a the most difficult layout to use and you don't really need it. I recommend you to look at this visual guide pick a layout and learn it properly. The tutorial for each LayoutManager explains what do you need to put in the constraints parameter.
The call container.add(component) exists because sometimes the LayoutManager does not need extra information (like the BoxLayout), in the other cases it just uses the "default" constraints for the LayoutManager in use, which may not be what you need.
For example the line in your main:
game.janela.add(game);
Is correct, but what it actually does is calling game.janela.add(game, defaultConstraints); where defaultConstraints is the default constraints value for the LayoutManager of the JFrame janela. Because you didn't explicitely specify a layout for the frame it is using the default layout for JFrames: BorderLayout, and the default constraints for the BorderLayout is the constant BorderLayout.CENTER.
So what that line actually does is:
game.janela.add(game, BorderLayout.CENTER);
Which incidentally is what you wanted to do.
To summarize:
Most calls to add must have two parameters: the component and the constraints. Each LayoutManager uses different constraints. You must be aware of what means to not specify the constraints for your LayoutManager. Do not start learning about how to properly use LayoutMangers with the GridBagLayout it's much more complex.
A quick way to somehow paint components to a graphics object is calling the paint method of component class. So in your render method:
g.fillRect(0, 0, getWidth(), getHeight());
menu.startGame.paint(g);
...
But as you'll soon see that everything is painted on the top left as components are laid out as said in the other answer and to get everything working to how you want them to work is a bit more complicated.
Now the following advice is based on my limited knowledge and was quickly put together so there are probably better ways.
About the menu class:
You are extending java.awt.Canvas when I think it would be best to extend a container like javax.swing.JPanel as you want it (I assume) to hold those 3 buttons.
Next would be to set the appropriate layout for this application, which would be null. So instead of:
game.janela.setLayout(new GridBagLayout());
it would now be:
setLayout(null);
This is because you want components (which are those buttons) to be paint on top of another component which is the Game class that extends Canvas and null allows you to do that.
Because the layout is now null, you must specify the bounds of the components which are the x and y coordinates alone with the width and the height otherwise everything will just be 0, 0, 0, 0 and nothing would show up.
So in the Game's constructor
setBounds(0, 0, width * scale, height * scale);
and janela.setPreferredSize(size); instead of setPreferredSize(size);
Back in the Menu class you will have to set the bounds of the buttons like so:
Dimensions sgSize = startGame.getPreferredSize();
startGame.setBounds(50, 50, sgSize.width, sgSize.height);
I am using preferred size to get the optimal width and height of the button that was set in the buttons UI (I think).
and add them to the Menu which is now a JPanel instead of adding them to the JFrame(janela). (add(startGame);) Also, don't forget to add the game to the menu panel.
and it should work like so:
(http://i.imgur.com/7cAopvC.png) (image)
Alternatively you could make your own widget toolkit or custom layout, but I wouldn't recommend that. I had this same problem last year but ended up moving to OpenGL but anyway, I hope this has helped :)
It appears that there is no API call to calculate the width (in pixels) of a text string in Java FX 2.2. There have been suggestions of workarounds on other forums, but my efforts to create or find any code that returns the width of a String, either using the default font or otherwise, have failed. Any help would be appreciated.
If you are just measuring the default font without CSS:
Place the String to be measured in a Text object.
Get the width of the Text object's layout bounds.
If you need to apply CSS:
Place the String to be measured in a Text object.
Create a throwaway Scene and place the Text object in the Scene.
Take a snapshot of the Text (if you are using Java 7) or call applyCss for Java 8.
Get the width of the Text object's layout bounds.
This works because it forces a layout pass on the Text which calculates it's layout bounds.
The scene in step 2 is required because that is just the way the CSS processor works (it needs a node to be located in a Scene to be able to do its job). Definitely read the linked javadoc for applyCss if you want to understand the processing further.
Sample Code
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.text.Text;
import javafx.stage.Stage;
// displays the width in pixels of an arbitrary piece of text.
public class MeasureText extends Application {
public static void main(String[] args) { launch(args); }
#Override public void start(Stage stage) throws Exception {
final Text text = new Text("XYZZY");
new Scene(new Group(text));
// java 7 =>
// text.snapshot(null, null);
// java 8 =>
text.applyCss();
final double width = text.getLayoutBounds().getWidth();
stage.setScene(new Scene(new Label(Double.toString(width))));
stage.show();
}
}
Sample program output (displays the width in pixels of an arbitrary piece of text):
How (if at all) would this change if the text was printed to a graphicscontext with a set font?
Apply the font to a text object containing the same message you will plot to the canvas. Unlike when you are measuring text plotted to the scene graph, items plotted to a canvas do not have CSS applied to them, so you don't need to place the Text object in a scene and have CSS applied to it before measuring the text. You can measure the layout bounds of your text object and it will be the same as the bounds of the text plotted within the canvas with the same font.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.canvas.*;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.scene.text.*;
import javafx.stage.Stage;
// displays the width in pixels of an arbitrary piece of text (which has been plotted on a canvas).
public class MeasureText extends Application {
#Override
public void start(Stage stage) throws Exception {
final String msg = "XYZZY";
final Text text = new Text(msg);
Font font = Font.font("Arial", 20);
text.setFont(font);
final double width = text.getLayoutBounds().getWidth();
Canvas canvas = new Canvas(200, 50);
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.setFont(font);
gc.fillText(msg, 0, 40);
stage.setScene(new Scene(
new VBox(new Label(Double.toString(width)), canvas))
);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
I tried this:
Text theText = new Text(theLabel.getText());
theText.setFont(theLabel.getFont());
double width = theText.getBoundsInLocal().getWidth();
and it seems to be working fine.
This solution works up until java 8:
float width = com.sun.javafx.tk.Toolkit.getToolkit().getFontLoader().computeStringWidth("", gc.getFont());
float height = com.sun.javafx.tk.Toolkit.getToolkit().getFontLoader().getFontMetrics(gc.getFont()).getLineHeight();
Those classes have since been removed and are not available in newer java version!
Bounds bounds = TextBuilder.create().text(text).font(font).build().getLayoutBounds();
double width=bounds.getWidth();
double height=bounds.getHeight();