24

JWindow共有する画面の領域を選択するために、に基づいてカスタムUIを作成しようとしています。JWindowサイズを変更し、を使用してウィンドウの中央を「切り取る」ために、コードを拡張して追加しましAWTUtilities.setWindowShape()た。

コードを実行すると、ウィンドウが負のx方向とy方向、つまり上下にサイズ変更されるため、ちらつきが発生します。発生しているように見えるのは、コンポーネントが更新される前にウィンドウのサイズが変更されて描画されることです。以下は、コードの簡略化されたバージョンです。実行すると、トップパネルを使用してウィンドウのサイズを左上に変更できます。ウィンドウの背景は緑色に設定されており、表示したくないピクセルがどこにあるかが明確になっています。

編集:を使用してウィンドウを正しく整形するようにコードを改善し、ComponentListenerちらつきをさらに説明するために下部にダミーコンポーネントを追加しました(スクリーンショットも更新されました)。

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Area;

import javax.swing.JPanel;
import javax.swing.JWindow;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.EtchedBorder;
import javax.swing.border.LineBorder;

import com.sun.awt.AWTUtilities;

public class FlickerWindow extends JWindow implements MouseListener, MouseMotionListener{

    JPanel controlPanel;
    JPanel outlinePanel;
    int mouseX, mouseY;
    Rectangle windowRect;
    Rectangle cutoutRect;
    Area windowArea;

    public static void main(String[] args) {
        FlickerWindow fw = new FlickerWindow();
    }

    public FlickerWindow() {
        super();
        setLayout(new BorderLayout());
        setBounds(500, 500, 200, 200);
        setBackground(Color.GREEN);

        controlPanel = new JPanel();
        controlPanel.setBackground(Color.GRAY);
        controlPanel.setBorder(new EtchedBorder(EtchedBorder.LOWERED));
        controlPanel.addMouseListener(this);
        controlPanel.addMouseMotionListener(this);

        outlinePanel = new JPanel();
        outlinePanel.setBackground(Color.BLUE);
        outlinePanel.setBorder(new CompoundBorder(new EmptyBorder(2,2,2,2), new LineBorder(Color.RED, 1)));

        add(outlinePanel, BorderLayout.CENTER);
        add(controlPanel, BorderLayout.NORTH);
        add(new JButton("Dummy button"), BorderLayout.SOUTH);
        setVisible(true);
        setShape();

        addComponentListener(new ComponentAdapter() {           
            @Override
            public void componentResized(ComponentEvent e) {
                setShape();
            }});
    }


    public void paint(Graphics g) {
        // un-comment or breakpoint here to see window updates more clearly
        //try {Thread.sleep(10);} catch (Exception e) {}
        super.paint(g);
    }

    public void setShape() {
        Rectangle bounds = getBounds();
        Rectangle outlineBounds = outlinePanel.getBounds();
        Area newShape = new Area (new Rectangle(0, 0, bounds.width, bounds.height));
        newShape.subtract(new Area(new Rectangle(3, outlineBounds.y + 3, outlineBounds.width - 6, outlineBounds.height - 6)));
        setSize(bounds.width, bounds.height);
        AWTUtilities.setWindowShape(this, newShape);
    }

    public void mouseDragged(MouseEvent e) {
        int dx = e.getXOnScreen() - mouseX;
        int dy = e.getYOnScreen() - mouseY;

        Rectangle newBounds = getBounds();
        newBounds.translate(dx, dy);
        newBounds.width -= dx;
        newBounds.height -= dy;

        mouseX = e.getXOnScreen();
        mouseY = e.getYOnScreen();

        setBounds(newBounds);
    }

    public void mousePressed(MouseEvent e) {
        mouseX = e.getXOnScreen();
        mouseY = e.getYOnScreen();
    }

    public void mouseMoved(MouseEvent e) {}
    public void mouseClicked(MouseEvent e) {}
    public void mouseReleased(MouseEvent e) {}
    public void mouseEntered(MouseEvent e) {}
    public void mouseExited(MouseEvent e) {}
}

オーバーライドさpaint()れたメソッドは、ブレークポイントとして使用するThread.sleep()ことも、コメントを外して、更新が発生したときにそれをより明確に表示することもできます。

私の問題は、setBounds()レイアウトする前にウィンドウを画面にペイントする方法に起因しているようです。


サイズ変更前のウィンドウ。見た目は次のとおりです。

代替テキスト


オーバーライドされたメソッドのブレークポイントで見られるように、サイズ変更中のウィンドウ(上と左)が大きくなりますpaint()):

代替テキスト


オーバーライドされたメソッドのブレークポイントで見られるように、小さいサイズ(下と右)のサイズ変更中のウィンドウpaint()):

代替テキスト


確かに、これらのスクリーンショットは積極的なマウスドラッグの動きの間に撮影されますが、より穏やかなマウスドラッグでもちらつきは非常に厄介になります。

大きなスクリーンショットへのサイズ変更の緑色の領域は、ペイント/レイアウトが完了する前に描画される新しい背景を示しています。これは、基になるComponentPeerウィンドウマネージャーまたはネイティブウィンドウマネージャーで発生しているようです。'サイズ変更'スクリーンショットの青い領域は、JPanel'背景が表示されていることを示していますが、現在は古くなっています。これは、Linux(Ubuntu)およびWindowsXPで発生します。

画面に変更を加える前に、またはをバックバッファにサイズ変更して、このちらつきの影響を回避Windowする方法を見つけた人はいますか?これを回避するために設定できるシステムプロパティJWindowがあるかもしれませんが、見つかりませんでした。java.awt....


編集#2:ちらつきの性質を明確に確認するために、呼び出しをコメントアウトしAWTUtilities.setWindowShape()(オプションでThread.sleep(10)行のコメントを解除しpaint())、トップパネルを積極的にドラッグします。

編集#3: Windows7またはMacOSXのSunJavaでこの動作をテストできる人はいますか?

4

3 に答える 3

3

これは特に役立つ答えではないことは認めますが、正確に Swing とは何かを理解することは役立つかもしれません。

Swing は、OS から実際に少しのスペースを取得する以外は、独自の作業をすべて実行します。すべての描画、ウィジェットなどは Java コードです。2D グラフィックス カード アクセラレーションと OS レンダリング トリックの恩恵を受けずに実行されているため、実行速度が遅いということではありません。

DirectDraw を覚えていますか? 今日ではすべてがそれを備えており、ウィンドウ操作は非常にスムーズです。しかし、何らかの理由でそれがインストールされていないコンピューター (たとえば、ドライバーなしで XP をインストールした場合) を手に入れた場合、まさにこのタイプの速度低下に気付くでしょう。

Swing では、独自のスペースをすべて管理するため、OS はこれらのレンダリング トリックを実行してユーザーを支援することはできません。

誰かがあなたのコンピューターの問題を解決する最適化を行うかもしれませんが、基本的な問題を実際に解決することにはならないのではないかと心配しています.Swingは遅く、速くなりません.

ネイティブ ツールキットを調べる必要があります。AWT は問題ありませんが、多くのウィジェットなどがありません。ネイティブでビルトインなので、それが必要な場合は十分に高速です。私は、Eclipse や Vuze (とりわけ) が使用する SWT に傾倒しています。AWT のネイティブ性と Swing の使いやすさと機能を組み合わせており、もちろんどこでも実行できます。

編集:あなたのコメントをもう少し読んだ後、ウィンドウがどのように発生するかを完全に理解していることは明らかです-私は見下したくありません。それだけでなく、サイズ変更にもっと興味がありますが、これは私のコメントとはあまり関係がありません。ネイティブ コードで高速であるため、SWT をお勧めしますが、それは上記の答えとは異なります。

于 2010-12-04T18:58:36.017 に答える
1

別のアプローチは、ペイントする前に、ユーザーがドラッグ/サイズ変更を完了するのを待つことです。おそらく、バウンディングボックスを使用して、サイズ変更イベントが完了するまでウィンドウのサイズをユーザーに表示します。

多くのウィンドウアプリケーションがそのアプローチを取るか、ちらつきに対処することに気づきました。私が試したほぼすべてのアプリで、同じ問題(Java以外)があるようなアグレッシブなサイズ変更を試みたため、問題はSwing自体ではなくグラフィックサブシステムにある可能性があります。

于 2010-12-02T16:53:26.650 に答える
1

私はあなたの例を試しました。ウィンドウのサイズを変更するときに、小さなフリックが実際に見られました。setBounds()で始まり、で終わるコードフラグメントを置き換えようとしましAWTUtilities.setWindowShape(this, newShape);

setSize(newBounds.width, newBounds.height);

フリックが消えたのを見ました。したがって、特別な理由がない限り、このソリューションをお勧めしますsetBounds

于 2010-12-01T12:46:32.353 に答える