Флажки Tristate в Java
Я мог бы действительно использовать три-установленный флажок в Java. Это звучит как простая вещь, но я видел только очень уродливые реализации [примечание: ссылка теперь не работает].
Три радиокнопки просто занимают слишком много места и, вероятно, могут запутать пользователей в моем случае. Это в основном для поиска диалога. Мне нужны варианты true, false или "пофиг". Есть ли другая техника, которую используют люди?
9 ответов
Я нашел способ сделать флажок с тремя состояниями, просто добавив слушателя:
public class TriStateActionListener implements ActionListener{
final protected Icon icon;
public TriStateActionListener(Icon icon){
this.icon=icon;
}
public static Boolean getState(javax.swing.JCheckBox cb){
if (cb.getIcon()==null) return null;
if (cb.isSelected()) return true;
else return false;
}
public void actionPerformed(ActionEvent e) {
javax.swing.JCheckBox cb=(javax.swing.JCheckBox)e.getSource();
if (!cb.isSelected()){
cb.setIcon(icon);
}
else if (cb.getIcon()!=null){
cb.setIcon(null);
cb.setSelected(false);
}
}
}
Тогда в коде приложения это просто одна строка:
jCheckBox1.addActionListener(new TriStateActionListener(getResourceMap().getIcon("TriStateIcon")));
После всех отзывов, я думаю, что выпадающий список может быть лучшим выбором. Но я хотел бы поделиться своим кодом здесь для всех остальных.
В этой реализации три состояния могут быть установлены только программно. Чтобы выглядеть и чувствовать себя переносимым, он использует изображения, которые должны быть помещены в один и тот же пакет Java.
public class TristateCheckBox extends JCheckBox {
private static final long serialVersionUID = 1L;
private boolean halfState;
private static Icon selected = new javax.swing.ImageIcon(TristateCheckBox.class.getResource("selected.png"));
private static Icon unselected = new javax.swing.ImageIcon(TristateCheckBox.class.getResource("unselected.png"));
private static Icon halfselected = new javax.swing.ImageIcon(TristateCheckBox.class.getResource("halfselected.png"));
@Override
public void paint(Graphics g) {
if (isSelected()) {
halfState = false;
}
setIcon(halfState ? halfselected : isSelected() ? selected : unselected);
super.paint(g);
}
public boolean isHalfSelected() {
return halfState;
}
public void setHalfSelected(boolean halfState) {
this.halfState = halfState;
if (halfState) {
setSelected(false);
repaint();
}
}
}
Образец кадра:
public class NewJFrame19 extends javax.swing.JFrame {
private final TristateCheckBox myCheckBox;
public NewJFrame19() {
myCheckBox = new TristateCheckBox();
myCheckBox.setText("123123");
add(myCheckBox);
jButton1 = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
getContentPane().setLayout(new java.awt.FlowLayout());
jButton1.setText("jButton1");
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButton1ActionPerformed(evt);
}
});
getContentPane().add(jButton1);
pack();
}
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
myCheckBox.setHalfSelected(true);
}
public static void main(String args[]) {
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Windows".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(NewJFrame19.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(NewJFrame19.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(NewJFrame19.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(NewJFrame19.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new NewJFrame19().setVisible(true);
}
});
}
private javax.swing.JButton jButton1;
}
JIDE открыли для себя некоторые очень приятные функциональные возможности в своем общем слое, одним из которых является чекбокс tristate
Я бы посоветовал вам запустить демо-версию веб-старта, чтобы увидеть, отвечает ли он вашим потребностям
Флажки Tristate - это стандартная идиома пользовательского интерфейса для древовидных представлений с частично проверенными дочерними узлами. Они широко используются в управлении слоями в сложных иерархических представлениях, таких как Google Планета Земля.
Я не знаю, почему кто-то дал бы решения с дополнительными иконками png-файлов, в то время как java api дает большую функциональность для переопределения метода paintIcon(..).
Лучшее легкое решение для запоминания состояния CheckBox - это атрибут IMO ClientProperty.
/*
* Tri-state checkbox example
* @s1w_
*/
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class TCheckBox extends JCheckBox implements Icon, ActionListener {
final static boolean MIDasSELECTED = true; //consider mid-state as selected ?
public TCheckBox() { this(""); }
public TCheckBox(String text) {
super(text);
putClientProperty("SelectionState", 0);
setIcon(this);
addActionListener(this);
}
public TCheckBox(String text, int sel) {
/* tri-state checkbox has 3 selection states:
* 0 unselected
* 1 mid-state selection
* 2 fully selected
*/
super(text, sel > 1 ? true : false);
switch (sel) {
case 2: setSelected(true);
case 1:
case 0:
putClientProperty("SelectionState", sel);
break;
default:
throw new IllegalArgumentException();
}
addActionListener(this);
setIcon(this);
}
@Override
public boolean isSelected() {
if (MIDasSELECTED && (getSelectionState() > 0)) return true;
else return super.isSelected();
}
public int getSelectionState() {
return (getClientProperty("SelectionState") != null ? (int)getClientProperty("SelectionState") :
super.isSelected() ? 2 :
0);
}
public void setSelectionState(int sel) {
switch (sel) {
case 2: setSelected(true);
break;
case 1:
case 0: setSelected(false);
break;
default: throw new IllegalArgumentException();
}
putClientProperty("SelectionState", sel);
}
final static Icon icon = UIManager.getIcon("CheckBox.icon");
@Override
public void paintIcon(Component c, Graphics g, int x, int y) {
icon.paintIcon(c, g, x, y);
if (getSelectionState() != 1) return;
int w = getIconWidth();
int h = getIconHeight();
g.setColor(c.isEnabled() ? new Color(51, 51, 51) : new Color(122, 138, 153));
g.fillRect(x+4, y+4, w-8, h-8);
if (!c.isEnabled()) return;
g.setColor(new Color(81, 81, 81));
g.drawRect(x+4, y+4, w-9, h-9);
}
@Override
public int getIconWidth() {
return icon.getIconWidth();
}
@Override
public int getIconHeight() {
return icon.getIconHeight();
}
public void actionPerformed(ActionEvent e) {
TCheckBox tcb = (TCheckBox)e.getSource();
if (tcb.getSelectionState() == 0)
tcb.setSelected(false);
tcb.putClientProperty("SelectionState", tcb.getSelectionState() == 2 ? 0 :
tcb.getSelectionState() + 1);
// test
System.out.println(">>>>IS SELECTED: "+tcb.isSelected());
System.out.println(">>>>IN MID STATE: "+(tcb.getSelectionState()==1));
}
}
использование: TCheckBox tcb = new TCheckBox("My CheckBox");
Эти "уродливые реализации" - старая ссылка. Одно из предложений на этой странице было обновлено пару лет назад. Я не проверял старую реализацию, поэтому я не знаю, лучше или хуже новая.
Изменить пользовательский интерфейс. Флажок Tristate необычен и может действительно запутать пользователей. Раскрывающийся список является хорошим вариантом, но для более чем одного вхождения в диалоге он также может привести пользователя в замешательство.
Я бы просто использовал тот, который вы опубликовали.
Пока ваша сложность находится в другом классе (который работает) и действует как любой другой элемент управления, кого это волнует? (Похоже, это предположение лежит в основе всего свинга, большинство классов свинга, похоже, об этом сложно.)