6

Swing (Java 1.6、Windows) が mouseEntered および mouseExited イベントを希望どおりにトリガーしないように見えるという問題があります。JScrollPane に多数の JPanel を縦に積み重ねたいアプリケーションがあり、マウスがその上にあるときに別の色で強調表示する必要があります。単純な問題ですが、マウスホイールを使用してスクロールするたびに、まったく動作しません。

問題を説明するためにサンプル アプリケーションを作成しました (コードは以下にあります)。以下の画像はその画像であり、「実際の」アプリケーションではありません。

マウス カーソルをパネルの端に置くと、正しく強調表示されます。ここで、マウス ホイールを使用して下にスクロールすると、カーソルがボックス B の上にあり、適切な mouseEntered/mouseExited イベントがトリガーされて、A が白くなり、B が赤くなることが期待されます。

代替テキスト
(出典: perp.se )

代替テキスト
(出典: perp.se )

しかし、それは起こらないようです。

「1ピクセル移動」、「ボタンをクリック」、「別のステップをスクロール」など、別のマウスイベントをトリガーすると、Bが強調表示されます。これを知っていれば、おそらくハック的な方法で解決できるかもしれませんが、適切な解決策がある場合はむしろしたくありません。

だから基本的に私が疑問に思っているのは、これが Swing のバグと見なされるのか、それとも私が間違ったことをしているだけなのかということです。

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;

public class ScrollTest extends JFrame {

    public static class LetterPanel extends JPanel {

        private static final Font BIG_FONT = new Font(Font.MONOSPACED, Font.BOLD, 24);

        public LetterPanel(String text) {
            setBackground(Color.WHITE);
            setBorder(BorderFactory.createLineBorder(Color.BLACK));

            addMouseListener(new MouseAdapter() {

                @Override
                public void mouseEntered(MouseEvent e) {
                    setBackground(Color.RED);
                }

                @Override
                public void mouseExited(MouseEvent e) {
                    setBackground(Color.WHITE);
                }
            });

            setLayout(new GridLayout(1, 1));
            setPreferredSize(new Dimension(-1, 50));

            JLabel label = new JLabel(text, SwingConstants.CENTER);
            label.setFont(BIG_FONT);
            add(label);
        }
    }

    public ScrollTest() {
        setLayout(new GridLayout(1, 1));
        setSize(400, 400);

        JPanel base = new JPanel();

        JScrollPane jsp = new JScrollPane(base);
        jsp.getVerticalScrollBar().setUnitIncrement(16);
        add(jsp);

        base.setLayout(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = 0; 
        gbc.gridheight = 1;
        gbc.gridwidth = 1;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        gbc.insets = new Insets(0, 0, 10, 0);
        gbc.weightx = 1.0;

        for (char c = 'A'; c <= 'Z'; c++) {
            base.add(new LetterPanel(String.valueOf(c)), gbc);
            gbc.gridy++;
        }
    }

    public static void main(String[] args) {
        final JFrame f = new ScrollTest();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        SwingUtilities.invokeLater(new Runnable() {

            public void run() {
                f.setVisible(true);
            }
        });
    }
}
4

2 に答える 2

5

これは、Tooltips and Scrollpanesで説明されている問題と同様の問題のようです。つまり、マウス自体は移動せず、ビューポートが移動するため、マウス イベントは生成されません。マウスの位置でコンポーネントを追跡するために AdjustmentListener を使用する以外の正確な解決策はわかりません。変更するたびに、前のパネルに mouseExited イベントを発生させ、新しいパネルに mouseEntered イベントを発生させることができます。

于 2009-11-20T21:15:49.417 に答える
3

コードでこれを確実に再現できますが、スクロールが完全に完了していない場合に限ります。私のマウスでは、マウス ホイールのスクロールが終了したときに、少なくとも「キャッチ」のようなものがあります。非常にゆっくりスクロールすると移動できますが、マウスホイールが「キャッチ」に達するまでハイライトは変更されません。

これを行うと、前のパネルでマウス入力メッセージが受信されます (表示されているのと同じ動作)。

それを見て、マウスをスクロールしますが、マウスホイールを「キャッチ」するのに十分スクロールしない限り、実際には終了/入力イベントを受け取りません。「キャッチ」が発生するまで、WindowsがメッセージをJavaに送信しない可能性があります...私のテストから、それはどのように見えるかです。

MouseWheelListener インターフェイスと MouseInfo クラスを調べるとよいでしょう。ホイールの動きを検出し、MouseInfo.getPointerInfo().getLocation() を使用して現在の場所を特定し、現在のコンポーネントを特定して強調表示を変更できると思います。

于 2009-11-20T11:01:55.833 に答える