2013-08-06 105 views
1

我想工作到我的程序的概念基本上是:如何遠程切換JPanel?

- 主窗口:保存程序的主框架主類,即:

public class MainWindow extends JFrame { 
    ... 
} 

- 其他類:類該擴展JPanel,使得它們可以容易地添加到主窗口作爲一個對象或實體,即:

public class SomePanel extends JPanel { 
    ... 
} 

這樣,我可以說,對於主窗口:

public MainWindow() { 
... 
SomePanel sp = new SomePanel(); 
add(sp); 
... 
} 

當一些動作事件被觸發時,我可以說,在主窗口類:

// remove the current panel 
getContentPane().remove(sp); 
// insert the new panel 
getContentPane().add(someOtherPanel); 
validate(); 
repaint(); 

的概念,我想,就像是CardLayout,除了我還沒有得到解決,以學習CardLayout但我感覺就像嘗試這個概念。不過,在某些時候我可能會學習CardLayout,這取決於更容易些。

但是我的主要問題是,如果一切都在不同的類中,那麼如何基於ActionEvent的觸發器如此遠程切換JPanel?我認爲這些類之間必須有一些共享組件,但這似乎不起作用。我在正確的軌道上嗎?

我嘗試使用remove()和add()函數的代碼似乎沒有工作,因爲當我觸發組件的ActionEvent(監聽器被添加以及所有內容)時,沒有任何更改。我還包括validate()和repaint(),但仍然沒有任何反應。

我不再是初學者,但也不是非常有經驗,所以如果有什麼明顯的我失蹤了,請耐心等待。謝謝你的幫助。

回答

7

你絕對是在正確的軌道上,幾乎擁有它。請注意,在構造函數中如何使用add(sp);,但在底部示例中使用getContentPane().remove(sp);getContentPane().add(someOtherPanel);JPanel的方法肯定是remove(Component c),所以請使用它。

此外,如果您在一個位置操作組件,一切都會更容易。我喜歡以主要方法或主要類別做正確的事。例如:

public class Start implements ActionListener { 
    Window theWindow = new Window(); 
    CustomPanel mainMenu = new CustomPanel(); 
    CustomPanel optionsMenu = new CustomPanel(); 
    Button myButton = new Button(); 
    public static void main(String[] args) { 
     theWindow.add(mainMenu); 
     mainMenu.add(myButton); 
     myButton.addActionListener(this); 

     theWindow.setVisible(true); 
     theWindow.repaint(); 
    } 

    public void actionPerformed(Event e) { 
     theWindow.remove(mainMenu); 
     theWindow.add(optionsMenu); 
     theWindow.repaint(); 
    } 

請注意,即使不必使用自定義類進行所有這些操作,也很容易。我建議你這樣構建你的程序和gui。

同樣如下MadProgrammer所述,您可以使用theWindow.revalidate()而不是repaint()

+1

'theWindow.revalidate()'可能會更好地工作 – MadProgrammer

+0

我沒有意識到這種方法,我總是使用'repaint'。謝謝,我編輯了我的回覆。 – snickers10m

+0

現在我可以放心:D – MadProgrammer

5

您可以設計一個模型來控制不同動作顯示的內容。這個模型將被共享,以便底層操作可以訪問它,並且不需要不必要地公開組件。但那將取決於您的要求...

因此,例如。您可以建立一個允許您將組件與命名操作關聯的模型(例如)。當您的應用程序發生某些操作時,您需要將模型告知setCurrentAction並將其傳遞給可用的操作名稱。

你可以,另外,使用像一個ChangeListener這將通知利害關係人,當前視圖已經改變,它應該妥當。

這樣,你從UI

用一個例子

此更新分離模式是一個概念證明。最主要的一點是要證明,通過它可以從用戶界面分離模式的一種手段,因此模型並不關心它的控制輸出,只知道它可以告訴別人......

import java.awt.BorderLayout; 
import java.awt.Component; 
import java.awt.EventQueue; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.util.HashMap; 
import java.util.Map; 
import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 
import javax.swing.event.ChangeEvent; 
import javax.swing.event.ChangeListener; 
import javax.swing.event.EventListenerList; 

public class PageFlipper { 

    public static void main(String[] args) { 
    new PageFlipper(); 
    } 

    public PageFlipper() { 
    startUI(); 
    } 

    public void startUI() { 
    EventQueue.invokeLater(new Runnable() { 
     @Override 
     public void run() { 
     try { 
      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
     } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
      ex.printStackTrace(); 
     } 

     JFrame frame = new JFrame("Testing"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.add(new MainView()); 
     frame.pack(); 
     frame.setLocationRelativeTo(null); 
     frame.setVisible(true); 
     } 
    }); 
    } 

    public class MainView extends JPanel { 

    private DefaultViewModel model; 

    public MainView() { 
     setLayout(new BorderLayout()); 
     model = new DefaultViewModel(); 
     model.addChangeListener(new ChangeListener() { 
     @Override 
     public void stateChanged(ChangeEvent e) { 
      System.out.println("Current view = " + model.getCurrentViewName()); 
      removeAll(); 
      add(model.getCurrentView()); 
      revalidate(); 
      repaint(); 
     } 
     }); 
     model.addView("Menu", new ActionPane("Menu", "Settings", model)); 
     model.addView("Settings", new ActionPane("Settings", "Menu", model)); 
     model.setCurrentView("Menu"); 
    } 

    } 

    public class ActionPane extends JPanel { 

    private final String nextView; 
    private final ViewModel model; 

    public ActionPane(String name, String nextView, ViewModel model) { 
     this.nextView = nextView; 
     this.model = model; 
     setLayout(new BorderLayout()); 
     JLabel label = new JLabel(name); 
     label.setHorizontalAlignment(JLabel.CENTER); 
     label.setVerticalAlignment(JLabel.CENTER); 
     add(label); 

     JButton btn = new JButton("Next"); 
     btn.addActionListener(new ActionListener() { 
     @Override 
     public void actionPerformed(ActionEvent e) { 
      ActionPane.this.model.setCurrentView(ActionPane.this.nextView); 
     } 
     }); 
     add(btn, BorderLayout.SOUTH); 
    } 

    } 

    public interface ViewModel { 

    public void setCurrentView(String name); 
    public Component getCurrentView(); 
    public void addChangeListener(ChangeListener listener); 
    public void removeChangeListener(ChangeListener listener); 

    } 

    public class DefaultViewModel implements ViewModel { 

    private final Map<String, Component> views; 
    private final EventListenerList listenerList; 
    private String currentView; 

    public DefaultViewModel() { 
     views = new HashMap<>(25); 
     listenerList = new EventListenerList(); 
    } 

    public void addView(String name, Component comp) { 
     views.put(name, comp); 
    } 

    public void removeView(String name) { 
     views.remove(name); 
    } 

    @Override 
    public void setCurrentView(String name) { 
     if (currentView == null ? name != null : !currentView.equals(name)) { 
     currentView = name; 
     fireStateChanged(); 
     } 
    } 

    public String getCurrentViewName() { 
     return currentView; 
    } 

    @Override 
    public Component getCurrentView() { 
     return currentView == null ? null : views.get(currentView); 
    } 

    @Override 
    public void addChangeListener(ChangeListener listener) { 
     listenerList.add(ChangeListener.class, listener); 
    } 

    @Override 
    public void removeChangeListener(ChangeListener listener) { 
     listenerList.remove(ChangeListener.class, listener); 
    } 

    protected void fireStateChanged() { 
     ChangeListener[] listeners = listenerList.getListeners(ChangeListener.class); 
     if (listeners.length > 0) { 
     ChangeEvent evt = new ChangeEvent(this); 
     for (ChangeListener listener : listeners) { 
      listener.stateChanged(evt); 
     } 
     } 
    } 

    } 

} 

你可以很容易修改它有更加明確的/動作名稱(即使用某種Object代替String),以及提供更先進的導航(例如像nextprevious

0

你可以試試這個:

〜添加兩個jpanels一次

〜只要有一個事件,開關面板的能見度...

例如:

//global variables 
int i = 0; 
JPanel p2 = new JPanel(); 
JPanel p = new JPanel(); 

時,有一個事件調用此方法:switchPanels(),但你能說出它,你想怎麼。 ..:D

public void switchPanels() { 
    i++; 
    if(i % 2 == 0){ 
     p.setVisible(true); 
     p2.setVisible(false); 
    }else{ 
     p.setVisible(false); 
     p2.setVisible(true); 
    } 

}