I'm using Eclipse 3.7.2 and I would like to use WindowBuilder too. My problem is it generates useless code for me. When I'm running my application I can see nothing but a little piece of the titlebar of the window of my program. This window's size is 0×0 no matter what have I set through the code. When I'm resizing it there is just a blank frame and nothing else. It turned out when I was debugging my code that the constructor - made by WindowBuilder - has been called and running without errors. However this constructor does not make any effect on my program. I have no clue what to do.
thanks
When you go "New" > "Other" > "WindowBuilder" > "Swing designer" > "JFrame" (than name your class) you should get this:
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
public class Stack extends JFrame {
private JPanel contentPane;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Stack frame = new Stack();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public Stack() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
}
}
In oposite way: Go "Help" > "Install new software" > " already installed". Check that you have installed these things (Swing designer and below):
The best process is to let WindowBuilder create the framework of the GUI. With WB installed, just use the new Class icon in the toolbar. This will create the best method naming for WB to continue. WB cannot parse just any code. It needs to have some structure. See the example below.
Related
Background
I want to create a GUI application using the java swing library. For layout I require it to be a GridLayout as the program outline requires this.
Aim
To render a panel with text inside it.
What I have tired
Using setBounds to move the text - this worked and the text did render, however it does not work with the GridLayout therefore does not meet the required specs.
Reading atricles and documentation on GridLayout and rendering of JLabels - Tried the examples - failed.
Using intellij debugger - results show the JLabel is not null, and the text is set to the correct value, along with the enabled and visible properties being true.
Increasing and decreasing GirdLayout rows and columns - failed.
Altering the size of the panel - failed.
Changing the foreground colour to something like green - failed.
Code
public class MainPanel extends JPanel {
public MainPanel(JFrame frame) {
setBounds(40,40,200,200);
setBackground(Color.BLUE);
JLabel label = new JLabel("Hello World", SwingConstants.CENTER);
label.setFont(new Font("Tahoma", Font.PLAIN, 25));
label.setVisible(true);
add(label);
setLayout(new GridLayout(1, 1));
}
}
Result
Conclusion
As you can see, the panel does render (the blue square), however there is no text inside of it. I'm rather confused as code very similar to this has worked on aother project, and there is no obvious reason this shouldn't work.
Your code is essentially OK with the provisos I mentioned. Proof: (obviously you can separate out your own class as a top level one later):
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
public class F extends JFrame {
private void setGui() {
try {
setLocation(0, 100);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setContentPane(new MainPanel());
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
try {
EventQueue.invokeAndWait(() -> {
F f = new F();
f.setGui();
f.setSize(200, 200);
f.setVisible(true);
});
} catch (Exception e) {
e.printStackTrace();
}
}
}
class MainPanel extends JPanel {
public MainPanel() {
setLayout(new GridLayout(1, 1));
setBounds(40,40,200,200);
setBackground(Color.BLUE);
JLabel label = new JLabel("Hello World", SwingConstants.CENTER);
label.setFont(new Font("Tahoma", Font.PLAIN, 25));
add(label);
}
}
When running below simple app and changing font anti-aliasing (WIN+R "sysdm.cpl" -> System Properties -> Advanced -> Performance Settings -> Smooth edges of screen fonts) one can see that the JTextArea gets the wrong font (and stays with it also if toggle anti-aliasing again):
import java.awt.Font;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
public class Main
{
public static void main(String[] args)
{
JFrame frame = new JFrame();
JPanel mainPanel = new JPanel();
JLabel label = new JLabel("labelMessage:");
mainPanel.add(label);
final JTextArea textArea = new JTextArea("textAreaMessage")
{
// #Override
// public void setFont(Font f)
// {
// super.setFont(label.getFont());
// }
};
textArea.setEditable(false);
textArea.setOpaque(false);
textArea.setFont(label.getFont());
mainPanel.add(textArea);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setVisible(true);
}
}
Only, when uncommenting the override of setFont it works like one would expect.
When setting there a breakpoint one can see that when the font anti-aliasing is changed there is a AATextListener fired:
Where at some point the defaults are installed:
editor.setFont(UIManager.getFont(prefix /*TextArea*/ + ".font"));
So it is clear why it is happening but I do not know how to solve it in a good fashion.
Possible solutions:
Override the methods like shown above in the code
Use e.g. -Dswing.useSystemFontSettings=false (or -Dswing.aatext=true or awt.useSystemAAFontSettings) BUT then the font looks ugly so not acceptable without further enhancements
Set via UIManager the defaults
Remove/disable the listener? Seems to be hard coded and not be doable easy?
or 3. could be a solution but would require much work in a big legacy app.
NOTE: This is just a simple example. In our app the problem is much bigger as not only set fonts are lost, but almost everything, like borders of buttons, the custom ComponentUIs etc. And the described way how to reproduce it was just to have it easy reproducible, means we encounter this issue also spontaneously when e.g. the app runs for some hours. We then see that some windows event is firing the listener and destroying the look and feel of our app (often the PC was not used at all for almost an hour when this suddenly happens).
Maybe I will also ask the OpenJDK community the next days, as well. If so, I will link the ticket ID here.
Windows version: Windows Enterprise 10 Version 20H2 (Build 19042.1348)
Java version: zulu11.50.19-ca-jdk11.0.12-win_x64
Demo which listens for change like proposed by #VGR. When font anti aliasing is changed the UI will be re-rendered.
import java.awt.Toolkit;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
public class Main
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(() -> {
final JFrame frame = new JFrame();
final JPanel mainPanel = new JPanel();
Toolkit tk = Toolkit.getDefaultToolkit();
tk.addPropertyChangeListener("awt.font.desktophints"/*SunToolkit.DESKTOPFONTHINTS*/, new PropertyChangeListener()
{
#Override
public void propertyChange(PropertyChangeEvent evt)
{
SwingUtilities.invokeLater(() -> render(mainPanel));
}
});
render(mainPanel);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setVisible(true);
});
}
private static void render(JPanel parent)
{
parent.removeAll();
final JPanel panel = new JPanel();
final JLabel label = new JLabel("labelMessage:");
panel.add(label);
final JTextArea textArea = new JTextArea("textAreaMessage");
textArea.setEditable(false);
textArea.setOpaque(false);
textArea.setFont(label.getFont());
panel.add(textArea);
parent.add(panel);
parent.revalidate();
parent.repaint();
}
}
It's an old question but I'd like to explain what's going on here.
textArea.setFont(label.getFont());
You use the font of the label for textArea. Since you didn't change the font, the font is a UIResource, therefore the font gets reset to the default font whenever UI components are updated because of a desktop property change or any other update, like Look-and-Feel change.
When such an event occurs, the UI of all the components is updated using updateUI() method of JComponent.
Creating a new instance of Font removes the magic of UIResource:
Font labelFont = label.getFont();
textArea.setFont(labelFont.deriveFont(labelFont.getStyle()));
The font of the textArea is not reset by updateUI. Yet the font will not change even when you want it to change, for example when the Look-and-Feel of your app is updated to another LaF.
A better solution is to override updateUI method and set the font for textArea there:
final JTextArea textArea = new JTextArea("textAreaMessage") {
#Override
public void updateUI() {
super.updateUI();
setFont(UIManager.getFont("Label.font"));
}
};
This approach handles both the initial setup as well as any updates. This can be a new reusable component which is used to display selectable text, if you also set the background and foreground colors and make the text non-editable by default. (If you set the background and foreground colors, which I recommend doing, you won't need textArea.setOpaque(false);, it makes paint and repaint faster.)
The runnable example:
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
public class UIFontUpdate {
private final JFrame frame;
public static void main(String[] args) {
SwingUtilities.invokeLater(UIFontUpdate::new);
}
private UIFontUpdate() {
frame = new JFrame("UI Font Update");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel mainPanel = new JPanel();
JLabel label = new JLabel("labelMessage:");
mainPanel.add(label);
final JTextArea textArea = new JTextArea("textAreaMessage") {
#Override
public void updateUI() {
super.updateUI();
setFont(UIManager.getFont("Label.font"));
}
};
textArea.setEditable(false);
textArea.setOpaque(false);
mainPanel.add(textArea);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
new Thread(this::callUpdateUI).start();
}
public void callUpdateUI() {
try {
Thread.sleep(2000);
} catch (InterruptedException ignored) { }
System.out.println("UI updating...");
SwingUtilities.invokeLater(() ->
SwingUtilities.updateComponentTreeUI(frame));
}
}
I'm simulating update to properties without actually changing system settings. I'm using callUpdateUI which is run on another thread, and after 2 seconds it updates the UI.
To test that the approach works when changing the Look-and-Feel, change the code callUpdateUI to:
SwingUtilities.invokeLater(() -> {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException
| IllegalAccessException
| UnsupportedLookAndFeelException ignored) {
}
SwingUtilities.updateComponentTreeUI(frame);
});
As for testing-reasons I tried to open a JDialog window with the panel and its contents of the main application frame. As I already had anything in there I wanted to see if I could simply set the JDialogs contentPane to the one I passed over. So in simplyfied form this came together:
testsforSO.java :
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class testsforSO extends JFrame {
private static final long serialVersionUID = -3890178393751567629L;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
testsforSO frame = new testsforSO();
frame.setSize(300, 300);
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public testsforSO() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("I am the Frame");
getContentPane().setLayout(new BorderLayout(0, 0));
JPanel panel = new JPanel();
panel.setLayout(null);
JButton btnRestart = new JButton("Restart");
btnRestart.setBounds(10, 10, 50, 50);
btnRestart.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
testsforSO.main(null);
dispose();
}
});
panel.add(btnRestart);
getContentPane().add(panel);
repaint();
// -----------DELETE These comments-------------
// JDialog myDialg = new JDialog(this);
// myDialg.setContentPane(panel);
// myDialg.setVisible(true);
// myDialg.setSize(300,300);
// myDialg.setLocation(new Point(250, 250));
// myDialg.setTitle("I am Dialog from within the script");
myDialog.main(panel);
}
}
and myDialog.java :
import java.awt.Container;
import java.awt.EventQueue;
import javax.swing.JDialog;
public class myDialog extends JDialog {
private static final long serialVersionUID = 7079322237622743228L;
public static void main(Container myContainer) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
myDialog frame = new myDialog(myContainer);
frame.setVisible(true);
frame.setContentPane(myContainer);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public myDialog(Container myContainer) {
setContentPane(myContainer);
getContentPane().setLayout(null);
setBounds(200,200,200,200);
}
}
When starting the main frame I assumed it would contain the restarting button as well as the dialog does. But interestingly it was only the dialog with the button.
However when hitting it, the main frame properly restarted, a second dialog was set up and it contained the button again. This time however the main frame had the button as well, just without any function. Clicking on it does absolutely nothing.
Then I tried further and checked if that behaviour would change if I added the dialog directly into the main applications code (see the commented lines) and, starting the application once again only the dialog in its own class showed the button. Even hitting this one now restarted properly but the button won't show up on any other window except the lonely declared dialog.
What am I missing here and how could I refactor my code to work properly if even at all in this manner?
Understand that Swing components can only be present in one container, and while you may see the visual residue of a component in a container, the actual component is only present in the last container added to.
Myself, if I wanted dialog and jframe to have the same content pane components, I'd create a factory method to create the contentPane, and then use it to create two unique but identical contentPanes.
Also, I'd be remiss if I didn't mention something about your use of null layouts. While null layouts and setBounds() might seem to Swing newbies like the easiest and best way to create complex GUI's, the more Swing GUI'S you create the more serious difficulties you will run into when using them. They won't resize your components when the GUI resizes, they are a royal witch to enhance or maintain, they fail completely when placed in scrollpanes, they look gawd-awful when viewed on all platforms or screen resolutions that are different from the original one.
For instance, when I ran your code, this is the dialog that I saw:
You hard coded the button's size to be too small to show its text on my platform. If you had used layout managers, and called pack() on the top-level window, the button would show appropriately.
I am trying to create a simple JFrame menu where there is a nice background, which works, along with some text. The text is a bit buggy. Here is how it looks (http://imgur.com/nRpzA30)
As you can see, only one line of the text appears not the second line.
Along with that. Two GUI's appear when I run the program. One is completley empty, and one looks like the picture above.
Finally I can't use the method logo.setHorizontalAlignment(JLabel.NORTH); without getting an error, same with a few others. The two I tested and worked were only .CENTER, and .LEFT.
Any help would be great!
Oh and almost forgot, here's my code :)
package character;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.io.IOException;
/**
* Created by Niknea on 6/28/14.
*/
public class characterSelector extends JFrame{
JPanel cselectorText;
JFrame cselectorButtons;
JLabel logo, characterName, label;
JButton previous, next;
public characterSelector(String title){
super(title);
this.createCharacterSelector();
this.setSize(1920, 1033);
this.setResizable(true);
this.setVisible(true);
}
public void createCharacterSelector(){
try {
label = new JLabel(new ImageIcon(ImageIO.read(getClass().getResource("/resources/Grass_Background.jpg"))));
cselectorButtons = new JFrame();
logo = new JLabel("SoccerKidz [REPLACE W/ COOL LOGO]");
characterName = new JLabel("<Character Name>");
logo.setPreferredSize(new Dimension(50, 50));
logo.setFont(new Font(logo.getFont().getName(), Font.HANGING_BASELINE, 50));
characterName.setFont(new Font(characterName.getFont().getName(), Font.HANGING_BASELINE, 50));
cselectorButtons.add(logo);
cselectorButtons.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
cselectorButtons.setContentPane(label);
cselectorButtons.setLayout(new BorderLayout());
characterName.setForeground(Color.CYAN);
characterName.setHorizontalAlignment(JLabel.CENTER);
cselectorButtons.add(characterName);
logo.setForeground(Color.CYAN);
logo.setHorizontalAlignment(JLabel.LEFT);
cselectorButtons.add(logo);
cselectorButtons.pack();
cselectorButtons.setLocationRelativeTo(null);
cselectorButtons.setVisible(true);
} catch (IOException exp) {
exp.printStackTrace();
}
}
}
Thanks again! :)
As you can see, only one line of the text appears not the second line.
You set the layout of cselectorButtons to BorderLayout. Then you add JLabel("<Character Name>");, which is fine. But then you add JLabel("SoccerKidz [REPLACE W/ COOL LOGO]");. Here's what's happening. With BorderLayout, when you just add(component), generally you want to specify a BorderLayout.[POSITION] as the second argument to the add. If you don't, every component that you add, without the position specified, will be added the the BorderLayout.CENTER implicitly by default. The problem with this is each position can only have one component. So in your case, the first label gets kicked out the center, only showing the second one you added.
Two GUI's appear when I run the program. One is completley empty, and one looks like the picture above.
When look at your code. Your class is a JFrame in which you add nothing to, and this.setVisible(true). And also you a JFrame cselectorButtons; in which you do add components and also cselectorButtons.setVisible(true);. Can you guess which one is the one you're seeing that's not empty. Don't extends JFrame. Just use the instance one you currently are using.
Finally I can't use the method logo.setHorizontalAlignment(JLabel.NORTH); without getting an error.
It doesn't take much to take a look at the API for JLabel. That being said, what makes you think aligning something horizontally, should include an option to position to the north. Doesn't make sense
public void setHorizontalAlignment(int alignment)
Sets the alignment of the label's contents along the X axis.
Parameters:
alignment - One of the following constants defined in SwingConstants: LEFT, CENTER (the default for image-only labels), RIGHT, LEADING (the default for text-only labels) or TRAILING.
I suggest you take a look at Layout out Components Within a Container and A Visual Guide to Layout Managers for other possibly layout managers you can use, if BorderLayout doesn't suit you. Also keep in mind you can nest different panels with different layout managers to get your desired result. But first you need to learn how they work.
UPDATE
I made some changes, which works. I'm also looking at your pastebin code, and can't really see any difference. You may want to investigate my code to try and look for differences
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
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.SwingUtilities;
/**
* Created by Niknea on 6/28/14.
*/
public class CharacterSelector {
JPanel cselectorText;
JFrame cselectorButtons;
JLabel logo, characterName, label;
JButton previous, next;
public CharacterSelector() {
createCharacterSelector();
}
public void createCharacterSelector() {
try {
label = new JLabel(new ImageIcon(ImageIO.read(getClass()
.getResource("/resources/Grass_Background.jpg"))));
cselectorButtons = new JFrame();
logo = new JLabel("SoccerKidz [REPLACE W/ COOL LOGO]");
characterName = new JLabel("<Character Name>");
logo.setPreferredSize(new Dimension(50, 50));
logo.setFont(new Font(logo.getFont().getName(),
Font.HANGING_BASELINE, 50));
characterName.setFont(new Font(characterName.getFont().getName(),
Font.HANGING_BASELINE, 50));
cselectorButtons.add(logo);
cselectorButtons.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
cselectorButtons.setContentPane(label);
cselectorButtons.setLayout(new BorderLayout());
characterName.setForeground(Color.CYAN);
characterName.setHorizontalAlignment(JLabel.CENTER);
cselectorButtons.add(characterName);
logo.setForeground(Color.CYAN);
logo.setHorizontalAlignment(JLabel.LEFT);
cselectorButtons.add(logo, BorderLayout.NORTH);
cselectorButtons.pack();
cselectorButtons.setLocationRelativeTo(null);
cselectorButtons.setVisible(true);
} catch (IOException exp) {
exp.printStackTrace();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
new CharacterSelector();
}
});
}
}
I'm working on a complex java swing project.
during initialization I set the frame size to 1280X1024.
sometimes when I launch my app the frame starts with the expected dimensions
other times the frame actual size is 1282X1053 (always this size).
I have two question, while trying to pinpoint the source for this issue.
1) is there a way to set a watch point when the frame size is changed?
I'm using eclipse, and when I tried to set a watch point, it breaks when every component I have changes size. this is unacceptable as I have too many components to manually follow.
2) due to the fact that the issue doesn't reproduce every time, I'm worried that maybe somewhere in the code I access Java swing component outside the EDT. is there a way to verify that all the calls to all the swing components in my code are done from the EDT?
EDIT:
the below code is a sample of what I use.
I can't attach the code to build the panels as it is too complex to fit here
EDIT 2: the code below works. the problem is happens because of the commented lines before calling setVisible
package com.earlysense.nursestation;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.lang.reflect.InvocationTargetException;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class MyFrame extends JFrame {
private JPanel west;
private JPanel center;
/**
* Initializes the panels
*/
public void init() {
setLocation(0, 0);
setPreferredSize(new Dimension(1280, 1024));
setUndecorated(true); // The frame is fixed. It cannot be moved or resized.
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel p = new JPanel(new BorderLayout());
west = new JPanel();
west.add(new JLabel("west"));
center = new JPanel();
center.add(new JLabel("center"));
p.add(BorderLayout.WEST, west);
p.add(BorderLayout.CENTER, center);
getContentPane().add(p);
}
public static void main(String[] args) {
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
MyFrame frame = new MyFrame();
frame.init();
frame.pack();
// at this point frame.getSize() returns 1280X1024
// add components to west and center panel which depends on the frame size to set self size
frame.setVisible(true);
// at this point frame.getSize() sometimes returns 1282X1053
}
});
} catch (InterruptedException e) {/* Do nothing */
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
It seems like a bug in java.
was known in java 1.3, but apparently still happens. I'm using ubuntu 13.10 64bit, jdk: OpenJDK Runtime Environment (IcedTea6 1.12.6) (6b27-1.12.6-1ubuntu2.1)
link
I set the frame size to 1280X1024.
Why? My screen is 1024 x 768, so I guess I can't use your application? Don't hardcode values. Instead use:
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
SwingUtilities.invokeAndWait(new Runnable() {
Why are you using invokdeAndWait? All the Swing tutorial and suggestions by people in the forum use invokeLater(..).