Change current card in card layout with slide effect in swing

后端 未结 3 1481
梦如初夏
梦如初夏 2021-01-25 05:24

I\'m trying to change current visible in card layout with slide effect. But I see a flick at the start of slide which I\'m not able to debug/solve. How can I avoid that flick?

相关标签:
3条回答
  • 2021-01-25 05:42

    The main problem is that you are stepping on CardLayout's toes. CardLayout both manages bounds (location and size) and visibility of your components, so your loop here:

        for (int i = 0; i < 10; i++) {
            try {
                Thread.sleep(500L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            label2.setLocation(label1.getX() + 10 - label1.getWidth(), label1.getY());
            label1.setLocation(label1.getX() + 10, label1.getY());
            label2.setVisible(true);
        }
    

    is conflicting with what CardLayout does. By default, CardLayout will automatically show the first component you added and hide all the others. It also sets up the bounds of all components to the same bounds.

    At the end of the first iteration, the visibility of label2 changes (from false to true) which eventually triggers your CardLayout to reperform the layout of your components which sets the bounds of all the components to the same bounds which is why you are seeing the overlapping. CardLayout is not meant to have multiple components visible simultaneously.

    Note that you are running all this off the EDT (Event Dispatching Thread) which is really a bad idea. It can cause deadlocks and unpredictable behaviour (such as the one you are seeing here).

    0 讨论(0)
  • 2021-01-25 05:45

    a few comments and could be comments only

    • idea with Thread.sleep is correct but started only from Runnable.Thread

    • for Swing GUI is there Swing Timer,

    • Swing Timer guarantee to move any of (without flickering with already) visible JComponents layed by standard LayoutManager

    but in this (my code example) case I'm again using Swing Timer nor that all events would be done on EDT, by invoking from Runnable living own life without impact to the rest of Swing events, GUI e.i.,

    notice this issue is based on AWT nested / inherits, for example for JComboBoxes popup (resize and with doLayout()) doesn't works

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    
    public class ShakingButtonDemo implements Runnable {
    
        private JButton button;
        private JRadioButton radioWholeButton;
        private JRadioButton radioTextOnly;
    
        public static void main(String[] args) throws Exception {
            SwingUtilities.invokeLater(new ShakingButtonDemo());
        }
    
        @Override
        public void run() {
            radioWholeButton = new JRadioButton("The whole button");
            radioTextOnly = new JRadioButton("Button text only");
            radioWholeButton.setSelected(true);
            ButtonGroup bg = new ButtonGroup();
            bg.add(radioWholeButton);
            bg.add(radioTextOnly);
            button = new JButton("  Shake with this Button  ");
            button.addActionListener(new ActionListener() {
    
                @Override
                public void actionPerformed(ActionEvent e) {
                    shakeButton(radioWholeButton.isSelected());
                }
            });
            JPanel p1 = new JPanel();
            p1.setBorder(BorderFactory.createTitledBorder("Shake Options"));
            p1.setLayout(new GridLayout(0, 1));
            p1.add(radioWholeButton);
            p1.add(radioTextOnly);
            JPanel p2 = new JPanel();
            p2.setLayout(new GridLayout(0, 1));
            p2.add(button);
            JFrame frame = new JFrame();
            frame.setTitle("Shaking Button Demo");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(p1, BorderLayout.NORTH);
            frame.add(p2, BorderLayout.SOUTH);
            frame.setSize(240, 160);
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    
        private void shakeButton(final boolean shakeWholeButton) {
            final Point point = button.getLocation();
            final Insets margin = button.getMargin();
            final int delay = 75;
            Runnable r = new Runnable() {
    
                @Override
                public void run() {
                    for (int i = 0; i < 30; i++) {
                        try {
                            if (shakeWholeButton) {
                                moveButton(new Point(point.x + 5, point.y));
                                Thread.sleep(delay);
                                moveButton(point);
                                Thread.sleep(delay);
                                moveButton(new Point(point.x - 5, point.y));
                                Thread.sleep(delay);
                                moveButton(point);
                                Thread.sleep(delay);
                            } else {// text only
                                setButtonMargin(new Insets(margin.top, margin.left + 3, margin.bottom, margin.right - 2));
                                Thread.sleep(delay);
                                setButtonMargin(margin);
                                Thread.sleep(delay);
                                setButtonMargin(new Insets(margin.top, margin.left - 2, margin.bottom, margin.right + 3));
                                Thread.sleep(delay);
                                setButtonMargin(margin);
                                Thread.sleep(delay);
                            }
                        } catch (InterruptedException ex) {
                            ex.printStackTrace();
                        }
                    }
                }
            };
            Thread t = new Thread(r);
            t.start();
        }
    
        private void moveButton(final Point p) {
            SwingUtilities.invokeLater(new Runnable() {
    
                @Override
                public void run() {
                    button.setLocation(p);
                }
            });
        }
    
        private void setButtonMargin(final Insets margin) {
            SwingUtilities.invokeLater(new Runnable() {
    
                @Override
                public void run() {
                    button.setMargin(margin);
                }
            });
        }
    }
    
    0 讨论(0)
  • 2021-01-25 05:55

    May be this http://java-sl.com/tip_slider.html ?

    0 讨论(0)
提交回复
热议问题