Swing:创建一个UWP(“Metro”) – 就像按钮一样

我想设计一个看起来像UWP的Swing按钮 – 就像[Windows设置应用]一样: UWP按钮示例

这是我到目前为止:

setContentAreaFilled(假)

使用以下代码:

Font f = new Font("Segoe UI", Font.PLAIN, 20); Color gray = new Color(204, 204, 204); button.setFont(f); button.setBackground(gray); button.setContentAreaFilled(false); button.setFocusPainted(false); button.setFocusable(false); button.setForeground(Color.BLACK); button.setBorder(BorderFactory.createEmptyBorder(10, 14, 10, 14)); 

无论是否button.setContentAreaFilled(Boolean b);背景颜色都无法改变button.setContentAreaFilled(Boolean b); property设置为falsetrue ,因为EmptyBorderinheritance了Windows Swing按钮的默认颜色。

hover(hover时颜色更改)也会在属性设置为false停止运行。

设置button.setContentAreaFilled(true); 给出以下结果,这也是不理想的,因为按钮的背景仍然没有从默认颜色改变(+它有一个轮廓):

setContentAreaFilled(真)

我的问题是,基本上:如何修改我的代码以获得以下类似UWP的设计?

默认:

默认

徘徊:

徘徊

你可以通过多种方式“可能”做到这一点

  • 创建工厂方法以应用模拟function所需的属性和侦听器
  • 创建一个从JButtonAbstractButton扩展的新类,并在自包含的包中提供所需的核心function/属性
  • 您可以为自己提供UI委托,并在核心自定义按钮的外观

每种方法都有它的优点和缺点,你需要决定哪种方法能更好地满足你的整体需求。

例如,将自定义外观委托提供到现有代码库中要容易得多,因为您不需要更改代码,除了在您想要使用它时安装外观

以下是使用外观委托代理的示例,这只是一个概念certificate,可能还有许多其他function/工作需要完成 – 例如,我想提供更多关于例如,要使用的颜色和边框上的滚动厚度

正常 滚下

 import java.awt.Color; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javaapplication24.Test.MetroLookAndFeel; import javax.swing.AbstractButton; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import javax.swing.border.Border; import javax.swing.border.CompoundBorder; import javax.swing.border.EmptyBorder; import javax.swing.border.LineBorder; import javax.swing.plaf.basic.BasicButtonUI; public class Test { public static void main(String[] args) { new Test(); } public Test() { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { ex.printStackTrace(); } JFrame frame = new JFrame("Testing"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(new TestPane()); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } public class TestPane extends JPanel { public TestPane() { setBorder(new EmptyBorder(10, 10, 10, 10)); JButton fancyPB = new JButton("Restart Now"); fancyPB.setUI(new MetroLookAndFeel()); JButton normalPB = new JButton("Restart Now"); setLayout(new GridBagLayout()); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.insets = new Insets(4, 4, 4, 4); add(fancyPB, gbc); add(normalPB, gbc); } } public class MetroLookAndFeel extends BasicButtonUI { // This could be computed properties, where the border color // is determined based on other properties private Border focusBorder = new CompoundBorder(new LineBorder(Color.DARK_GRAY, 3), new EmptyBorder(7, 13, 7, 14)); private Border unfocusedBorder = new EmptyBorder(10, 14, 10, 14); @Override protected void installDefaults(AbstractButton b) { super.installDefaults(b); Font f = new Font("Segoe UI", Font.PLAIN, 20); Color gray = new Color(204, 204, 204); b.setFont(f); b.setBackground(gray); b.setContentAreaFilled(false); b.setFocusPainted(false); // This seems like an oddity... b.setFocusable(false); b.setForeground(Color.BLACK); // b.setBorder(BorderFactory.createEmptyBorder(10, 14, 10, 14)); b.setBorder(unfocusedBorder); } @Override protected void installListeners(AbstractButton b) { super.installListeners(b); b.addMouseListener(new MouseAdapter() { @Override public void mouseEntered(MouseEvent e) { ((JButton)e.getSource()).setBorder(focusBorder); } @Override public void mouseExited(MouseEvent e) { ((JButton)e.getSource()).setBorder(unfocusedBorder); } }); } } } 

这是一个例子

 import java.awt.Color; import java.awt.Font; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.WindowConstants; import javax.swing.border.CompoundBorder; import javax.swing.border.LineBorder; public class WinButton { public static void main(String[] args) { final JButton button = createWinButton("Restart now"); JFrame frm = new JFrame("Test"); JPanel layoutPanel = new JPanel(); layoutPanel.add(button); frm.add(layoutPanel); frm.setSize(200, 200); frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); frm.setLocationRelativeTo(null); frm.setVisible(true); } private static JButton createWinButton(String text) { final JButton button = new JButton(text); Font f = new Font("Segoe UI", Font.PLAIN, 20); Color gray = new Color(204, 204, 204); button.setFont(f); button.setBackground(gray); button.setContentAreaFilled(false); button.setFocusPainted(false); button.setFocusable(false); button.setForeground(Color.BLACK); button.setOpaque(true); button.setBorder(BorderFactory.createEmptyBorder(10, 14, 10, 14)); button.addMouseListener(new MouseAdapter() { @Override public void mouseEntered(MouseEvent e) { Color borderColor = new Color(100, 100, 100); button.setBorder(new CompoundBorder(new LineBorder(borderColor, 3), BorderFactory.createEmptyBorder(7, 11, 7, 11))); } @Override public void mouseExited(MouseEvent e) { button.setBorder(BorderFactory.createEmptyBorder(10, 14, 10, 14)); } }); return button; } } 

为了操纵鼠标事件,例如hover,您必须自己处理这些事件,其中一种方法是创建自己的按钮。


编辑

正如Sergiy Medvynskyy所回答的那样,在按钮上添加鼠标监听器将是一种更好的做法,因为不需要修改按钮类本身。


您可能还必须使用LaF(UIManager外观和感觉),因为它可以为UI组件添加不需要的效果。

请注意,这可能会影响所有界面组件。

以下是一个基本的例子。

按钮:

 import java.awt.Color; import java.awt.Font; import java.awt.event.MouseEvent; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.border.Border; public class UWPButton extends JButton{ private final Border regularBorder; private final Border hoverBorder; private final Color bgColor = new Color(204, 204, 204); private final Color transparent; private final Font metroFont = new Font("Segoe UI", Font.PLAIN, 20); public UWPButton() { super(); // thickness of the button's borders int thickness = 4; // Create a transparent color, to use for the regular border // could also be the bgColor (204 204 204) Color c = new Color(1f, 0f, 0f, 0f); transparent = c; // Creates a compound border to be present on the button majority of the time. // uses an invisible line border on the outside in order to change border smoothly // the inside border is just an empty border for insets. regularBorder = BorderFactory.createCompoundBorder( BorderFactory.createLineBorder(transparent, thickness), //outside BorderFactory.createEmptyBorder(10, 14, 10, 14)); //inside // Creates a compound border which will be used when the mouse hovers the button. // the outside border has a darker colour than the background // the inside border is just an empty border for insets. hoverBorder = BorderFactory.createCompoundBorder( BorderFactory.createLineBorder(bgColor.darker(), thickness), //outside BorderFactory.createEmptyBorder(10, 14, 10, 14)); //inside // configures the button initButton(); } // Here is where the mouse events are treated. @Override protected void processMouseEvent(MouseEvent e) { // Gets the ID of the event, // if it is a mouse entering the button, sets the new border // if it is the mouse exiting the button, resets the border to the default. switch(e.getID()){ case MouseEvent.MOUSE_ENTERED: this.setBorder(hoverBorder); break; case MouseEvent.MOUSE_EXITED: this.setBorder(regularBorder); break; } // the parent then does all the other handling. super.processMouseEvent(e); } // Configures the button. private void initButton(){ setFont(metroFont); setBorder(regularBorder); setBackground(bgColor); setFocusPainted(false); } } 

更改LaF:如果您通过IDE拖放创建了框架,那么您的主内部应该有这样的内容(这来自netbeans):

将“Nimbus”更改为“Metro”(或删除LaF设置),以便界面管理器不会渲染所有Nimbus内容。 注意:没有“Metro”LaF,这只是禁用应用的LaF。

 // other stuff above // // change "Nimbus" for something else or just remove this try-catch block try { for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) { if ("Nimbus".equals(info.getName())) { javax.swing.UIManager.setLookAndFeel(info.getClassName()); break; } } } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | javax.swing.UnsupportedLookAndFeelException ex) { java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } // other stuff bellow 

更多关于LaF(外观和感觉): https : //docs.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html