JLabel.setText() not working after setting size - java

I have a JLabel that I require to change dynamically when a button is pressed. I am using JLabel.setText(s)
However, it is not working. I've tried:
JLabel.repaint()
JLabel.validate()
JLabel.revalidate()
The thing I find strange is that it works fine when I don't set the size of the JLabel using any of:
JLabel.setPrefferedSize()
JLabel.setMinimumSize()
JLabel.setSize()
Can anyone help me with why it isn't working after I set one of the size properties?

What your button is doing is probably a very long task and you want to keep the user informed about the process.
To do this you have to create a new Thread which performs the long task and when you set new text to your label, wrap the label.setText() statement into an invokeLater():
public void buttonAction()
{
new Thread(new Runnable()
{
public void run()
{
// Here your long task
// When you want to call Label.setText(), do it like this:
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
label.setText("Loading 1/13...");
}
});
// Here another part of your task....
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
label.setText("Done!");
}
});
}
}).start();
}

For sizing components in Swing, ultimately the layout of the parent container has the final say on the size of the component.
For example, in FlowLayout, calling setPreferredSize(), setSize(), or setMaximumSize() on a component all have the result of giving the label that size, and not sizing over it. However, with setMinimumSize() it will start at that size, then size above it.
For BorderLayout, if the component is added to the center, none of the sizing methods affect the component - it just takes the maximum amount of space available.
If you set the layout of the parent container to null you can explicitly size components, however, you will lose the automatic resizing that you have with other layouts.

Figured out my problem,
I was using:
JLabel.setPreferredSize(100, JLabel.getheight());
I changed to:
JLabel.setPreferredSize(100, 22);

JLabel.setPreferredSize(100, JLabel.getheight());
As you are setting the preferred size here, the height of JLabel must not have been previously set :), if you try the same line after setting the height, I think it should work well.
Also sometimes JPanel<xx>.updateUI(); is required to refresh the displayed UI.enter code here

Related

Change ImageIcon in JLabel using Timer

I have two classes: logic and the JFrame. In frame I have a JLabel and a JButton, and I would like to:
When this button is clicked, the ImageIcon in the label changes after a determined time using a Swing Timer, like if it is flashing. To do it I loaded two images with different brightness (img1b and img1). I tried to make the timer change the image twice with different delays, but I was unsuccessful. I also put a listener in the button and implemented the actionPerformed as below:
public void actionPerformed(ActionEvent e) {
if(e.getSource().equals(btnImg1)) {
logic.piscaImagen(img1, lblImg1);
logic.piscaImagen(img1b, lblImg1);
In logic class:
public void piscaImagen(ImageIcon img, JLabel lbl) {
Timer timer = new Timer(1250, null);
timer.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt){
if(lbl.getIcon() != img){
lbl.setIcon(img);
}
}
});
timer.setRepeats(false);
timer.start();
}
But when I run it nothing changes in the logic.piscaImagen. Any tips?
logic.piscaImagen(img1, lblImg1);
logic.piscaImagen(img1b, lblImg1);
It looks to me like you are starting two Timers. So the first Timer fires and it changes the image, then the second timer fires and it restores the image so basically you only see the first image.
All you need is one Timer. Each time the Timer fires you change the image. So the basic code in your Timer would be:
if (lbl.getIcon() == img1)
lbl.setIcon(img1b);
else
lbl.setIcon(img1);
Or for a more flexible solution you can use the Animated Icon.
The Animated Icon will allow you to specify a List of Icons to display. Then when the Timer fires the next Icon in the List is displayed. You can set the Animated Icon for continuous display or you can control the number of cycles.
EDIT: answer inaccurate, repaint() not necessary - see comments.
You're missing the repaint() call that tells the program it needs to update the display.
#Override
public void actionPerformed(ActionEvent evt) {
if(lbl.getIcon() != img){
lbl.setIcon(img);
lbl.repaint();
}
}
(your if statement was also missing a closing brace, unsure what impact that would have / if it was a typo)

Refresh java program with Button

I am trying to make a refresh button that will essentially restart the program when ever I click the button. I don't know how I should go about doing this.
I've place the Graphical User Interface i decided to use do complete this action. Any and all help would be greatly appreciated.
package pdfView;
import javax.swing.*;
import java.awt.*;
public class View extends JFrame {
public View() {
super("PDF Viewer");
setLookAndFeel();
setSize(500, 125);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
FlowLayout flo = new FlowLayout();
setLayout(flo);
JTextField Search = new JTextField ("Search", 29);
JButton Search1 = new JButton("Search");
//this is where i have the button
JButton ReFresh = new JButton("ReFresh");
add(Search);
add(Search1);
add(ReFresh);
setVisible(true);
}
private void setLookAndFeel() {
try {
UIManager.setLookAndFeel(
"com.sun.java.squing.plaf.nimbus.NimbusLookAndFeel"
);
} catch (Exception exc){
}
}
public static void main(String[] args) {
View pdf = new View();
}
}
What do you mean by refresh or restart?
Do you mean:
Let the application be as it is, just update what it's showing?
Really restart the application?
Updating what the application is showing
You first need to decide what actually should cause your application to refresh. You already talked about a Button. The mechanism for activating something like a button is called Action. You can do that stuff manually, using an ActionListener, or you could extend AbstractAction, which is what I recommend. Extending AbstractAction allows you to use the same logical action something in more than one location on the UI. Look at typical applications, they offer Cut/Copy/Paste through menu, toolbar, popupmenu and keyboard shortcuts. The simplest way to achieve this in Java is using Action by extending AbstractAction.
The methods you need to call to update your application are invalidate(), validate() or repaint().
Restarting an application
So you want to run through main() again? That should actually not be required, unless you have an application that supports updating itself. Even then it can sometimes be avoided by smart usage of a ClassLoader.
Some more notes on your code
Usage by extension anti-pattern
I wouldn't extend JFrame just to display a window on the screen. Usage by extension is an anti-pattern. You don't need to extend JFrame to get a JFrame displayed on the screen and do what you want.
Referring static members
I would refer to constants via their original declaration. I.e. I'd refer to EXIT_ON_CLOSE via WindowConstants.EXIT_ON_CLOSE, not JFrame.EXIT_ON_CLOSE.
Typo
You have a typo in your UIManager.setLookAndFeel() code. Search for swing and you will see the typo.
Exception information
You might actually want to print the exception to stderr using exc.printStackTrace() instead of ignoring it completely, because when you have a typo in the LaF class name, as you do, and you don't print the exception, you might actually not come to know what's going wrong.
Sequence of widget construction and UIManager.setLookAndFeel()
The sequence of UIManager.setLookAndFeel() and the effective new JFrame() via super(...) does not guarantee you that the whole UI will be in Nimbus, parts of it might still be in Metal. I recommend to set the LaF before even constructing the first widget, to be on the safe side. As far as I remember, it's not guaranteed that changing the LaF after component construction has an effect, unless you tell the UIManager to update the LaF. See also this quote from the documentation of UIManager:
Once the look and feel has been changed it is imperative to invoke updateUI on all JComponents. The method SwingUtilities.updateComponentTreeUI(java.awt.Component) makes it easy to apply updateUI to a containment hierarchy. Refer to it for details. The exact behavior of not invoking updateUI after changing the look and feel is unspecified. It is very possible to receive unexpected exceptions, painting problems, or worse.
http://docs.oracle.com/javase/8/docs/api/javax/swing/UIManager.html
setSize() vs. pack() with a little help of Insets and Border
Instead of setting the size manually, you might want to play with Insets or Border and JFrame.pack() in order to get a decent layout of your window. Setting the size manually assumes that you know a lot about the screen resolution and the font size of the user.
The pack() method performs automatic size calculation based on the contents. Insets and Border allow you to create some space and borders, even with some designs or labels, around components so they wouldn't be cramped tightly in a window but be nicely spaced.
First you have to assign an actionListener to the ReFresh Jbutton.
You can either implement the interface ActionListener to the class, and override the actionPerformed() method like this
public class View extends JFrame implements ActionListener{
private JButton ReFresh;
public View() {
super("PDF Viewer");
setLookAndFeel();
setSize(500, 125);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
FlowLayout flo = new FlowLayout();
setLayout(flo);
JTextField Search = new JTextField ("Search", 29);
JButton Search1 = new JButton("Search");
//this is where i have the button
ReFresh = new JButton("ReFresh");
ReFresh.addActionListener(this);
add(Search);
add(Search1);
add(ReFresh);
setVisible(true);
}
private void setLookAndFeel() { //right way for nimbus: http://docs.oracle.com/javase/tutorial/uiswing/lookandfeel/nimbus.html
try {
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
}
catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void actionPerformed(ActionEvent e)
{
if(e.equals(ReFresh))
{
super.repaint();
}
}}
public static void main(String[] args) {
View pdf = new View();
}
Or you can do inline assignment to addActionListener, like this
ReFresh.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
super.repaint();
}
});
You can try these methods to refresh/reload the JFrame,
invalidate();
validate();
repaint();
you can also use dispose(); and then new View(); to create the new JFrame, but in this sequence it will close the window and create new one.
or you can even try setVisible(false); then setVisible(true);
I recommend the first 3.

How to resize Swing control which is inside SwingNode in JavaFX8?

How to resize Swing control which is inside SwingNode in JavaFX8?
Sometimes, I has controls resized inside SwingNode. But SwingNode seems to resist this.
It is said in resize() apidoc, that
Applications should not invoke this method directly. If an application
needs to directly set the size of the SwingNode, it should set the
Swing component's minimum/preferred/maximum size constraints which
will be propagated correspondingly to the SwingNode and it's parent
will honor those settings during layout.
But apparently it does not work.
Example code is below.
The question is: how to allow control to turn bigger?
public class Try_Sizes_01 extends Application {
private static final Logger log = LoggerFactory.getLogger(Try_Sizes_01.class);
private static final String text = "Very Long Text For Appear On Button ";
private static int position = 7;
//private JButton button = new JButton("short");
private JButton button = new JButton(text.substring(0, position));
private SwingNode swingNode = new SwingNode();
{
swingNode.setContent(button);
}
#Override
public void start(Stage stage) throws Exception {
Group group = new Group();
group.getChildren().add(swingNode);
Scene scene = new Scene(group);
stage.setTitle("Try_Sizes_01");
stage.setScene(scene);
stage.show();
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
/*
button.setText(button.getText() + text.charAt(position));
position++;
if( position >= text.length() ) {
position=0;
}
*/
button.setPreferredSize(new Dimension((int)button.getPreferredSize().getWidth()+10, (int)button.getPreferredSize().getHeight()));
button.setMinimumSize(new Dimension((int)button.getPreferredSize().getWidth(), (int)button.getPreferredSize().getHeight()));
//button.revalidate();
//button.setBounds(0, 0, (int)button.getBounds().getWidth()+10, (int)button.getBounds().getHeight());
Platform.runLater(new Runnable() {
#Override
public void run() {
//swingNode.autosize(); // does not work
//swingNode.resize(button.getBounds().getWidth(), button.getBounds().getHeight()); // does not work and cancels button resizing
//swingNode.setContent(button); // works sometimes but imperfect
}
});
log.info("Swing thread");
log.info("Preferred width is now = {}", button.getPreferredSize().getWidth());
log.info("Bounds width is now = {}", button.getBounds().getWidth());
}
}).start();
}
});
}
public static void main(String[] args) {
launch(args);
}
}
After fighting for hours with basically the same issue, I finally figured out what was going on.
Basically, the problem is that the parent of the SwingNode is trying to set its size when layout occurs, based on the size of the parent. So when you resize your button, and then trigger a layout, the parent of the SwingNode sets it back to its default size. This is occurring because SwingNode overrides the isResizable() method to return true, giving permission to its parent objects to resize it.
In order to avoid this, you can:
Create a custom subclass of SwingNode which overrides isResizable() to false,
or:
Call setAutosizeChildren(false) on the Group which contains the SwingNode.
The latter technique will probably need to be used if you are defining your classes in FXML.
Note, by the way, that you can still call resize(width,height) on a SwingNode even if it overrides isResizable() to false.
I'm not sure if its exactly the same case, but seems related in the sense of getting swing components to size properly with the parent containers. In my case I had a SwingNode containing a JFreeChart (ChartPanel), which I simply couldn't get to resize properly when the parent frame (a border pane within a SplitPane) was itself resized. In the end i simply added a listener to the height/width properties:
pane.widthProperty().addListener((w,o,n)->c.resizeChart((int)n.intValue(), (int)pane.getHeight()));
pane.heightProperty().addListener((w,o,n)->c.resizeChart((int)pane.getWidth(), (int)n.intValue()));
Nothing else I tried could emulate this.
Thanks
I found the pane listener helps but due to the proprietary nature of my component it still didn't resize. I was using fxml and attempting to place the SwingNode inside a Pane for layout purposes. I then I noticed a number of the examples used a StackPane rather than just a Pane and suddently have just made this change the code worked. This was inside a AnchorPane which also seemed to ensure the initial display of the component filled all the available space. In summary a StackPane within the AnchorPane with all the Anchors set to 0 ensured the controlled filled all the initial available space and then did all the resizing, when the manual resize listeners where added it all started working.
pane.widthProperty().addListener((w,o,n)->c.resizeChart((int)n.intValue(), (int)pane.getHeight()));
pane.heightProperty().addListener((w,o,n)->c.resizeChart((int)pane.getWidth(), (int)n.intValue()));

Closing the Main JFrame

I have a main jFrame with the help of which i press button and open new JFrames but the problem is that when i open other JFrame the previous ones still remains there where as what i want is that when i press next button then i move forward to the new JFrame (the previous one should not be there) and when i press previous button i move back to the previous JFrame.
I know there are functions of dispose,they do well like jframe1.dispose() but i dont get it how to hide the very first JFrame whose code in the main is written like this
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run()
{
new GraphicalInterface().setVisible(true);
}
});
}
how do i set this as .setVisible(false) in the button code?
You need to retain a reference to the JFrame, so you can set it's visibility later.
private JFrame myFrame;
public void run() {
myFrame = new GUI();
myFrame.setVisible(true);
}
public void hide() {
myFrame.setVisible(false);
}
Note that a JFrame is a top-level container, you are only really supposed to have one per application. It may be better if instead of using multiple JFrames you use just one, and swap in various JPanels instead.
It would safe resources if you keep just one frame and set a new panel as content.
Your question was how to handle the reference to the frame? Please provide the code where the next frame is created.
You could assign your GUI (extends JFrame I suppose) to a variable and call .setVisible(false) on that object. Since your object from the code above is more or less anonymous, you won't have access on that.
You could also check this.

Java Refreshing a screen

I have a screen in which one of its components is made invisible depending on a boolean value. If the boolean changes after the screen has been created, how do I refresh the screen to take this into account?
I think revalidate() is more appropriate here if you are dealing with JComponents.
From the JavaDoc:
Supports deferred automatic layout.
Calls invalidate and then adds this component's validateRoot to a list of components that need to be validated. Validation will occur after all currently pending events have been dispatched. In other words after this method is called, the first validateRoot (if any) found when walking up the containment hierarchy of this component will be validated. By default, JRootPane, JScrollPane, and JTextField return true from isValidateRoot.
This method will automatically be called on this component when a property value changes such that size, location, or internal layout of this component has been affected. This automatic updating differs from the AWT because programs generally no longer need to invoke validate to get the contents of the GUI to update.
Call the validate() method on the container that needs to be laid out -- probably your window's content pane.
Try calling repaint() which in turn will call paintComponent().
I thought that (with Java 6?) you need not do anything... This should happen automatically - no?
With the following example, it does happen automatically...
public class TT extends JFrame
{
public TT()
{
setLayout(new FlowLayout());
JLabel label = new JLabel();
label.setText("Label:");
add(label);
final JTextField textField = new JTextField();
add(textField);
JButton button = new JButton();
button.setText("Button");
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
if (textField.isVisible())
{
textField.setVisible(false);
}
else
{
textField.setVisible(true);
}
}
});
add(button);
setSize(100,100);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
TT frame = new TT();
frame.setDefaultCloseOperation(TT.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
[Add] And using a layout manager like GridBagLayout would also solve the problem of "Re-Laying out" the page.

Categories