Переместите jcomponent назад без использования JLayeredPane

Я написал DragAndDrop MouseListener.

Компонент A — это фоновое изображение, которое находится за компонентом B. Оба они расположены на панели JPanel.

Я сделал изображение перетаскиваемым. Однако я хочу, чтобы изображение оставалось за компонентом B, когда я его перетаскиваю.

Однако каждый раз, когда я перетаскиваю изображение, я полагаю, что Java выделяет ему фокус или что-то в этом роде, поэтому оно выводится на передний план.

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

Я знаю, что могу использовать JLayeredPane и использовать метод moveToBack каждый раз, когда я перетаскиваю, но я бы предпочел не использовать JLayeredPane и просто использовать JPanel. Есть ли эквивалент moveToBack для JPanel?

Или есть способ заставить компонент сохранить текущий слой (возможно, не получить фокус), чтобы я мог перетаскивать его в текущий слой?

ВОТ ПРИМЕР

import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

import javax.swing.JButton;
import javax.swing.JFrame;

public class OverlapTester extends JFrame {
public static final long serialVersionUID = 172L;



public static void main(String[] args) {
    
    
    OverlapTester frame = new OverlapTester();
    
    frame.initialize();

    
}

public void initialize() {
    setLayout(null);
    
    JButton bottom = new JButton("bottom");
    JButton top = new JButton("top");
    bottom.setBounds(0,0,100,100);
    top.setBounds(0,0,50,50);
    
    add(top);
    add(bottom);
    
    int bottomZOrder = 0;

    
    bottom.addMouseListener(new MouseListener(){
        @Override
        public void mouseEntered(MouseEvent e) {
            e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
        }
        @Override
        public void mouseExited(MouseEvent e) {
            e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
        }
        @Override
        public void mouseReleased(MouseEvent e) {
            e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
        }
        @Override
        public void mousePressed(MouseEvent e) {
            e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
        }
        @Override
        public void mouseClicked(MouseEvent e) {
            e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
        }
    });
    
    bottom.addMouseMotionListener(new MouseMotionListener(){
        @Override
        public void mouseDragged(MouseEvent e) {
            e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
        }
        
        @Override
        public void mouseMoved(MouseEvent e) { 
            e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
        }
    });
    
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setExtendedState(MAXIMIZED_BOTH);
    setVisible(true);
}





}

person ThePrince    schedule 21.05.2021    source источник
comment
См.: stackoverflow.com/questions/67630144/. Вы получили ответ на свой последний вопрос и, по-видимому, не прочитали предложение, поскольку вы до сих пор не приняли ответ или не прокомментировали, почему предложение не помогло. Так что я пропущу это. Я подозреваю, что решение будет состоять из одного оператора, но вам нужно опубликовать минимально воспроизводимый пример, чтобы продемонстрировать проблему.   -  person camickr    schedule 22.05.2021


Ответы (1)


Компонент A — это фоновое изображение, которое находится за компонентом B. Оба они расположены на панели JPanel.

Компоненты Swing окрашиваются на основе их ZOrder. Самый высокий ZOrder закрашивается первым.

ZOrder назначается как компонент, добавляемый на панель. Таким образом, первому добавленному компоненту присваивается ZOrder 0, а второму компоненту — ZOrder 1.

Поэтому добавляйте фоновое изображение на панель в последнюю очередь, и оно всегда будет иметь самый высокий ZOrder, что означает, что оно будет прорисовано первым, поэтому другие компоненты будут прорисованы поверх него.

Например:

panel.add(someOtherComponent);
panel.add(background);

Или вы можете использовать:

Container.setComponentZOrder(...)

метод для динамического изменения ZOrder после добавления компонента.

Редактировать:

Ответ, который я дал, заключался в том, что вы были либо/или решением. Вам нужно выбрать только один подход.

  1. Вы правильно реализовали первый подход, который заключается в добавлении фонового компонента последним. Так что нет необходимости играть с ZOrder. Этот подход отлично работает, когда ZOrder остается фиксированным.

  2. Второй подход — это когда вы хотите, чтобы ZOrder динамически изменялся, например, когда у вас есть несколько компонентов, и вы хотите изменить его при взаимодействии с каждым компонентом. Однако вы неправильно реализовали этот подход. Вы использовали 0 для ZOrder, что означает, что компонент всегда будет рисоваться последним и, следовательно, поверх любого другого компонента.

В вашем текущем примере нет необходимости динамически изменять ZOrder, поэтому вы можете удалить весь связанный код.

Как видите, нижняя кнопка последовательно добавляется на передний план.

Отрисовка Swing оптимизирована так, чтобы компоненты не перекрывались.

Однако в случае с JButton у него есть автоматическая логика перерисовки, когда вы наводите курсор на кнопку, чтобы перерисовать границу. Поэтому, когда кнопка перерисовывается, она все равно закрашивается поверх другого компонента.

Поэтому вам нужно указать Swing НЕ оптимизировать рисование. Поэтому, когда один компонент перекрашивается, все они будут перекрашиваться при перекрытии. Вы делаете это, переопределяя метод isOptimizedDrawingEnabled(...), как показано ниже:

import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

import javax.swing.JButton;
import javax.swing.*;

public class OverlapTester extends JFrame {

public static void main(String[] args) {

    OverlapTester frame = new OverlapTester();

    frame.initialize();

}

public void initialize() {

    JPanel contentPane = new JPanel(null)
    {
        @Override
        public boolean isOptimizedDrawingEnabled()
        {
            return false;
        }
    };
    add(contentPane);

//    setLayout(null);

    JButton bottom = new JButton("bottom");
    JButton top = new JButton("top");
    bottom.setBounds(0,0,100,100);
    top.setBounds(0,0,50,50);

//    add(top);
//    add(bottom);
    contentPane.add(top);
    contentPane.add(bottom);

//    int bottomZOrder = 0;
    int bottomZOrder = 1;


    bottom.addMouseListener(new MouseListener(){
        @Override
        public void mouseEntered(MouseEvent e) {
            e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
        }
        @Override
        public void mouseExited(MouseEvent e) {
            e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
        }
        @Override
        public void mouseReleased(MouseEvent e) {
            e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
        }
        @Override
        public void mousePressed(MouseEvent e) {
            e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
        }
        @Override
        public void mouseClicked(MouseEvent e) {
            e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
        }
    });

    bottom.addMouseMotionListener(new MouseMotionListener(){
        @Override
        public void mouseDragged(MouseEvent e) {
            e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
        }

        @Override
        public void mouseMoved(MouseEvent e) {
            e.getComponent().getParent().setComponentZOrder(e.getComponent(), bottomZOrder);
        }
    });

    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setExtendedState(MAXIMIZED_BOTH);
    setVisible(true);
}


}
person camickr    schedule 22.05.2021
comment
Когда я нажимаю и перетаскиваю изображение, оно выдвигается на передний план. Я хочу держать его сзади, пока манипулирую им, но Swing всегда перемещает его вперед. То же самое происходит с другим компонентом - как только я начинаю манипулировать им, он выводится на передний план, и я не хочу, чтобы он это делал. Я хочу программно сохранить его сзади, чтобы этого не произошло. - person ThePrince; 23.05.2021
comment
Здравствуйте, я попробовал ответ, и, хотя он интуитивно понятен, он у меня не работает. Я отредактировал свой исходный вопрос, включив в него работающий пример. Как вы можете видеть, нижняя кнопка постоянно добавляется на передний план, несмотря на попытки сохранить ее внизу. - person ThePrince; 23.05.2021
comment
@ThePrince, именно по этой причине к каждому вопросу должен быть предоставлен минимально воспроизводимый пример. Вы заявили, что пытались отобразить фоновое изображение. Обычно люди используют JLabel для отображения фонового изображения. JButton ведет себя не так, как JLabel, из-за эффекта прокрутки кнопки, поэтому вам нужно добавить дополнительную логику. См. редактирование. - person camickr; 23.05.2021
comment
Да, я работал с JLabel с изображением. Он содержал функциональность DragAndDrop, код которой был немного длиннее. Я ошибочно предположил, что он будет вести себя так же, поскольку у меня был целый пользовательский класс, управляющий функцией перетаскивания. Спасибо за пример, буду тестировать. - person ThePrince; 23.05.2021