CardLayout works, but "cards" randomly disappear

R

roadkill

Hi all,

I have included code at the bottom of this message,
it compiles, runs, and exhibits the behavior I will
describe.

The concensus seems to be that the "nicest" way to
have a number of "screens" or "panels" that are
interchangeable (i.e. switch between them) is to
use CardLayout, which does look like a nifty way
to do this.

I have tried to implement this, and it "sorta"
works, but with some problems.

The "screens" get laid out and show correctly,
and the action (from a button click) triggers
the screen changes fine, but after a seemingly
random number of switches "back and forth", the
screen switch eventually results in a blank
panel.

Basically, I wired up two screens, each with
a button that switches to the other screen.
Sometimes, one screen comes up blank after
3, 5, 7, or 9 switches, and sometimes the
other comes up blank after 2, 4, 6, or 8
switches.

The random-ness makes me think it could be
something about how I am doing this resulting
in my objects not staying "wired in", and
getting cleaned up by the GC.

Anyway, if someone could take a look at the
code (maybe run it if so inclined) and give
me some hints as to what I may be doing
wrong, I would appreciate it greatly.

PS - you'll need to supply some images to
actually run it - the background is a 1024x768
and I am using JDK 1.4.2_06 on linux (Slackware 10)

//=-=-=-=-=-=-=-=-=-=-= Code Example =-=-=-=-=-=-=-=-=-=-=
import java.io.*;

import java.awt.Dimension;
import java.awt.CardLayout;
import java.awt.FlowLayout;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JButton;

public class Example extends JFrame implements ActionListener {

public static void main( String args[]) {
new Example().show();
return;
}

private void exitForm( java.awt.event.WindowEvent evt) {
System.exit( 0);
}

public Example() {
pRoot = null;
pBGImg = new ImageIcon( "./img/bg_default.png");
initComponents();
return;
}

private void initComponents() {
setTitle( "Example");
addWindowListener( new java.awt.event.WindowAdapter() {
public void windowClosing( java.awt.event.WindowEvent
evt)
{ exitForm( evt); }
}
);
launchScreen( "main");
return;
}

public void actionPerformed( ActionEvent e) {
String szCmd = e.getActionCommand();
if ( szCmd == "usr_exit") {
dispose();
} else if ( szCmd == "usr_act_01") {
launchScreen( "save");
} else if ( szCmd == "usr_act_02") {
launchScreen( "main");
}
return;
}

private void launchScreen( String sName) {
JComponent pScreen = null;
CardLayout pLayout = null;
if ( pRoot == null) {
JLayeredPane pLayers = new JLayeredPane();
JLabel pBG = new JLabel( pBGImg);
pBG.setBounds( 0, 0, 1024, 768);
pLayers.add( pBG, JLayeredPane.DEFAULT_LAYER);

pRoot = new JPanel( new CardLayout());
pRoot.setOpaque( false);
pRoot.setBounds( 0, 0, 1024, 768);

pScreen = generateMainScreen();
pScreen.setBounds( 0, 0, 1024, 768);
pRoot.add( pScreen, "main");

pScreen = generateSaveScreen();
pScreen.setBounds( 0, 0, 1024, 768);
pRoot.add( pScreen, "save");

pLayers.add( pRoot, JLayeredPane.PALETTE_LAYER);
setLayeredPane( pLayers);
}
pLayout = (CardLayout)(pRoot.getLayout());
pLayout.show( pRoot, sName);
pack();
setSize( new Dimension( 1024, 778));
setResizable( false);
return;
}

private JComponent generateMainScreen() {
JPanel pRet = new JPanel();
pRet.setOpaque( false);
pRet.setLayout( new BorderLayout());

FlowLayout pLayout = new FlowLayout();
pLayout.setVgap( 40);
JPanel pBtns = new JPanel();
pBtns.setLayout( pLayout);
pBtns.setOpaque( false);

JButton pBtn = new JButton();
pBtn.setContentAreaFilled( false);
pBtn.setBorderPainted( false);
pBtn.setFocusPainted( false);
pBtn.setEnabled( true);
pBtn.addActionListener( this);
pBtn.setActionCommand( "usr_exit");
pBtn.setIcon( new ImageIcon( "./img/btn01.png"));
pBtn.setPressedIcon( new ImageIcon( "./img/btn01_pressed.png"));
pBtns.add( pBtn);

pBtn = new JButton();
pBtn.setContentAreaFilled( false);
pBtn.setBorderPainted( false);
pBtn.setFocusPainted( false);
pBtn.setEnabled( true);
pBtn.addActionListener( this);
pBtn.setActionCommand( "usr_act_01");
pBtn.setIcon( new ImageIcon( "./img/btn02.png"));
pBtn.setPressedIcon( new ImageIcon( "./img/btn02_pressed.png"));
pBtns.add( pBtn);

pRet.add( pBtns, BorderLayout.SOUTH);
return( pRet);
}

private JComponent generateSaveScreen() {
JPanel pRet = new JPanel();
pRet.setOpaque( false);
pRet.setLayout( new BorderLayout());

FlowLayout pLayout = new FlowLayout();
pLayout.setVgap( 40);
JPanel pBtns = new JPanel();
pBtns.setLayout( pLayout);
pBtns.setOpaque( false);

JButton pBtn = new JButton();
pBtn.setContentAreaFilled( false);
pBtn.setBorderPainted( false);
pBtn.setFocusPainted( false);
pBtn.setEnabled( true);
pBtn.addActionListener( this);
pBtn.setActionCommand( "usr_act_02");
pBtn.setIcon( new ImageIcon( "./img/btn03.png"));
pBtn.setPressedIcon( new ImageIcon( "./img/btn03_pressed.png"));
pBtns.add( pBtn);

pRet.add( pBtns, BorderLayout.SOUTH);
return( pRet);
}

private JPanel pRoot;
private ImageIcon pBGImg;
}
 
R

Rhino

Have you tried executing your code in a decent debugger, like the one in
Eclipse? I'll bet that would show you the problem, whatever it is....

Rhino

roadkill said:
Hi all,

I have included code at the bottom of this message,
it compiles, runs, and exhibits the behavior I will
describe.

The concensus seems to be that the "nicest" way to
have a number of "screens" or "panels" that are
interchangeable (i.e. switch between them) is to
use CardLayout, which does look like a nifty way
to do this.

I have tried to implement this, and it "sorta"
works, but with some problems.

The "screens" get laid out and show correctly,
and the action (from a button click) triggers
the screen changes fine, but after a seemingly
random number of switches "back and forth", the
screen switch eventually results in a blank
panel.

Basically, I wired up two screens, each with
a button that switches to the other screen.
Sometimes, one screen comes up blank after
3, 5, 7, or 9 switches, and sometimes the
other comes up blank after 2, 4, 6, or 8
switches.

The random-ness makes me think it could be
something about how I am doing this resulting
in my objects not staying "wired in", and
getting cleaned up by the GC.

Anyway, if someone could take a look at the
code (maybe run it if so inclined) and give
me some hints as to what I may be doing
wrong, I would appreciate it greatly.

PS - you'll need to supply some images to
actually run it - the background is a 1024x768
and I am using JDK 1.4.2_06 on linux (Slackware 10)

//=-=-=-=-=-=-=-=-=-=-= Code Example =-=-=-=-=-=-=-=-=-=-=
import java.io.*;

import java.awt.Dimension;
import java.awt.CardLayout;
import java.awt.FlowLayout;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JButton;

public class Example extends JFrame implements ActionListener {

public static void main( String args[]) {
new Example().show();
return;
}

private void exitForm( java.awt.event.WindowEvent evt) {
System.exit( 0);
}

public Example() {
pRoot = null;
pBGImg = new ImageIcon( "./img/bg_default.png");
initComponents();
return;
}

private void initComponents() {
setTitle( "Example");
addWindowListener( new java.awt.event.WindowAdapter() {
public void windowClosing( java.awt.event.WindowEvent
evt)
{ exitForm( evt); }
}
);
launchScreen( "main");
return;
}

public void actionPerformed( ActionEvent e) {
String szCmd = e.getActionCommand();
if ( szCmd == "usr_exit") {
dispose();
} else if ( szCmd == "usr_act_01") {
launchScreen( "save");
} else if ( szCmd == "usr_act_02") {
launchScreen( "main");
}
return;
}

private void launchScreen( String sName) {
JComponent pScreen = null;
CardLayout pLayout = null;
if ( pRoot == null) {
JLayeredPane pLayers = new JLayeredPane();
JLabel pBG = new JLabel( pBGImg);
pBG.setBounds( 0, 0, 1024, 768);
pLayers.add( pBG, JLayeredPane.DEFAULT_LAYER);

pRoot = new JPanel( new CardLayout());
pRoot.setOpaque( false);
pRoot.setBounds( 0, 0, 1024, 768);

pScreen = generateMainScreen();
pScreen.setBounds( 0, 0, 1024, 768);
pRoot.add( pScreen, "main");

pScreen = generateSaveScreen();
pScreen.setBounds( 0, 0, 1024, 768);
pRoot.add( pScreen, "save");

pLayers.add( pRoot, JLayeredPane.PALETTE_LAYER);
setLayeredPane( pLayers);
}
pLayout = (CardLayout)(pRoot.getLayout());
pLayout.show( pRoot, sName);
pack();
setSize( new Dimension( 1024, 778));
setResizable( false);
return;
}

private JComponent generateMainScreen() {
JPanel pRet = new JPanel();
pRet.setOpaque( false);
pRet.setLayout( new BorderLayout());

FlowLayout pLayout = new FlowLayout();
pLayout.setVgap( 40);
JPanel pBtns = new JPanel();
pBtns.setLayout( pLayout);
pBtns.setOpaque( false);

JButton pBtn = new JButton();
pBtn.setContentAreaFilled( false);
pBtn.setBorderPainted( false);
pBtn.setFocusPainted( false);
pBtn.setEnabled( true);
pBtn.addActionListener( this);
pBtn.setActionCommand( "usr_exit");
pBtn.setIcon( new ImageIcon( "./img/btn01.png"));
pBtn.setPressedIcon( new ImageIcon( "./img/btn01_pressed.png"));
pBtns.add( pBtn);

pBtn = new JButton();
pBtn.setContentAreaFilled( false);
pBtn.setBorderPainted( false);
pBtn.setFocusPainted( false);
pBtn.setEnabled( true);
pBtn.addActionListener( this);
pBtn.setActionCommand( "usr_act_01");
pBtn.setIcon( new ImageIcon( "./img/btn02.png"));
pBtn.setPressedIcon( new ImageIcon( "./img/btn02_pressed.png"));
pBtns.add( pBtn);

pRet.add( pBtns, BorderLayout.SOUTH);
return( pRet);
}

private JComponent generateSaveScreen() {
JPanel pRet = new JPanel();
pRet.setOpaque( false);
pRet.setLayout( new BorderLayout());

FlowLayout pLayout = new FlowLayout();
pLayout.setVgap( 40);
JPanel pBtns = new JPanel();
pBtns.setLayout( pLayout);
pBtns.setOpaque( false);

JButton pBtn = new JButton();
pBtn.setContentAreaFilled( false);
pBtn.setBorderPainted( false);
pBtn.setFocusPainted( false);
pBtn.setEnabled( true);
pBtn.addActionListener( this);
pBtn.setActionCommand( "usr_act_02");
pBtn.setIcon( new ImageIcon( "./img/btn03.png"));
pBtn.setPressedIcon( new ImageIcon( "./img/btn03_pressed.png"));
pBtns.add( pBtn);

pRet.add( pBtns, BorderLayout.SOUTH);
return( pRet);
}

private JPanel pRoot;
private ImageIcon pBGImg;
}
 
R

roadkill

I have not tried a debugger yet - my rationale for posting
without trying a debugger is something along the lines of
having prolific trace statements and exception handlers
that prove that the code executes, all methods getting
called as expected, no exceptions being thrown, and
nothing interrupting the expected flow.

Of course, I posted a "sparse, to-the-point" version of
the code (i.e. without all the diagnostics). Its doing the
same stuff and displays the same symptoms.

I will, for the sake of curiosity, run the app in a debugger
and see what could possibly come to light - I'll report the
results shortly.
In the meantime, any ideas on what the code's problem
may be ?
 
R

roadkill

OK, so now I have run the example app through
the Eclipse debugger - I get the same information,
which is all methods are called when I expect, all
do what is intended, no exceptions, the app seems
to run fine, the "update" machinery just seems to
randomly decide to not paint the screen properly.

I am not saying that its not my code's fault, just
describing the appearance of the symptom.

I expect I am doing some little thing wrong, maybe
in the wrong order or sequence, that is indirectly
affecting (adversely) the GUI constructs. I will
eventually find it, I am sure - it would be nice if
someone with more specific experience had a
hint for me...

Thanks in advance
 
A

Andrew Thompson

..a hint for me...

I tried your code but could not get it to 'display the problem'.

- I put that in "'" because I had no images and converted it to
use JLabels[1] instead.
- I was not sure how the UI was supposed to look.
- What appeared was not in any way logical to me.

At the time, I was about to suggest you make some fundamental changes
to the example before reposting. They might include..

- Change the huge 1024x768 to 400x300 (my screen res. is
currently 800x600, so it was quite irritating that I needed
to find and replace all the values before I could try it.

- Reproduce the problem with JLabels, rather than images.

- Indent your code (with ' ', rather that tabs) so that
it is readable

- It seemed I needed to make changes to your code before it
would compile (recollection fuzzy). Please check carefully
that the code you post is ready for others to see.

For further tips on preparing an example, see..
<http://www.physci.org/codes/sscce.jsp>

HTH
 
S

Sudsy

Andrew said:
..a hint for me...


I tried your code but could not get it to 'display the problem'.

- I put that in "'" because I had no images and converted it to
use JLabels[1] instead.
- I was not sure how the UI was supposed to look.
- What appeared was not in any way logical to me.
<snip>

I got a mess of pixels on the screen, probably doing the same as
Andrew. Searching and replacing the absolute dimensions with ones
defined in private static final variables, indenting the code so
that it would make some sense...
All of which leads me to believe that you're mixing Swing and AWT
semantics. I understand from others that there are some serious
issues with the way that drawing threads are used in Swing; I
wouldn't know as I stick to AWT.
Perhaps a Swing expert would be able to look at your (indented)
code and tell you exactly where the impedance mismatch occurs...
 
A

Andrew Thompson

All of which leads me to believe that you're mixing Swing and AWT
semantics.

My suspicion was that it was with a combination of the
setBounds/packing/layouts, but it is hard to take it further
without a clear understanding of the nature of the GUI.

One point that comes to mind in relation to that understanding.

'button1' and 'btn01.png' might better have been called 'exit' and
'exit.png' as a way of assisting the reader to understand what
is -supposed- to happen. Comments are also good for that, vis..

// exit button
pBtn.setIcon( new ImageIcon( "./img/btn01.png"));
 
R

roadkill

I found the issue, though am not entirely
certain about the details of what was happening
under the covers. Thanks to all of you for
devoting some attention to my problem.

Sorry about the previously posted code - at the
time, the images seemed trivial, but in
retrospect I can see what a hassle they do present.
As far as tabs/spaces go, I tried both and neither
seems to result in the indentation being preserved
in the article after its posted - I didn't think
it was something that I had to be overly concerned
with.

I have re-done the example with plain JButtons
and a background color instead of an image, and
I have put comments in to identify the change that
fixes the problem. If anyone cares to explain the
details of what was happening, and if this fix is
indeed an "OK" thing to do, I would be interested.

I'll try indentation with spaces - the preview
still shows the indentation not being preserved,
but maybe its just my browser or something...
if not, I am not sure there's anything I can do
about it.

// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
import java.awt.Point;
import java.awt.Color;
import java.awt.CardLayout;
import java.awt.FlowLayout;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JButton;

public class Example extends JFrame implements ActionListener {

public static void main( String args[]) {
new Example().show();
return;
}

private void exitForm( java.awt.event.WindowEvent evt) {
System.exit( 0);
}

public Example() {
pResolution = new Point( 640, 480);
pRoot = null;
initComponents();
return;
}

private void initComponents() {
setTitle( "Example");
addWindowListener( new java.awt.event.WindowAdapter() {
public void windowClosing( java.awt.event.WindowEvent evt)
{ exitForm( evt); }
}
);
launchScreen( "main");
return;
}

public void actionPerformed( ActionEvent e) {
String szCmd = e.getActionCommand();
if ( szCmd == "exit") {
dispose();
} else if ( szCmd == "switch") {
launchScreen( "switch");
} else if ( szCmd == "main") {
launchScreen( "main");
}
return;
}

private void launchScreen( String sName) {
CardLayout pLayout = null;

// Create the root (or "base") only once
if ( pRoot == null) {
JLayeredPane pLayers = new JLayeredPane();
JPanel pBG = new JPanel();
pBG.setBackground( Color.GRAY);
pBG.setBounds( 0, 0, pResolution.x, pResolution.y);
pLayers.add( pBG, JLayeredPane.DEFAULT_LAYER);

pRoot = new JPanel( new CardLayout());
pRoot.setOpaque( false);
pRoot.setBounds( 0, 0, pResolution.x, pResolution.y);

pRoot.add( generateMainScreen(), "main");
pRoot.add( generateSwitchScreen(), "switch");

pLayers.add( pRoot, JLayeredPane.PALETTE_LAYER);
setLayeredPane( pLayers);

//=-=-=-=-=-= Moved these three lines to here =-=
pack();
setSize( pResolution.x, pResolution.y);
setResizable( false);
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
}

pLayout = (CardLayout)(pRoot.getLayout());
pLayout.show( pRoot, sName);

// Here's where the three lines were before
// pack();
// setSize( pResolution.x, pResolution.y);
// setResizable( false);

return;
}

private JComponent generateMainScreen() {
JPanel pRet = new JPanel();
pRet.setOpaque( false);
pRet.setLayout( new BorderLayout());

FlowLayout pLayout = new FlowLayout();
pLayout.setVgap( 40);
JPanel pBtns = new JPanel();
pBtns.setLayout( pLayout);
pBtns.setOpaque( false);

JButton pBtn = new JButton();
pBtn.setText( "Exit");
pBtn.setEnabled( true);
pBtn.addActionListener( this);
pBtn.setActionCommand( "exit");
pBtns.add( pBtn);

pBtn = new JButton();
pBtn.setText( "Switch");
pBtn.setEnabled( true);
pBtn.addActionListener( this);
pBtn.setActionCommand( "switch");
pBtns.add( pBtn);

pRet.add( pBtns, BorderLayout.SOUTH);
return( pRet);
}

private JComponent generateSwitchScreen() {
JPanel pRet = new JPanel();
pRet.setOpaque( false);
pRet.setLayout( new BorderLayout());

FlowLayout pLayout = new FlowLayout();
pLayout.setVgap( 40);
JPanel pBtns = new JPanel();
pBtns.setLayout( pLayout);
pBtns.setOpaque( false);

JButton pBtn = new JButton();
pBtn.setText( "Back");
pBtn.setEnabled( true);
pBtn.addActionListener( this);
pBtn.setActionCommand( "main");
pBtns.add( pBtn);

pRet.add( pBtns, BorderLayout.SOUTH);
return( pRet);
}

private JPanel pRoot;
private Point pResolution;
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top