Jpanel Which One of Listeners Is Proper for Visibility Is Changed

JPanel which one of Listeners is proper for visibility is changed

If you want to listen EXACTLY the visibility changes - use ComponentListener or ComponentAdapter:

    JPanel panel = new JPanel ();
panel.addComponentListener ( new ComponentAdapter ()
{
public void componentShown ( ComponentEvent e )
{
System.out.println ( "Component shown" );
}

public void componentHidden ( ComponentEvent e )
{
System.out.println ( "Component hidden" );
}
} );

But that visibility might not be the one you think about. isVisible() flag will be true even if the Component is not added to any Container and hence not showing at all!

That visibility a has a slightly different purpose. You can use it to manually hide the Component that is already added and shown somewhere in your application. In that case, (if you use setVisible(false)) it will become hidden and every ComponentListener of that Component will be informed about that change.

So, talking about actual visibility...

This is what you should use to listen to actual component appearance/disappearance:

    JPanel panel = new JPanel ();
panel.addAncestorListener ( new AncestorListener ()
{
public void ancestorAdded ( AncestorEvent event )
{
// Component added somewhere
}

public void ancestorRemoved ( AncestorEvent event )
{
// Component removed from container
}

public void ancestorMoved ( AncestorEvent event )
{
// Component container moved
}
} );

I always use that listener to determine when the Component is added somewhere and also to listen when it is moved/removed.

Also, you can always check if the Component is actually visible to application user by calling isShowing() method:

boolean userCanSeeThePanel = panel.isShowing();

This will return true ONLY if that panel is added to VISIBLE to user frame and isVisible() flag is also true (it is usually true, unless you set it to false).

I guess that's all I can tell you about visibility. I might have misunderstood your question. Correct me if I am wrong in that case.

JPanel visibility

I don't know whether you have tested what @Marvin Jude said. But for my example, the instance is untouchable when its parent container is invisible.

  1. Use panel.setVisible(true); or panel.setVisible(true); to change the visibility of JPanel.
  2. The button's listener is not triggered if MainPanel is not visible.

See code below.

    import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.*;

public class MyFrame extends JFrame{

/**
*
*/
private static final long serialVersionUID = 1L;

public MyFrame(){
MainPanel panel = new MainPanel();
add(panel,BorderLayout.CENTER);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
pack();
panel.setVisible(true);
}

class MainPanel extends JPanel{

/**
*
*/
private static final long serialVersionUID = 1L;
public MainPanel(){
JButton button = new JButton("I am a button");
add(button);
button.addActionListener(new ActionListener(){

@Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
System.out.println("JButton is clicked...");
}
});
}
}

public static void main(String args[]){
Runnable runnable = new Runnable() {
@Override
public void run() {
MyFrame myFrame = new MyFrame();
myFrame.setVisible(true);
}
};
SwingUtilities.invokeLater(runnable);
}
}

java event for when the component becomes visible

The "visible" property does not mean visible "on screen". It only indicates if the the component itself is to be displayed or not. Since components are visible by default and the listeners are only notified when a property changes your listener is never notified.

To the best of my knowledge there is no dedicated event involved telling a component when it enters the visible region of the display. Also note that setting an icon on a label may alter its preferred size, breaking the entire layout. This can be worked around by manually giving the labels a fixed preferred size (which should be simple in case of thumbnails).

A lazy approach would be to overwrite paintComponent on the labels and check if the thumb needs to be loaded in paintComponent:

 protected void paintComponent(Graphics g) {
if (getIcon() == null) {
// create thumbnail
}
super.paintComponent(g);
}

This isn't the best approach, as your code will run inside Swings event dispatch thread. This means any delay in loading the thumbnail will block rendering of your UI.

A saner approach IMO would be to just request loading of the thumbnail and defer the actual loading to a background thread. When that thread completes loading, it can then use SwingUtilities.invoke (or invokeLater) to update the label (which triggers a repaint automatically if I'm not mistaken).

The effect would be that the labels scrolled in briefly show empty, then update as soon as the thumb is available.

How to use an ActionListener to make a JPanel Visible

You can fix your program by passing a reference of your frame to your panel1. See my example below.

Frame class

import javax.swing.*;

public class Frame1 {

private JFrame frame = new JFrame();
private Panel1 panel1;
private Panel2 panel2;

Frame1() {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setState(JFrame.MAXIMIZED_BOTH);
frame.setSize(1280, 1024);
frame.setLayout(null);
panel1 = new Panel1(this);
frame.add(panel1.getPanel());
panel2 = new Panel2();
frame.add(panel2.getPanel());
frame.setVisible(true);
}

public Panel2 getPanel2() {
return panel2;
}

}

Panel1 class

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class Panel1 {
private JPanel panel = new JPanel();
private Frame1 frame1;
private JButton jButton1 = new JButton();

public Panel1(Frame1 frame1) {
this.frame1 = frame1;
panel.setSize(1280, 1024);
panel.setLayout(null);
panel.setBackground(Color.BLUE);
panel.add(jButton1);
panel.setVisible(true);
jButton1.setBounds(300,300,400,200);
jButton1.setBackground(Color.BLACK);
jButton1.setVisible(true);
jButton1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
panel.setVisible(false);
frame1.getPanel2().getPanel().setVisible(true);
}
});
}

public JPanel getPanel() {
return panel;
}
}

Panel2 class

import javax.swing.*;
import java.awt.*;

public class Panel2 {
private JButton jButton2 = new JButton();
private JPanel panel = new JPanel();

public Panel2() {
panel.setSize(1280, 1024);
panel.setLayout(null);
panel.add(jButton2);
panel.setBackground(Color.RED);
panel.setVisible(false);

jButton2.setBounds(100,100,400,200);
jButton2.setBackground(Color.BLACK);
jButton2.setVisible(true);
}

public JPanel getPanel() {
return panel;
}
}

Changing the visibilty of a label

You've got some "magic thinking" going on. To wit:

  • You've set the visibility of the component based on a boolean variable
  • You expect the visibility of the component to magically change when the boolean variable changes -- but the component has no idea, no notification that this change has occurred, and so this is guaranteed to fail.

To get success, you will need to change the visibility of the component itself from within a listener. In other words, within the ActionListener, you will need to call .setVisible(true/false) on the component of interest.

    btnAnzahl.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
uebernehmen();
lblNote.setVisible(bNoteVis);
}
});

Other unrelated issues:

  • doing this, contentPane.setLayout(null);, and this, lblNote.setBounds(10, 68, 87, 16); will lead to siginficant frustration over time as it leads to inflexible GUI's that might look sort-of OK on one platform, but not OK on others, and that are hard to extend and modify. Much better to learn and use layout managers
  • If your goal is to change multiple components, then best to swap components using a CardLayout. Have a look at the CardLayout Tutorial for the details on how to use this tool.
  • Also, rather than toggle a JLabel's visibility, I'd change its text so that it still takes up space on the GUI.

For example:

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ItemEvent;
import javax.swing.*;

@SuppressWarnings("serial")
public class Notenbilanz3 extends JPanel {
private static final String LABEL_TEXT = "Noten Anzahl";
private JLabel lblNote = new JLabel(LABEL_TEXT);
private JTextField txtField1 = new JTextField(10);
private JCheckBox checkBox = new JCheckBox("Check Box", true);

public Notenbilanz3() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.anchor = GridBagConstraints.LINE_START;
gbc.gridwidth = 2;
gbc.insets = new Insets(3, 3, 3, 3);
add(lblNote, gbc);

gbc.gridx = 0;
gbc.gridy = 1;
gbc.gridwidth = 1;
add(txtField1, gbc);
gbc.gridx = 1;
add(checkBox, gbc);

checkBox.addItemListener(l -> {
String text = l.getStateChange() == ItemEvent.SELECTED ? LABEL_TEXT : " ";
lblNote.setText(text);
});
}

public static void main(String[] args) {
SwingUtilities.invokeLater(()-> {
JFrame frame = new JFrame("Foo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Notenbilanz3());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}

How to figure out which JPanel in a JScrollpane is being seen?

Assuming the setup as outlined in my comment to your question, the basic approach is to compare the parent's (the component that contains the 3 panels) visibleRect with its children's bounds. Something like:

final JComponent parent = new JPanel(); // new PageScrollable();
parent.setLayout(new BoxLayout(parent, BoxLayout.PAGE_AXIS));
Color[] color = new Color[] {Color.YELLOW, Color.RED, Color.GREEN};
for (int i = 0; i < color.length; i++) {
JTable table = new JTable(10, 5);
// color it to see some difference
table.setBackground(color[i]);
// set a name for logging
table.setName("table at: " + i);
parent.add(table);
}

JScrollPane scrollPane = new JScrollPane(parent);
Action visible = new AbstractAction() {

@Override
public void actionPerformed(ActionEvent e) {
Rectangle rect = parent.getVisibleRect();
for (int i = 0; i < parent.getComponentCount(); i++) {
// implement logic as needed to compare the parent's visible rect
// with the children's bounds
if (rect.intersects(parent.getComponent(i).getBounds())) {
System.out.println("found: " + parent.getComponent(i).getName());
}
}
}

};
frame.add(scrollPane);
frame.add(new JButton(visible), BorderLayout.SOUTH);

As an aside: to fine-tune scrolling behaviour you might consider a custom panel which implements Scrollable, something like:

/**
* Implement a panel of type Scrollable to fine-tune its scrolling behaviour.
* This implements the prefScrollableSize to the prefSize of the first child
* and both block/unit increment to the height of the prefScrollable.
*/
public static class PageScrollable extends JPanel implements Scrollable {

@Override
public Dimension getPreferredScrollableViewportSize() {
if (getComponentCount() > 0) {
return getComponent(0).getPreferredSize();
}
return super.getPreferredSize();
}

@Override
public int getScrollableUnitIncrement(Rectangle visibleRect,
int orientation, int direction) {
return getPreferredScrollableViewportSize().height;
}

@Override
public int getScrollableBlockIncrement(Rectangle visibleRect,
int orientation, int direction) {
return getPreferredScrollableViewportSize().height;
}

@Override
public boolean getScrollableTracksViewportWidth() {
return false;
}

@Override
public boolean getScrollableTracksViewportHeight() {
return false;
}

}

Listening/Handling JPanel events

I think that this issue corresponding with HierarchyListener, for comparing

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class ContainerListener extends JFrame {

private static final long serialVersionUID = 1L;

public ContainerListener() {
super("Test");
setContentPane(new TestPanel());
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
pack();
setLocationRelativeTo(null);
setVisible(true);
}

public static void main(String[] parameters) {
EventQueue.invokeLater(new Runnable() {

@Override
public void run() {
ContainerListener containerListener = new ContainerListener();
}
});
}

private class TestPanel extends JPanel {

private static final long serialVersionUID = 1L;

TestPanel() {
setLayout(new FlowLayout(FlowLayout.LEFT));
add(new JButton(new AbstractAction("Add label") {

private static final long serialVersionUID = 1L;
private int n = 0;

@Override
public void actionPerformed(ActionEvent event) {
TestPanel.this.add(new JLabel("Label " + ++n));
validate();
}
}));
addHierarchyListener(new HierarchyListener() {

@Override
public void hierarchyChanged(HierarchyEvent e) {
System.out.println("Components Change: " + e.getChanged());
if ((e.getChangeFlags() & HierarchyEvent.DISPLAYABILITY_CHANGED) != 0) {
if (e.getComponent().isDisplayable()) {
System.out.println("Components: " + e.getChanged());
} else {
System.out.println("Components: " + e.getChanged());
}
}
}
});
addContainerListener(new ContainerAdapter() {

@Override
public void componentAdded(ContainerEvent event) {
System.out.println("componentAdded : " + event.getChild() + "containerName" + " was added");
}
});

}

@Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
}
}


Related Topics



Leave a reply



Submit