[英]Swing - Remove selected border and change arrow color of JComboBox
So you can do this by implementing a ComboBoxUI
, or, actually, subclassing BasicComboBoxUI
for example.所以你可以通过实现一个
ComboBoxUI
来做到这一点,或者,实际上,例如,子类化BasicComboBoxUI
。 The second option is better, because you only need to tweak some code in some places and you are ready (instead of implementing your own ComboBoxUI
from scratch).第二种选择更好,因为您只需要在某些地方调整一些代码就可以了(而不是从头开始实现自己的
ComboBoxUI
)。 So follows the code which does what you requested (hopefully):因此,请遵循执行您要求的代码(希望如此):
import java.awt.Color;
import java.awt.GridBagLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.LookAndFeel;
import javax.swing.plaf.basic.BasicArrowButton;
import javax.swing.plaf.basic.BasicComboBoxUI;
public class MainComboBoxUI {
public static class MyComboBoxUI extends BasicComboBoxUI {
@Override
protected void installDefaults() {
super.installDefaults();
LookAndFeel.uninstallBorder(comboBox); //Uninstalls the LAF border for both button and label of combo box.
}
@Override
protected JButton createArrowButton() {
//Feel free to play with the colors:
final Color background = Color.CYAN.darker(); //Default is UIManager.getColor("ComboBox.buttonBackground").
final Color pressedButtonBorderColor = Color.RED; //Default is UIManager.getColor("ComboBox.buttonShadow"). The color of the border of the button, while it is pressed.
final Color triangle = Color.BLACK; //Default is UIManager.getColor("ComboBox.buttonDarkShadow"). The color of the triangle.
final Color highlight = background; //Default is UIManager.getColor("ComboBox.buttonHighlight"). Another color to show the button as highlighted.
final JButton button = new BasicArrowButton(BasicArrowButton.SOUTH, background, pressedButtonBorderColor, triangle, highlight);
button.setName("ComboBox.arrowButton"); //Mandatory, as per BasicComboBoxUI#createArrowButton().
return button;
}
}
public static void main(final String[] args) {
final JComboBox<String> combo = new JComboBox<>(new String[]{"A string", "B string 2", "C string 3"});
combo.setUI(new MyComboBoxUI());
final JPanel panel = new JPanel(new GridBagLayout());
panel.add(combo);
panel.setBackground(Color.RED.darker());
final JFrame frame = new JFrame("MainComboBoxUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
First of, we remove the border from the combo box inside installDefaults()
method.首先,我们从
installDefaults()
方法内的组合框中删除边框。 That will remove the border from both the button and the label.这将从按钮和标签中删除边框。 Then we mimic the
createArrowButton()
method of BasicComboBoxUI
to create our own custom button.然后我们模仿
BasicComboBoxUI
的createArrowButton()
方法来创建我们自己的自定义按钮。 The default implementation of BasicComboBoxUI.createArrowButton()
creates a BasicArrowButton
with some construction-time colors. BasicComboBoxUI.createArrowButton()
的默认实现创建了BasicArrowButton
带有一些构建时颜色的BasicArrowButton
。 Those colors change the button's triangle's color for example and the background color.例如,这些颜色会更改按钮的三角形颜色和背景颜色。
That is for creating a BasicArrowButton
.那是为了创建一个
BasicArrowButton
。 Although, if you want better control over the button (for example instead of a triangle you need an icon and/or some text on the button) then you can simply create a plain JButton
inside the createArrowButton()
instead of a BasicArrowButton
.虽然,如果您想更好地控制按钮(例如,您需要一个图标和/或按钮上的一些文本而不是三角形),那么您可以简单地在
createArrowButton()
内创建一个普通的JButton
而不是BasicArrowButton
。 Then you can initialize it inside the same method, or, preferably modify it inside the configureArrowButton()
.然后你可以在相同的方法中初始化它,或者最好在
configureArrowButton()
修改它。 Like the following code does:就像下面的代码一样:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.LookAndFeel;
import javax.swing.plaf.basic.BasicComboBoxUI;
public class MainComboBoxUI2 {
public static class MyComboBoxUI extends BasicComboBoxUI {
@Override
protected void installDefaults() {
super.installDefaults();
LookAndFeel.uninstallBorder(comboBox);
}
@Override
protected JButton createArrowButton() {
final JButton button = new JButton("V");
button.setName("ComboBox.arrowButton"); //Mandatory, as per BasicComboBoxUI#createArrowButton().
return button;
}
@Override
public void configureArrowButton() {
super.configureArrowButton(); //Do not forget this!
arrowButton.setBackground(Color.CYAN.darker());
arrowButton.setForeground(Color.BLUE);
}
}
public static void main(final String[] args) {
final JComboBox<String> combo = new JComboBox<>(new String[]{"A string", "B string 2", "C string 3"});
combo.setUI(new MyComboBoxUI());
combo.setPreferredSize(new Dimension(150, 45)); //Needed to be able to show the button's text.
final JPanel panel = new JPanel(new GridBagLayout());
panel.add(combo);
panel.setBackground(Color.RED.darker());
final JFrame frame = new JFrame("MainComboBoxUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
The only problem with the custom plain JButton
approach (ie the second approach) is that the LayoutManager
of the JComboBox
will not take into account the preferred size of the arrow button if a protected flag inside the UI (named squareButton ) is true
.自定义普通
JButton
方法(即第二种方法)的唯一问题是,如果 UI 内的受保护标志(名为squareButton )为true
,则JComboBox
的LayoutManager
将不会考虑箭头按钮的首选大小。 If that flag is true
, then the button's width is set equal to the button's height, which in turn is set equal to the combo box height.如果该标志为
true
,则按钮的宽度设置为等于按钮的高度,而按钮的高度又设置为等于组合框的高度。 That's why in the second approach, I set the preferred size of the combo box manually to give it a height of 45 pixels which is enough to be able to display the text inside the button (in that specific case, where the text is equal to "V").这就是为什么在第二种方法中,我手动设置组合框的首选大小,使其高度为 45 像素,这足以能够在按钮内显示文本(在这种特定情况下,文本等于“V”)。
You can set the value of this flag for a single UI instance manually by overriding installDefaults()
method in the BasicComboBoxUI
and setting it to false
for example.例如,您可以通过覆盖
BasicComboBoxUI
中的installDefaults()
方法并将其设置为false
来手动为单个 UI 实例设置此标志的值。 Otherwise, you can set its value for all combo boxes via calling UIManager.put("ComboBox.squareButton", Boolean.FALSE);
否则,您可以通过调用
UIManager.put("ComboBox.squareButton", Boolean.FALSE);
为所有组合框设置其值UIManager.put("ComboBox.squareButton", Boolean.FALSE);
in your code early enough (ie before the instantiation of each combo box).在您的代码中足够早(即在每个组合框的实例化之前)。 But as it turns out, because I tested it, when setting this value to
false
the size of the button overlaps the display area's size (the display area is where the selected value of the combo box is visible).但事实证明,因为我测试了它,当将此值设置为
false
时,按钮的大小与显示区域的大小重叠(显示区域是组合框的选定值可见的地方)。
After some more digging, I found out that the cause of this problem is that the UI's getMinimumSize(...)
method does not take into account the button's insets... That means the default border of the JButton
around the text/icon is not accounted for.进一步挖掘后,我发现这个问题的原因是 UI 的
getMinimumSize(...)
方法没有考虑按钮的 insets ......这意味着文本/图标周围的JButton
的默认边框是不计入。 So after setting the squareButton flag to false
, you will also need to override this method.因此,在将squareButton标志设置为
false
,您还需要覆盖此方法。
Putting them all together, you get the following final approach/code:将它们放在一起,您将获得以下最终方法/代码:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.LookAndFeel;
import javax.swing.UIManager;
import javax.swing.plaf.basic.BasicComboBoxUI;
public class MainComboBoxUI3 {
public static class MyComboBoxUI extends BasicComboBoxUI {
@Override
protected void installDefaults() {
super.installDefaults();
LookAndFeel.uninstallBorder(comboBox);
}
@Override
protected JButton createArrowButton() {
final JButton button = new JButton("Drop");
button.setName("ComboBox.arrowButton"); //Mandatory, as per BasicComboBoxUI#createArrowButton().
return button;
}
@Override
public void configureArrowButton() {
super.configureArrowButton(); //Do not forget this!
arrowButton.setBackground(Color.CYAN.darker());
arrowButton.setForeground(Color.BLUE);
//arrowButton.setBorder(javax.swing.BorderFactory.createEmptyBorder());
}
//Overrided getMinimumSize to take into account the button's insets for both width and height:
@Override
public Dimension getMinimumSize(final JComponent c) {
final Dimension mindim = super.getMinimumSize(c);
final Insets buttonInsets = arrowButton.getInsets();
return new Dimension(mindim.width + buttonInsets.left + buttonInsets.right, mindim.height + buttonInsets.top + buttonInsets.bottom);
}
}
public static void main(final String[] args) {
UIManager.put("ComboBox.squareButton", Boolean.FALSE); //Set all the combo boxes' button to non-square...
final JComboBox<String> combo = new JComboBox<>(new String[]{"A string", "B string 2", "C string 3"});
combo.setUI(new MyComboBoxUI());
final JPanel panel = new JPanel(new GridBagLayout());
panel.add(combo);
panel.setBackground(Color.RED.darker());
final JFrame frame = new JFrame("MainComboBoxUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
And the result looks like this:结果如下所示:
Finally, if you want smaller border for the drop down button (ie the one with text "Drop" in the above picture), you can set the border of the arrowButton
to (for example) javax.swing.BorderFactory.createEmptyBorder()
inside the configureArrowButton()
method...最后,如果希望下拉按钮的边框变小(即上图中带有文字“Drop”的那个),可以将
arrowButton
按钮的边框设置为(例如) javax.swing.BorderFactory.createEmptyBorder()
inside configureArrowButton()
方法...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.