我有一个Java8程序,其中-parent是一个jframe,它有菜单、几个按钮、一个文本字段和一个具有固定数量的不可编辑行的jtable。不能动态更改行数和数据数。
菜单中有 UIManager.getInstalledLookAndFeels()
最初jtable行边框可见
如果外观和感觉改变为 [Nimbus javax.swing.plaf.nimbus.NimbusLookAndFeel]
,然后尝试任何其他lookandfeel,行边框将消失。
我正在使用 SwingUtilities.updateComponentTreeUI(parentFrame)
应用lnf。lnf应用于包括jtable在内的所有组件,但一旦nimbus lnf应用,然后选择任何其他lnf,行边界就消失了。
作为一种选择 repaint()
没有任何区别。
在图像中
(1) 是程序启动时行边框可见的位置
(2) 当nimbus lnf应用时
(3) lnf已更改为“金属”,但行边框不可见
请建议。
示例代码:
package com.sv.runcmd;
import com.sv.core.logger.MyLogger;
import com.sv.swingui.SwingUtils;
import com.sv.swingui.component.AppExitButton;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import static com.sv.core.Constants.SP_DASH_SP;
import static com.sv.swingui.UIConstants.EMPTY_BORDER;
public class LnFExample extends JFrame {
public static void main(String[] args) {
new LnFExample().initComponents();
}
private static final String APP_TITLE = "LnF";
private DefaultTableModel model;
private JTable tblCommands;
private JMenuBar mbarSettings;
public LnFExample() {
super(APP_TITLE);
SwingUtilities.invokeLater(this::initComponents);
}
/**
* This method initializes the form.
*/
private void initComponents() {
Container parentContainer = getContentPane();
parentContainer.setLayout(new BorderLayout());
JButton btnExit = new AppExitButton(true);
createTable();
JPanel topPanel = new JPanel(new GridLayout(2, 1));
topPanel.add(btnExit);
topPanel.setBorder(EMPTY_BORDER);
JPanel lowerPanel = new JPanel(new BorderLayout());
JScrollPane jspCmds = new JScrollPane(tblCommands);
lowerPanel.add(jspCmds);
parentContainer.add(topPanel, BorderLayout.NORTH);
parentContainer.add(lowerPanel, BorderLayout.CENTER);
btnExit.addActionListener(evt -> exitForm());
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent evt) {
exitForm();
}
});
createAppMenu();
setPosition();
}
private final MyLogger logger = MyLogger.createLogger("rc.log");
private void createAppMenu() {
mbarSettings = new JMenuBar();
JMenu menuSettings = new JMenu("Settings");
menuSettings.add(getThemesMenu());
mbarSettings.add(menuSettings);
setJMenuBar(mbarSettings);
}
public UIManager.LookAndFeelInfo[] getAvailableLAFs() {
return UIManager.getInstalledLookAndFeels();
}
public JMenu getThemesMenu() {
JMenu menu = new JMenu("Theme");
int i = 'a';
int x = 0;
for (UIManager.LookAndFeelInfo l : getAvailableLAFs()) {
JMenuItem mi = new JMenuItem((char) i + SP_DASH_SP + l.getName());
if (i <= 'z') {
mi.setMnemonic(i);
}
int finalX = x;
mi.addActionListener(e -> applyTheme(finalX, l));
menu.add(mi);
i++;
x++;
}
return menu;
}
UIManager.LookAndFeelInfo themeToApply;
public void applyTheme(int idx, UIManager.LookAndFeelInfo lnf) {
themeToApply = lnf;
SwingUtilities.invokeLater(this::applyLnF);
}
public void applyLnF() {
try {
UIManager.setLookAndFeel(themeToApply.getClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e) {
e.printStackTrace();
}
SwingUtilities.updateComponentTreeUI(this);
}
private void createTable() {
model = SwingUtils.getTableModel(new String[]{"Col1"});
createRows();
Border borderBlue = new LineBorder(Color.BLUE, 1);
tblCommands = new JTable(model);
}
private void createRows() {
for (int i = 1; i <= 10; i++) {
model.addRow(new String[]{"Row- " + i});
}
}
private void setPosition() {
// Setting to right most position
pack();
GraphicsConfiguration config = getGraphicsConfiguration();
Rectangle bounds = config.getBounds();
Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(config);
int x = bounds.x + bounds.width - insets.right - getWidth();
int y = bounds.y + insets.top + 10;
setLocation(x, y);
setVisible(true);
}
/**
* Exit the Application
*/
private void exitForm() {
setVisible(false);
dispose();
logger.dispose();
System.exit(0);
}
}
3条答案
按热度按时间hkmswyz61#
正如评论和@camickr所讨论的,这可能是一个带有nimbus或metal laf的bug。
不过,我已经做了一个解决办法,你可以使用现在。
本质上,我超越了
prepareRenderer
的JTable
并检查是否正在使用金属laf(并且它没有在启动时设置,或者它将在面板周围绘制两个边框)JTable
)如果满足这些条件,我们只需将每行的边界设置为new MetalBorders.TableHeaderBorder()
:testapp.java文件:
8fq7wneg2#
在windows10上使用jdk11也得到了相同的结果。
我怀疑问题出在
UIResource
接口。注意,这只是一个标记接口,没有实际的方法来实现。我的理解是,这个接口应该在swing组件的属性上实现。例如关于字体、边框、颜色、图标属性的各种组件。
当你调用
SwingUtilities.updateComponentTreeUI(parentFrame)
实现UIResource
将替换为新laf的相应属性。查看uimanager默认值。它将列出每个swing组件的所有属性。
您将看到,对于大多数laf,属性都是示例中的
FontUIResource
,或ColorUIResource
等等。然而,对于nimbus laf,许多属性缺少“…uiresource”。
所以我建议这是一个光环问题,我不知道如何解决它。
编辑:
调试时很难判断这是否是金属laf问题。。。或是灵气问题
这是一个灵气问题。
从上述链接下载代码,然后进行以下更改:
现在在非nimbus之间切换laf,您将看到非nimbus laf的默认表呈现器在类名中包含uiresource,这将向我指示它们实现uiresource接口。
现在切换到nimbus laf。呈现器在类名中没有uiresource。
现在切换回任何其他laf,渲染不正确,因为nimbus渲染器没有被正确的laf渲染器替换。
注意,这不是laf问题。它就是这样设计的。这允许您创建可在所有laf中使用的自定义呈现器(当然,除非您使用uiresource接口标记呈现器)。
出于某种原因,nimbus开发人员似乎没有用uiresource接口标记呈现器,因此一旦设置了呈现器,就不会用laf的其余部分更改它们。
因此,另一种解决方案是创建一个“ Package 器”呈现器,该呈现器只需 Package 一个默认呈现器并调用其默认呈现器逻辑,但也可以实现uiresource接口。然后需要用 Package 器渲染器替换每个默认的nimbus渲染器。
svgewumm3#
我收到了一封邮件,回复了我从甲骨文提出的关于这个问题的bug,他们也可以把它复制成bug。jdk-8258567。
链接:http://bugs.java.com/bugdatabase/view_bug.do?bug_id=jdk-8258567