是否可以将转换应用于Swing中的自定义或预制控件?一方面允许转换,另一方面,实现可能存在一些差距。
注意问题是关于如何应用来自控件父级的transfomations,而不是关于如何使用转换。即转变必须由父母发布,而孩子应该遵守它。因此,请提示如何转换标准Swing控件或如何编写遵循PARENT转换的自定义控件。
在绘制子项之前将变换应用于Graphics
并且不起作用的简单示例:
public class Tester_TransformDuringPaint_01 {
private static Logger log = LoggerFactory.getLogger(Tester_TransformDuringPaint_01.class);
private static class JPanelEx extends JPanel {
private AffineTransform transform = new AffineTransform();
public AffineTransform getTransform() {
return transform;
}
public void setTransform(AffineTransform transform) {
this.transform = transform;
}
@Override
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
AffineTransform savedTransform = g2.getTransform();
g2.transform(transform);
super.paintComponent(g);
g2.drawOval(0, 0, 100, 100);
g2.setTransform(savedTransform);
}
@Override
protected void paintChildren(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
AffineTransform savedTransform = g2.getTransform();
g2.transform(transform);
super.paintChildren(g);
g2.setTransform(savedTransform);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JButton button = new JButton("Button");
button.setBounds(0,20,100,60);
JPanelEx panel = new JPanelEx();
panel.setLayout(null);
panel.setBounds(10, 10, 640, 480);
panel.setBackground(Color.PINK);
panel.setTransform(AffineTransform.getScaleInstance(2, 1));
panel.add(button);
JFrameEx frame = new JFrameEx();
frame.setLayout(null);
frame.add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(0.5);
frame.center();
frame.setVisible(true);
}
});
}
}
得出以下内容:
虽然按钮的左半部分看起来很活跃,但更大的部分看起来已经死了。
这是因为API的不同部分使用不同的方法绘制按钮。
修改了O'Reilly hack 51
以下是基于@ lbalazscs示例的代码,该示例表明即使转换是“在边界内”,转换也不起作用
public class BackwardsJButton extends JButton {
public BackwardsJButton(String text) {
super(text);
}
public void paint(Graphics g) {
if (g instanceof Graphics2D) {
Graphics2D g2 = (Graphics2D) g;
AffineTransform savedTransform = g2.getTransform();
AffineTransform flipTrans = new AffineTransform();
double widthD = (double) getWidth();
//flipTrans.setToTranslation(widthD, 0);
//flipTrans.scale(-2.0, 1);
flipTrans.scale(0.5, 1);
g2.transform(flipTrans);
super.paint(g);
g2.setTransform(savedTransform);
} else {
super.paint(g);
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
buildFrame();
}
});
}
private static void buildFrame() {
JFrame f = new JFrame("Test");
f.setLayout(new FlowLayout());
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.add(new BackwardsJButton("BackwardsJLabel"));
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
输出如下(您可能需要调整窗口大小并移动鼠标才能看到它,因为Swing bug位于鼠标悬停代码中:
答案 0 :(得分:3)
你有一些创新的想法如何滥用Swing:)
可以在绘制组件时应用仿射变换,但前提是您在组件的范围内感到满意(例如,您可以镜像文本)。如果覆盖绘制,则更改组件的绘制方式,但这不会更改其大小,因为大小完全取决于其他变量,并且仍然无法在其边界之外可靠地绘制。
我认为改造预制组件的绘画并不是一个好主意,因为即使你以图形方式成功,也会在原始位置点击鼠标。
请注意,完成后需要重置转换,因为相同的Graphics对象将用于绘制其他组件。
AffineTransform savedTransform = g.getTransform();
g.setTransform(specialTransform);
... your drawing here
g.setTransform(savedTransform);
编辑:这是转换组件的完整运行示例
import javax.swing.*;
import javax.swing.plaf.metal.MetalButtonUI;
import java.awt.*;
import java.awt.geom.AffineTransform;
public class ScaledButton extends JButton {
public ScaledButton(String text) {
super(text);
}
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Color savedColor = g2.getColor();
g2.setColor(getBackground());
g2.fill(new Rectangle(0, 0, getWidth(), getHeight()));
g2.setColor(savedColor);
AffineTransform backup = g2.getTransform();
g2.scale(0.5, 1);
super.paintComponent(g);
g2.setTransform(backup);
}
@Override
protected void paintBorder(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
AffineTransform backup = g2.getTransform();
g2.scale(0.5, 1);
super.paintBorder(g);
g2.setTransform(backup);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
buildFrame();
}
});
}
private static void buildFrame() {
JFrame f = new JFrame("Test");
f.setLayout(new FlowLayout());
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.add(new ScaledButton("ScaledButton"));
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}