不久前,我写了一个缩放到鼠标摆动面板,处理高亮、平移、鼠标缩放、选择等。非常好。
我今天又去玩了几次,但都没用。我很困惑。我知道我有一个很好的例子——在某个地方。但在我的驾驶过程中,我的任何实验都不起作用。我开始努力让它再次发挥作用。
最终我发现了问题所在。它是JDK 11和我的新iMac的某种组合。我上一次做这个的时候,是在我的旧Mac上(我不记得在那里我可能用过JDK 11,也不记得有没有用过JDK 11)。
如果您使用代码,您会看到显然有某种(2X?)在JDK 11下进行缩放,但不是JDK 8。我不知道它是否试图补偿我机器上的大显示屏,或者发生了什么。
但是您尝试在JDK 11下缩放或平移,发现它没有保持在鼠标的中心,以及跟踪突出显示是如何错误的,等等。
如何在JDK 11下正常工作?它是Mac唯一的东西吗?或者是一台带有“影院大小显示器”的Mac?
以下是代码:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
public class TestPanel {
public static void main(String[] args) throws Exception {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI() {
JFrame f = new JFrame("Test Zoom");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLayout(new BorderLayout());
TestPanelZoom p = new TestPanelZoom();
f.add(p, BorderLayout.CENTER);
f.setPreferredSize(new Dimension(400, 500));
f.pack();
f.setVisible(true);
}
private static class TestPanelZoom extends JPanel {
boolean hilighted = false;
private int hiliteX = -1;
private int hiliteY = -1;
boolean selected = false;
private int selectX = -1;
private int selectY = -1;
private AffineTransform at = new AffineTransform();
public TestPanelZoom() {
setBackground(Color.WHITE);
setForeground(Color.BLACK);
addMouseAdapter();
at.setToIdentity();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(400, 500);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setTransform(at);
paintPanel(g2d);
g2d.dispose();
}
private void paintPanel(Graphics2D g2) {
g2.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(
RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
Color c = g2.getColor();
g2.setColor(Color.WHITE);
g2.fill(getBounds());
g2.setColor(c);
for (int i = 0; i < 400; i += 50) {
Line2D line = new Line2D.Double(i, 0, i, 350);
g2.draw(line);
line = new Line2D.Double(0, i, 350, i);
g2.draw(line);
}
if (hilighted) {
Rectangle2D rect = new Rectangle2D.Double(hiliteX * 50 + 5, hiliteY * 50 + 5, 40, 40);
g2.setColor(Color.GREEN);
g2.fill(rect);
}
if (selected) {
Rectangle2D rect = new Rectangle2D.Double(selectX * 50 + 10, selectY * 50 + 10, 30, 30);
g2.setColor(Color.RED);
g2.fill(rect);
}
}
private void addMouseAdapter() {
MouseAdapter ma = new MouseAdapter() {
int lx, ly;
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
AffineTransform t = new AffineTransform();
double delta = 1 + 0.05f * e.getPreciseWheelRotation();
int x = e.getX();
int y = e.getY();
t.translate(x, y);
t.scale(delta, delta);
t.translate(-x, -y);
t.concatenate(at);
at = t;
revalidate();
repaint();
}
@Override
public void mousePressed(MouseEvent e) {
lx = e.getX();
ly = e.getY();
}
@Override
public void mouseDragged(MouseEvent e) {
update(e);
}
@Override
public void mouseReleased(MouseEvent e) {
update(e);
}
@Override
public void mouseClicked(MouseEvent e) {
Point2D srcPt = getSrcPoint(e);
selected = true;
selectX = (int) (srcPt.getX() / 50);
selectY = (int) (srcPt.getY() / 50);
revalidate();
repaint();
}
@Override
public void mouseMoved(MouseEvent e) {
Point2D srcPt = getSrcPoint(e);
hilighted = true;
hiliteX = (int) (srcPt.getX() / 50);
hiliteY = (int) (srcPt.getY() / 50);
revalidate();
repaint();
}
public void update(MouseEvent e) {
Point2D srcPt = new Point2D.Double(e.getX(), e.getY());
Point2D lastPt = new Point2D.Double(lx, ly);
try {
at.inverseTransform(srcPt, srcPt);
at.inverseTransform(lastPt, lastPt);
} catch (NoninvertibleTransformException noninvertibleTransformException) {
throw new RuntimeException(noninvertibleTransformException);
}
double dx = srcPt.getX() - lastPt.getX();
double dy = srcPt.getY() - lastPt.getY();
at.translate(dx, dy);
lx = e.getX();
ly = e.getY();
revalidate();
repaint();
}
public Point2D getSrcPoint(MouseEvent e) {
Point2D srcPt = new Point2D.Double(e.getX(), e.getY());
try {
at.inverseTransform(srcPt, srcPt);
} catch (NoninvertibleTransformException ex) {
throw new RuntimeException(ex);
}
return srcPt;
}
};
addMouseListener(ma);
addMouseMotionListener(ma);
addMouseWheelListener(ma);
}
}
}
编辑:
在进一步研究之后,无论出于何种原因,在JDK 11下,Graphics2D的默认转换缩放为2。
在这段代码中,如果您打印出默认转换,那么在JDK 11(在我的环境中)上您会得到:
AffineTransform[[2.0, 0.0, 0.0], [0.0, 2.0, 0.0]]
在JDK 8上,您将获得身份。
AffineTransform[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
System.out.println(g2d.getTransform());
g2d.setTransform(at);
paintPanel(g2d);
g2d.dispose();
}
最初,我使用自己的原始仿射翻译(AffineTransform)来强制它进行识别。在JDK 8上,这是一个NOP,JDK 11,没有那么多。
我尝试了这个方法,第一次将默认转换(在
)设置为图形上下文的“默认”(使用其基本世界视图与强制自己的世界视图)。这可以使网格具有适当的大小,但会影响光标的位置。
// I remove setting `at` up above, and setting it to identity also.
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (at == null) {
at = g2d.getTransform();
}
g2d.setTransform(at);
paintPanel(g2d);
g2d.dispose();
}
所以这不是解决办法。
也许有一种方法可以通过利用上下文的默认转换来使其工作,但我还没有弄清楚。我必须假设默认转换是流动的,不仅仅是JDK到JDK,而是机器到机器。它甚至可能在多显示器情况下发生变化。
编辑:
继续。
因此,在屏幕上创建和显示的窗口是我在Java中要求的大小的2倍。我通过创建窗口的屏幕截图来检查这一点。
在JDK 8中,使Java中的100像素线变为显示器上的200像素线的机制在我的代码中并不明显。
在JDK 11中,可以看到他们试图通过直接使用仿射变换将其向上移动。
同样,在JDK 8中,鼠标坐标缩放到Java坐标系。所以如果你在屏幕上放一个400x400的盒子,把鼠标从一个角落移动到另一个角落,即使这个盒子的实际像素是800x800,鼠标的范围也只是0-400。
JDK 8中的问题是,由于转换,屏幕坐标不再与模型坐标匹配。绘制400x400方框时,屏幕上绘制的是400x400时间2(由于变换)。但鼠标坐标不在屏幕坐标中。原始鼠标位于0-400范围内,而不是0-800范围内。因此,您不能再使用图形变换将鼠标坐标转换回模型坐标。隐藏在被子里的是恶作剧和诡计。简单地说,转换不是规范的。这就是为什么我的鼠标被弄得一团糟。
另外,我在另一台分辨率较低的Mac上运行了示例,完全没有问题。JDK 11下的默认转换是身份。
为了子孙后代,我想发布最终的代码,以防其他人想要一个工作示例,而不是试图将原始代码与讨论并列。
package pkg;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
public class TestPanel {
public static void main(String[] args) throws Exception {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI() {
JFrame f = new JFrame("Test Zoom");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLayout(new BorderLayout());
TestPanelZoom p = new TestPanelZoom();
f.add(p, BorderLayout.CENTER);
f.setPreferredSize(new Dimension(400, 500));
f.pack();
f.setVisible(true);
}
private static class TestPanelZoom extends JPanel {
boolean hilighted = false;
private int hiliteX = -1;
private int hiliteY = -1;
boolean selected = false;
private int selectX = -1;
private int selectY = -1;
private AffineTransform at = new AffineTransform();
public TestPanelZoom() {
setBackground(Color.WHITE);
setForeground(Color.BLACK);
addMouseAdapter();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(400, 500);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.transform(at);
paintPanel(g2d);
g2d.dispose();
}
private void paintPanel(Graphics2D g2) {
g2.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(
RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
Color c = g2.getColor();
g2.setColor(Color.WHITE);
g2.fill(getBounds());
g2.setColor(c);
for (int i = 0; i < 400; i += 50) {
Line2D line = new Line2D.Double(i, 0, i, 350);
g2.draw(line);
line = new Line2D.Double(0, i, 350, i);
g2.draw(line);
}
if (hilighted) {
Rectangle2D rect = new Rectangle2D.Double(hiliteX * 50 + 5, hiliteY * 50 + 5, 40, 40);
g2.setColor(Color.GREEN);
g2.fill(rect);
}
if (selected) {
Rectangle2D rect = new Rectangle2D.Double(selectX * 50 + 10, selectY * 50 + 10, 30, 30);
g2.setColor(Color.RED);
g2.fill(rect);
}
}
private void addMouseAdapter() {
MouseAdapter ma = new MouseAdapter() {
int lx, ly;
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
AffineTransform t = new AffineTransform();
double delta = 1 + 0.05f * e.getPreciseWheelRotation();
int x = e.getX();
int y = e.getY();
t.translate(x, y);
t.scale(delta, delta);
t.translate(-x, -y);
t.concatenate(at);
at = t;
revalidate();
repaint();
}
@Override
public void mousePressed(MouseEvent e) {
lx = e.getX();
ly = e.getY();
}
@Override
public void mouseDragged(MouseEvent e) {
update(e);
}
@Override
public void mouseReleased(MouseEvent e) {
update(e);
}
@Override
public void mouseClicked(MouseEvent e) {
Point2D srcPt = getSrcPoint(e);
selected = true;
selectX = (int) (srcPt.getX() / 50);
selectY = (int) (srcPt.getY() / 50);
revalidate();
repaint();
}
@Override
public void mouseMoved(MouseEvent e) {
Point2D srcPt = getSrcPoint(e);
hilighted = true;
hiliteX = (int) (srcPt.getX() / 50);
hiliteY = (int) (srcPt.getY() / 50);
revalidate();
repaint();
}
public void update(MouseEvent e) {
Point2D srcPt = new Point2D.Double(e.getX(), e.getY());
Point2D lastPt = new Point2D.Double(lx, ly);
try {
at.inverseTransform(srcPt, srcPt);
at.inverseTransform(lastPt, lastPt);
} catch (NoninvertibleTransformException noninvertibleTransformException) {
throw new RuntimeException(noninvertibleTransformException);
}
double dx = srcPt.getX() - lastPt.getX();
double dy = srcPt.getY() - lastPt.getY();
at.translate(dx, dy);
lx = e.getX();
ly = e.getY();
revalidate();
repaint();
}
public Point2D getSrcPoint(MouseEvent e) {
Point2D srcPt = new Point2D.Double(e.getX(), e.getY());
try {
at.inverseTransform(srcPt, srcPt);
} catch (NoninvertibleTransformException ex) {
throw new RuntimeException(ex);
}
return srcPt;
}
};
addMouseListener(ma);
addMouseMotionListener(ma);
addMouseWheelListener(ma);
}
}
}
我看不出JDK 8和11之间有什么区别,但问题是Graphics2D
上下文已经被转换以匹配屏幕配置,所以你在哪里做g2d.setTransform(at)
你需要做g2d.transform(at)
。然后一切都会像你期望的那样工作。(我在OS X 11.4上使用JDK 17运行)
所以appComponent
应该是(我还添加了一些日志记录):
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
AffineTransform t = g2d.getTransform();
System.out.println("Base G2D:" + t);
System.out.println("Ours:" + at);
g2d.transform(at);
System.out.println("Final:" + g2d.getTransform());
paintPanel(g2d);
g2d.dispose();
}
我已经在OpenJDK Runtime Environment 18.9(build 11.0.2 9)和Java(TM)SE Runtime Environment(build 1.8.0\u 201-b09)上测试了这一点。
我现在也用11.0.11进行了测试:
$ rm *.class
$ java -version
openjdk version "11.0.11" 2021-04-20
OpenJDK Runtime Environment AdoptOpenJDK-11.0.11+9 (build 11.0.11+9)
OpenJDK 64-Bit Server VM AdoptOpenJDK-11.0.11+9 (build 11.0.11+9, mixed mode)
$ javac TestPanel.java
$ java TestPanel
Base G2D:AffineTransform[[2.0, 0.0, 0.0], [0.0, 2.0, 0.0]]
Ours:AffineTransform[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]
Final:AffineTransform[[2.0, 0.0, 0.0], [0.0, 2.0, 0.0]]
嗯,这是一个非常新的提示。我声明要在window builder的帮助下自己编写GUI应用程序的代码,我已经决定停止使用netbeans,因为我在这里读到一些人说这很好。你可能认为我没有调查,但相信我,我做了功课。。。 我尝试了甲骨文所说的方式: > 公共类MyClass实现ActionListener{ someComponent。addActionListener(instanceOfMyCl
例: “foo”和“bar”可以是任何字符串键,但它们在键集中应该是唯一的。 我知道,使用Swagger,我可以定义一个对象数组,但这给出了一个不同的API,因为那时我们将拥有如下内容: 我已经阅读了“开放API规范”-“添加地图数据类型支持#38”页面。据我了解,它推荐使用additionalProperties,但似乎并没有回答我的需求(或者说与我使用的Swagger UI 2.1.4不兼容)
我们在代理后运行服务,以便: 被路由到公共地址 或者从另一个角度定义: 当nginx在上接收到请求时,它会去掉前缀,并将请求传递给路径上的service。 在设置任何东西之前(使用默认的SpringDoc配置),我可以正确地看到超文本传输协议上的昂首阔步的文档://service-post: 8080/swagger-ui.html。 设置主机上公共地址的路径。com,我正在使用: 然而,这似乎完
理想情况下,我们将有一个显示所有标记为public的控制器/方法的大摇大摆的页面,以及另一个显示所有endpoint的密码安全endpoint。这可能吗?
我有一个java项目(tomcat webapp)和一些REST Api。我想为他们生成大摇大摆的文档。我从本教程(github)开始。我没有maven我们使用蚂蚁任务。我加入了swagger-annotations-1.5.0。jar和所有随swagger jaxrs jar 1.5.0版本附带的jar(如果有用的话,我可以包括一个完整的列表),我已经注释了一些方法,我有一个如下的配置类: }
我们在我们的泽西应用程序中使用了@Role允许注释来限制用户对应用编程接口某些部分的访问。我们如何在SwaggerUI中显示这些信息? 到目前为止,我已经用@ApiOperation注释了方法以显示in/out参数,并尝试使用@Authorization/@AuthorizationScope,但我只为我们不使用的oauth2显示了它。最接近out case的是ApiKeyAuthDefiniti