引言:
众所周知,swing的默认样式已经控件是非常基础,并且不是特别好看的,本节将介绍如何美化界面,以及拓展控件
目录
- JFrame添加背景图以及应用图标
- 全局字体抗锯齿
- 自定义系统关闭窗口功能
- JCheckBox修改勾选图标
- JCombobox设置边框背景颜色
- JMenu修改字体居中显示
- JTextField输入框添加图标
- JTable样式居中背景调整或隐藏某一列
- ComboboxUI美化
- JButton配置隐藏文字聚焦框
- JPassword配置文本显示以及隐藏
一、JFrame添加背景图以及应用图标
代码入下:实现JFrame
public MyFrame() {
super();
setTitle("XXX");
try {
URL imgURL = MyFrame.class.getResource("/static/image/titleLogin.png");
Image image = ImageIO.read(imgURL);
setIconImage(image);
} catch (IOException e) {
e.printStackTrace();
}
try{
URL imgURL = MyFrame.class.getResource("/static/image/backgroud.png");
ImageIcon img = new ImageIcon(ImageIO.read(imgURL));
JLabel imgLabel = new JLabel(img);//将背景图放在标签里。
this.getLayeredPane().add(imgLabel, new Integer(Integer.MIN_VALUE));//注意这里是关键,将背景标签添加到jfram的LayeredPane面板里。
imgLabel.setBounds(0,0,img.getIconWidth(), img.getIconHeight());//设置背景标签的位置
Container cp=this.getContentPane();
cp.setLayout(new BorderLayout());
((JPanel)cp).setOpaque(false);
}catch(IOException e1){
e1.printStackTrace();
}
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setBackground(new java.awt.Color(255, 255, 255));
setPreferredSize(new Dimension(920,492));
setSize(920,492);
setLocationRelativeTo(null);
setResizable(false);
}
二、全局字体抗锯齿
代码如下:需要注意要在JFrame之前调用UIs.setUI();
import javax.swing.*;
import javax.swing.plaf.FontUIResource;
import java.awt.*;
import java.util.HashMap;
import java.util.Map;
public class UIs {
private static final String FALLBACK_FONT_FAMILY_NAME = Font.SANS_SERIF;
private static final Map<String, String> FONT_FAMILY_NAMES = new HashMap<>();
private static final String[] BEST_FONT_FAMILIES = {
"微软雅黑", "arial", "sans-serif"
};
private static final int BEST_FONT_SIZE = 14; // 12px
static {
GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
String[] fontFamilyNames = env.getAvailableFontFamilyNames();
for (String fontFamilyName : fontFamilyNames) {
FONT_FAMILY_NAMES.put(fontFamilyName.toLowerCase(), fontFamilyName);
}
if (!FONT_FAMILY_NAMES.containsKey("serif")) {
FONT_FAMILY_NAMES.put("serif", Font.SERIF);
}
if (!FONT_FAMILY_NAMES.containsKey("sans-serif")) {
FONT_FAMILY_NAMES.put("sans-serif", Font.SANS_SERIF);
}
}
public static void enableAntiAliasing() {
System.setProperty("awt.useSystemAAFontSettings", "on");
System.setProperty("swing.aatext", "true");
}
public static String getLookAndFeel() {
try {
for (UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
return info.getClassName();
}
}
} catch (Exception ignore) {
}
return UIManager.getCrossPlatformLookAndFeelClassName();
}
public static String getFontFamily(String[] fontFamilies) {
for (String fontFamily : fontFamilies) {
fontFamily = fontFamily.toLowerCase();
if (FONT_FAMILY_NAMES.containsKey(fontFamily)) {
return FONT_FAMILY_NAMES.get(fontFamily);
}
}
return FALLBACK_FONT_FAMILY_NAME;
}
public static String[] getBestFontFamilies() {
return BEST_FONT_FAMILIES;
}
public static int getBestFontSize() {
return BEST_FONT_SIZE;
}
public static void setUI() {
enableAntiAliasing();
// set LookAndFeel
// try {
// UIManager.setLookAndFeel(getLookAndFeel());
// } catch (Exception ignore) {
// }
// set DefaultFont
String bestFontFamily = getFontFamily(getBestFontFamilies());
for (Map.Entry<Object, Object> entry : UIManager.getDefaults().entrySet()) {
if (entry.getValue() instanceof FontUIResource) {
FontUIResource fontUIRes = (FontUIResource) entry.getValue();
entry.setValue(new FontUIResource(
bestFontFamily,
fontUIRes.getStyle(),
getBestFontSize() > fontUIRes.getSize() ?
getBestFontSize() : fontUIRes.getSize()
));
}
}
}
}
三、自定义系统关闭窗口功能
1.首先,重写JFrame的processWindowEvent
@Override
protected void processWindowEvent(WindowEvent pEvent) {
if (pEvent.getID() == WindowEvent.WINDOW_CLOSING) {
/** 防止用户多次点击“关闭”按钮造成重复保存 **/
//处理JFrame关闭事件……
CommonBtnEvent.exitSystemBtnHandler();
} else {
//忽略其他事件,交给JFrame处理
super.processWindowEvent(pEvent);
}
}
2.其次,书写自己的CommonBtnEvent方法
import lombok.extern.slf4j.Slf4j;
import javax.swing.*;
/**
* @Author:hongyueyuan
* @Date: 2022/3/19
*/
@Slf4j
public class CommonBtnEvent {
public static void exitSystemBtnHandler() {
log.info("退出系统操作");
int result = -1;
try{
LookAndFeel lookAndFeel=UIManager.getLookAndFeel();
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
result = JOptionPane.showConfirmDialog(null, "是否要退出系统?", "退出确认", JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
UIManager.setLookAndFeel(lookAndFeel);
}catch(Exception e){
log.error("",e);
}
if (result == JOptionPane.YES_OPTION){
//退出系统
System.exit(0);
}
}
}
四、 JCheckBox修改勾选图标
代码如下:直接设置属性setIcon与setSelectedIcon
import javax.imageio.ImageIO;
import javax.swing.*;
/**
* @Author:hongyueyuan
* @Date: 2022/4/24
*/
public class JComCheckBox extends JCheckBox {
public JComCheckBox() {
try{
setIcon(new ImageIcon(ImageIO.read(JComCheckBox.class.getResourceAsStream("/static/image/checkbox_unselect.png"))));
setSelectedIcon(new ImageIcon(ImageIO.read(JComCheckBox.class.getResourceAsStream("/static/image/checkbox_select.png"))));
}catch (Exception e){
e.printStackTrace();
}
}
}
五、JCombobox设置边框背景颜色
代码如下:
import javax.swing.*;
import java.awt.*;
/**
* @Author:hongyueyuan
* @Date: 2022/4/24
*/
public class JComCombobox extends JComboBox {
public JComCombobox() {
setFont(new java.awt.Font("微软雅黑", 0, 28)); // NOI18N
setForeground(new java.awt.Color(38, 38, 38));
setBorder(new javax.swing.border.LineBorder(new java.awt.Color(24, 144, 255), 2, true));
setPreferredSize(new java.awt.Dimension(420, 74));
setMinimumSize(new java.awt.Dimension(420, 74));
}
@Override
protected void paintComponent(Graphics g) {
Graphics2D g2d= (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
//消除画图锯齿
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
super.paintComponent(g2d);
}
}
六、JMenu修改字体居中显示
特别注意:由于JMenuItem配置setHorizontalAlignment(SwingConstants.CENTER);没有效果;所以用下面的方式
1.首次,重写BasicMenuItemUI
import javax.swing.*;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicMenuItemUI;
import java.awt.*;
/**
* @Author:hongyueyuan
* @Date: 2022/4/25
*/
public class CustomMenuUI extends BasicMenuItemUI {
public static ComponentUI createUI(JComponent c) {
return new CustomMenuUI();
}
@Override
protected void paintText(Graphics g, JMenuItem menuItem, Rectangle textRect, String text) {
int w2 = menuItem.getBounds().width/2-2;
textRect.translate(w2 - textRect.width/2, 0);
Graphics2D g2d= (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
//消除画图锯齿
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
super.paintText(g2d, menuItem, textRect, text);
}
}
2、JMenuItem配置UI
JPopupMenu popupMenu = new JPopupMenu();
// 创建 一级菜单
JMenuItem classMenuItem = new JMenuItem("切换班级");
classMenuItem.setBackground(Color.white);
classMenuItem.setFont(new java.awt.Font("微软雅黑", 0, 14));
classMenuItem.setForeground(new Color(38,38,38));
classMenuItem.setPreferredSize(new Dimension(126,50));
classMenuItem.setSize(new Dimension(126,50));
classMenuItem.setMinimumSize(new Dimension(126,50));
classMenuItem.setMaximumSize(new Dimension(126,50));
classMenuItem.setHorizontalAlignment(SwingConstants.CENTER);
classMenuItem.setHorizontalTextPosition(SwingConstants.CENTER);
classMenuItem.setVerticalAlignment(SwingConstants.CENTER);
classMenuItem.setVerticalTextPosition(SwingConstants.CENTER);
classMenuItem.setUI(new CustomMenuUI());
popupMenu.add(classMenuItem);
七、JTextField输入框添加图标
特别注意:setMargin和setBorder不能同时存在,setBorder会被setMargin覆盖没有下效果,paintBorder方法
代码如下:
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
/**
* @Author:hongyueyuan
* @Date: 2022/3/9
*/
public class JTextFieldUser extends JTextField {
private ImageIcon icon;
@Override
protected void paintBorder(Graphics g) {
//设置外边框
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(new Color(217,217,217));
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.drawRoundRect(0, 0, getWidth() - 1, getHeight() - 1, 1, 1);
g2d.dispose();
}
public JTextFieldUser() throws IOException {
// 获取当前路径下的图片
setFont(new java.awt.Font("微软雅黑", 0, 16)); // NOI18N
setToolTipText("账号"); // NOI18N
setPreferredSize(new java.awt.Dimension(360, 50));
setSelectionColor(new java.awt.Color(24, 144, 255));
URL imgURL = JTextFieldUser.class.getResource("/static/image/user.png");
BufferedImage image = ImageIO.read(imgURL);
int imgwidth=image.getWidth();
int imgheight=image.getHeight();
icon=new ImageIcon(image);
//配置文本输入向右偏移imgwidth*2的宽度
Insets insets = new Insets(0, imgwidth*2, 0, 0);
setMargin(insets);
}
@Override
public void paintComponent(Graphics g) {
Insets insets = getInsets();
super.paintComponent(g);
int iconWidth = icon.getIconWidth();
int iconHeight = icon.getIconHeight();
int Height = this.getHeight();
//在文本框中画上之前图片
icon.paintIcon(this, g, iconWidth/2, (Height - iconHeight) / 2);
}
}
八、JTable样式居中背景调整或隐藏某一列 代码如下:
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import sun.swing.table.DefaultTableCellHeaderRenderer;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.List;
/**
* @Author:hongyueyuan
* @Date: 2022/3/14
*/
@NoArgsConstructor
@Slf4j
public class StudentListTable {
private static final String[] COL_NAMES = {"studentId", "学生名称", "状态"};
public void initTable(List<PcStudentListResp> list, JTable jtable) throws IOException {
jtable.setEnabled(false);
jtable.setGridColor(new java.awt.Color(250, 250, 250));
jtable.setBackground(new Color(255,255,255));
jtable.setShowVerticalLines(false);
String[] colNames = COL_NAMES;
DefaultTableModel model = new DefaultTableModel(colNames, 0) {
@Override
public Class<?> getColumnClass(int column) {
if (getRowCount() > 0) {
Object value = getValueAt(0, column);
if (value != null) {
return getValueAt(0, column).getClass();
}
}
return super.getColumnClass(column);
}
};
int iconHeight = 25;
URL penConnectUrl = StudentListPanel.class.getResource("/static/image/connect.png");
BufferedImage penConnectImg = ImageIO.read(penConnectUrl);
penConnectImg.getScaledInstance(iconHeight, iconHeight, Image.SCALE_FAST);
ImageIcon penConnectIcon = new ImageIcon(penConnectImg);
URL penDisconnectUrl = StudentListPanel.class.getResource("/static/image/disconnect.png");
BufferedImage penDisconnectImg = ImageIO.read(penDisconnectUrl);
penDisconnectImg.getScaledInstance(iconHeight, iconHeight, Image.SCALE_FAST);
ImageIcon penDisconnectIcon = new ImageIcon(penDisconnectImg);
if (list == null || list.size() == 0) {
log.info("学生列表为空");
} else {
for (int i = 0; i < list.size(); i++) {
Object[] rowData = null;
if (list.get(i).getStatus().equals(PenConnectStatusEnum.CONNECT_STATUS.getCode())) {
rowData = new Object[]{list.get(i).getId(), list.get(i).getSmName(), penConnectIcon};
} else {
rowData = new Object[]{list.get(i).getId(), list.get(i).getSmName(), penDisconnectIcon};
}
model.addRow(rowData);
}
}
jtable.setModel(model);
jtable.setRowHeight(45);
DefaultTableCellRenderer tcr = new DefaultTableCellRenderer();//单元格渲染器
tcr.setHorizontalAlignment(SwingConstants.CENTER);//居中显示
jtable.setDefaultRenderer(Object.class, tcr);//设置渲染器
jtable.getTableHeader().setPreferredSize(new Dimension(jtable.getWidth() / 2, 45));
jtable.getTableHeader().setReorderingAllowed(false);
jtable.getTableHeader().setResizingAllowed(false);
//jtable.getTableHeader().setBackground(new Color(250,250,250));
jtable.getTableHeader().setBorder(BorderFactory.createEmptyBorder(0,0,0,0));
DefaultTableCellRenderer tableRender = new DefaultTableCellRenderer();//单元格渲染器
tableRender.setHorizontalAlignment(SwingConstants.CENTER);//居中显示
tableRender.setBackground(new Color(250,250,250));
tableRender.setFont(new java.awt.Font("微软雅黑", 1, 14));
tableRender.setForeground(Color.BLACK);
//tableRender.setBorder(BorderFactory.createLineBorder(Color.red));
jtable.getTableHeader().setDefaultRenderer(tableRender);
jtable.getTableHeader().setFont(new Font("微软雅黑", 1, 14));
jtable.setEnabled(false);
jtable.getTableHeader().setForeground(new Color(26,26,26));
hideColumn(jtable, 0);
}
protected void hideColumn(JTable table, int index) {
//隐藏某一列
TableColumn tc = table.getColumnModel().getColumn(index);
tc.setMaxWidth(0);
tc.setPreferredWidth(0);
tc.setMinWidth(0);
tc.setWidth(0);
table.getTableHeader().getColumnModel().getColumn(index).setMaxWidth(0);
table.getTableHeader().getColumnModel().getColumn(index).setMinWidth(0);
}
}
九、ComboboxUI美化
代码如下: 1.首先,拓展BasicComboBoxUI
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.plaf.basic.BasicComboBoxUI;
import javax.swing.plaf.basic.BasicComboPopup;
import javax.swing.plaf.basic.ComboPopup;
import java.awt.*;
/**
* @Author:hongyueyuan
* @Date: 2022/4/25
*/
public class CustomComboxUI extends BasicComboBoxUI {
private static Color DEFAULT_COLOR = new Color(24, 144, 255);
@Override
public void installUI(JComponent c) {
super.installUI(c);
JComboBox comboBox = (JComboBox) c;
comboBox.setFocusable(true);
comboBox.setOpaque(false);
comboBox.setRenderer(new MyListCellRenderer());
}
@Override
protected JButton createArrowButton() {
// 也可以使用BasicComboBoxUI里的arrowButton对象
ImageIcon DOWN_ICON =null;
try{
DOWN_ICON = new ImageIcon(ImageIO.read(CustomComboxUI.class.getResourceAsStream("/static/image/downBtn.png")));
}catch(Exception e){
}
JButton arrow = new JButton();
// 设置自己定义的UI
arrow.setUI(new MyButtonUI());
// 设置下拉箭头图标
arrow.setIcon(DOWN_ICON);
// 设置无法获得焦点
arrow.setFocusable(false);
// 设置边距,调整图标位置
// arrow.setMargin(new Insets(0, 20, 0, 0));
return arrow;
}
@Override
public void paint(Graphics g, JComponent c) {
// 也可以使用BasicComboBoxUI里的combobox对象
JComboBox comboBox = (JComboBox) c;
hasFocus = comboBox.hasFocus();
Rectangle r = rectangleForCurrentValue();
// JComboBox的textfield的绘制,并不是靠Renderer来控制
// 它会通过paintCurrentValueBackground来绘制背景
// 然后通过paintCurrentValue去绘制显示的值
Graphics2D g2d = (Graphics2D) g;
if (!comboBox.isEditable()) {
paintCurrentValueBackground(g2d, r, hasFocus);
paintCurrentValue(g2d, r, hasFocus);
} else {
paintCurrentValueBackground(g2d, r, hasFocus);
}
// 获取焦点时,用不同颜色来区分
if (comboBox.hasFocus()) {
g2d.setColor(DEFAULT_COLOR);
} else {
g2d.setColor(Color.GRAY);
}
// 边框透明度
//g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
// 绘制边框,后两个参数控制圆角
// 边框也有占位,所以宽高都需要减去2,否则会导致边框不全
g2d.drawRoundRect(0, 0, comboBox.getWidth() - 2, comboBox.getHeight() - 2, 2, 2);
}
@Override
protected ComboPopup createPopup() {
BasicComboPopup popup = (BasicComboPopup) super.createPopup();
// 获取到popup,为其设置边框,和combobox的颜色保持同步
popup.setBorder(BorderFactory.createLineBorder(DEFAULT_COLOR));
return popup;
}
}
2.拓展BasicButtonUI
import javax.swing.*;
import javax.swing.plaf.basic.BasicButtonUI;
/**
* @Author:hongyueyuan
* @Date: 2022/4/25
*/
public class MyButtonUI extends BasicButtonUI implements SwingConstants {
@Override
public void installUI(JComponent c) {
super.installUI(c);
JButton button = (JButton) c;
button.setContentAreaFilled(false);//父类不用绘制内容
button.setFocusPainted(false);//父类不用绘制焦点
button.setBorderPainted(false);//父类不用绘制边框
}
}
3.其次,JComboBox设置UI
gradeCombobox.setUI(new CustomComboxUI());
十、 JButton配置隐藏文字聚焦框
代码如下:
showPasswordBtn.setFocusPainted(false);
十一、 JPasswordField配置文本显示以及隐藏
jspf.setEchoChar(char(0));//这行代码可以显示明文
jspf.setEchoChar('*');//这行代码用于隐藏