2009-05-06 109 views
3

我遵循this guide的方法2,所以現在我有一個ModalInternalFrame阻止輸入到所有其他幀,就像我想要的。但是,我從這個例子做了一個改變,現在我有兩個問題。關閉一個模式JInternalFrame

的變化

我刪除了的JOptionPane,因爲重點是要表明我自己的窗格。爲了使它關閉,我將closeable設置爲true,並添加了一個InternalFrameListener,其代碼與JOptionPane的示例偵聽器相同。這不起作用,所以我還在doDefaultCloseAction的末尾添加了代碼。

的問題

  1. 的ModalInternal框架永遠不會消失。我認爲一些例外情況正在拋出,但...
  2. 我看不到任何拋出的異常,我不知道他們要去哪裏。通常,當處於調試模式時,Eclipse將在UncaughtExceptionHandler異常發生之前停止,但在這種情況下不會發生這種情況。

守則

如果我的問題的說明沒有幫助,這是我的版本ModalInternalFrame的。如果你想要更多的代碼,我也可以發佈。對不起,這是很長的,但我儘量簡潔。

public class ModalInternalFrame extends JInternalFrame { 
    public ModalInternalFrame(String title, JRootPane rootPane, 
      Component desktop) { 
     super(title, false, true, false, false); 

     // create opaque glass pane 
     final JPanel glass = new JPanel(); 
     glass.setOpaque(false); 

     // Attach mouse listeners 
     MouseInputAdapter adapter = new MouseInputAdapter() { }; 
     glass.addMouseListener(adapter); 
     glass.addMouseMotionListener(adapter); 

     this.addInternalFrameListener(new InternalFrameListenerAdapter() { 
      public void internalFrameClosed(InternalFrameEvent e) { close(); } 
      public void internalFrameClosing(InternalFrameEvent e){ close(); } 
     }); 

     // Change frame border 
     putClientProperty("JInternalFrame.frameType", "optionDialog"); 

     // Size frame 
     Dimension size = getPreferredSize(); 
     Dimension rootSize = desktop.getSize(); 

     setBounds((rootSize.width - size.width)/2, 
       (rootSize.height - size.height)/2, size.width, size.height); 
     desktop.validate(); 
     try { setSelected(true); } 
     catch (PropertyVetoException ignored) { } 

     glass.add(this);    // Add modal internal frame to glass pane 
     rootPane.setGlassPane(glass); // Change glass pane to our panel 
     glass.setVisible(true);  // Show glass pane, then modal dialog 
    } 

    private void close(){ 
     if (isVisible()) { 
      try { setClosed(true); } 
      catch (PropertyVetoException ignored) { } 
      setVisible(false); 
      rootPane.getGlassPane().setVisible(false); 
     } 
    } 

    @Override public void doDefaultCloseAction() { 
     super.doDefaultCloseAction(); 
     close(); 
    } 

    @Override public void setVisible(boolean flag) { 
     super.setVisible(flag); 
     if (flag) startModal(); 
     else stopModal(); 
    } 

    private synchronized void startModal() { 
     try { 
      if (SwingUtilities.isEventDispatchThread()) { 
       EventQueue theQueue = getToolkit().getSystemEventQueue(); 
       while (isVisible()) { 
        AWTEvent event = theQueue.getNextEvent(); 
        Object source = event.getSource(); 
        if (event instanceof ActiveEvent) { 
         ((ActiveEvent) event).dispatch(); 
        } else if (source instanceof Component) { 
         ((Component) source).dispatchEvent(event); 
        } else if (source instanceof MenuComponent) { 
         ((MenuComponent) source).dispatchEvent(event); 
        } else { 
         System.err.println("Unable to dispatch: " + event); 
        } 
       } 
      } else { while (isVisible()) { wait(); } } 
     } catch (InterruptedException ignored) { 
     } 

    } 

    private synchronized void stopModal() { notifyAll(); } 

} 

更新:我發現,模態對話框適合我的需要罰款,但如果有人確實有一個想法,我會很高興聽到這個消息。我還沒有嘗試過的一件事是將每個方法都包裝在try {catch(Exception e){}中,這可能會有很大幫助。

+0

如果調試失敗,至少添加系統輸出/犯錯的到目前被忽略catch塊。 – Pool 2009-05-12 19:46:37

+0

David Moles的解決方案適合您嗎?如果是這樣,你應該接受它,因爲這個問題仍然是開放的。 – BoffinbraiN 2010-12-23 13:57:52

+0

@BoffinbraiN實際上,在我嘗試David的解決方案之前,我放棄了模態內部框架方法。我想接受它,但是隻有在我有獨立確認的情況下才有效,而且我沒有時間自己嘗試。 – 2011-01-05 19:41:45

回答

0
 public void internalFrameClosing(InternalFrameEvent e){ close(); } 

調用close()會導致internalFrameClosing()再次調用,直到堆棧溢出。

嘗試徹底刪除該監聽器。

+0

謝謝,當我有機會時,我會試試這個。我發現了一個模式JInternalFrames的替代方案,但我仍然希望看到這個工作。 – 2009-07-08 03:56:50

1

我不能完全得到你的代碼運行,但這裏有一個簡單的版本,基於Sun例如,不工作 - 主框架中有一個按鈕(佔所有可用空間),但單擊該按鈕將被阻止,直到內部框架已關閉。

您可以看到,我所做的大部分工作都是用我自己的框架取代new JOptionPane().createInternalFrame()業務。我的猜測是,當你嘗試進行自己的事件調度時,你會過於複雜。

或者我錯過了什麼?

public class Foo { 

    public static void main(String[] args) { 
    JFrame frame = new JFrame(); 
    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 
    frame.setSize(600, 400); 
    frame.setLocationByPlatform(true); 

    JButton desktop = new JButton(new AbstractAction("Click me if you can") { 
     @Override 
     public void actionPerformed(ActionEvent e) { 
     System.out.println("I have been clicked"); 
     } 
    }); 
    frame.getContentPane().add(desktop); 

    frame.setVisible(true); 

    JInternalFrame modal = 
     new JInternalFrame("Modal Popup", false, true, false, false); 
    JLabel popupContent = new JLabel("I am the popup"); 
    popupContent.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); 
    modal.add(popupContent); 
    modal.pack(); 

    JPanel glass = new JPanel(); 
    glass.setOpaque(false); 
    glass.add(modal); 
    frame.setGlassPane(glass); 
    glass.setVisible(true); 
    modal.setVisible(true); 

    modal.addInternalFrameListener(new ModalAdapter(glass)); 
    } 
} 

class ModalAdapter extends InternalFrameAdapter { 
    Component glass; 

    public ModalAdapter(Component glass) { 
    this.glass = glass; 

    // Associate dummy mouse listeners 
    // Otherwise mouse events pass through 
    MouseInputAdapter adapter = new MouseInputAdapter() { 
    }; 
    glass.addMouseListener(adapter); 
    glass.addMouseMotionListener(adapter); 
    } 

    public void internalFrameClosed(InternalFrameEvent e) { 
    glass.setVisible(false); 
    } 
} 
1

我只是爲一個項目做了這件事。我所做的只是將主窗口對象傳遞給Jinternalframe。主對象有一個跟蹤模態是否被鎖定的信號量。關閉Jinternalframe(擴展名)後,調用主對象的信號量。很簡單。 這不是主要的代碼,但你的想法:

//called frame 
public CallingFrame parent; 
public void setParent(CallingFrame parent_){ 
    this.parent=parent_; 
} 
private void frameClosed(javax.swing.event.InternalFrameEvent evt) { 
    parent.modalLocked=false; 
} 

在我的情況下,應用程序使用的標籤與圖像的部分叫internalframes,所以代碼與

//calling frame  
CalledFrame cf=new CalledFrame(); 
cf.setParent(this); 
cf.setVisible(true); 
modalLoacked=true; 
private void jLabel1MouseReleased(java.awt.event.MouseEvent evt) { 
    if (modalLocked) 
    return; 
    else// (do your things) 
    } 

我也跟着開始教程,但大多數是過於複雜的事情,當一個單一的信號量會做一些技巧,不讓你點擊任何區域,而一個被調用的框架沒有關閉。

2

試試這個。我是從威比IT博客帖子上JInternal框架:http://webbyit.blogspot.com/2011/03/managing-jinternalframes-within.html

import java.awt.*; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import java.beans.PropertyChangeEvent; 
import java.beans.PropertyVetoException; 
import java.beans.VetoableChangeListener; 
import java.util.logging.Level; 
import java.util.logging.Logger; 
import javax.swing.*; 
import javax.swing.event.InternalFrameAdapter; 
import javax.swing.event.InternalFrameEvent; 

/** 
* An extended <code>JInternalFrame</code> that provides modality in a child/parent hierarchy. 
* <a href="From http://webbyit.blogspot.com/2011/03/managing-jinternalframes-within.html">source: webby it internal frames blog post</a> 
* 
* @author webbyit 
*/ 
public class ModalityInternalFrame extends JInternalFrame { 

    protected JDesktopPane desktopPane; 
    protected JComponent parent; 
    protected ModalityInternalFrame childFrame; 
    protected JComponent focusOwner; 
    private boolean wasCloseable; 

    public ModalityInternalFrame() { 
     init(); // here to allow netbeans to use class in gui builder 
    } 

    public ModalityInternalFrame(JComponent parent) { 
     this(parent, null); 
    } 

    public ModalityInternalFrame(JComponent parent, String title) { 
     this(parent, title, false); 
    } 

    public ModalityInternalFrame(JComponent parent, String title, boolean resizable) { 
     this(parent, title, resizable, false); 
    } 

    public ModalityInternalFrame(JComponent parent, String title, boolean resizable, boolean closeable) { 
     this(parent, title, resizable, closeable, false); 
    } 

    public ModalityInternalFrame(JComponent parent, String title, boolean resizable, boolean closeable, 
      boolean maximizable) { 
     this(parent, title, resizable, closeable, maximizable, false); 
    } 

    public ModalityInternalFrame(JComponent parent, String title, boolean resizable, boolean closeable, 
      boolean maximizable, 
      boolean iconifiable) { 
     super(title, resizable, closeable, maximizable, iconifiable); 
     setParentFrame(parent); 
     //setFocusTraversalKeysEnabled(false); 
     if (parent != null && parent instanceof ModalityInternalFrame) { 
      ((ModalityInternalFrame) parent).setChildFrame(ModalityInternalFrame.this); 

      /* 
      * set focus to the new frame and show the frame Code added by Jasir 
      */ 
      try { 
       ((ModalityInternalFrame) parent).setSelected(false); 
       setSelected(true); 
       setVisible(true); 
      } catch (PropertyVetoException ex) { 
       Logger.getLogger(ModalityInternalFrame.class.getName()).log(Level.SEVERE, null, ex); 
      } 
     } 

     // Add glass pane 
     ModalityInternalGlassPane glassPane = new ModalityInternalGlassPane(this); 
     setGlassPane(glassPane); 


     // Add frame listeners 
     addFrameListener(); 

     // Add frame veto listenr 
     addFrameVetoListener(); 

     init(); 


     // calculate size and position 


    } 

    private void setParentFrame(JComponent parent) { 
     desktopPane = JOptionPane.getDesktopPaneForComponent(parent); 
     this.parent = parent == null ? JOptionPane.getDesktopPaneForComponent(parent) : parent; // default to desktop if no parent given 
    } 

    public JComponent getParentFrame() { 
     return parent; 
    } 

    public void setChildFrame(ModalityInternalFrame childFrame) { 
     this.childFrame = childFrame; 
    } 

    public ModalityInternalFrame getChildFrame() { 
     return childFrame; 
    } 

    public boolean hasChildFrame() { 
     return (childFrame != null); 
    } 

    protected void addFrameVetoListener() { 
     addVetoableChangeListener(new VetoableChangeListener() { 

      public void vetoableChange(PropertyChangeEvent evt) throws PropertyVetoException { 
       if (evt.getPropertyName().equals(JInternalFrame.IS_SELECTED_PROPERTY) 
         && evt.getNewValue().equals(Boolean.TRUE)) { 
        if (hasChildFrame()) { 
         //childFrame.setSelected(true); 
         if (childFrame.isIcon()) { 
          childFrame.setIcon(false); 
         } 
         throw new PropertyVetoException("no!", evt); 
        } 
       } 
      } 
     }); 
    } 

    /** 
    * Method to control the display of the glass pane, dependant on the frame 
    * being active or not 
    */ 
    protected synchronized void addFrameListener() { 
     addInternalFrameListener(new InternalFrameAdapter() { 

      @Override 
      public void internalFrameActivated(InternalFrameEvent e) { 
       if (hasChildFrame() == true) { 
        getGlassPane().setVisible(true); 
        grabFocus(); 
       } else { 
        getGlassPane().setVisible(false); 
       } 
      } 

      @Override 
      public void internalFrameOpened(InternalFrameEvent e) { 
       getGlassPane().setVisible(false); 
       try { 
        setSelected(true); 
       } catch (PropertyVetoException ex) { 
        Logger.getLogger(ModalityInternalFrame.class.getName()).log(Level.SEVERE, null, ex); 
       } 
      } 

      @Override 
      public void internalFrameClosing(InternalFrameEvent e) { 
       if (parent != null && parent instanceof ModalityInternalFrame) { 
        ((ModalityInternalFrame) parent).childClosing(); 
       } 
      } 
     }); 
    } 

    /** 
    * Method to handle child frame closing and make this frame available for 
    * user input again with no glass pane visible 
    */ 
    protected void childClosing() { 
     setClosable(wasCloseable); 
     getGlassPane().setVisible(false); 
     if (focusOwner != null) { 
      java.awt.EventQueue.invokeLater(new Runnable() { 

       @Override 
       public void run() { 
        try { 
         moveToFront(); 
         setSelected(true); 
         focusOwner.grabFocus(); 
        } catch (PropertyVetoException ex) { 
        } 
       } 
      }); 
      focusOwner.grabFocus(); 
     } 
     getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); 
     setChildFrame(null); 
     getDesktopPane().setSelectedFrame(this); 
     System.out.println(getDesktopPane().getSelectedFrame()); 
    } 

    /* 
    * Method to handle child opening and becoming visible. 
    */ 
    protected void childOpening() { 
     // record the present focused component 
     wasCloseable = isClosable(); 
     setClosable(false); 
     focusOwner = (JComponent) getMostRecentFocusOwner(); 
     grabFocus(); 
     getGlassPane().setVisible(true); 
     getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); 
    } 

    @Override 
    public void show() { 
     if (parent != null && parent instanceof ModalityInternalFrame) { 
      // Need to inform parent its about to lose its focus due 
      // to child opening 
      ((ModalityInternalFrame) parent).childOpening(); 
     } 
     calculateBounds(); 
     super.show(); 
    } 

    protected void init() { 
     javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); 
     getContentPane().setLayout(layout); 
     layout.setHorizontalGroup(
       layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGap(0, 394, Short.MAX_VALUE)); 
     layout.setVerticalGroup(
       layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGap(0, 274, Short.MAX_VALUE)); 

     pack(); 
    } 

    public void calculateBounds() { 
     Dimension frameSize = getPreferredSize(); 
     Dimension parentSize = new Dimension(); 
     Dimension rootSize = new Dimension(); // size of desktop 
     Point frameCoord = new Point(); 

     if (desktopPane != null) { 
      rootSize = desktopPane.getSize(); // size of desktop 
      frameCoord = SwingUtilities.convertPoint(parent, 0, 0, desktopPane); 
      parentSize = parent.getSize(); 
     } 

     //setBounds((rootSize.width - frameSize.width)/2, (rootSize.height - frameSize.height)/2, frameSize.width, frameSize.height); 

     // We want dialog centered relative to its parent component 
     int x = (parentSize.width - frameSize.width)/2 + frameCoord.x; 
     int y = (parentSize.height - frameSize.height)/2 + frameCoord.y; 

     // If possible, dialog should be fully visible 
     int ovrx = x + frameSize.width - rootSize.width; 
     int ovry = y + frameSize.height - rootSize.height; 
     x = Math.max((ovrx > 0 ? x - ovrx : x), 0); 
     y = Math.max((ovry > 0 ? y - ovry : y), 0); 
     setBounds(x, y, frameSize.width, frameSize.height); 
    } 

    /** 
    * Glass pane to overlay. Listens for mouse clicks and sets selected on 
    * associated modal frame. Also if modal frame has no children make class 
    * pane invisible 
    */ 
    class ModalityInternalGlassPane extends JComponent { 

     private ModalityInternalFrame modalFrame; 

     public ModalityInternalGlassPane(ModalityInternalFrame frame) { 
      modalFrame = frame; 
      addMouseListener(new MouseAdapter() { 

       @Override 
       public void mouseClicked(MouseEvent e) { 
        if (modalFrame.isSelected() == false) { 
         try { 
          modalFrame.setSelected(true); 
          if (modalFrame.hasChildFrame() == false) { 
           setVisible(false); 
          } 
         } catch (PropertyVetoException e1) { 
          //e1.printStackTrace(); 
         } 
        } 
       } 
      }); 
     } 

     @Override 
     public void paint(Graphics g) { 
      super.paint(g); 
      g.setColor(new Color(255, 255, 255, 100)); 
      g.fillRect(0, 0, getWidth(), getHeight()); 
     } 
    } 
} 
-2

你可以只添加setClosable(true);在構造函數中

相關問題