I'm started to make a "testing suite" in java. I'm currently working on sentence completion type tests. Basically I have a text with placeholders, where the user should put in some text, and which will be evaluated later. I found out that by using FlowLayout I could fit the JLabels and JTextFields after each other. The problem is when a block of text is too long. It should span into multiple lines, and I'm not sure how to actually do that. And while that's okay, if I push a small text from the end of the line to a new line, but I'm still stuck if the whole text block is longer than the line width.
And I don't want to reinvent the wheel, so is there any opensource libraries for testing suites? My googlefu failed.
The best solution I've found to this problem is using Rob Camick's WrapLayout
WrapLayout is essentially an extension of FlowLayout which wraps the content when it can no longer fit horizontally.
Check out the linked blog above as it explains why your having the problems you are.
Updated
Another option would be to use JTextPane and insert fields into, for example...
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.HeadlessException;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTextPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.text.BadLocationException;
import javax.swing.text.StyledDocument;
public class TestText {
public static void main(String[] args) {
new TestText();
}
public TestText() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JTextPane tp = new JTextPane();
tp.replaceSelection("Asd, asd, asd, fgh ");
addField(tp);
tp.replaceSelection(" more funky text here ");
addField(tp);
tp.replaceSelection(" and this must wrap on the edge. The color code of red is: #");
addField(tp);
tp.replaceSelection(". ");
tp.setEditable(false);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new JScrollPane(tp));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
protected void addField(JTextPane tp) {
JTextField field = new JTextField(10);
field.setAlignmentY(0.75f);
tp.insertComponent(field);
}
});
}
}
Note, the editor itself is not editable, but the text fields are...
Related
I want to create a Java application that displays text on the screen, in such a way that it is not contained in any form or canvas, at least not any visible one, but rather just display it on top of the thing that is currently displaying on the computer.
I'd prefer to use it in pure Java, but I guess if there is some third party library or compiled C API's then that's fine too.
If possible then I'd also like something like Ubuntu's Always on top feature, so that if I click some other window the text still is displayed on top of it.
Is there any way to make JFrames transparent?
This is kind of what I'm aiming for, only doing it in Java
http://2.bp.blogspot.com/-QkxT8pC17nw/T1n_rlr20aI/AAAAAAAAAj0/xbJjYObc4Bw/s1600/screenCaptureRainmeter.png
Conceptually, you problem basically boils down to making the window transparent. To that end you should start by looking at How to Create Translucent and Shaped Windows
The next thing to keep in mind is the fact that most Swing component's are opaque by default, so just beware of that
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
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.setUndecorated(true);
frame.setBackground(new Color(0, 0, 0, 0));
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() {
setOpaque(false);
setLayout(new GridBagLayout());
JLabel label = new JLabel("I'm on top");
label.setFont(label.getFont().deriveFont(Font.BOLD, 64));
label.setForeground(Color.WHITE);
add(label);
}
}
}
You may also want to have a look at Window#setAlwaysOnTop
A JButton has a different appearance when rolled over. That appearance is different from the "selected" appearance.
I want to display my button "as if" it was rolled over, so that user understands that if he hits the Return key, that button will be triggered.
The problem is not the same as setting the default button, because I am in a situation where I really want to get the user to understand that although he wouldn't expect it, if he hits enter that button will be activated. More details below for those who want some. Setting button as default would make button the default one, but wouldn't be significantly signaling to the user.
In my case the strong enough signal is the appearance that the button has when it is rolled over.
How to do that ?
More details on the situation, for those who want some :
I have a list of buttons representing options, and a text box at the top, which acts as a filter on the buttons
when filter is such that only one option remains, hitting return directly clicks that option's button
in reality user would have had to select the button with tab or arrow, and then hit enter.
since that shortcut is not obvious I want to signal it to user
Based on your question, what you "really" want, is the JRootPane#setDefaultButton, which will highlight the button, in a OS specific manner and if the user presses the default "action" key (Enter in most cases) will call it's ActionListener
For example...
The "normal" button is just a plain old JButton, the Hacked sets the rollOver to enabled and Default has been set as the default button for the JRootPane
As you can see, you're suggest fix does nothing on MacOS, don't know what it might do on other platforms
I suggest you have a look at How to Use Root Panes for more details
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
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 {
private JButton asDefault = new JButton("Default");
public TestPane() {
JButton hack = new JButton("Hacked");
hack.getModel().setRollover(true);
hack.setRolloverEnabled(true);
asDefault.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Defaulted");
}
});
add(new JButton("Normal"));
add(hack);
add(asDefault);
}
#Override
public void addNotify() {
super.addNotify();
JRootPane rootPane = SwingUtilities.getRootPane(this);
if (rootPane != null) {
rootPane.setDefaultButton(asDefault);
}
}
}
}
So using button.getModel().setRollover(true); doesn't work on all platforms and on those platforms it does work on, I suspect the user will simply need to move the mouse through it to return it to normal
button.getModel().setRollover(true);
I am having difficulties displaying a JFrame with all of the contents showing immediately. I would like to show the JFrame with all Components already added, but the window appears to become visible out-of-focus, wait a second, then come into focus with the Component(s) added. The code for my SSCCE is extremely short/simple, so I don't know why this effect is happening.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class DelayTest
{
public static void main(String[] args)
{
JLabel label = new JLabel("DELAY TEST");
label.setHorizontalAlignment(JLabel.CENTER);
label.setPreferredSize(new Dimension(400, 60));
JFrame frame = new JFrame("Delay Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(label);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
I know that this effect does not happen if I comment out label.setPreferredSize(new Dimension(400,60));, so though it may simply be a correlation & not a causation, I'm guessing somehow PreferredSizes have to do with it. But, why?
ALSO, this effect occurs even if I create the GUI in a separate Runnable thread apart from the main thread. Although clearly the effect is related to the order of thread execution, I do not believe that specific factor is the cause.
Upon startup:
About 1 second later:
The likely delay is caused by the need for the system to initialize the synchronize the Event Dispatching Thread with the native system before it can render content.
You should make sure that your UI is initialised and shown from within the context of the Event Dispatching Thread, which should make the initial startup more synchronised...
Take a look at Initial Threads for more details
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestDelay {
public static void main(String[] args) {
new TestDelay();
}
public TestDelay() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JLabel label = new JLabel("Delay Test");
Font font = label.getFont();
label.setFont(font.deriveFont(Font.BOLD, 24f));
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(label);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
Is there any way to show a phrase, per se, "Welcome!", letter by letter with a very small delay between them? I would provide what I've tried but I haven't even come close to barely working, nothing worth mentioning. I suppose I would have to use a loop containing a scanner, yes? Any help appreciated, thanks:)
Caveats
Swing is a single threaded framework, that is, all updates and modifications to the UI are expected to be executed from within the context of the Event Dispatching Thread.
Equally, any operation which blocks the EDT will prevent it from processing (amongst other things), paint updates, meaning that the UI won't be updated until the block is removed.
Example
There are a few ways you could achieve this. You could use a SwingWorker and while it would be a good learning exercise, it would probably be a little over kill for this problem.
Instead, you can use a javax.swing.Timer. This allows you to schedule callbacks at regular intervals, these callbacks are executed within the context of the EDT which will you allow you to update the UI safely.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class AnimatedLabel {
public static void main(String[] args) {
new AnimatedLabel();
}
public AnimatedLabel() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.setSize(100, 100);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private String text = "Hello";
private JLabel label;
private int charIndex = 0;
public TestPane() {
setLayout(new GridBagLayout());
label = new JLabel();
add(label);
Timer timer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String labelText = label.getText();
labelText += text.charAt(charIndex);
label.setText(labelText);
charIndex++;
if (charIndex >= text.length()) {
((Timer)e.getSource()).stop();
}
}
});
timer.start();
}
}
}
Take a look at Concurrency in Swing for more details
Update from comments
The main problem is your text value is wrapped in <html>
static String text = "<html>Welcome! I will ask simple, two-answer questions, and you will answer them. Simple as that. </html>";
And then you apply it to your label...
final JLabel centerText = new JLabel(text);
So when the timer runs, it ends up append the text again...
"<html>Welcome! I will ask simple, two-answer questions, and you will answer them. Simple as that. </html><html>Welcome! I will ask simple, two-answer questions, and you will answer them. Simple as that. </html>"
Which is invalid, because everything after the </html> will be ignored.
Instead, remove the <html> tags from the text
static String text = "Welcome! I will ask simple, two-answer questions, and you will answer them. Simple as that.";
And set the initial text of the label with <html>
final JLabel centerText = new JLabel("<html>);
Don't worry, Swing will take care of it...
I've added an image that I want to use as a background image and I want to put jLabels on top of it. So I use the image icon feature and show the image, but when I try to put a jLabel on it, it gets moved off to the side. I've tried several tutorials and it appears to work on youtube, but when I try to do the same thing on my own they get moved out of position.
field.setIcon(new javax.swing.ImageIcon(getClass().getResource("/wiffleball/resources/field2.png"))); // NOI18N
The JLabel doesn't have a layout manager by default. Label's also have default text positioning, which is normally aligned to the left, you need to change all these default values...
You may want to use a different layout manager other the BorderLayout, but this is just an example...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Font;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class SimpleLabel {
public static void main(String[] args) {
new SimpleLabel();
}
public SimpleLabel() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JLabel label = new JLabel(new ImageIcon("C:\\hold\\thumbnails\\_cg_836___Tilting_Windmills___by_Serena_Clearwater.png"));
label.setHorizontalAlignment(JLabel.CENTER);
label.setVerticalAlignment(JLabel.CENTER);
label.setLayout(new BorderLayout());
JLabel child = new JLabel("Can you see me?");
child.setForeground(Color.WHITE);
child.setFont(label.getFont().deriveFont(Font.BOLD, 24f));
child.setHorizontalAlignment(JLabel.CENTER);
child.setVerticalAlignment(JLabel.CENTER);
child.setHorizontalTextPosition(JLabel.CENTER);
child.setVerticalTextPosition(JLabel.CENTER);
label.add(child);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(label);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
I put everything on a jPanel and that seemed to do it. It just took some tinkering with. Thanks!