2012-07-05 135 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); 
      } 
     }); 
    } 
}