5

矢印、丸みを帯びた角、そして時間があれば影の効果を備えた Google Chrome のお気に入りスタイルのポップオーバーを作成したいと思います。Java Swing で。最善のアプローチは何ですか?スプラッシュスクリーン? それとも単純なAWT Windowですか? 他のアイデア?ありがとう!

4

1 に答える 1

7

いくつかのオプションがあり、それぞれに長所と短所があります...

  1. カスタム形状のウィンドウを作成する - このアプローチを使用すると、一部のシステムでは形状のウィンドウの背後に追加のシェードを作成できます。また、これはほとんどのシステムで機能します (Linux JDK でも機能するはずです)。このアプローチの悪い点 (実際には使用できなくなります) は、形状の境界線がエイリアス化されていないことです。楕円形のウィンドウを作成すると、その側面が粗くなります。

  2. 描画された形状で不透明で装飾されていないウィンドウを作成します。このアプローチは、(1) アプローチの主な問題を修正します。完全に透明なウィンドウに描画している形状に別名を付けることができます。これの悪い点は、Win および Mac システムでしか機能しないことです。(ほとんどの) どの Linux システムでも、長方形のウィンドウが表示され、サポートされていない操作に関する大量のエラーが表示されます。

  3. java-window 内にカスタム形状のポップアップを作成し、レイヤード ウィンドウまたはガラス ペインに配置します。これにより、互換性の問題を完全に回避し、(2) のアプローチの利点を得ることができます。ただし、このアプローチには悪い点があります。このようなポップアップは、ウィンドウのルート ペインの境界にしか表示できません。これは、ほとんどの場合、他の 2 つの方法よりもはるかに優れています。これは、使用するリソースが少なく、追加のウィンドウが作成されず、ポップアップのすべての部分を制御できるためです。

3番目のアプローチについて-自分のプロジェクトWebLookAndFeelで作成したTooltipManagerを確認できます-ウィンドウガラスペインを使用して、カスタム形状の半透明のツールチップをシャドウ効果で表示します。また、すぐにウィンドウ PopupManager を追加して、「内部」ウィンドウ ポップアップをすばやく作成できるようにします。

アプローチの例を次に示します。

すべての例で使用されたコードの一部

シェイプの作成方法:

private static Area createShape ()
{
    Area shape = new Area ( new RoundRectangle2D.Double ( 0, 20, 500, 200, 20, 20 ) );

    GeneralPath gp = new GeneralPath ( GeneralPath.WIND_EVEN_ODD );
    gp.moveTo ( 230, 20 );
    gp.lineTo ( 250, 0 );
    gp.lineTo ( 270, 20 );
    gp.closePath ();
    shape.add ( new Area ( gp ) );

    return shape;
}

コンポーネントをドラッグしてウィンドウを移動できるマウス アダプタ:

public static class WindowMoveAdapter extends MouseAdapter
{
    private boolean dragging = false;
    private int prevX = -1;
    private int prevY = -1;

    public WindowMoveAdapter ()
    {
        super ();
    }

    public void mousePressed ( MouseEvent e )
    {
        if ( SwingUtilities.isLeftMouseButton ( e ) )
        {
            dragging = true;
        }
        prevX = e.getXOnScreen ();
        prevY = e.getYOnScreen ();
    }

    public void mouseDragged ( MouseEvent e )
    {
        if ( prevX != -1 && prevY != -1 && dragging )
        {
            Window w = SwingUtilities.getWindowAncestor ( e.getComponent () );
            if ( w != null && w.isShowing () )
            {
                Rectangle rect = w.getBounds ();
                w.setBounds ( rect.x + ( e.getXOnScreen () - prevX ),
                        rect.y + ( e.getYOnScreen () - prevY ), rect.width, rect.height );
            }
        }
        prevX = e.getXOnScreen ();
        prevY = e.getYOnScreen ();
    }

    public void mouseReleased ( MouseEvent e )
    {
        dragging = false;
    }
}

最初のアプローチの例:

public static void main ( String[] args )
{
    JFrame frame = new JFrame ();
    frame.setUndecorated ( true );

    JPanel panel = new JPanel ();
    panel.setBackground ( Color.BLACK );
    WindowMoveAdapter wma = new WindowMoveAdapter ();
    panel.addMouseListener ( wma );
    panel.addMouseMotionListener ( wma );
    frame.getContentPane ().add ( panel );

    Area shape = createShape ();
    AWTUtilities.setWindowShape ( frame, shape );
    frame.setSize ( shape.getBounds ().getSize () );
    frame.setLocationRelativeTo ( null );

    frame.setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE );
    frame.setVisible ( true );
}

ご覧のとおり、丸みを帯びた形状の角はかなり荒く、見栄えがよくありません

2番目のアプローチ:

public static void main ( String[] args )
{
    JFrame frame = new JFrame ();
    frame.setUndecorated ( true );

    final Area shape = createShape ();
    JPanel panel = new JPanel ()
    {
        protected void paintComponent ( Graphics g )
        {
            super.paintComponent ( g );

            Graphics2D g2d = ( Graphics2D ) g;
            g2d.setRenderingHint ( RenderingHints.KEY_ANTIALIASING,
                    RenderingHints.VALUE_ANTIALIAS_ON );

            g2d.setPaint ( Color.BLACK );
            g2d.fill ( shape );
        }
    };
    panel.setOpaque ( false );
    WindowMoveAdapter wma = new WindowMoveAdapter ();
    panel.addMouseListener ( wma );
    panel.addMouseMotionListener ( wma );
    frame.getContentPane ().add ( panel );

    AWTUtilities.setWindowOpaque ( frame, false );
    frame.setSize ( shape.getBounds ().getSize () );
    frame.setLocationRelativeTo ( null );

    frame.setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE );
    frame.setVisible ( true );
}

これで完璧に見えるはずです。唯一の問題は、Windows と Mac (少なくとも 1.6.x JDK) でのみ正しく動作することです。前回、さまざまなOSで確認したのは、少なくとも約1か月前でした。

3番目のアプローチ

public static void main ( String[] args )
{
    JFrame frame = new JFrame ();

    JPanel panel = new JPanel ( new BorderLayout () );
    panel.setOpaque ( false );
    WindowMoveAdapter wma = new WindowMoveAdapter ();
    panel.addMouseListener ( wma );
    panel.addMouseMotionListener ( wma );
    frame.getContentPane ().add ( panel );

    panel.add ( new JButton ( "Test" ) );

    final Area shape = createShape ();

    JPanel glassPane = new JPanel ( null )
    {
        public boolean contains ( int x, int y )
        {
            // This is to avoid cursor and mouse-events troubles
            return shape.contains ( x, y );
        }
    };
    glassPane.setOpaque ( false );
    frame.setGlassPane ( glassPane );
    glassPane.setVisible ( true );

    JComponent popup = new JComponent ()
    {
        protected void paintComponent ( Graphics g )
        {
            super.paintComponent ( g );

            Graphics2D g2d = ( Graphics2D ) g;
            g2d.setRenderingHint ( RenderingHints.KEY_ANTIALIASING,
                    RenderingHints.VALUE_ANTIALIAS_ON );

            g2d.setPaint ( Color.BLACK );
            g2d.fill ( shape );
        }
    };
    popup.addMouseListener ( new MouseAdapter ()
    {
        // To block events on the popup
    });
    glassPane.add ( popup );
    popup.setBounds ( shape.getBounds () );
    popup.setVisible ( true );

    frame.setSize ( 800, 500 );
    frame.setLocationRelativeTo ( null );

    frame.setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE );
    frame.setVisible ( true );
}

これは、ガラス板に配置されたポップアップの簡単な例です。ご覧のとおり、JFrame 内にのみ存在しますが、エイリアス側があり、どのタイプの OS でも適切に動作します。

于 2012-04-11T06:32:28.790 に答える