2012-07-05 136 views
1

我试图更改当前卡片布局中可见的幻灯片效果。但我在幻灯片的开头看到一个轻弹,我无法调试/解决。我怎样才能避免轻弹?更改卡片布局中带有滑动效果的卡片布局中的当前卡片

下面是示例代码重现错误:

import java.awt.CardLayout; 

import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 

public class Main { 
    public static void main(String[] args) { 
     JFrame frame = new JFrame(); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     JPanel panel = new JPanel(new CardLayout()); 
     JLabel label1 = new JLabel("Harry Joy"); 
     panel.add(label1, "1"); 
     JLabel label2 = new JLabel("Harsh Raval"); 
     panel.add(label2, "2"); 
     frame.add(panel); 
     frame.pack(); 
     frame.setVisible(true); 
     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); 
     } 
     label2.setVisible(false); 
     CardLayout cl = (CardLayout)panel.getLayout(); 
     cl.next(panel); 
    } 
} 

在这里,在第一label1( “哈里喜悦”)被显示。然后我制作label2(“Harsh Raval”)可见,并尝试更改两者的位置以提供滑动效果。但是,这里发生的事情是第一次两个标签都显示在彼此的顶部,然后开始滑动。我怎么能阻止这个,我的意思是把两个标签放在一起?如果你运行一次,你可以更好地了解我的意思。

+0

* “这里是SSCCE:” *嗯。没有。一个SSCCE需要一个格式良好的类和一个'main()'(除非是一个applet)。 – 2012-07-05 11:50:40

+0

@AndrewThompson更新:) – 2012-07-05 11:51:43

+0

这不是一个SSCCE,因为没有主要和没有进口。只有当EDT用完时,你的例子才“有效”,这是一个坏主意。 – 2012-07-05 11:52:20

回答

3

主要问题是您正在踩CardLayout的脚趾。 CardLayout两个管理范围(位置和大小),以及您的组件的可见性,使您的循环在这里:

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); 
    } 

是什么呢CardLayout发生冲突。默认情况下,CardLayout将自动显示您添加的第一个组件,并隐藏所有其他组件。它还将所有组件的边界设置为相同的边界。

在第一次迭代中,LABEL2变化的可见性(从falsetrue)最终触发您CardLayout来再进行你的组件的布局,将所有组件的边界来这就是为什么同样的边界结束你看到了重叠。 CardLayout并不意味着可以同时看到多个组件。

请注意,您正在美国东部时间(事件调度线程)运行这是一个坏主意。它会导致死锁和不可预知的行为(例如你在这里看到的那个)。

+0

在我的应用程序中,我使用'SwingUtilities.invokeLater(..)'并面临同样的问题。所以我不认为这是由于我在美国东部时间以外运行。关于将label2的可见性设置为true:我这样做是因为如果我不这样做,那么我不会看到label2滑动,只有先滑出,然后最后显示label2,而不是我需要的情况。我尝试删除'setVisible(true)'行,并且效果很好,完全没有重叠,但正如我所说的那样,第一个标签只有滑出效果,第二个标签没有效果。所以看起来问题在于设置label2的可见性。 – 2012-07-05 12:48:31

+1

@HarryJoy我在'SwingUtilities.invokeLater()'中运行了上面显示的那个例子,因为你会阻塞EDT,所以你不会看到任何东西,这意味着“Paint事件”不能被处理。重叠也可能不会发生,因为'label2'的可见性改变触发了要执行的布局,而且在将来EventQueue事件中也会发生,所以您的问题与您在EDT上运行的事实以及可见性改变标签2。考虑使用摆动计时器来做滑动效果。 – 2012-07-05 12:57:21

+0

好的。我想我必须告诉你我到底有什么:首先,我创建一个框架和我的自定义面板,它具有CardLayout,使此框架可见。我在main方法和'SwingUtilities.invokeLater()'中执行这个操作。然后,我启动一个用于更改组件位置的'java.swing.Timer',这个例子中的循环内部实际上是'Timer'的'ActionLerformed()'ActionListener'方法的内部。这是你的建议吗? – 2012-07-05 13:06:09

2

可能是这样的http://java-sl.com/tip_slider.html

+0

同样的事情发生在这个例子中。当你从最后一个组件滑到第一个时,有时候会看到和我一样的问题。在本例中,正确地看到它会增加监听器类中的计时器延迟。我很想知道这个原因,如果可能的话,这个解决方案。 – 2012-07-05 12:12:38

2

一些意见和可能是评论仅供

  • Thread.sleep想法是正确的,但只从Runnable.Thread

  • 开始为Swing GUI有Swing Timer

  • Swing Timer确保移动任何(没有闪烁已经)可见JComponents铺设标准LayoutManager

但在这(我的代码示例)的情况下,我再次使用Swing的计时器,也不是所有的事件将在美国东部时间来完成,从Runnable的生活自己的生活调用,而不影响挥杆事件的其余部分,GUI EI,

通知这个问题是基于AWT嵌套/继承,例如用于JComboBoxes弹出(调整大小,并用的doLayout())不工作

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); 
      } 
     }); 
    } 
}