2013-07-24 9 views
11

Ich verwende derzeit diesen Code, um einen JDialog zu erstellen;Anzeige von JDialog als Blatt funktioniert nicht

package com.kamuara.reposync.window; 

import java.awt.Dialog; 
import java.awt.Font; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 

import javax.swing.JButton; 
import javax.swing.JDialog; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.UIManager; 

public class SheetDialog { 

    private JFrame _windowFrame; 

    public static void main(String[] args) { 
     System.setProperty("apple.awt.documentModalSheet", "true"); 
     System.setProperty("apple.awt.brushMetalLook", "true"); 

     try { 
      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
      new SheetDialog(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    public SheetDialog() { 
     _windowFrame = new JFrame(); 
     _windowFrame.setResizable(false); 
     _windowFrame.setBounds(100, 100, 451, 320); 
     _windowFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     _windowFrame.getContentPane().setLayout(null); 
     _windowFrame.setVisible(true); 

     JButton showDialogButton = new JButton("Show Dialog"); 
     showDialogButton.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       showSheetDialog(_windowFrame, "Test", "This should be a sheet dialog", "Oke"); 
      } 
     }); 
     showDialogButton.setBounds(328, 263, 117, 29); 
     _windowFrame.getContentPane().add(showDialogButton); 
    } 

    public void showSheetDialog(JFrame owner, String title, String message, String button) { 
     final JDialog messageDialog = new JDialog(owner, title, Dialog.ModalityType.DOCUMENT_MODAL); 
     messageDialog.setBounds(30, 0, owner.getWidth() - 60, 130); 

     // TODO: only when os is osx 
     messageDialog.getRootPane().putClientProperty("apple.awt.documentModalSheet", "true"); 
     messageDialog.setLayout(null); 

     int offsetX = 25; 

     JLabel titleLabel = new JLabel(title); 
     titleLabel.setFont(new Font("Lucida Grande", Font.BOLD, 13)); 
     titleLabel.setBounds(offsetX, 10, 100, 25); 
     messageDialog.getContentPane().add(titleLabel); 

     JLabel messageLabel = new JLabel(message); 
     messageLabel.setVerticalTextPosition(JLabel.TOP); 
     messageLabel.setHorizontalTextPosition(JLabel.LEFT); 
     messageLabel.setFont(new Font("Lucida Grande", Font.PLAIN, 11)); 
     messageLabel.setBounds(offsetX, 10, messageDialog.getWidth() - 10, messageDialog.getHeight() - 60); 
     messageDialog.getContentPane().add(messageLabel); 

     JButton okButton = new JButton(button); 
     okButton.setBounds(messageDialog.getWidth() - 105, messageDialog.getHeight() - 35, 100, 25); 
     okButton.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent arg0) { 
       messageDialog.dispose(); 
      } 
     }); 
     messageDialog.getContentPane().add(okButton); 

     messageDialog.setVisible(true); 
    } 
} 

ich zuvor mit Java 6, um die Anwendung zu kompilieren und die Einstellung der clientProperty apple.awt.documentModalSheet war perfekt funktioniert der Dialog als „Blatt“ auf OSX angezeigt, aber jetzt habe ich angefangen mit Java 7 (Update 25) und den Dialog wird nicht mehr als Blatt angezeigt. Ich finde keine Update-Dokumentation zu diesem Thema. Haben sie etwas daran geändert? Wie kann ich das lösen? Das aktuelle Interface-Design sieht mit einem Sheet viel besser aus als ein Dialog.

aktualisieren

fand ich den folgenden Fehlerbericht, die das gleiche Problem scheint zu sein, wie ich erlebe;

http://bugs.sun.com/view_bug.do?bug_id=8010197

Wer weiß, wie diese zu lösen? Ich habe in Bibliotheken wie QuaQua geschaut, aber ich würde lieber keine Bibliothek verwenden, weil ich nur die Blatt-Funktionalität will.

Update 2

Ich versuchte Quaqua, aber die Bibliothek derzeit genau das gleiche Problem, wenn es mit Java 7. Alle Abhilfen Kompilieren?

aktualisieren 3

Ersetzt Code mit Beispielarbeits (http://pastebin.com/PJ8VGdPb)

aktualisieren 4

SWT Fand heraus, hat einen Stil für ihre Shell-Klasse namens SWT.SHEET, die funktioniert immer noch in Java7, ich bevorzuge nicht eine Bibliothek wie SWT, aber es scheint die einzige Lösung zu sein.

+0

Für bessere Hilfe, früher, ein [SSCCE] (http://sscce.org/). –

+0

Auf Ihre Anfrage; Sehen Sie sich den Pastbin-Link für ein funktionierendes Beispiel an. – Thys

+0

Wenn es ein SSCCE ist, ist es kurz genug, um direkt in der Frage zu schreiben. –

Antwort

2

Soweit ich weiß, hat Apple nicht offiziell ihre Version von JDK 7 veröffentlicht. Die neueste Version des JDK Apple hat für ihr OS X optimiert ist immer noch JDK 6. Das ist auch der Grund, warum Updates für Java durch AppStore-Aktualisierungsregisterkarte. Diese Updates kommen nicht direkt von Oracle.

Wenn Sie JDK 7 direkt von Oracle heruntergeladen haben, handelt es sich um eine allgemeinere, nicht optimierte Version.

Also, ich glaube, Sie müssen nur warten, für Apple ihre OS X freizugeben JDK optimiert 7.

Ich erlebte arbeiten viele OS X verfügt nicht, wenn ich von Oracle herunterladen:

  • Trackpad Gesten
  • Natives Aqua Look'n'Feel funktioniert nicht, auch wenn Sie versuchen, es manuell über UIManager einzustellen.
  • Anwendungssymbol funktioniert nicht, wenn JOptionPane verwendet wird.
  • JMenus werden in den JFrame selbst eingefügt, anstatt zum oberen Bildschirmrand zu wechseln.
+0

Sie könnten eine Weile auf ein Apple JDK warten. :) – Trejkaz

1

Es scheint, bevor JDK den Fehler beheben, müssen Sie das Blatt selbst implementieren.

Die wichtigsten Punkte sind:

  1. die Glasscheibe des Fensterrahmens Verwenden Sie das Blatt Dialog
  2. Verwenden Sie das GridBagLayout (mit NORTH Anker) setzen den Dialog oben zu halten | Zentrum der Scheibe
  3. das Blatt Animieren, wenn Show/disappeare durch den Dialog immer wieder zu malen, jedes Mal mehr/weniger Teil des Dialogs

die folgende malen ist die exampl e Code

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.GraphicsConfiguration; 
import java.awt.GraphicsEnvironment; 
import java.awt.GridBagConstraints; 
import java.awt.GridBagLayout; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.image.BufferedImage; 

import javax.swing.Box; 
import javax.swing.JComponent; 
import javax.swing.JDialog; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.Timer; 
import javax.swing.border.LineBorder; 

public class SheetableJFrame extends JFrame implements ActionListener { 

    public static final int INCOMING = 1; 
    public static final int OUTGOING = -1; 
    public static final float ANIMATION_DURATION = 1000f; 
    public static final int ANIMATION_SLEEP = 50; 

    JComponent sheet; 
    JPanel glass; 
    Sheet animatingSheet; 
    boolean animating; 
    int animationDirection; 
    Timer animationTimer; 
    long animationStart; 
    BufferedImage offscreenImage; 

    public SheetableJFrame() { 
     super(); 
     glass = (JPanel) getGlassPane(); 
     glass.setLayout(new GridBagLayout()); 
     animatingSheet = new Sheet(); 
     animatingSheet.setBorder(new LineBorder(Color.black, 1)); 
    } 

    public JComponent showJDialogAsSheet(JDialog dialog) { 
     sheet = (JComponent) dialog.getContentPane(); 
     sheet.setBorder(new LineBorder(Color.black, 1)); 
     glass.removeAll(); 
     animationDirection = INCOMING; 
     startAnimation(); 
     return sheet; 
    } 

    public void hideSheet() { 
     animationDirection = OUTGOING; 
     startAnimation(); 
    } 

    private void startAnimation() { 
     glass.repaint(); 
     // clear glasspane and set up animatingSheet 
     animatingSheet.setSource(sheet); 
     glass.removeAll(); 
     GridBagConstraints gbc = new GridBagConstraints(); 
     gbc.anchor = GridBagConstraints.NORTH; 
     glass.add(animatingSheet, gbc); 
     gbc.gridy = 1; 
     gbc.weighty = Integer.MAX_VALUE; 
     glass.add(Box.createGlue(), gbc); 
     glass.setVisible(true); 

     // start animation timer 
     animationStart = System.currentTimeMillis(); 
     if (animationTimer == null) animationTimer = new Timer(ANIMATION_SLEEP, this); 
     animating = true; 
     animationTimer.start(); 
    } 

    private void stopAnimation() { 
     animationTimer.stop(); 
     animating = false; 
    } 

    // used by the Timer 
    public void actionPerformed(ActionEvent e) { 
     if (animating) { 
      // calculate height to show 
      float animationPercent = (System.currentTimeMillis() - animationStart)/ANIMATION_DURATION; 
      animationPercent = Math.min(1.0f, animationPercent); 
      int animatingHeight = 0; 

      if (animationDirection == INCOMING) { 
       animatingHeight = (int) (animationPercent * sheet.getHeight()); 
      } else { 
       animatingHeight = (int) ((1.0f - animationPercent) * sheet.getHeight()); 
      } 
      // clip off that much from sheet and put it into animatingSheet 
      animatingSheet.setAnimatingHeight(animatingHeight); 
      animatingSheet.repaint(); 

      if (animationPercent >= 1.0f) { 
       stopAnimation(); 
       if (animationDirection == INCOMING) { 
        finishShowingSheet(); 
       } else { 
        glass.removeAll(); 
        glass.setVisible(false); 
       } 
      } 
     } 
    } 

    private void finishShowingSheet() { 
     glass.removeAll(); 
     GridBagConstraints gbc = new GridBagConstraints(); 
     gbc.anchor = GridBagConstraints.NORTH; 
     glass.add(sheet, gbc); 
     gbc.gridy = 1; 
     gbc.weighty = Integer.MAX_VALUE; 
     glass.add(Box.createGlue(), gbc); 
     glass.revalidate(); 
     glass.repaint(); 
    } 

    class Sheet extends JPanel { 
     Dimension animatingSize = new Dimension(0, 1); 
     JComponent source; 
     BufferedImage offscreenImage; 

     public Sheet() { 
      super(); 
      setOpaque(true); 
     } 

     public void setSource(JComponent source) { 
      this.source = source; 
      animatingSize.width = source.getWidth(); 
      makeOffscreenImage(source); 
     } 

     public void setAnimatingHeight(int height) { 
      animatingSize.height = height; 
      setSize(animatingSize); 
     } 

     private void makeOffscreenImage(JComponent source) { 
      GraphicsConfiguration gfxConfig = GraphicsEnvironment.getLocalGraphicsEnvironment() 
        .getDefaultScreenDevice().getDefaultConfiguration(); 
      offscreenImage = gfxConfig.createCompatibleImage(source.getWidth(), source.getHeight()); 
      Graphics2D offscreenGraphics = (Graphics2D) offscreenImage.getGraphics(); 
      source.paint(offscreenGraphics); 
     } 

     public Dimension getPreferredSize() { 
      return animatingSize; 
     } 

     public Dimension getMinimumSize() { 
      return animatingSize; 
     } 

     public Dimension getMaximumSize() { 
      return animatingSize; 
     } 

     public void paint(Graphics g) { 
      // get the bottom-most n pixels of source and paint them into g, where n is height 
      BufferedImage fragment = offscreenImage.getSubimage(0, offscreenImage.getHeight() - animatingSize.height, 
        source.getWidth(), animatingSize.height); 
      g.drawImage(fragment, 0, 0, this); 
     } 
    } 
} 

Der Testcode

import java.beans.PropertyChangeEvent; 
import java.beans.PropertyChangeListener; 

import javax.swing.JDialog; 
import javax.swing.JOptionPane; 

public class SheetTest extends Object implements PropertyChangeListener { 

    JOptionPane optionPane; 
    SheetableJFrame frame; 

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

    public SheetTest() { 
     frame = new SheetableJFrame(); 
     // build JOptionPane dialog and hold onto it 
     optionPane = new JOptionPane("Do you want to close?", JOptionPane.QUESTION_MESSAGE, JOptionPane.CANCEL_OPTION); 
     frame.setSize(640, 480); 
     frame.setVisible(true); 
     optionPane.addPropertyChangeListener(this); 

     JDialog dialog = optionPane.createDialog(frame, "irrelevant"); 
     frame.showJDialogAsSheet(dialog); 
    } 

    public void propertyChange(PropertyChangeEvent pce) { 
     if (pce.getPropertyName().equals(JOptionPane.VALUE_PROPERTY)) { 
      System.out.println("Selected option " + pce.getNewValue()); 
      frame.hideSheet(); 
     } 
    } 
} 

Referenz
http://oreilly.com/pub/h/4852
http://book.javanb.com/swing-hacks/swinghacks-chp-6-sect-6.html

0

Hier ist ein super zwielichtigen Hack, den ich mit dem die Flagge der JDK jetzt die Sets kam scheint zu vergessen zu setzen und das Fenster manuell zu positionieren am richtigen Platz. Es gibt jedoch immer noch einen fehlenden Schatten, also frage ich mich, ob irgendjemand es verbessern kann. ;)

Dies verwirrt interne Klassen und private Felder, so dass es in jeder gegebenen neuen Version des JDK brechen kann, aber es funktioniert immer noch auf 8u5. Vielleicht wird es einen Einblick geben, wie diese internen AWT-Klassen strukturiert sind.

public static void makeSheet(Dialog dialog) { 
    dialog.addNotify(); 
    ComponentPeer peer = dialog.getPeer(); 

    // File dialogs are CFileDialog instead. Unfortunately this means this hack 
    // can't work for those. :(
    if (peer instanceof LWWindowPeer) { 
     LWWindowPeer windowPeer = (LWWindowPeer) dialog.getPeer(); 
     //XXX: Should check this before casting too. 
     CPlatformWindow platformWindow = (CPlatformWindow) windowPeer.getPlatformWindow(); 
     try { 
      Method method = CPlatformWindow.class.getDeclaredMethod(
       "setStyleBits", int.class, boolean.class); 
      method.setAccessible(true); 
      method.invoke(platformWindow, 64 /* CPlatformWindow.SHEET */, true); 

      Window parent = dialog.getOwner(); 
      dialog.setLocation(dialog.getLocation().x, 
           parent.getLocation().y + parent.getInsets().top); 
     } catch (Exception e) { 
      Logger.getLogger(SheetHack.class.getName()) 
       .log(Level.WARNING, "Couldn't call setStyleBits", e); 
     } 
    } 
}