4

変更できないオブジェクトがある場合、インジェクションを使用せずにそのメソッドをJPanel変更する方法はありますか?paintComponent

私が考えていた 1 つのアプローチは、JPanelGraphicsオブジェクトを取得し、それを に渡し、paintComponent()このGraphicsオブジェクトに対して操作を実行し、最後にそれを自分のカスタム でペイントすることJPanelでした。JPanelこれに関する問題は、元のpaintComponent()が呼び出されるたびにこれを実行できるようにする必要があることです。

paintComponent() の内容を置き換える必要はありません。追加するだけで済みます。

例えば:

JFrame frame = null;
for (Frame f : JFrame.getFrames()) {
  if (((JFrame) f).getTitle().equals("Title")) {
    JPanel panel = null;
    // ... Cycle through all components and get the one that's a JPanel

    // I want to use ColorConvertOp to make panel greyscale
  }
}
4

4 に答える 4

6

1 つのアプローチは、Decorator パターンを使用して既存のクラスをラップすることです。その後、デコレーターは paintComponent を実装して、最初に元のコンポーネントにデリゲートし、その後でその上にペイントすることができます。このアプローチでは、実際にコンポーネントの作成を制御する必要があります。または、コンポーネント階層が作成された後にコンポーネントを置き換える必要があります (親コンテナーの getComponents() を使用して、変更するコンポーネントを見つけます)。

于 2012-07-30T17:46:58.787 に答える
5

1つの可能性は、aを使用してGlassPane、それをあなたの真上に配置することだと思いますJPanel(パネルがその位置を変更した場合は、リスナーを使用してパネルに追従させることができます)。次に、ガラス板に自分のものを描くだけで、オーバーレイされます。

もちろん、これは本当にエレガントではありません...しかし、paintComponentsインジェクションなしで既存のインスタンスの動作を変更する可能性はありません。(私が間違っていることを証明してください、この世界のJavaオタク!:P)

于 2012-07-30T17:24:04.927 に答える
3

これで@Durandalの答えが完成すると思います:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class TestPanels {

    private static final boolean GRAY_SCALE = true;

    protected void initUI() {
        final JFrame frame = new JFrame(TestPanels.class.getSimpleName());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JPanel unmodifiablePanel = new JPanel(new GridBagLayout());
        JLabel label = new JLabel("Some unmodifiable test label");
        unmodifiablePanel.add(label);
        unmodifiablePanel.setBackground(Color.GREEN);
        JPanel wrappingPanel = new JPanel(new BorderLayout()) {
            private ColorConvertOp op = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
            private BufferedImage image;

            @Override
            public void paint(Graphics g) {
                if (!GRAY_SCALE) {
                    super.paint(g);
                    return;
                }
                BufferedImage bi = getImage();
                if (bi != null) {
                    Graphics big = bi.createGraphics();
                    super.paint(big);
                    big.dispose();
                    bi = op.filter(bi, null);
                    g.drawImage(bi, 0, 0, null);
                }
            }

            protected BufferedImage getImage() {
                if (image == null) {
                    if (getWidth() > 0 && getHeight() > 0) {
                        image = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
                    }
                } else if (image.getWidth() != getWidth() || image.getHeight() != image.getHeight()) {
                    image = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
                }
                return image;
            }

        };
        wrappingPanel.add(unmodifiablePanel);

        frame.add(wrappingPanel);
        frame.setSize(200, 200);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new TestPanels().initUI();
            }
        });
    }
}

GRAY_SCALE フラグを false にすると、通常のレンダリング方法を確認できます。

于 2012-07-30T19:20:30.577 に答える
1

クラスの構成を変更する機能がある場合は、そのクラスを拡張してからsuper.paintComponent(g)、拡張クラスを呼び出すことができます。例:

public class NewPanel extends OldPanel{

    public void paintComponent(Graphics g){
        super.paintComponent(g);
        // Insert additional painting here
    }
}

この場合、既存のクラスのペイントを構築するために、新しいクラスが必要になります。

これが行うことは、親クラスのペイントで行われたすべてを実行し、さらに多くのことを行うオプションを提供することです(これはあなたが探しているもののようです)。

編集
しかし...あなたがこれにアクセスできないことを考えると、あなたのオプションはより制限されます。パネルがnullレイアウトマネージャーを使用している場合は、親の上にペイントする子jpanelを追加できます(ただし、レイアウトマネージャーは、子がペイントできる領域の量を制限します)。これはロングショットです。

リフレクションを使用することもできますが、(バイトコードインジェクション以外の)唯一のオプションです。これはバイトコードインジェクションと同じくらい醜いようです-これがあなたがやろうとしていることのまともな概要です: Javaリフレクション:実行時にメソッドをオーバーライドまたは生成するにはどうすればよいですか?

私の個人的な好みは、クラスを逆コンパイルし、必要に応じて変更し、再コンパイルして、元のjarに挿入し直すことです。これはおそらくいくつかの保証やライセンスを無効にし、他の問題に巻き込まれるでしょう...しかし少なくともそれは維持可能です。

于 2012-07-30T17:14:34.113 に答える