Parts of JComponents incompatible with Ubuntu? - java

I have a program that outputs the calculation result in a JFrame that contains a JPanel (for extensibility), which contains a JLabel, which displays the said output (which is a string).
I found JLabel's default font to be rather small and hard to read, and so increased the font size and replaced it with a Windows specific font, but didn't think much of it since I checked with a font that doesn't exist, and noticed the program worked fine even if the font doesn't exist. (on both Windows 7 and 8)
However, when run on Ubuntu, the result was a JFrame that was the minimal size.
So now I'm wondering if this is an example of some incompatibility on JVM, or a problem with the copy of Ubuntu it was run on.
The following code should replicate the problem on Ubuntu (or maybe Linux in general) if this is a JVM issue.
import java.awt.BorderLayout;
import java.awt.Font;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Main {
public Main(){
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel lbl = new JLabel("SOME TEXT");
lbl.setFont(new Font("font that doesnt exist", Font.PLAIN, 20));
JPanel pnl = new JPanel();
pnl.add(lbl);
frame.add(pnl, BorderLayout.CENTER);
frame.setVisible(true);
frame.pack();
frame.setLocationRelativeTo(null);
}
public static void main (String[] args)
{
Main main = new Main();
}
}
PS the Ubuntu computer is not mine, so I can't exactly test as I want

Testing on Ubuntu 14, Java 7, font substitution appears to work in the usual way. Note the need to invoke pack() and then setVisible(), as well as to start the UI on the EDT.
import java.awt.Font;
import java.awt.GridLayout;
import java.io.File;
import javax.swing.*;
public class TestFrame extends JFrame {
public TestFrame() {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLayout(new GridLayout(0, 1));
JLabel label1 = new JLabel("Some big, bold, serif text.");
label1.setFont(new Font(Font.SERIF, Font.BOLD, 24));
this.add(label1);
JLabel label2 = new JLabel("Some big, bold, default text.");
label2.setFont(new Font("42", Font.BOLD, 24));
this.add(label2);
this.pack();
this.setLocationRelativeTo(null);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new TestFrame().setVisible(true); }
});
}
}

Related

Strange rendering issue with Java Swing libaray

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);
}
}

Java Swing Moving Away From Null Layout

I built a great GUI using the frowned upon null layout (I defined a lot of constants and used a window resize listener to make it easy). Everything worked perfectly until I started using a new computer. Now, the component's are not positioned properly (from the picture you can see that the components are offset down and right). After researching the problem I learned that layout managers make sure that the components are positioned properly throughout different machines. Because of this, I would like to start rebuilding the GUI in an actual layout manager. The problem is that I often feel limited in the way I position components when attempting to use an actual layout manager.
For anyone who is curious, I was originally using a dell inspiron laptop with windows 10, and have moved to an Asus Laptop (I don't know the actual model, but the touch screen can detach from the keyboard), also with windows 10.
My question:
Which layout manager would be the fastest and easiest to build the GUI shown in the picture above (out of the stock Swing Layouts and others). I would like this layout to respect the components' actual sizes for only a few but not all of the components. Using this layout, how would I go about positioning the inventory button (the hammer at the bottom left) so that the bottom left corner of the inventory button is 5 pixels up and right from the bottom left corner of the container, even after resizing the container?
Thanks in advance. All help is appreciated.
EDIT: The "go find a key" and "Attempt to force the door open" options should have their sizes respected.
The simplest solution that comes to my mind is a BorderLayout for the main panel. Add the textarea to NORTH / PAGE_START. Make another BorderLayout containing the inventory button (WEST / LINE_START) and the location label (EAST / LINE_END). Add that to SOUTH / PAGE_END of the main BorderLayout. Then just add a BoxLayout with vertical alignment to the main BorderLayout's CENTER containing the two buttons. Here's a tutorial for the standard layout managers.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Insets;
import java.awt.image.BufferedImage;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
public class Example {
public Example() {
JTextArea textArea = new JTextArea("There is a locked door");
textArea.setRows(5);
textArea.setBorder(BorderFactory.createLineBorder(Color.GRAY));
textArea.setEditable(false);
WhiteButton button1 = new WhiteButton("Go find a key") {
#Override
public Dimension getMinimumSize() {
return new Dimension(200, 25);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 25);
}
#Override
public Dimension getMaximumSize() {
return new Dimension(200, 25);
}
};
WhiteButton button2 = new WhiteButton("Attempt to force the door open");
button2.setMargin(new Insets(0, 60, 0, 60));
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.Y_AXIS));
buttonPanel.add(button1);
buttonPanel.add(Box.createVerticalStrut(5));
buttonPanel.add(button2);
WhiteButton inventoryButton = new WhiteButton(
new ImageIcon(new BufferedImage(50, 50, BufferedImage.TYPE_INT_RGB)));
JLabel locationLabel = new JLabel("Location: 0");
locationLabel.setVerticalAlignment(JLabel.BOTTOM);
JPanel southPanel = new JPanel(new BorderLayout());
southPanel.add(inventoryButton, BorderLayout.WEST);
southPanel.add(locationLabel, BorderLayout.EAST);
JPanel mainPanel = new JPanel(new BorderLayout(0, 5));
mainPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
mainPanel.add(textArea, BorderLayout.NORTH);
mainPanel.add(buttonPanel);
mainPanel.add(southPanel, BorderLayout.SOUTH);
JFrame frame = new JFrame("Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Example();
}
});
}
private class WhiteButton extends JButton {
public WhiteButton() {
setBackground(Color.WHITE);
}
public WhiteButton(String text) {
this();
setText(text);
}
public WhiteButton(ImageIcon icon) {
this();
setIcon(icon);
setBorder(BorderFactory.createLineBorder(Color.GRAY));
}
}
}

Event dispatch thread exception?

Here is my code, I run it on eclipse and it displays the frame the button and the field, using the button should return the value of the equation typed in the field fe. When i put 2+2 in the field and click "oblicz" it should return 4 but it does not, and it drops some weird exception. Am I missing something?
static JTextField pole1;
public static void main(String[]args)
{
JFrame frame = new JFrame("applet 1.0");
frame.setSize(700, 600);
frame.setLocation(300, 100);
frame.setResizable(false);
frame.setLayout(null);
frame.setVisible(true);
// pole
pole1 = new JTextField();
pole1.setBounds(10, 10, 230, 50);
Font F1 = new Font("Comic Sans",Font.BOLD,20);
pole1.setFont(F1);
pole1.setHorizontalAlignment(JTextField.RIGHT);
frame.add(pole1);
// button
JButton button = new JButton("oblicz");
button.setBounds(10, 80, 100, 70);
button.setBorder(null);
frame.add(button);
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent arg0)
{
{
String str = pole1.getText();
ScriptEngineManager mgr = new ScriptEngineManager();
ScriptEngine engine = mgr.getEngineByName("JavaScript");
String foo = str;
try
{
pole1.setText(String.valueOf(engine.eval(foo)));
}
catch (ScriptExecption e)
{
}
}
}
});
Your code as written worked for me.
However, I made some changes to your code to use Swing more effectively.
I removed all the code from the main method and replaced it with a call to the SwingUtilities invokeLater method. The invokeLater method puts the creation and use of the Swing components on the Event Dispatch thread. Oracle and I demand that all Swing applications start on the Event Dispatch thread.
I put the JTextField and JButton on a JPanel. Do not add Swing components other than JPanel or other panel type components to a JFrame.
I separated the creation of a JFrame from the creation of a JPanel. Divide and conquer. Separation of concerns makes the code easier to read and test.
I created the JPanel and JFrame before I made it visible. Call the JFrame methods in the order I posted.
I removed the null layout and the absolute positioning of the Swing components. Swing was designed to be used with Swing layout managers. Learn them. Use them.
I used a couple of empty JPanel borders to add some white space around the components.
I fixed some syntax problem in your action listener. In my Eclipse IDE, I deleted your try / catch block and let Eclipse generate the try / catch block. I added a printStackTrace method call so that any exception would print out as a stack trace.
Here's the code.
package com.ggl.testing;
import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class JavascriptCalculator implements Runnable {
private JButton button;
private JTextField pole1;
public static void main(String[] args) {
SwingUtilities.invokeLater(new JavascriptCalculator());
}
#Override
public void run() {
JFrame frame = new JFrame("Applet 1.0");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createPanel());
frame.pack();
frame.setLocationByPlatform(true);
frame.getRootPane().setDefaultButton(button);
frame.setVisible(true);
}
private JPanel createPanel() {
JPanel panel = new JPanel();
panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
panel.setLayout(new BorderLayout());
// pole
JPanel polePanel = new JPanel();
polePanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 10, 0));
pole1 = new JTextField(20);
Font f1 = new Font("Comic Sans", Font.BOLD, 20);
pole1.setFont(f1);
pole1.setHorizontalAlignment(JTextField.RIGHT);
polePanel.add(pole1);
panel.add(polePanel, BorderLayout.CENTER);
// button
button = new JButton("oblicz");
panel.add(button, BorderLayout.SOUTH);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
String str = pole1.getText().trim();
ScriptEngineManager mgr = new ScriptEngineManager();
ScriptEngine engine = mgr.getEngineByName("JavaScript");
String foo = str;
try {
pole1.setText(String.valueOf(engine.eval(foo)));
} catch (ScriptException e) {
e.printStackTrace();
}
}
});
return panel;
}
}

How to edit JTextField?

I want to write a simple Swing application with a button and a text field at the bottom. I'm using a JTextField but it is not clickable. I searched on the web and SO, but I could not find a solution. In question How to Set Focus on JTextField?, I found the following :
addWindowListener( new WindowAdapter() {
public void windowOpened( WindowEvent e ){
entry.requestFocus();
}
});
but this does not help. In this other question (How do you set a focus on Textfield in Swing?) I found Component.requestFocus() but this does not work either. I also tried
entry.setFocusable(true);
entry.setEditable(true);
entry.setEnabled(true);
without effects. My code:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class StackSample extends JFrame {
public StackSample() {
initUI();
pack();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private void initUI() {
JPanel panel = new JPanel(new BorderLayout());
add(panel, BorderLayout.CENTER);
JPanel bottomPanel = new JPanel(new FlowLayout());
panel.add(bottomPanel, BorderLayout.SOUTH);
JButton buttonDraw = new JButton("Draw");
bottomPanel.add(buttonDraw);
JTextField entry = new JTextField();
bottomPanel.add(entry);
setPreferredSize(new Dimension(250, 150));
setLocationRelativeTo(null);
}
private static final long serialVersionUID = 8359448221778584189L;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
MyApp app = new MyApp();
app.setVisible(true);
}
});
}
}
Your JTextField is clickable. The only problem is that it's too small.
This is because you're using FlowLayout, which will make components as small as possible.
One solution is to simply switch to a layout that allows components to fill as much space as possible, such as BoxLayout:
JPanel bottomPanel = new JPanel();
bottomPanel.setLayout(new BoxLayout(bottomPanel,BoxLayout.X_AXIS));
You haven't specified a size for your JTextField, so it defaults to zero characters wide. Try using the constructor that specifies the number of columns.
Also, what is MyApp? I can't see any evidence that your StackSample is ever created or used.

Need help setting the background image using JLabel?

I just started GUI programming in Java and I am having trouble setting the background image to a JFrame using JLabel. I have read many answers to the same question on this website but the code is too complicated for a beginner.
My source code is as follows and the image I'm using is already in src folder (I get the output window but there is no image in it):
public class staffGUI extends JFrame {
private JLabel imageLabel = new JLabel(new ImageIcon("staff-directory.jpg"));
private JPanel bxPanel = new JPanel();
public staffGUI(){
super("Staff Management");
bxPanel.setLayout(new GridLayout(1,1));
bxPanel.add(imageLabel);
this.setLayout(new GridLayout(1,1));
this.add(bxPanel);
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
this.setResizable(false);
this.pack();
}
ImageIcon(String) "Creates an ImageIcon from the specified file". The actual physical image is loaded in a background thread, so even though the call might return immediately, the actually loading could still be running in the background.
This means that ImageIcon does not throw any errors if the image can't be loaded, making sometimes annoying to work with. I prefer to use ImageIO.read where possible, as it will throw an IOException when it can't read a image for some reason.
The reason you image is not loading is because the image doesn't actually exist from the context of the JVM, which is looking in the current working directory of the image.
When you included resources within the context of the program, they can no longer be addressed as files and need to be loaded through the use of Class#getResource or Class#getResourceAsStream, depending on your needs.
For example
imageLabel = new JLabel(getClass().getResource("/staffdirectory/staff-directory.jpg"));
Where possible, you should supply the path to the image from the context of the source root
Can you give an example how I can use the "ImageIO.read" in my code?
import java.awt.GridLayout;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class staffGUI extends JFrame {
private JLabel imageLabel;
private JPanel bxPanel = new JPanel();
public staffGUI() {
super("Staff Management");
imageLabel = new JLabel();
try {
BufferedImage img = ImageIO.read(getClass().getResource("/staffdirectory/staff-directory.jpg"));
imageLabel.setIcon(new ImageIcon(img));
} catch (IOException ex) {
ex.printStackTrace();
}
bxPanel.setLayout(new GridLayout(1, 1));
bxPanel.add(imageLabel);
this.setLayout(new GridLayout(1, 1));
this.add(bxPanel);
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
this.setResizable(false);
this.pack();
}
}
Try this example i am sure it will work. Make sure that you have a images folder inside your src folder and put the image in it.
private JLabel imageLabel = new JLabel(getClass().getResource("/staffdirectory/staff-directory.jpg"));
will not work and eclipse will give error as JLabel(URL) is not defined; secondly private modifier is not allowed here.
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.Toolkit;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
class BackgroundImageJFrame extends JFrame {
private static final long serialVersionUID = 6337428393053702097L;
JButton b1;
JLabel l1;
public BackgroundImageJFrame() {
setTitle("Background Color for JFrame");
setSize(400, 400);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
setLayout(new BorderLayout());
JLabel background = new JLabel(
new ImageIcon(Toolkit.getDefaultToolkit().getImage(
getClass().getResource("/images/free-wallpaper-4.jpg"))));
add(background);
background.setLayout(new FlowLayout());
l1 = new JLabel("Here is a button");
b1 = new JButton("I am a button");
background.add(l1);
background.add(b1);
setSize(400, 400);
}
public static void main(String args[]) {
new BackgroundImageJFrame();
}
}

Categories

Resources