在模态 JDialog 之外时光标不正确?
Incorrect cursor when outside of modal JDialog?
当使用方法 setCursor()
更改组件使用的光标时,所有组件都可以正常工作,包括 JFrame
和 JDialog
。
这里的问题在于 模态 JDialog
。当鼠标在对话框内时,光标显示在右侧。但是,当鼠标移到 对话框外 时,光标将重新设置为 OS 默认值,即使基础 JFrame
使用相同的自定义光标作为对话框。
我搜索了很多,发现了一些相关的问题,但是 none 对此有一个正确的答案。
我正在使用 Windows 10; JDK1.8.0_40.
SSCCE:
package br.shura.knockback;
import java.awt.Cursor;
import java.awt.Dimension;
import javax.swing.*;
public class DialogCursorSSCCE extends JFrame {
public DialogCursorSSCCE() {
Cursor cursor = new Cursor(Cursor.CROSSHAIR_CURSOR);
JButton button = new JButton("Click me to open dialog.");
button.addActionListener(event -> {
JDialog dialog = new JDialog();
JLabel label = new JLabel("Move the mouse outside this dialog.");
int width = label.getFontMetrics(label.getFont()).stringWidth(label.getText());
label.setPreferredSize(new Dimension(width + 10, 50));
dialog.add(label);
dialog.pack();
dialog.setCursor(cursor);
dialog.setLocationRelativeTo(button);
dialog.setModal(true);
dialog.setTitle("Dialog");
dialog.setVisible(true);
});
button.setAlignmentX(CENTER_ALIGNMENT);
button.setMaximumSize(new Dimension(400, 100));
setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
add(button);
setCursor(cursor);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setExtendedState(MAXIMIZED_BOTH);
setTitle("DialogCursorSSCCE");
}
public static void main(String[] args) {
new DialogCursorSSCCE().setVisible(true);
}
}
But, when the mouse is moved outside the dialog, the cursor is re-set to the OS default,
我对正在发生的事情的猜测是对话框的边框是一个 OS 对等组件。因此,当您离开 Swing 组件时,会为 OS 对等生成鼠标悬停事件,因此光标设置为 OS 默认值。
当您完全离开对话框时,框架不会收到任何事件,因为对话框是模态的,所以系统光标在框架上时仍会显示。
注意光标进入标题栏时的变化。
现在尝试以下操作:
JDialog dialog = new JDialog();
dialog.setUndecorated(true);
dialog.getRootPane().setWindowDecorationStyle(JRootPane.PLAIN_DIALOG);
现在光标只会在到达边界时发生变化,因为 Swing 正在绘制标题栏。
我也试过:
JDialog dialog = new JDialog();
dialog.setUndecorated(true);
所以没有装饰,但是当光标离开window时,光标仍然会发生变化。
我不知道有什么办法。
我讨厌 'impossible' 答案 - 实际上我必须这样做。所以这是我发现的解决方法:
1) 使用 ProgressMonitor(如此处:https://docs.oracle.com/javase/tutorial/uiswing/components/progress.html)- 不是我的情况,因为我必须强烈自定义它
2) 模拟模态。这是关于我的意思的基本想法(是的,我知道我不会以这种方式锁定主框架的 GUI - 你也可以这样做 - 幸运的是:不是我的情况)
mainFrame.addComponentListener(componentListener = new ComponentListener() {
@Override
public void componentShown(ComponentEvent e) {
}
@Override
public void componentResized(ComponentEvent e) {
placeDialog();
}
@Override
public void componentMoved(ComponentEvent e) {
placeDialog();
}
@Override
public void componentHidden(ComponentEvent e) {
}
});
((Window) mainFrame).addWindowListener(windowListener = new WindowListener() {
@Override
public void windowOpened(WindowEvent e) {
placeDialog();
}
@Override
public void windowIconified(WindowEvent e) {
dialog.setVisible(false);
}
@Override
public void windowDeiconified(WindowEvent e) {
placeDialog();
}
@Override
public void windowDeactivated(WindowEvent e) {
}
@Override
public void windowClosing(WindowEvent e) {
}
@Override
public void windowClosed(WindowEvent e) {
closeDialog();
}
@Override
public void windowActivated(WindowEvent e) {
placeDialog();
}
});
}
private void placeDialog() {
dialog.setVisible(true);
dialog.requestFocus();
dialog.setLocation(mainFrame.getLocation().x + mainFrame.getWidth()/2 - dialog.getWidth()/2,
mainFrame.getLocation().y + mainFrame.getHeight()/2 - dialog.getHeight()/2);
}
毕竟不要忘记从 mainFrame 中删除监听器(就像在 Finally 部分)
希望很多投票者有更好的解决方案:)
当使用方法 setCursor()
更改组件使用的光标时,所有组件都可以正常工作,包括 JFrame
和 JDialog
。
这里的问题在于 模态 JDialog
。当鼠标在对话框内时,光标显示在右侧。但是,当鼠标移到 对话框外 时,光标将重新设置为 OS 默认值,即使基础 JFrame
使用相同的自定义光标作为对话框。
我搜索了很多,发现了一些相关的问题,但是 none 对此有一个正确的答案。
我正在使用 Windows 10; JDK1.8.0_40.
SSCCE:
package br.shura.knockback;
import java.awt.Cursor;
import java.awt.Dimension;
import javax.swing.*;
public class DialogCursorSSCCE extends JFrame {
public DialogCursorSSCCE() {
Cursor cursor = new Cursor(Cursor.CROSSHAIR_CURSOR);
JButton button = new JButton("Click me to open dialog.");
button.addActionListener(event -> {
JDialog dialog = new JDialog();
JLabel label = new JLabel("Move the mouse outside this dialog.");
int width = label.getFontMetrics(label.getFont()).stringWidth(label.getText());
label.setPreferredSize(new Dimension(width + 10, 50));
dialog.add(label);
dialog.pack();
dialog.setCursor(cursor);
dialog.setLocationRelativeTo(button);
dialog.setModal(true);
dialog.setTitle("Dialog");
dialog.setVisible(true);
});
button.setAlignmentX(CENTER_ALIGNMENT);
button.setMaximumSize(new Dimension(400, 100));
setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
add(button);
setCursor(cursor);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setExtendedState(MAXIMIZED_BOTH);
setTitle("DialogCursorSSCCE");
}
public static void main(String[] args) {
new DialogCursorSSCCE().setVisible(true);
}
}
But, when the mouse is moved outside the dialog, the cursor is re-set to the OS default,
我对正在发生的事情的猜测是对话框的边框是一个 OS 对等组件。因此,当您离开 Swing 组件时,会为 OS 对等生成鼠标悬停事件,因此光标设置为 OS 默认值。
当您完全离开对话框时,框架不会收到任何事件,因为对话框是模态的,所以系统光标在框架上时仍会显示。
注意光标进入标题栏时的变化。
现在尝试以下操作:
JDialog dialog = new JDialog();
dialog.setUndecorated(true);
dialog.getRootPane().setWindowDecorationStyle(JRootPane.PLAIN_DIALOG);
现在光标只会在到达边界时发生变化,因为 Swing 正在绘制标题栏。
我也试过:
JDialog dialog = new JDialog();
dialog.setUndecorated(true);
所以没有装饰,但是当光标离开window时,光标仍然会发生变化。
我不知道有什么办法。
我讨厌 'impossible' 答案 - 实际上我必须这样做。所以这是我发现的解决方法:
1) 使用 ProgressMonitor(如此处:https://docs.oracle.com/javase/tutorial/uiswing/components/progress.html)- 不是我的情况,因为我必须强烈自定义它
2) 模拟模态。这是关于我的意思的基本想法(是的,我知道我不会以这种方式锁定主框架的 GUI - 你也可以这样做 - 幸运的是:不是我的情况)
mainFrame.addComponentListener(componentListener = new ComponentListener() {
@Override
public void componentShown(ComponentEvent e) {
}
@Override
public void componentResized(ComponentEvent e) {
placeDialog();
}
@Override
public void componentMoved(ComponentEvent e) {
placeDialog();
}
@Override
public void componentHidden(ComponentEvent e) {
}
});
((Window) mainFrame).addWindowListener(windowListener = new WindowListener() {
@Override
public void windowOpened(WindowEvent e) {
placeDialog();
}
@Override
public void windowIconified(WindowEvent e) {
dialog.setVisible(false);
}
@Override
public void windowDeiconified(WindowEvent e) {
placeDialog();
}
@Override
public void windowDeactivated(WindowEvent e) {
}
@Override
public void windowClosing(WindowEvent e) {
}
@Override
public void windowClosed(WindowEvent e) {
closeDialog();
}
@Override
public void windowActivated(WindowEvent e) {
placeDialog();
}
});
}
private void placeDialog() {
dialog.setVisible(true);
dialog.requestFocus();
dialog.setLocation(mainFrame.getLocation().x + mainFrame.getWidth()/2 - dialog.getWidth()/2,
mainFrame.getLocation().y + mainFrame.getHeight()/2 - dialog.getHeight()/2);
}
毕竟不要忘记从 mainFrame 中删除监听器(就像在 Finally 部分)
希望很多投票者有更好的解决方案:)