Question

Is it possible to get the top card in Java's CardLayout? I've tried looping through each component to check for visibility with isVisible() but it seems that they're all "visible".

Edit: By "top card" I mean the one that's currently at the "top", being displayed, not the first or last cards. Also, I don't know if it helps but I'm looking for a JPanel (or a subclass thereof)

Edit: Code snippet

for (Component component : getComponents()) {
 if (component instanceof JPanel && component.isVisible()) {
  currentPanel = (JPanel) component;
  System.out.println(currentPanel.getClass().getName());
 }
}  

The above code always prints out every component class's name, regardless if they are the visible card or not.

Edit: I'm using this as part of a school assignment. I'm not trying to get a freebie here, the assignment does not revolve around this layout. It just seems to be the most convenient layout for changing between panels. My teacher has specified that there is to be no third party code in the project. I've seen the implementation from camickr's link before but I can't use it. I can loosely implement similar features it and maybe give a reference it in the documentation but I can't simply download and use it.

Edit: The reason I'm trying to get the top card is because I have a toolbar with an "Add" button. Instead of having one add button for each of my two possible things I wanted it to know which to add simply by looking at what panel is currently being viewed. If there is another, more appropriate way to do this please let me know.

Edit: Thanks everyone for helping out. I figured out what the problem was. I guess it was my fault since I didn't provide enough detail. Two of my cards are JScrollPanes and I also needed to look through its contents to find out if one of those panels was the one I was seeing. I didn't check for isVisible() on the scroll pane itself, i had been looking at it's contends that are always visible, it was the scroll pane who's visibility I needed to verify.

public JPanel getCurrentPanel() {
        JPanel currentPanel = null;

        for (Component component : getComponents()) {
            if (component.isVisible()) {
                if (component instanceof JPanel) 
                    currentPanel = (JPanel) component;
                else if (component instanceof JScrollPane)
                    currentPanel = (JPanel) ((JScrollPane) component).getViewport().getComponent(0);
            }
        }

        return currentPanel;
    }
Was it helpful?

Solution

If you modify the code snippet you added to the question you can easily tell which card is visible. In my test frame, when the button is pushed, it prints out the name of the currently visible card, before flipping to the next card. Modifying your code, the important thing to keep in mind is that you need to call getComponents() on the component that actually has the CardLayout. That way, only one of its children is visible. I'm guessing in your code you are calling getComponents on the frame that contains your JPanel with CardLayout.

class TestFrame
        extends JFrame
        implements ActionListener
{
    public TestFrame()
    {
        cards = new JPanel(new CardLayout() );
        card_list = new JPanel[5];

        for (int i = 0; i < card_list.length; i++) {
            String text = "Card " + i;
            JPanel card = createCard(text);
            card_list[i] = card;
            cards.add(card, text);
        }

        add(cards);
    }

public JPanel getCurrentCard()
{
    JPanel card = null;

    for (Component comp : cards.getComponents() ) {
        if (comp.isVisible() == true) {
            card = (JPanel)comp;
            System.out.println(card.getName() );
        }
    }
    System.out.println();

    return card;
}

public void actionPerformed(ActionEvent evt)
{
    JPanel card = getCurrentCard();

    CardLayout cl = (CardLayout)(cards.getLayout() );
    cl.next(cards);
}

    public JPanel createCard(String text)
    {
        JPanel card = new JPanel();
        card.setName(text);

        JButton btn = new JButton(text);
        btn.addActionListener(this);

        card.add(btn);
        return card;
    }

    JPanel cards;
    JPanel[] card_list;
}

In the actionPerformed() method, I printed the name of the card, but you have a reference to the currently visible card.

OTHER TIPS

I extended the CardLayout to provide this type of functionality. See Card Layout Focus.

Edit:

Then loop through the components looking for the compnent with a ZOrder of 0. This is the one that is painted on top. Actually you don't even have to iterate through all the components, just get the component at position 0. Check out my blog on the Overlap Layout for a more detailed description of how ZOrder works.

Component visibleComponent = panelWithCardLayout.getComponent(0);

Edit2:

The above edit is wrong. ZOrder has no meaning when used with a CardLayout. So you can't simply get component 0.

In the implementation of CardLayout.first() which is supposed to set the top card visible you have the following:

int ncomponents = parent.getComponentCount();
for (int i = 0 ; i < ncomponents ; i++) {
    Component comp = parent.getComponent(i);
    if (comp.isVisible()) {
        comp.setVisible(false);     // hide previously visible components
        break;
    }
}

if (ncomponents > 0) {
    currentCard = 0;
    parent.getComponent(0).setVisible(true);   // set visibility of component 0
    parent.validate();
}

so I suppose you can get hold of the "top card" by yourContainer.getComponent(0).

You can set variable that changes depending on the card visibility

for example

int cardShow;

and then you set your card visible

cards.show(card1, "card1");
cardShow = 1;

and when you try to get which card is visible just use

if (cardShow == 1)
//code in case of card1 is visible
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top