我有一个 JTextPane,我向其中添加文本,而一些文本具有通过 StyleConstants.setIcon()
设置的图像。我还向 JTextPane 添加了一个鼠标监听器,以检测鼠标何时被单击/悬停在图像上,但是它仅在图像的左侧部分检测到它。我做错了什么吗?
SSCCE(将鼠标悬停在图像上会更改鼠标光标以指示它何时检测到图像):
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Graphics;
import java.awt.Point;
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.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.
*/
public class JTextPaneImage {
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));
try {
StyledDocument doc = (StyledDocument)textPane.getDocument();
// Add some text
doc.insertString(0, "Some text ", null);
// Add the image
SimpleAttributeSet style = new SimpleAttributeSet();
StyleConstants.setIcon(style, createImage());
doc.insertString(doc.getLength(), "test", 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) {
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();
}
});
}
}
最佳答案
您使用强 text.viewToModel(mouseLocation)
来检测偏移量,然后从获得的偏移量中检索样式。
逻辑是返回更接近鼠标位置的偏移量。因此,当您单击 View 的右半部分时,将返回下一个偏移量( View 后的偏移量)。您可以尝试同样设置一个大字母(例如 m 大字体)。当您靠近字母时,结束插入符将设置在字母之后。这里的逻辑是一样的。
因此您在图像之后获得位置并从该位置获得样式,但在 ImageView 文本元素之后属性中没有图标并且您没有图像。
更新:
为了提供正确的行为,我建议使用 modelToView() 并传递获得的偏移量。从矩形中,您可以确定您点击的 X 位置是否 < 矩形的 X。如果插入矩形的 x 大于鼠标 X,您可以尝试以前的偏移。
更新 2:您可以覆盖 IconView 并使用 paint() 方法来存储 ImageView 的最后绘制的矩形。存储在 map 中最后绘制的矩形。在鼠标移动/单击时检查 map 以查找其中一个矩形是否包含该点。
或
您可以使用 View 的方法 getChildAllocation() 描述了类似的东西 here计算图像边界。从 Root View 开始,向下直到计算 X、Y 的正确 View 的叶子。如果叶 subview 是 IconView,那么您就完成了图像。
关于java - 在当前鼠标位置检测图像仅适用于部分图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24036650/