JFrame
的{{1}}方法都不起作用。请亲自尝试(可能需要几次重试),请:
pack()
(您可以通过在使其不可调整后直接显示框架来修复它。)
为什么会这样?
答案 0 :(得分:3)
作为参考,这是Mac OS X上的变体外观。注意,
一个像素的差异表明空间可能用于焦点指示;但是作为@ Marco13 comments,偶尔的外观暗示了一个(非显而易见的)线程问题。
由于外观似乎与平台有关,因此标签会显示操作系统和版本系统属性。
该示例会覆盖getPreferredSize()
以按照建议here建立随附面板的几何图形。
如果实施通过填写每个像素来尊重opacity property,则无需调用super.paintComponent()
。
@ AyCe的Windows屏幕截图中显示的不规则位置包含@ Marco13建议的线程问题。
Mac OS X:
Windows 7(@AyCe):
Ubuntu 14:
import javax.swing.*;
import java.awt.*;
public class FramePackBug {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
JFrame window = new JFrame("Buggy");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setResizable(false);
window.setBackground(Color.RED);
JPanel jp = new JPanel() {
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.GREEN);
g.fillRect(0, 0, getWidth(), getHeight());
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 100);
}
};
window.add(jp);
window.add(new JLabel(System.getProperty("os.name") + ", "
+ System.getProperty("os.version")), BorderLayout.NORTH);
window.pack();
window.setLocation((i % 5) * (window.getWidth() + 5),
(i / 5) * (window.getHeight() + 5) + 20);
window.setVisible(true);
}
}
});
}
}
答案 1 :(得分:1)
编辑:请参阅下面的更新
对不起,这不是(还是?)最终的解决方案,但我仍在调查这个问题,并希望分享第一个见解,也许它对其他人有帮助,以便进一步分析:
奇怪的行为是由帧的getInsets()
方法引起的。覆盖方法时,可以看到它在大多数情况下返回left
,right
和bottom
为3
的插图,但它们是出现错误时4
:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Insets;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class FramePackBug {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
for (int i = 0; i < 20; i++) {
final int ii = i;
JFrame window = new JFrame("Buggy")
{
@Override
public Insets getInsets()
{
Insets insets = super.getInsets();
if (insets.left == 4)
{
System.out.printf(
"Wrong insets in %d : %s\n", ii, insets);
}
return insets;
}
};
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setResizable(false);
window.setBackground(Color.RED);
JPanel jp = new JPanel() {
public void paintComponent(Graphics g) {
g.setColor(Color.GREEN);
g.fillRect(0, 0, 200, 100);
}
};
jp.setPreferredSize(new Dimension(200, 100));
window.add(jp);
window.pack();
window.setLocation((i % 5) * 250, (i / 5) * 150);
window.setVisible(true);
}
}
});
}
}
我已经扫描了底层实现,最终委托给WWindowPeer
和一些基于窗口样式进行奇怪计算的本机方法(也就是说,取决于窗口是否可调整大小或我没有确定错误的一些候选原因,但仍然没有最终结论。 (这似乎是随机发生的事实并不能使调试更容易,当然......)
旁注:简单地调用pack()
方法两次会导致始终的框架正确显示给我,但当然,这最多只能只要没有识别出奇怪行为的根本原因,就会被视为一种愚蠢的解决方法。
我深入挖了一层,但仍未找到最终解决方案。
sun.awt.windows.WFramePeer
类的初始化方法实现如下:
void initialize() {
super.initialize();
Frame target = (Frame)this.target;
if (target.getTitle() != null) {
setTitle(target.getTitle());
}
setResizable(target.isResizable());
setState(target.getExtendedState());
}
super
来电进入sun.awt.windows.WWindowPeer
,并执行以下操作:
void initialize() {
super.initialize();
updateInsets(insets_);
...
}
updateInsets
调用以本机方法结束。 native implementation of updateInsets
做了一些可疑的电话,询问&#34;样式&#34;窗口,并根据WS_THICKFRAME
属性调整插入,例如
if (style & WS_THICKFRAME) {
m_insets.left = m_insets.right =
::GetSystemMetrics(SM_CXSIZEFRAME);
我可以肯定地说,这些updateInsets
来电的结果是错误。它们对于不可调整的帧而言太大,最终导致错误。我可以不肯定地说:在哪些错误的插图(有时)更新(对于某些帧)以正确反映不可调整帧的大小。
潜在的解决方法?
从第一个更新的片段中可以看出,WFramePeer
的初始化最终会调用
setResizable(target.isResizable());
setResizable
最终再次委托本地方法,而native implementation of the setResizable
method中又有style
和WS_THICKFRAME
。
因此,将sun.awt.windows.WFramePeer#initialize()
方法更改为首先设置&#34;可调整大小&#34;属性,然后向上传递调用(它将导致updateInsets
被调用)解决了我的问题:
void initialize() {
Frame target = (Frame)this.target;
setResizable(target.isResizable());
super.initialize();
if (target.getTitle() != null) {
setTitle(target.getTitle());
}
setState(target.getExtendedState());
}
通过此修改,可正确计算插图,并且始终正确显示帧。
答案 2 :(得分:0)
我不确定这是否正确,但您可以尝试在set方法之后放置setResizable()方法,因为setResizeable(false)可能会禁用pack函数。