Some previous entries here address paintComponent() being called repeatedly, but the answers hinged on paintComponent itself calling repaint().
Using Nimbus L&F, if I subclass JPanel and add a JButton or JTextField, then my JPanel's paintComponent() method gets called whenever I enter or leave a child. In addition, if the JTextField gets focus, my panel's paintComponent() method gets called for every flash of the text field's position cursor. My paintComponent() method does nothing other than print that it is being called. Here's an example:
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class Tester extends JPanel {
public Tester() {
JPanel p = new JPanel();
JTextField t1 = new JTextField( "text in nested panel" );
p.add( t1 );
this.add( p );
JTextField t2 = new JTextField( "text" );
this.add( t2 );
JButton b = new JButton( "button" );
this.add( b );
setPreferredSize( new Dimension( 400, 200 ) );
}
#Override
public void paintComponent( Graphics g ) {
super.paintComponent( g );
System.out.println( "paint" );
}
public static void main( final String[] args ) {
SwingUtilities.invokeLater( new Runnable() {
#Override
try {
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if ( "Nimbus".equals( info.getName() ) ) {
UIManager.setLookAndFeel( info.getClassName() );
break;
}
}
} catch (Exception ex) {
System.out.println( "No Nimbus" );
}
final String name = new String( "GuiViewer" );
final JFrame jf = new JFrame( name );
jf.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
final Tester comp = new Tester();
jf.add( comp );
jf.pack();
jf.setVisible( true );
}
} );
}
}
When you click in the first text field (nested inside another JPanel), you do not get continual calls to paintComponent(). But if you click in the second one, you continually get calls. If you comment out the setting of Nimbus L&F, the paintComponent() doesn't get repeated calls. The Nimbus implementation of JTextField and JButton act like their paintComponent method calls parent.repaint(). Is this a bug in Nimbus, or is it that way by design?
This seems to be a design choice of Nimbus.
If you inspect the result of JTextField#isOpaque, it returns false (making it transparent). This means that when ever the component is repainted, the parent container must first be repainted as well.
The JTextField is triggering a repaint each time the caret is updated (blinks on and off)
The reason why your first JTextField doesn't cause a repaint on the Tester is because it's sitting inside a opaque container, so only it's immediate parent container will be repainted.
Try making the JTextField opaque (t2.setOpaque(true);) and see what happens
Related
If I minimize a JFrame which was Aero-snapped to the left of the screen by clicking on the minimize-button of the Windows WindowDecoration and unminimize it by Alt-Tabbing or clicking it in the Windows TaskBar, the frame gets restored correctly snapped to the left. Good!
But if I minimize the frame by
setExtendedState( getExtendedState() | Frame.ICONIFIED );
and look at the preview by hovering over the Windows TaskBar, it shows the frame a wrong position.
After unminimizing it by Alt-Tabbing or clicking it in the Windows TaskBar, the frame gets restored at this wrong position and size. The frame-bounds are the "unsnapped" values, which Windows normally remembers to restore if you drag the frame away from the ScreenBorder.
A screen recording of the Bug:
My conclusion is, that Java does not know about AeroSnap and delivers the wrong bounds to Windows. (For example Toolkit.getDefaultToolkit().isFrameStateSupported( Frame.MAXIMIZED_VERT ) ); returns false.)
This is my fix for the bug:
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.Point;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
/**
* Fix for the "Frame does not know the AeroSnap feature of Windows"-Bug.
*
* #author bobndrew 20160106
*/
public class SwingFrameStateWindowsAeroSnapBug extends JFrame
{
Point location = null;
Dimension size = null;
public SwingFrameStateWindowsAeroSnapBug( final String title )
{
super( title );
initUI();
}
private void initUI()
{
setDefaultCloseOperation( EXIT_ON_CLOSE );
setLayout( new FlowLayout() );
final JButton minimize = new JButton( "Minimize" );
final JButton maximize = new JButton( "Maximize" );
final JButton normal = new JButton( "Normal" );
add( normal );
add( minimize );
add( maximize );
pack();
setSize( 200, 200 );
final ActionListener listener = actionEvent ->
{
if ( actionEvent.getSource() == normal )
{
setExtendedState( Frame.NORMAL );
}
else if ( actionEvent.getSource() == minimize )
{
//Size and Location have to be saved here, before the minimizing of an AeroSnapped WindowsWindow leads to wrong values:
location = getLocation();
size = getSize();
System.out.println( "saving location (before iconify) " + size + " and " + location );
setExtendedState( getExtendedState() | Frame.ICONIFIED );//used "getExtendedState() |" to preserve the MAXIMIZED_BOTH state
//does not fix the bug; needs a Window-Drag after DeMinimzing before the size is applied:
// setSize( size );
// setLocation( location );
}
else if ( actionEvent.getSource() == maximize )
{
setExtendedState( getExtendedState() | Frame.MAXIMIZED_BOTH );
}
};
minimize.addActionListener( listener );
maximize.addActionListener( listener );
normal.addActionListener( listener );
addWindowStateListener( windowEvent ->
{
System.out.println( "oldState=" + windowEvent.getOldState() + " newState=" + windowEvent.getNewState() );
if ( size != null && location != null )
{
if ( windowEvent.getOldState() == Frame.ICONIFIED )
{
System.out.println( "Fixing (possibly) wrong size and location on de-iconifying to " + size + " and " + location + "\n" );
setSize( size );
setLocation( location );
//Size and Location should only be applied once. Set NULL to avoid a wrong DeMinimizing of a following Windows-Decoration-Button-Minimize!
size = null;
location = null;
}
else if ( windowEvent.getOldState() == (Frame.ICONIFIED | Frame.MAXIMIZED_BOTH) )
{
System.out.println( "Set size and location to NULL (old values: " + size + " and " + location + ")" );
//Size and Location does not have to be applied, Java can handle the MAXIMIZED_BOTH state. Set NULL to avoid a wrong DeMinimizing of a following Windows-Decoration-Button-Minimize!
size = null;
location = null;
}
}
} );
}
public static void main( final String[] args )
{
SwingUtilities.invokeLater( new Runnable()
{
#Override
public void run()
{
new SwingFrameStateWindowsAeroSnapBug( "AeroSnap and the Frame State" ).setVisible( true );
}
} );
}
}
This seems to work for all situations under Windows7, but it feels like too much messing around with the window-management. And I avoided to test this under Linux or MacOS for some reason ;-)
Is there a better way to let AeroSnap and Java Frames work together?
Edit:
I've filed a bug at Oracle: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8147840
Is there a better way to let AeroSnap and Java Frames work together?
Not much better. Directly setting the extended state bypasses the OS's treatment of setting it.
If you take a look at the source code of JFrame#setExtendedState you will see that it calls the FramePeer's setState method. The JDK's JFrame implementation of the FramePeer interface is the WFramePeer class, which declares its setState method as native. So, you're out of luck until Oracle does something about it or you use native code (see below).
Fortunately, you don't necessarily have to go nuts with event listeners and caching bounds. Hiding and showing the frame is enough to "reset" the size to what it was before the minimization:
public class AeroResize extends JFrame {
public AeroResize(final String title) {
super(title);
initUI();
}
private void initUI() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new FlowLayout());
final JButton minimize = new JButton("Minimize");
final JButton maximize = new JButton("Maximize");
final JButton normal = new JButton("Normal");
add(normal);
add(minimize);
add(maximize);
pack();
minimize.addActionListener(e -> {
setVisible(false);
setExtendedState(getExtendedState() | JFrame.ICONIFIED);
setVisible(true);
// setLocation(getLocationOnScreen()); // Needed only for the preview. See comments section below.
});
}
public static void main(final String[] args) {
SwingUtilities.invokeLater(() -> new AeroResize("AeroSnap and the Frame State").setVisible(true));
}
}
Though this does have a side-effect of not giving a detailed preview of the frame's contents:
Solution using native code
If you'd care to use JNA, then you can completely mimic the native platform's minimization. You'll need to include jna.jar and jna-platform.jar in your build path.
import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import com.sun.jna.Native;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef.HWND;
public class AeroResize extends JFrame {
public AeroResize(final String title) {
super(title);
initUI();
}
private void initUI() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new FlowLayout());
final JButton minimize = new JButton("Minimize");
final JButton maximize = new JButton("Maximize");
final JButton normal = new JButton("Normal");
add(normal);
add(minimize);
add(maximize);
pack();
minimize.addActionListener(e -> {
HWND windowHandle = new HWND(Native.getComponentPointer(AeroResize.this));
User32.INSTANCE.CloseWindow(windowHandle);
});
}
public static void main(final String[] args) {
SwingUtilities.invokeLater(() -> new AeroResize("AeroSnap and the Frame State").setVisible(true));
}
}
It's pretty self explanatory. You get a pointer to the window and use the native CloseWindow (which actually minimizes, go figure) on it. Note that the minimalistic way I wrote it will cause a small delay the first time the button is pressed because the User32 instance is loaded. You can load it on startup to avoid this first-time delay.
Credit goes to the accepted answer here.
This seems to be a Swing bug. The bug report on the Bug Database:
JDK-7029238 : componentResized not called when the form is snapped
In this report the bug could not be reproduced, now you encountered the same bug (I think it is the same, or related at least), maybe it is a good time to re-open this report. (I did not find any other reference to this, so I assume it hasn´t been fixed)
I have an always-on-top window that I want to remain above all other windows. Using setAlwaysOnTop(true) seems to work for most purposes, but fails when it comes to JComboBox dropdown menus. Is there any way to prevent this from happening? Attached below is a SSCCE and picture of the undesired functionality.
EDIT: Not sure if the behavior is OS-dependent, but I'm noticing the issue on Windows 7 using Java 7. On top is supported on this OS.
EDIT 2: Seems that JPopupMenu has an override on alwaysOnTop() to return true. This is the source of the problem, since on-top components do not have a defined order in how they appear on top of each other (OS-dependent). Worse still, the method is package private. Quite problematic...
Undesired Behavior:
SSCCE:
import java.awt.BorderLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JTextField;
public class OnTopTest
{
public static void main( String[] args )
{
new OnTopTest();
}
public OnTopTest()
{
JDialog onTop = new OnTopWindow();
JDialog other = new OtherWindow();
System.out.println("IS ON TOP SUPPORTED? " + onTop.isAlwaysOnTopSupported());
other.setVisible( true );
onTop.setVisible( true );
}
private class OnTopWindow extends JDialog
{
public OnTopWindow()
{
setLayout( new BorderLayout() );
JButton button = new JButton("Button");
add( button, BorderLayout.CENTER );
setSize( 100, 100 );
setAlwaysOnTop( true );
}
}
private class OtherWindow extends JDialog
{
public OtherWindow()
{
setLayout( new BorderLayout() );
JTextField textField = new JTextField("Text");
add( textField, BorderLayout.NORTH);
JButton button = new JButton("Button");
add( button, BorderLayout.CENTER );
JComboBox comboBox = new JComboBox( new Object[] {"Item1", "Item2", "Item3"} );
add( comboBox, BorderLayout.SOUTH );
setSize( 200, 200 );
}
}
}
I'm pretty sure this is handled by the Operating System and that Java cannot force the dropdown to not overlap the other window, as searching for this without specifying Java reported the same behaviour in many different languages.
You can test with a JMenu to confirm, but I'm sure it will also happen as menus and some other controls (like dropdowns) will (by necessity) show above any other window.
Working on a help system, I'd like each component to offer some help when the the mouse is over it and the "?" key is pressed. Sort of like tooltips, except with much more extensive help - essentially a little web browser is intended to pop up and display text, images or more.
What I'm finding is that no matter where the mouse is, the input always goes to the same KeyListener. Is there only supposed to be one active at a time?
For what it's worth, this is the now-working version - thanks for suggestions!
/**
* Main class JavaHelp wants to support a help function so that when
* the user types F1 above a component, it creates a popup explaining
* the component.
* The full version is intended to be a big brother to tooltips, invoking
* an HTML display with clickable links, embedded images, and the like.
*/
import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
import java.awt.event.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
class Respond2Key extends AbstractAction
{
Component jrp;
// Contract consructor
public Respond2Key( String text)
{
super( text );
}
// Constructor that makes sure it gets done right
public Respond2Key( String text, Component jrpIn)
{
super( text );
System.out.println( "creating Respond2Key with component " + jrpIn
.toString
() );
jrp = jrpIn;
}
public void setJrp( Component j) {
jrp = j;
}
// Functionality: what is the response to a key
public void actionPerformed(ActionEvent e)
{
// use MouseInfo to get position, convert to pane coords, lookup component
Point sloc = MouseInfo.getPointerInfo().getLocation();
SwingUtilities.convertPointFromScreen( sloc, (Component) jrp );
Component c = jrp.getComponentAt( sloc );
System.out.printf( "Mouse at %5.2f,%5.2f Component under mouse is %s\n",
sloc.getX(), sloc.getY(), c.toString() );
}
}
//----------------------------------------------------------------
// The main class
//----------------------------------------------------------------
public class JavaHelp extends JFrame
{
// The object constructor
public JavaHelp()
{
// Start construction
super( "Help System" );
this.setSize( 640, 480 );
Container contents = getContentPane();
contents.setLayout( new FlowLayout() );
JButton b1 = butt( "button1", 64, 48 );
JButton b2 = butt( "button2", 96, 48 );
JButton b3 = butt( "button3", 128, 48 );
JPanel p1 = pane( "hello", 100, 100 );
JPanel p2 = pane( "world", 200, 100 );
contents.add( b1 );
contents.add( p1 );
contents.add( b2 );
contents.add( p2 );
contents.add( b3 );
JRootPane jrp = this.getRootPane();
jrp.getInputMap( jrp.WHEN_IN_FOCUSED_WINDOW)
.put( KeyStroke.getKeyStroke( "F1" ), "helpAction" );
jrp.getActionMap().put( "helpAction",
new Respond2Key("frame",(Component)contents)
);
this.setVisible( true );
this.requestFocus();
this.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
}
// Inner classes for instantiating and listening to button, and panel.
class ButtonListener implements ActionListener
{
private String label = null;
public void setLabel(String s) {label = s;}
public void actionPerformed(ActionEvent e)
{
System.out.printf( "Dealing with event labeled %s source %s\n\n",
label,
e.getSource().toString() );
}
}
// def butt( from, name, w, h) = new Jbutton (...)
protected JButton butt( String s, int w, int h)
{
JButton b = new JButton( s );
b.setSize( w, h );
ButtonListener oj = new ButtonListener();
oj.setLabel( s );
b.addActionListener( oj );
return (b);
}
// def pane = new Jpanel(...)
protected JPanel pane(String name, int w, int h)
{
JPanel p = new JPanel();
p.setMinimumSize( new Dimension( w, h ) );
p.add( new Label( name ) );
p.setBackground( Color.black );
p.setForeground( Color.red );
return (p);
}
//--------------------------------
public static void main(String[] args)
{
JavaHelp jh = new JavaHelp();
}
}
the input always goes to the same KeyListener.
A KeyEvent is always dispatched to the component with focus, the mouse location has nothing to do with how the key event is generated.
Instead of using a KeyListener, you should be using Key Bindings. When you using Key Bindings you can invoke an Action whenever a KeyStroke is generated by adding the binding to the root pane of the JFrame. Read the section from the Swing tutorial on Key Bindings for more information.
Now in the Action that you create to listen for the "?" KeyStroke you can then:
use the MouseInfo class to get the current mouse location.
use the SwingUtilities.convertPointFromScreen(...) to convert the mouse point to be relative to the root pane
then you can use the Conatiner.getComponentAt(...) to get the actual component the mouse is over
once you know the component you can display your help information.
I'm sure there's a better way, but one quick and dirty solution:
private final class HoverFocusListener extends MouseInputAdapter {
public void mouseEntered(MouseEvent e) {
e.getComponent().requestFocusInWindow();
}
}
Or, if necessary:
public void mouseEntered(MouseEvent e) {
e.getSource().setFocusable(true);
for (Component c : refToParent.getComponents()) c.setFocusable(false);
e.getComponent().requestFocusInWindow();
}
Then just .addMouseListener(new HoverFocusListener()) to all affected components.
the input consistently goes to a similar KeyListener.
A KeyEvent is constantly dispatched to the part with the center, the mouse area steers clear of how the key occasion is created.
Rather than utilizing a KeyListener, you ought to utilize Key Bindings. At the point when you utilizing Key Bindings, you can conjure an Action at whatever point a KeyStroke is produced by adding the limiting to the root sheet of the JFrame. Peruse the part from the Swing instructional exercise on Key Bindings for more data.
Presently in the Action that you make to tune in for the "?" KeyStroke you can then, at that point:
utilize the MouseInfo class to get the current mouse area.
utilize the SwingUtilities.convertPointFromScreen(...) to change over the mouse highlight be comparative with the root sheet
then, at that point, you can utilize the Container.getComponentAt(...) to get the genuine segment the mouse is finished
when you know the part you can show your assistance data.
// Fig. 14.6: LabelFrame.java
// Demonstrating the JLabel class.
import java.awt.FlowLayout; // specifies how components are arranged
import javax.swing.JFrame; // provides basic window features
import javax.swing.JLabel; // displays text and images
import javax.swing.SwingConstants; // common constants used with Swing
import javax.swing.Icon; // interface used to manipulate images
import javax.swing.ImageIcon; // loads images
public class LabelFrame extends JFrame
{
private JLabel label1; // JLabel with just text
private JLabel label2; // JLabel constructed with text and icon
private JLabel label3; // JLabel with added text and icon
// LabelFrame constructor adds JLabels to JFrame
public LabelFrame(){
{super( "Testing JLabel" );
setLayout( new FlowLayout() );
// JLabel constructor with a string argument
label1 = new JLabel( "Label with text" );
label1.setToolTipText( "This is label1" );
add( label1 );
//JLabel constructor with string, Icon and alignment arguments
Icon bug = new ImageIcon( getClass().getResource( "bug1.png" ) );
label2 = new JLabel( "Label with text and icon", bug,
SwingConstants.LEFT );
label2.setToolTipText( "This is label2" );
add( label2 );
label3 = new JLabel(); // JLabel constructor no arguments
label3.setText( "Label with icon and text at bottom" );
label3.setIcon( bug ); // add icon to JLabel
label3.setHorizontalTextPosition( SwingConstants.CENTER );
label3.setVerticalTextPosition( SwingConstants.BOTTOM );
label3.setToolTipText( "This is label3" );
add( label3 );
}
}
That was class one.
import javax.swing.JFrame;
public class LabelTest
{
public static void main( String[] args )
{
LabelFrame labelFrame = new LabelFrame(); // create LabelFrame
labelFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
labelFrame.setSize( 260, 180 ); // set frame size
labelFrame.setVisible( true ); // display frame
} // end main
}
This is class two.
I noticed that with the one untyped (LabelFrame) class did not have a type, but I copied from Deitel's Java book. I assumed we was correct, but so far this is not running because of that little piece of code. I am wondering if it could be an issue with the Java version, since mine is the latest, and the book is from 2012. If you could enlighten me on why this code won't run in Eclipse, that would be greatly appreciated. In addition, the add did not work. Thanks.
OK.. it seems the problem is that the code would not even compile cleanly. This was largely due to the lack of logical indentation leading to incorrectly placed brackets.
This code compile, but fails (here) at run-time due to the missing image.
import java.awt.FlowLayout; // specifies how components are arranged
import javax.swing.JFrame; // provides basic window features
import javax.swing.JLabel; // displays text and images
import javax.swing.SwingConstants; // common constants used with Swing
import javax.swing.Icon; // interface used to manipulate images
import javax.swing.ImageIcon; // loads images
public class LabelFrame extends JFrame
{
private JLabel label1; // JLabel with just text
private JLabel label2; // JLabel constructed with text and icon
private JLabel label3; // JLabel with added text and icon
// LabelFrame constructor adds JLabels to JFrame
public LabelFrame() {
super( "Testing JLabel" );
setLayout( new FlowLayout() );
// JLabel constructor with a string argument
label1 = new JLabel( "Label with text" );
label1.setToolTipText( "This is label1" );
add( label1 );
//JLabel constructor with string, Icon and alignment arguments
Icon bug = new ImageIcon( getClass().getResource( "bug1.png" ) );
label2 = new JLabel( "Label with text and icon", bug,
SwingConstants.LEFT );
label2.setToolTipText( "This is label2" );
add( label2 );
label3 = new JLabel(); // JLabel constructor no arguments
label3.setText( "Label with icon and text at bottom" );
label3.setIcon( bug ); // add icon to JLabel
label3.setHorizontalTextPosition( SwingConstants.CENTER );
label3.setVerticalTextPosition( SwingConstants.BOTTOM );
label3.setToolTipText( "This is label3" );
add( label3 );
}
public static void main( String[] args )
{
LabelFrame labelFrame = new LabelFrame(); // create LabelFrame
labelFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
labelFrame.setSize( 260, 180 ); // set frame size
labelFrame.setVisible( true ); // display frame
} // end main
}
The reason add is showing error is because you didn't "extend JFrame in the LabelFrame class,
It should be coded like this:
public class LabelFrame extends JFrame{
}
that should solve that problem, On the rest of your question, I'm having the same problem because the image is not there, It's null, If anyone can tell me how to get the image and use it, that would be greatly appreciated, Thanks!..
Copy and paste the picture in the package of your project and run the code.I hope it will work.
Another process:
Use
ImageIcon bug = new ImageIcon("java.png");//In the double quotes write the full path of the image.
instead of Icon bug = new ImageIcon( getClass().getResource( "bug1.png" ) );
I hope it will also work.
I faced the same problem. Here is the solution... just make a png image (using photoshop) and name it as bug1.png. Now just copy & paste the image in your project's src folder. Thats all.
In NetBeans, I have used the GUI editor to make a JFrame and I've put a JPanel in the frame.
At the moment, I'm trying to make a new button in the panel when the class constructs.
This is the code I have, but I can't seem to get it to work.
(The first line makes the button, the other lines try to show it.)
this.jPanel2.add(new JButton("Test"),BorderLayout.NORTH);
this.jPanel2.validate();
this.jPanel2.revalidate();
this.jPanel2.repaint();
this.jPanel2.setVisible(true);
this.revalidate();
this.setVisible(true);
this.repaint();
I've been googling all night, but can't seem to get it to work.
Some times when you don't see a button it is a layout manager issue (as in you aren't setting the right properties for the layout manager). You can test this by disabling it:
this.jPanel2.setLayoutManager(null);
And setting bounds for the button (JButton.setBounds()).
If the above fixes your problem, then you need to look into the requirements set by the LayoutManager you are using (see also the answer by Robin).
All the calls to validate(), revalidate() and repaint() are not needed to do this.
Normally the add call is sufficient.
Note: a BorderLayout can only contain one component in each location. So if you add another component in the NORTH location, your button will not be visible.
Second note: by default a JPanel does not have a BorderLayout but a FlowLayout. Have you set a BorderLayout on that specific panel ? Otherwise the BorderLayout#NORTH constraint is incorrect
All the validate,revalidate,repaint calls can be removed
Edit
It seems some sort of validation is needed after all. I was under the impression that Swing should be smart enough to listen for the event when something is added to a Container, and update whatever is necessary (a bit similar to updating a TableModel updates the JTable based on events, without the need to call repaint or the likes on the JTable).
However, when trying this in an SSCCE, I came to the following code (different versions, only post the most elaborate version)
without the scroll-pane, the validate calls seem to have no effect. I actually need to call pack again to make the new labels visible (not included in the SSCCE, but removing the scrollpane from the code is trivial)
with the scroll-pane, the validate call has an effect
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class AddLabelsAtRuntime {
private int fLabelCounter = 0;
private JPanel fLabelPanel;
private final JFrame fTestFrame;
public AddLabelsAtRuntime() {
fLabelPanel = new JPanel( );
BoxLayout boxLayout = new BoxLayout( fLabelPanel, BoxLayout.PAGE_AXIS );
fLabelPanel.setLayout( boxLayout );
fTestFrame = new JFrame( "Dynamically add labels" );
}
private JFrame createUI(){
Container contentPane = fTestFrame.getContentPane();
contentPane.setLayout( new BorderLayout() );
JScrollPane scrollPane = new JScrollPane( fLabelPanel );
scrollPane.setPreferredSize( new Dimension( 200, 200 ) );
contentPane.add( scrollPane, BorderLayout.CENTER );
contentPane.add( createButtonPanel(), BorderLayout.SOUTH );
fTestFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
fTestFrame.pack();
return fTestFrame;
}
private void addLabel(){
fLabelPanel.add( new JLabel( "Label " + ++fLabelCounter ) );
}
private JPanel createButtonPanel(){
JPanel buttonPanel = new JPanel( );
BoxLayout boxLayout = new BoxLayout( buttonPanel, BoxLayout.LINE_AXIS );
buttonPanel.setLayout( boxLayout );
JButton validateButton = new JButton( "Add + validate" );
validateButton.addActionListener( new ActionListener() {
#Override
public void actionPerformed( ActionEvent e ) {
addLabel();
fLabelPanel.validate();
fTestFrame.validate();
}
} );
buttonPanel.add( validateButton );
JButton noValidateButton = new JButton( "Add" );
noValidateButton.addActionListener( new ActionListener() {
#Override
public void actionPerformed( ActionEvent e ) {
addLabel();
}
} );
buttonPanel.add( noValidateButton );
JButton packButton = new JButton( "Add + pack" );
packButton.addActionListener( new ActionListener() {
#Override
public void actionPerformed( ActionEvent e ) {
addLabel();
fTestFrame.pack();
}
} );
buttonPanel.add( packButton );
return buttonPanel;
}
public static void main( String[] args ) {
EventQueue.invokeLater( new Runnable() {
#Override
public void run() {
AddLabelsAtRuntime addLabelsAtRuntime = new AddLabelsAtRuntime();
addLabelsAtRuntime.createUI().setVisible( true );
}
} );
}
}
Create Dynamic JButton with Image and ActionListener - Java Swing
Create JButton dynamically with Image and the ActionListener . You will be able to change the button height , width horizontal gap and vertical gap in one place.
you can find more details from here