您现在的位置是:网站首页 > 代码编程 > JAVA开发JAVA开发
【原】Swing界面优化JComboBox详细图文教程
不忘初心 2017-11-03 围观() 评论() 点赞() 附件(1) 【JAVA开发】
简介:之前写过一个SwingQQ的项目,在字体设置那些下拉选项中,没有找到如何优化UI,所以就还是用原生的组件,把整体界面的美观度都给拖累了,后来自己也在iteye上
之前写过一个SwingQQ的项目,在字体设置那些下拉选项中,没有找到如何优化UI,所以就还是用原生的组件,把整体界面的美观度都给拖累了,后来自己也在iteye上发表了几篇swing界面优化的帖子,但是始终还是没有将JComboBox组件给优化出来,最近研究了一下开源组件weblookandfeel,学习了一下实现思路,自己写个例子分享一下。
先给大家看一下之前那个惨不忍睹的界面(SwingQQ详解),就是选择颜色背景那块的下拉框,真的很丑
简直辣眼睛,下面来分析一下如何优化:
jcombobox总共有三个部分组成:editor、button、popup,分别是编辑区域、下拉按钮、展示区域
可以说,拉低美观的最主要原因就是这个按钮,其次是下拉框中的一些颜色搭配,就从这两个点入手了。
之前在iteye上也发表过其他组件优化的帖子(JTree的优化),里面提到了两个概念,一个是UI,一个是Renderer,这两个东西就是优化的代码所在了,在swing中,每个组件都会有一个UI,入口就是他里面的installUI()方法,也就是我们需要重写这个方法;Renderer的中文释义是“渲染”,他在swing中扮演渲染器的作用,UI负责调用它来渲染出每一个组件,里面会有一个get*CellRendererComponent()方法,这里用*号,是因为每个组件的名字都不一样,它会返回每个渲染后的单个元素。
好了,概念弄清楚了,下面我们来看看代码,根据上面所说,直接找到BasicComboBoxUI,里面有三个关于button的方法和一个关于popup(下拉框)的方法
/**
* This public method is implementation specific and should be private. Do
* not call or override.
*
* @see #createArrowButton
*/
public void configureArrowButton() {
if ( arrowButton != null ) {
arrowButton.setEnabled( comboBox.isEnabled() );
arrowButton.setFocusable(comboBox.isFocusable());
arrowButton.setRequestFocusEnabled(false);
arrowButton.addMouseListener( popup.getMouseListener() );
arrowButton.addMouseMotionListener( popup.getMouseMotionListener() );
arrowButton.resetKeyboardActions();
arrowButton.putClientProperty("doNotCancelPopup", HIDE_POPUP_KEY);
arrowButton.setInheritsPopupMenu(true);
}
}
/**
* This public method is implementation specific and should be private. Do
* not call or override.
*
* @see #createArrowButton
*/
public void unconfigureArrowButton() {
if ( arrowButton != null ) {
arrowButton.removeMouseListener( popup.getMouseListener() );
arrowButton.removeMouseMotionListener( popup.getMouseMotionListener() );
}
}
/**
* Creates a button which will be used as the control to show or hide
* the popup portion of the combo box.
*
* @return a button which represents the popup control
*/
protected JButton createArrowButton() {
JButton button = new BasicArrowButton(BasicArrowButton.SOUTH,
UIManager.getColor("ComboBox.buttonBackground"),
UIManager.getColor("ComboBox.buttonShadow"),
UIManager.getColor("ComboBox.buttonDarkShadow"),
UIManager.getColor("ComboBox.buttonHighlight"));
button.setName("ComboBox.arrowButton");
return button;
}
/**
* Creates the popup portion of the combo box.
*
* @return an instance of <code>ComboPopup</code>
* @see ComboPopup
*/
protected ComboPopup createPopup() {
return new BasicComboPopup( comboBox );
}
中间的方法可以不看,它是用来取消button的事件,主要就是第三个和第一个方法,第三个方法创建了一个Jbutton,第一个方法对这个Jbutton加入了一系列的配置和事件,它这个Jbutton是一个BasicArrowButton,我们可以不用,因为Jbutton很简单,完全可以自己来写;而最后一个方法则是用来重写popup的,框框没有过多要求,简洁大方就很好看了,所以只需要调整一下颜色即可。
so,直接上代码了,继承BasicComboBoxUI,重写相关的方法
package com.wolffy.ui;
import com.alee.laf.combobox.WebComboBoxUI;
import com.wolffy.render.MyListCellRenderer;
import javax.swing.*;
import javax.swing.plaf.basic.BasicComboBoxUI;
import javax.swing.plaf.basic.BasicComboPopup;
import javax.swing.plaf.basic.ComboPopup;
import java.awt.*;
/**
* Created by SongFei on 2017/10/24.
*/
public class MyComboBoxUI extends BasicComboBoxUI {
private static ImageIcon DOWN_ICON = new ImageIcon(WebComboBoxUI.class.getResource("icons/down.png"));
private static Color DEFAULT_COLOR = new Color(150, 207, 254);
@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对象
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;
}
}
代码中有两个地方需要注意,一个是paint方法,一个是MyButtonUI,之所以将paint方法也重写一下,因为它的背景和值都是绘制出来的,这个方法会被频繁调用,这里可以控制一下它的焦点颜色;至于MyButtonUI则是为了代码更清晰,将公共的代码拆分出来
package com.wolffy.ui;
import javax.swing.*;
import javax.swing.plaf.basic.BasicButtonUI;
/**
* Created by SongFei on 2017/11/1.
*/
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);//父类不用绘制边框
}
}
大家可以看到,MyButtonUI中也是一堆set,这些东西放到MyComboBoxUI的createArrowButton()方法中也是可以的。
按钮和整体的border,已经优化的差不多了,再来看看下拉框popup组件,因为它有很多item,所以是一个list集合的形式,它需要循环渲染,swing调用的是ListCellRenderer,上面说过了渲染器中,主要用到的方法是get*CellRendererComponent(),那么这里需要重写的方法就是getListCellRendererComponent()了。
下拉框中的内容,都是一行一行的,从左到右,只显示一个纯文本,我们可以用一个Jlabel来渲染,这个是最简单的,想要更多的效果,大家可以自行组合,比如说用Jpanel来渲染,Jpanel里面可以放N多组件
package com.wolffy.render;
import javax.swing.*;
import java.awt.*;
/**
* Created by SongFei on 2017/11/2.
*/
public class MyListCellRenderer implements ListCellRenderer {
private DefaultListCellRenderer defaultCellRenderer = new DefaultListCellRenderer();
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
// 每一行,都转换成jlabel来处理
JLabel renderer = (JLabel) defaultCellRenderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
// 每一行的jlabel的颜色
if (isSelected) {
renderer.setBackground(new Color(150, 207, 254));
renderer.setForeground(Color.WHITE);
} else {
renderer.setBackground(null);
}
// 字体靠左
renderer.setHorizontalAlignment(JLabel.LEFT);
// 左侧padding
renderer.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0));
// render的宽高
renderer.setPreferredSize(new Dimension(100, 25));
// list背景色,也就是向下的按钮左边儿那一块儿
list.setSelectionBackground(null);
list.setBorder(null);
return renderer;
}
}
UI和Renderer都已经重写了,那么我们来写一个Frame调用一下,看看效果
package com.wolffy.frame;
import com.wolffy.ui.MyComboBoxUI;
import javax.swing.*;
import java.awt.*;
/**
* Created by SongFei on 2017/10/24.
*/
public class LoginFrame extends JFrame {
private static final long serialVersionUID = 474825076033661007L;
private JPanel jPanel;
private JComboBox jComboBox;
public LoginFrame() {
initGUI();
}
private void initGUI() {
setSize(700, 500);
//setUndecorated(true);
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
jPanel = new JPanel();
jPanel.setLayout(null);
jPanel.setBorder(BorderFactory.createLineBorder(Color.GRAY));
getContentPane().add(jPanel, BorderLayout.CENTER);
String[] texts = {"张三", "李四", "王五", "赵六", "田七"};
jComboBox = new JComboBox<>(texts);
//jComboBox.setEditable(true);
jComboBox.setUI(new MyComboBoxUI());
jComboBox.setBounds(100, 70, 100, 50);
jPanel.add(jComboBox);
}
public static void main(String[] args) {
LoginFrame loginFrame = new LoginFrame();
loginFrame.setVisible(true);
//loginFrame.pack();
}
}
效果图如下:
和之前一比,简直不要太好看!
看完文章,有任何疑问,请加入群聊一起交流!!!
很赞哦! ()
相关文章
标签云
猜你喜欢
- IntelliJ IDEA 2019.2已经可以利用补丁永久破解激活了
- IntelliJ IDEA 2019.3利用补丁永久破解激活教程
- IntelliJ IDEA高版本最灵活的永久破解激活方法(含插件激活,时长你说了算)
- Jetbrains全家桶基于ja-netfilter的最新破解激活详细图文教程
- IntelliJ IDEA 2022.1永久破解激活教程(亲测可用,持续更新)
- 分享几个正版 IntelliJ IDEA 激活码(破解码、注册码),亲测可用,持续更新
- ja-netfilter到底需不需要mymap,2021.3.2版本激活失效?
- 如何激活idea2022.1及以上版本中的插件(亲测可用)
- 【史上最全】IntelliJ IDEA最新2022.1版本安装和激活视频教学(含插件)
- IntelliJ IDEA 2022.2 版本最新2099年永久激活方法,亲测可用,也可以开启新UI了。
站点信息
- 网站程序:spring + freemarker
- 主题模板:《今夕何夕》
- 文章统计:篇文章
- 标签管理:标签云
- 微信公众号:扫描二维码,关注我们