Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/378.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在当前鼠标位置检测图像只对图像的一部分起作用_Java_Swing_Jtextpane - Fatal编程技术网

Java 在当前鼠标位置检测图像只对图像的一部分起作用

Java 在当前鼠标位置检测图像只对图像的一部分起作用,java,swing,jtextpane,Java,Swing,Jtextpane,我有一个可以添加文本的JTextPane,而有些文本通过StyleConstants.setIcon()有一个图像集。我还向JTextPane添加了一个鼠标侦听器,用于检测鼠标何时被单击/悬停在图像上,但它仅在图像的左侧检测到鼠标。我做错什么了吗 SSCCE(将鼠标悬停在图像上会更改鼠标光标以指示何时检测到图像): 您可以使用strongtext.viewToModel(鼠标定位)检测偏移量,然后从获得的偏移量中检索样式 逻辑是将更接近鼠标位置的偏移返回。因此,当您单击视图的右半部分时,将返回

我有一个可以添加文本的JTextPane,而有些文本通过
StyleConstants.setIcon()
有一个图像集。我还向JTextPane添加了一个鼠标侦听器,用于检测鼠标何时被单击/悬停在图像上,但它仅在图像的左侧检测到鼠标。我做错什么了吗

SSCCE(将鼠标悬停在图像上会更改鼠标光标以指示何时检测到图像):


您可以使用strong
text.viewToModel(鼠标定位)
检测偏移量,然后从获得的偏移量中检索样式

逻辑是将更接近鼠标位置的偏移返回。因此,当您单击视图的右半部分时,将返回下一个偏移量(视图后的偏移量)。您可以尝试将相同的设置设置为一个大号字母(例如,使用大字体的m)。在靠近字母的位置单击时,插入符号设置为在字母后面。这里的逻辑是一样的

因此,您在图像之后获得位置,并从位置获取样式,但在图像视图文本元素之后,属性中没有图标,因此您没有图像

更新:

为了提供正确的行为,我建议使用modelToView()并传递获得的偏移量。从矩形中,您可以确定您的cliecked X位置是否<矩形的X。如果插入符号矩形的X大于鼠标X,您可以尝试上一个偏移

UPDATE2:您可以覆盖IconView并使用paint()方法存储图像视图最后绘制的矩形。将最后绘制的矩形存储在地图中。在鼠标移动/单击时,检查地图以确定其中一个矩形是否包含该点

您可以使用视图的方法getChildAllocation()来计算图像边界。从根视图开始,向下移动,直到叶计算X,Y的正确视图。如果叶视图为IconView,则查看图像。

基于此,我更改了SSCCE以实现其第一个解决方案,其中使用
modelToView()
在获得的偏移上检查鼠标位置是否实际位于该偏移上的元素位置上,如果不是,则使用上一个偏移

我不仅检查了x位置,还检查了y位置,因为如果没有其他内容,图像左下方的鼠标位置也可以识别为图像

SSCCE有一个按钮用于启用解决方案,以演示差异:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.JToggleButton;
import javax.swing.SwingUtilities;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.Element;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;

/**
 * SSCCE to show how detecting an image under the current mouse position only
 * works on part of the image. It adds a simple image to the document of the
 * JTextPane and changes the mouse cursor when it detects the mouse hovering
 * over the image.
 * 
 * To demonstrate the difference, you can turn the solution on and off by
 * clicking the button.
 */
public class JTextPaneImage {

    private static boolean enableSolution;

    private static void createWindow() {

        // Create window
        final JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // Create JTextPane and add to window
        final JTextPane textPane = new JTextPane();
        textPane.setEditable(false);
        textPane.addMouseMotionListener(new MouseAdapter() {

            @Override
            public void mouseMoved(MouseEvent e) {
                AttributeSet style = getAttributes(e);
                if (style != null && StyleConstants.getIcon(style) != null) {
                    textPane.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
                } else {
                    textPane.setCursor(Cursor.getDefaultCursor());
                }
            }
        });
        frame.add(new JScrollPane(textPane));

        // Just to disable/enable solution for demonstrating the difference
        final JToggleButton button = new JToggleButton("Enable solution");
        button.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                enableSolution = button.isSelected();
            }
        });
        frame.add(button, BorderLayout.SOUTH);

        // Add some text and images
        try {
            StyledDocument doc = (StyledDocument)textPane.getDocument();

            SimpleAttributeSet style = new SimpleAttributeSet();
            StyleConstants.setIcon(style, createImage());

            doc.insertString(doc.getLength(), "Some text ", null);
            doc.insertString(doc.getLength(), "test", style);
            doc.insertString(doc.getLength(), "abc\n", null);
            doc.insertString(doc.getLength(), "another image", style);
        } catch (BadLocationException ex) {
            Logger.getLogger(JTextPaneImage.class.getName()).log(Level.SEVERE, null, ex);
        }

        // Display everything
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    /**
     * Retrieves the style of where the mouse is positioned (assuming this is
     * a JTextPane).
     * 
     * @param e The mouse event containing the mouse position
     * @return The AttributeSet or null if none could be found
     */
    private static AttributeSet getAttributes(MouseEvent e) {
        JTextPane text = (JTextPane)e.getSource();
        Point mouseLocation = new Point(e.getX(), e.getY());
        int pos = text.viewToModel(mouseLocation);

        if (pos >= 0) {
            if (enableSolution) {

                /**
                 * Solution, this is basicially what is different:
                 * 
                 * Check if the found position is actually located where the
                 * mouse is located, or else use the previous one. It doesn't
                 * only check the x position (which would already help), but
                 * also the y position, because else the area below/left of the
                 * image may also be recognized as image (if there is no other
                 * content there).
                 */
                try {
                    Rectangle rect = text.modelToView(pos);
                    int lowerCorner = rect.y + rect.height;
                    if (e.getX() < rect.x && e.getY() < lowerCorner && pos > 0) {
                        pos--;
                    }
                } catch (BadLocationException ex) {
                    Logger.getLogger(JTextPaneImage.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            StyledDocument doc = text.getStyledDocument();
            Element element = doc.getCharacterElement(pos);
            return element.getAttributes();
        }
        return null;
    }

    /**
     * Creates a single 28x28 image filled with a single color.
     * 
     * @return The created ImageIcon
     */
    public static ImageIcon createImage() {
        BufferedImage image = new BufferedImage(28,28, BufferedImage.TYPE_INT_ARGB);
        Graphics g = image.getGraphics();
        g.setColor(Color.GREEN);
        g.fillRect(0, 0, 28, 28);
        g.dispose();
        return new ImageIcon(image);
    }

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

            @Override
            public void run() {
                createWindow();
            }
        });
    }
}

导入java.awt.BorderLayout;
导入java.awt.Color;
导入java.awt.Cursor;
导入java.awt.Graphics;
导入java.awt.Point;
导入java.awt.Rectangle;
导入java.awt.event.ActionEvent;
导入java.awt.event.ActionListener;
导入java.awt.event.MouseAdapter;
导入java.awt.event.MouseEvent;
导入java.awt.image.buffereImage;
导入java.util.logging.Level;
导入java.util.logging.Logger;
导入javax.swing.ImageIcon;
导入javax.swing.JFrame;
导入javax.swing.JScrollPane;
导入javax.swing.JTextPane;
导入javax.swing.JToggleButton;
导入javax.swing.SwingUtilities;
导入javax.swing.text.AttributeSet;
导入javax.swing.text.BadLocationException;
导入javax.swing.text.Element;
导入javax.swing.text.SimpleAttributeSet;
导入javax.swing.text.StyleConstants;
导入javax.swing.text.StyledDocument;
/**
*SSCCE显示如何仅在当前鼠标位置下检测图像
*对图像的一部分起作用。它将一个简单的图像添加到
*JTextPane并在检测到鼠标悬停时更改鼠标光标
*在图像上方。
* 
*要演示差异,可以通过以下方式打开和关闭解决方案:
*点击按钮。
*/
公共类JTextPaneImage{
私有静态布尔使能解决方案;
私有静态void createWindow(){
//创建窗口
最终JFrame=新JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//创建JTextPane并添加到窗口
最终JTextPane textPane=新JTextPane();
textPane.setEditable(false);
textPane.addMouseMotionListener(新的MouseAdapter(){
@凌驾
public void mouseMoved(MouseEvent e){
AttributeSet style=getAttributes(e);
if(style!=null&&StyleConstants.getIcon(style)!=null){
textPane.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_Cursor));
}否则{
setCursor(Cursor.getDefaultCursor());
}
}
});
frame.add(新的JScrollPane(textPane));
//只是为了禁用/启用用于演示差异的解决方案
最终JToggleButton按钮=新的JToggleButton(“启用解决方案”);
addActionListener(新建ActionListener()){
@凌驾
已执行的公共无效操作(操作事件e){
enableSolution=button.isSelected();
}
});
框架。添加(按钮,边框布局。南);
//添加一些文本和图像
试一试{
StyledDocument文档=(StyledDocument)textPane.getDocument();
SimpleAttributeSet样式=新的SimpleAttributeSet();
setIcon(style,createImage());
doc.insertString(doc.getLength(),“一些文本”,null);
doc.insertString(doc.getLength(),“test”,style);
doc.insertString(doc.getLength(),“abc\n”,null);
doc.insertString(doc.getLength(),“另一个图像”,样式);
}捕获(BadLocationException ex){
Logger.getLogger(JTextPaneImage.class.getName()).log(Level.SEVERE,null,ex);
}
//展示一切
frame.pack();
frame.setLocationByPlatform(真);
frame.setVisible(true);
}
/**
*检索鼠标所在位置的样式(假定为
*JTextPane)。
* 
*@param e包含鼠标位置的鼠标事件
*@retu
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.JToggleButton;
import javax.swing.SwingUtilities;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.Element;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;

/**
 * SSCCE to show how detecting an image under the current mouse position only
 * works on part of the image. It adds a simple image to the document of the
 * JTextPane and changes the mouse cursor when it detects the mouse hovering
 * over the image.
 * 
 * To demonstrate the difference, you can turn the solution on and off by
 * clicking the button.
 */
public class JTextPaneImage {

    private static boolean enableSolution;

    private static void createWindow() {

        // Create window
        final JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // Create JTextPane and add to window
        final JTextPane textPane = new JTextPane();
        textPane.setEditable(false);
        textPane.addMouseMotionListener(new MouseAdapter() {

            @Override
            public void mouseMoved(MouseEvent e) {
                AttributeSet style = getAttributes(e);
                if (style != null && StyleConstants.getIcon(style) != null) {
                    textPane.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
                } else {
                    textPane.setCursor(Cursor.getDefaultCursor());
                }
            }
        });
        frame.add(new JScrollPane(textPane));

        // Just to disable/enable solution for demonstrating the difference
        final JToggleButton button = new JToggleButton("Enable solution");
        button.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                enableSolution = button.isSelected();
            }
        });
        frame.add(button, BorderLayout.SOUTH);

        // Add some text and images
        try {
            StyledDocument doc = (StyledDocument)textPane.getDocument();

            SimpleAttributeSet style = new SimpleAttributeSet();
            StyleConstants.setIcon(style, createImage());

            doc.insertString(doc.getLength(), "Some text ", null);
            doc.insertString(doc.getLength(), "test", style);
            doc.insertString(doc.getLength(), "abc\n", null);
            doc.insertString(doc.getLength(), "another image", style);
        } catch (BadLocationException ex) {
            Logger.getLogger(JTextPaneImage.class.getName()).log(Level.SEVERE, null, ex);
        }

        // Display everything
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    /**
     * Retrieves the style of where the mouse is positioned (assuming this is
     * a JTextPane).
     * 
     * @param e The mouse event containing the mouse position
     * @return The AttributeSet or null if none could be found
     */
    private static AttributeSet getAttributes(MouseEvent e) {
        JTextPane text = (JTextPane)e.getSource();
        Point mouseLocation = new Point(e.getX(), e.getY());
        int pos = text.viewToModel(mouseLocation);

        if (pos >= 0) {
            if (enableSolution) {

                /**
                 * Solution, this is basicially what is different:
                 * 
                 * Check if the found position is actually located where the
                 * mouse is located, or else use the previous one. It doesn't
                 * only check the x position (which would already help), but
                 * also the y position, because else the area below/left of the
                 * image may also be recognized as image (if there is no other
                 * content there).
                 */
                try {
                    Rectangle rect = text.modelToView(pos);
                    int lowerCorner = rect.y + rect.height;
                    if (e.getX() < rect.x && e.getY() < lowerCorner && pos > 0) {
                        pos--;
                    }
                } catch (BadLocationException ex) {
                    Logger.getLogger(JTextPaneImage.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            StyledDocument doc = text.getStyledDocument();
            Element element = doc.getCharacterElement(pos);
            return element.getAttributes();
        }
        return null;
    }

    /**
     * Creates a single 28x28 image filled with a single color.
     * 
     * @return The created ImageIcon
     */
    public static ImageIcon createImage() {
        BufferedImage image = new BufferedImage(28,28, BufferedImage.TYPE_INT_ARGB);
        Graphics g = image.getGraphics();
        g.setColor(Color.GREEN);
        g.fillRect(0, 0, 28, 28);
        g.dispose();
        return new ImageIcon(image);
    }

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

            @Override
            public void run() {
                createWindow();
            }
        });
    }
}