2013-07-24 13 views
11

Obecnie używam tego kodu, aby utworzyć JDialog;Wyświetlanie JDialog jako arkusza nie działa

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

byłem poprzednio przy użyciu Java 6 skompilować aplikację i ustawiania clientProperty apple.awt.documentModalSheet pracował idealnie, aby wyświetlić okno dialogowe jako „arkusz” na OSX, ale teraz zacząłem używać Java 7 (update 25) i okno nie jest już wyświetlany jako arkusz. Nie mogę znaleźć żadnej aktualizacji dokumentacji na ten temat. Czy oni zmienili coś na ten temat? Jak mogę to rozwiązać? Bieżący projekt interfejsu wygląda lepiej z arkuszem niż z dialogiem.

Aktualizacja

znalazłem następujący raport o błędzie, który wydaje się być taki sam problem jak ja przeżywa;

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

Czy ktoś wie jak rozwiązać ten problem? Zajrzałem do bibliotek takich jak QuaQua, ale wolałbym nie używać żadnej biblioteki, ponieważ po prostu chcę funkcji arkusza.

Aktualizacja 2

Próbowałem QuaQua, ale biblioteka obecnie ma dokładnie ten sam problem przy kompilacji z Java 7. żadnego obejścia?

Aktualizacja 3

kod Zastąpiony z próbki pracy (http://pastebin.com/PJ8VGdPb)

Aktualizacja 4

Okazało się SWT ma styl dla swojej klasy Shell nazwie SWT.SHEET który nadal pracuje w Java7, wolę nie używać biblioteki takiej jak SWT, ale wydaje się, że jest to jedyne rozwiązanie.

+0

Aby uzyskać lepszą pomoc wcześniej, opublikuj [SSCCE] (http://sscce.org/). –

+0

Na życzenie; zobacz link do pastbin dla działającej próbki. – Thys

+0

Jeśli jest to SSCCE, jest wystarczająco krótkie, aby opublikować bezpośrednio w pytaniu. –

Odpowiedz

2

O ile mi wiadomo, Apple oficjalnie nie wydało swojej wersji JDK 7. Najnowsza wersja JDK Apple zoptymalizowana pod kątem OS X to nadal JDK 6. Dlatego też aktualizacje Java przechodzą Aktualizacja aplikacji AppStore. Te aktualizacje nie pochodzą bezpośrednio od Oracle.

Po pobraniu JDK 7 bezpośrednio z Oracle, jest to wersja bardziej ogólna, niezmodyfikowana.

Tak, myślę, że po prostu trzeba poczekać do Apple, aby zwolnić ich OS X zoptymalizowany JDK 7.

przeżyłem wiele OS X wyposażony, aby nie pracować, kiedy pobrać z Oracle:

  • Gesty na gładziku
  • Natywny wygląd Aqua Look'n'Feel nie działa, nawet przy próbie ustawienia ręcznie przez UIManager.
  • Ikona aplikacji nie działa podczas korzystania z JOptionPane.
  • JMenu będzie trzymać się JFrame zamiast przenosić się na górę ekranu.
+0

Być może czekasz chwilę na Apple JDK. :) – Trejkaz

1

Wydaje się, że zanim JDK naprawi błąd, musisz sam zaimplementować Arkusz.

Kluczowe punkty to:

  1. Użyj szyby w ramie okiennej trzymać arkusz dialogowe
  2. Użyj GridBagLayout (z NORTH kotwicy), aby umieścić okno na górze | centrum okienku
  3. Animacja płyty, kiedy pokaz/disappeare malując okno wielokrotnie, za każdym razem malować więcej/mniej części okna dialogowego

Poniżej jest exampl Kod e

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

Kod testu

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

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

0

Oto bardzo sprytny Hack wymyśliłem który ustawia flagę której JDK teraz wydaje się zapominać, aby ustawić i ręcznie pozycjonuje okno w odpowiednim miejscu. Wciąż brakuje cienia, więc zastanawiam się, czy ktoś może go ulepszyć. ;)

To męczące z klasami wewnętrznymi i polami prywatnymi, więc może się zepsuć w każdej nowej wersji JDK, ale nadal działa na 8u5. Może da wgląd w sposób, w jaki są zbudowane te wewnętrzne klasy AWT.

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); 
     } 
    } 
} 
Powiązane problemy