Как получить оптимальный размер пользовательского компонента? - PullRequest
0 голосов
/ 01 июля 2018

Я написал пользовательский компонент:

public class ImageView extends JComponent {

    private BufferedImage mImage;

    public ImageView() {
        this(480, 320);
    }



    public ImageView(int width, int height) {
        mImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        clear();
    }



    public BufferedImage getImage() {
        return mImage;
    }

    public void setImage(BufferedImage image) {
        mImage = image;
    }

    public void clear() {
        Graphics g = mImage.getGraphics();
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, mImage.getWidth(), mImage.getHeight());
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(mImage.getWidth(), mImage.getHeight());
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(Color.white);
        g.fillRect(0, 0, getWidth(), getHeight());
        int x = (getWidth() - mImage.getWidth()) / 2;
        int y = (getHeight() - mImage.getHeight()) / 2;
        g.drawImage(mImage, x, y,this);
    }
}

Но как я могу инициализировать mImage с оптимальным размером, чтобы он был такого же размера, как мой компонент, если пользователь вызвал конструктор по умолчанию?

1 Ответ

0 голосов
/ 02 июля 2018

Хотя ваш вопрос немного расплывчатый, я «думаю», что он идет по пути того, о чем вы просите ...

public class ImageView extends JComponent {

    protected static final Dimension DEFAULT_SIZE = new Dimension(480, 320);
    private BufferedImage mImage;

    public ImageView() {
        setBackground(Color.WHITE);
    }

    public ImageView(int width, int height) {
        this();
        mImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        clear();
    }

    public BufferedImage getImage() {
        return mImage;
    }

    public void setImage(BufferedImage image) {
        mImage = image;
    }

    public void clear() {
        if (mImage == null) {
            return;
        }
        Graphics g = mImage.getGraphics();
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, mImage.getWidth(), mImage.getHeight());
        g.dispose();
    }

    @Override
    public Dimension getPreferredSize() {
        return mImage == null ? DEFAULT_SIZE : new Dimension(mImage.getWidth(), mImage.getHeight());
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (mImage == null) {
            return;
        }
        //g.setColor(Color.white);
        //g.fillRect(0, 0, getWidth(), getHeight());
        int x = (getWidth() - mImage.getWidth()) / 2;
        int y = (getHeight() - mImage.getHeight()) / 2;
        g.drawImage(mImage, x, y,this);
    }
}

Обычно, когда mImage равен null, он возвращает предварительно определенное DEFAULT_SIZE компонента (а также не рисует изображение)

Нет, я хочу получить размер, который менеджер родительского макета установит для моего компонента. Если мой компонент заполнит все доступное пространство, которое было предоставлено менеджером макета, я хочу получить размер этого пространства. То есть Я могу установить в конструкторе по умолчанию размер изображения 300x300, но мой компонент будет иметь размер 400x300, потому что менеджер компоновки позволял заполнять большее пространство. Как я могу получить размер, который будет иметь мой компонент после запуска.

До тех пор, пока компонент не будет физически размещен родительским контейнером, нет способа узнать, какого размера он ему даст. Вы можете отслеживать изменения на setBounds, но я склонен находить invalidate лучший выбор (ИМХО).

Проблема в том, что все эти методы можно вызывать несколько раз в быстрой последовательности, поэтому, если вы выполняете операции, которые занимают время или требуют большого объема памяти, лучше использовать какой-то «отложенный обратный вызов». ", заставляя пройти необходимое количество времени, прежде чем выполнить требуемое действие.

Я склонен использовать Swing Timer, чтобы сделать это, просто он вызывает ActionListener на EDT, делая безопасным обновление пользовательского интерфейса из

public class ImageView extends JComponent {

    protected static final Dimension DEFAULT_SIZE = new Dimension(480, 320);
    private BufferedImage mImage;

    private  Timer invalidationTimer;

    public ImageView() {
        setBackground(Color.WHITE);
        invalidationTimer = new Timer(100, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                stateInvalidated();
            }
        });
        invalidationTimer.setRepeats(false);
    }

    public ImageView(int width, int height) {
        this();
        mImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        clear();
    }

    @Override
    public void invalidate() {
        super.invalidate(); 
        invalidationTimer.restart();
    }

    protected void stateInvalidated() {
        System.out.println(getWidth() + "x" + getHeight());
    }

    public BufferedImage getImage() {
        return mImage;
    }

    public void setImage(BufferedImage image) {
        mImage = image;
    }

    public void clear() {
        if (mImage == null) {
            return;
        }
        Graphics g = mImage.getGraphics();
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, mImage.getWidth(), mImage.getHeight());
        g.dispose();
    }

    @Override
    public Dimension getPreferredSize() {
        return mImage == null ? DEFAULT_SIZE : new Dimension(mImage.getWidth(), mImage.getHeight());
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (mImage == null) {
            return;
        }
        //g.setColor(Color.white);
        //g.fillRect(0, 0, getWidth(), getHeight());
        int x = (getWidth() - mImage.getWidth()) / 2;
        int y = (getHeight() - mImage.getHeight()) / 2;
        g.drawImage(mImage, x, y, this);
    }
}
...