Как можно скрыть часть JComponent от Mouseevents? Например, какая-то область JButton не реагирует, все в порядке - PullRequest
1 голос
/ 01 августа 2020

Эта проблема стоила мне много времени, чтобы определить, теперь мне любопытно, что вызывает такое странное поведение:

В этом примере существует класс JFrame, который отображает "страницу" JPanel, которая сама получает ссылка на "родительский" JFrame. Моя ошибка заключалась в том, что я поступил так в процессе создания объектов. ), который иногда отлично реагировал на мышь, иногда совсем не реагировал, а иногда работала только часть поверхности.

Итак, я попытался выделить это в минимальном примере ниже, который я мог продемонстрировать на JRE 1.8, JRE12 и JRE13 на обоих Windows 7 x64 и Windows 10 x64.

Для воспроизведения вам может потребоваться поиграть с размером кнопки вместо JFrame.setSize(). Поведение в моих системах таково, что кнопка очень хорошо реагирует на мышь с некоторой анимацией на mouseEntered, а щелчок мышью запускает ActionEvent. Но не в области фиксированного размера в правом нижнем углу кнопки . Если вы укажете go с помощью мыши, событие не будет запущено. Размер этой «мертвой» области остается постоянным при изменении windows размера и размера компонента, как вы можете попробовать с другим LayoutManagers в коде «страницы».

То же самое относится и к другим JComponents которые запускают события.

Мой вопрос: почему возникла проблема с ActionListening-System. Было бы интуитивно понятно, если бы прослушивание было либо полностью нарушено, либо вообще не было.

Из ответа я надеюсь узнать больше о внутренней генерации событий мыши в JComponents, чтобы быть более бдительными в мои программы будущего.

Вот основной JFRame:

import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class TESTFRAME extends JFrame {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new TESTFRAME();
            }
        });
    }

    public TESTFRAME() {
        super("TESTFRAME");
        PAGE page = new PAGE();
        /*
         * the following line causes very strange behaviour!
         */
        page.setParent(this);

    
        JPanel DISPLAY = new JPanel(new BorderLayout());
        DISPLAY.add(page);
        add(DISPLAY);
        setSize(800, 600);
        setLocationByPlatform(true);
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        setVisible(true);
    }
}

К вашему сведению, проверьте также, что происходит, когда закомментировали строку page.setParent(this);.

и это «страница», которая будет отображаться во фрейме:

import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JPanel;

public class PAGE extends JPanel implements ActionListener {

    public TESTFRAME parent = null;

    public PAGE() {
        // !!! activate the following line setting the GridLayout, to make button large
        // in the bottom right corners, I continue not being able to click
        // setLayout(new GridLayout(1, 0));

        JButton bt_large = new JButton("<html><br>large close button<br><br></html>");
        bt_large.addActionListener(this);
        add(bt_large);

        JButton bt_small = new JButton("small button");
        bt_small.addActionListener(this);
        add(bt_small);
    }

    public TESTFRAME getParent() {
        return parent;
    }

    public void setParent(TESTFRAME parent) {
        this.parent = parent;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("button click received!");
        if (parent != null) {
            parent.dispose();
        }
    }
}

Спасибо за понимание!

1 Ответ

2 голосов
/ 01 августа 2020

Проблема в том, что getParent() является методом класса Component.

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

Попробуйте переименование ваших методов в getParentFrame() и setParentFrame(), чтобы увидеть нормальное поведение.

Однако вам даже не нужны эти методы. Вместо этого вы можете получить доступ к родительскому фрейму панели, используя методы из JDK.

В вашем ActionListener вы можете иметь такой код:

Window window = SwingUtilities.windowForComponent( this );
window.dispose();
...