diff --git a/designer-base/src/main/java/com/fr/design/gui/itree/checkboxtree/NullTristateCheckBox.java b/designer-base/src/main/java/com/fr/design/gui/itree/checkboxtree/NullTristateCheckBox.java index 2d742165c..d46b12553 100644 --- a/designer-base/src/main/java/com/fr/design/gui/itree/checkboxtree/NullTristateCheckBox.java +++ b/designer-base/src/main/java/com/fr/design/gui/itree/checkboxtree/NullTristateCheckBox.java @@ -62,6 +62,7 @@ public class NullTristateCheckBox extends TristateCheckBox { @Override public void updateUI() { + super.updateUI(); clearAttribute(); } diff --git a/designer-base/src/main/java/com/fr/design/gui/itree/checkboxtree/TristateCheckBox.java b/designer-base/src/main/java/com/fr/design/gui/itree/checkboxtree/TristateCheckBox.java index b821b0731..dcf062703 100644 --- a/designer-base/src/main/java/com/fr/design/gui/itree/checkboxtree/TristateCheckBox.java +++ b/designer-base/src/main/java/com/fr/design/gui/itree/checkboxtree/TristateCheckBox.java @@ -1,33 +1,17 @@ package com.fr.design.gui.itree.checkboxtree; -import com.fr.design.constants.UIConstants; +import com.fine.theme.icon.LazyIcon; import com.fr.design.event.StateChangeListener; import com.fr.design.gui.icheckbox.UICheckBox; -import com.fr.design.utils.gui.GUIPaintUtils; -import com.fr.stable.Constants; -import sun.swing.SwingUtilities2; import javax.swing.AbstractAction; -import javax.swing.AbstractButton; import javax.swing.ActionMap; import javax.swing.ButtonGroup; import javax.swing.ButtonModel; import javax.swing.Icon; -import javax.swing.JComponent; import javax.swing.SwingUtilities; import javax.swing.event.ChangeListener; import javax.swing.plaf.ActionMapUIResource; -import javax.swing.plaf.basic.BasicHTML; -import javax.swing.plaf.metal.MetalCheckBoxUI; -import javax.swing.text.View; -import java.awt.Dimension; -import java.awt.Font; -import java.awt.FontMetrics; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Insets; -import java.awt.Rectangle; -import java.awt.RenderingHints; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemListener; @@ -54,6 +38,7 @@ import java.awt.event.MouseListener; * @author Dr. Heinz M. Kabutz */ public class TristateCheckBox extends UICheckBox { + /** * This is a type-safe enumerated type */ @@ -80,7 +65,6 @@ public class TristateCheckBox extends UICheckBox { public TristateCheckBox(String text, Icon icon, State initial) { super(text, icon); - setUI(new TristateCheckBoxUI()); // Add a listener for when the mouse is pressed super.addMouseListener(new MouseAdapter() { @Override @@ -106,19 +90,21 @@ public class TristateCheckBox extends UICheckBox { setState(initial); } + @Override + public Icon getSelectedIcon() { + return getState() == DO_NOT_CARE ? new LazyIcon("checkbox_part_checked") : super.getSelectedIcon(); + } + public TristateCheckBox(String text, State initial) { this(text, null, initial); - setUI(new TristateCheckBoxUI()); } public TristateCheckBox(String text) { this(text, DO_NOT_CARE); - setUI(new TristateCheckBoxUI()); } public TristateCheckBox() { this(null); - setUI(new TristateCheckBoxUI()); } /** @@ -359,84 +345,4 @@ public class TristateCheckBox extends UICheckBox { } } - private class TristateCheckBoxUI extends MetalCheckBoxUI { - @Override - public void paint(Graphics g, JComponent c) { - synchronized (this) { - AbstractButton b = (AbstractButton) c; - ButtonModel model = b.getModel(); - Dimension size = c.getSize(); - Font f = c.getFont(); - g.setFont(f); - FontMetrics fm = SwingUtilities2.getFontMetrics(c, g, f); - - Rectangle viewRect = new Rectangle(size); - Rectangle iconRect = new Rectangle(); - Rectangle textRect = new Rectangle(); - - Insets i = c.getInsets(); - viewRect.x += i.left; - viewRect.y += i.top; - viewRect.width -= (i.right + viewRect.x); - viewRect.height -= (i.bottom + viewRect.y); - - Icon altIcon = b.getIcon(); - - String text = SwingUtilities.layoutCompoundLabel( - c, fm, b.getText(), altIcon != null ? altIcon : getDefaultIcon(), - b.getVerticalAlignment(), b.getHorizontalAlignment(), - b.getVerticalTextPosition(), b.getHorizontalTextPosition(), - viewRect, iconRect, textRect, b.getIconTextGap()); - - // fill background - if (c.isOpaque()) { - g.setColor(b.getBackground()); - g.fillRect(0, 0, size.width, size.height); - } - - Graphics2D g2d = (Graphics2D) g; - g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - if (SELECTED.equals(getState())) { - GUIPaintUtils.fillPaint(g2d, iconRect.x, iconRect.y, iconRect.width, iconRect.height, false, Constants.NULL, - model.isEnabled() ? UIConstants.CHECKBOX_HOVER_SELECTED : UIConstants.DISABLED_ICON_COLOR, 0); - } else if (model.isRollover() && !SELECTED.equals(getState())) { - g.setColor(UIConstants.CHECKBOX_HOVER_SELECTED); - g2d.drawRoundRect(iconRect.x, iconRect.y, iconRect.width - 1, iconRect.height - 1, UIConstants.ARC, UIConstants.ARC); - } else { - g.setColor(UIConstants.LINE_COLOR); - g2d.drawRoundRect(iconRect.x, iconRect.y, iconRect.width - 1, iconRect.height - 1, UIConstants.ARC, UIConstants.ARC); - } - - if (SELECTED.equals(getState())) { - UIConstants.YES_ICON.paintIcon(c, g, iconRect.x + 2, iconRect.y + 2); - } else if (DO_NOT_CARE.equals(getState())) { - g.setColor(UIConstants.CHECKBOX_HOVER_SELECTED); - g2d.fillRoundRect(iconRect.x + 2, iconRect.y + 2, iconRect.width - 4, iconRect.height - 4, UIConstants.ARC, UIConstants.ARC); - } - g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); - - // Draw the Text - drawLine(text, g, b, c, textRect, fm); - } - } - - private void drawLine(String text, Graphics g, AbstractButton b, JComponent c, Rectangle textRect, FontMetrics fm) { - if (text != null) { - View v = (View) c.getClientProperty(BasicHTML.propertyKey); - if (v != null) { - v.paint(g, textRect); - } else { - int mnemIndex = b.getDisplayedMnemonicIndex(); - if (model.isEnabled()) { - g.setColor(b.getForeground()); - } else { - g.setColor(getDisabledTextColor()); - } - SwingUtilities2.drawStringUnderlineCharAt(c, g, text, - mnemIndex, textRect.x, textRect.y + fm.getAscent()); - } - } - } - - } } \ No newline at end of file diff --git a/designer-base/src/test/java/com/fr/design/gui/storybook/components/CheckBoxStoryBoard.java b/designer-base/src/test/java/com/fr/design/gui/storybook/components/CheckBoxStoryBoard.java index a9f50a8ea..6ce047d0e 100644 --- a/designer-base/src/test/java/com/fr/design/gui/storybook/components/CheckBoxStoryBoard.java +++ b/designer-base/src/test/java/com/fr/design/gui/storybook/components/CheckBoxStoryBoard.java @@ -3,10 +3,17 @@ package com.fr.design.gui.storybook.components; import com.fr.design.gui.icheckbox.UICheckBox; import com.fr.design.gui.ilable.UILabel; +import com.fr.design.gui.itree.checkboxtree.NullTristateCheckBox; +import com.fr.design.gui.itree.checkboxtree.TristateCheckBox; import com.fr.design.gui.storybook.Story; import com.fr.design.gui.storybook.StoryBoard; +import javax.swing.AbstractButton; +import javax.swing.JPanel; import java.awt.Component; +import java.awt.event.ItemListener; +import java.util.Arrays; +import java.util.List; import static com.fine.swing.ui.layout.Layouts.cell; import static com.fine.swing.ui.layout.Layouts.column; @@ -46,10 +53,46 @@ public class CheckBoxStoryBoard extends StoryBoard { cell(getDisabledStatus(new UICheckBox("测试"))), cell(getDisabledSelectedStatus(new UICheckBox("测试"))) ), + cell(new UILabel("三态选择框")).with(this::h3), + row(10, + cell(initTristateCheckboxGroup()) + ), flex() ); } + private JPanel initTristateCheckboxGroup() { + TristateCheckBox parent = new NullTristateCheckBox("父选框", TristateCheckBox.NOT_SELECTED); + UICheckBox checkBoxA = new UICheckBox("子选框1"); + UICheckBox checkBoxB = new UICheckBox("子选框1"); + UICheckBox checkBoxC = new UICheckBox("子选框1"); + List childBoxes = Arrays.asList(checkBoxA, checkBoxB, checkBoxC); + ItemListener sonListener = e -> { + int selectedCount = (int) childBoxes.stream().filter(AbstractButton::isSelected).count(); + if (selectedCount == 0) { + parent.setState(TristateCheckBox.NOT_SELECTED); + } else if (selectedCount == childBoxes.size()) { + parent.setState(TristateCheckBox.SELECTED); + } else { + parent.setState(TristateCheckBox.DO_NOT_CARE); + } + }; + childBoxes.forEach(it -> it.addItemListener(sonListener)); + parent.addStateChangeListener(() -> { + childBoxes.forEach(it -> it.removeItemListener(sonListener)); + if (parent.getState() == TristateCheckBox.SELECTED) { + childBoxes.forEach(it -> it.setSelected(true)); + } else if (parent.getState() == TristateCheckBox.NOT_SELECTED) { + childBoxes.forEach(it -> it.setSelected(false)); + } + childBoxes.forEach(it -> it.addItemListener(sonListener)); + }); + + return row(10, + cell(parent), cell(checkBoxA), cell(checkBoxB), cell(checkBoxC) + ).getComponent(); + } + private Component getDisabledStatus(UICheckBox c) { c.setEnabled(false); return c;