简体   繁体   English

Swing - 删除选定的边框并更改 JComboBox 的箭头颜色

[英]Swing - Remove selected border and change arrow color of JComboBox

I'm trying to remove the selected border of a JComboBox (top arrow) and change the arrow color (bottom arrow)我正在尝试删除 JComboBox 的选定边框(顶部箭头)并更改箭头颜色(底部箭头)

If possible, how do I remove the outer border?如果可能,如何删除外边框? (the darker gray one) (较深的灰色)

How do I go about doing this?我该怎么做?

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.然后我们模仿BasicComboBoxUIcreateArrowButton()方法来创建我们自己的自定义按钮。 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 ,则JComboBoxLayoutManager将不会考虑箭头按钮的首选大小。 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM