Но что, если я заново изобрету велосипед?
Могу ли я перехватить " ОК» закрытие диалогового окна в Swing и наложить вето на него, чтобы окно не закрывалось, используя только существующие классы? Я мог бы проверить некоторые вещи. Важно, чтобы «перехватывающий» код имел ссылку на сам диалог
Просто я пришел из бэкэнда и привык к сервлетам, фильтрам и тому подобному. Я также не знаю Swing, поэтому, возможно, мне не хватает знаний о подобных типах, доступных вне системы
Код: Выделить всё
import javax.swing.*;
import java.awt.*;
import java.awt.event.ItemEvent;
import java.util.stream.Stream;
public class InterceptorDemo {
public static void main(String[] args) {
JFrame frame = new JFrame("Interceptor Demo");
JPanel mainPanel = new JPanel();
JButton dialogButton = new JButton("Show dialog");
dialogButton.addActionListener(e -> {
ItemRadioButton toleratingItem = new ItemRadioButton(new ToleratingItem());
ItemRadioButton vetoingItem = new ItemRadioButton(new VetoingItem());
ButtonGroup radioGroup = new ButtonGroup();
DialogExtension dialog = new DialogExtension(frame, "Vetoable dialog");
JPanel radioPanel = new JPanel();
Stream.of(toleratingItem, vetoingItem).forEach(i -> {
radioPanel.add(i);
radioGroup.add(i);
i.addItemListener(itemEvent -> {
if (itemEvent.getStateChange() == ItemEvent.SELECTED) dialog.addInterceptor(i);
else if (itemEvent.getStateChange() == ItemEvent.DESELECTED) dialog.removeInterceptor(i);
});
});
dialog.add(radioPanel);
JButton okButton = new JButton("OK");
okButton.addActionListener(event -> dialog.disposeOk());
dialog.add(okButton, BorderLayout.SOUTH);
dialog.setLocationRelativeTo(dialog.getOwner());
dialog.pack();
dialog.setVisible(true);
});
mainPanel.add(dialogButton);
frame.add(mainPanel);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Код: Выделить всё
import javax.swing.*;
import java.awt.*;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class DialogExtension extends JDialog {
List okInterceptors = new CopyOnWriteArrayList();
public DialogExtension(Frame owner, String title) {
super(owner, title, true);
}
public void addInterceptor(OkInterceptor interceptor) {
okInterceptors.add(interceptor);
}
public void removeInterceptor(OkInterceptor interceptor) {
okInterceptors.remove(interceptor);
}
public void disposeOk() {
boolean notVetoed = okInterceptors.stream().allMatch(interceptor -> interceptor.okIntercepted(this));
if (notVetoed) super.dispose();
}
}
Код: Выделить всё
public interface Item extends OkInterceptor {
}
Код: Выделить всё
public interface OkInterceptor {
/**
* Accepts a dialog that is about to be disposed with OK, potentially vetoing such a disposal.
* In such a case, the dialog must not be disposed and no OK action should be taken.
*
* @param dialog dialog window that is going to be disposed with OK
* @return {@code false} if the dialog's OK disposal should be vetoed; {@code true} otherwise
*/
boolean okIntercepted(D dialog);
}
Код: Выделить всё
public class SafeItem implements Item {
@Override
public boolean okIntercepted(DialogExtension dialog) {
return true;
}
@Override
public String toString() {
return "Safe Item";
}
}
Код: Выделить всё
import javax.swing.*;
public class DangerousItem implements Item {
@Override
public boolean okIntercepted(DialogExtension dialog) {
return isDangerAcknowledged(dialog);
}
private static boolean isDangerAcknowledged(DialogExtension dialog) {
int pickedOption = JOptionPane.showConfirmDialog(dialog, "Are you sure? You picked Dangerous Item!", null, JOptionPane.YES_NO_OPTION);
return pickedOption == JOptionPane.OK_OPTION;
}
@Override
public String toString() {
return "Dangerous Item";
}
}
Код: Выделить всё
import dialogInterceptor.DialogExtension;
import dialogInterceptor.OkInterceptor;
import javax.swing.*;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
public class ItemRadioButton extends JRadioButton implements OkInterceptor {
public ItemRadioButton(I item) {
this(item, Objects::toString);
}
public ItemRadioButton(I item, Function stringFunction) {
super(stringFunction.apply(item));
setModel(new ItemRadioButtonModel(item));
}
@Override
public Object[] getSelectedObjects() {
return model.getSelectedObjects();
}
@SuppressWarnings("unchecked")
public I getItem() {
return (I) getSelectedObjects()[0];
}
@Override
@SuppressWarnings("unchecked")
public boolean okIntercepted(DialogExtension dialog) {
return Optional.ofNullable(getItem())
// bad, but it's just a demo
.filter(i -> i instanceof OkInterceptor)
.map(e -> ((OkInterceptor) e).okIntercepted(dialog))
.orElse(true);
}
private class ItemRadioButtonModel extends ToggleButtonModel {
private final I item;
private ItemRadioButtonModel(I item) {
this.item = item;
}
@Override
public Object[] getSelectedObjects() {
return new Object[]{item};
}
}
}

Обратите внимание, что я не писал никаких действий «ОК» в своей демонстрации, но вы можете легко представить это (это может быть операция с БД и т. д.)
Также обратите внимание, что диалоговое окно не должно знать о конкретных классах своих элементов (и о том, может ли кто-либо из них наложить вето на удаление ОК)
Подробнее здесь: https://stackoverflow.com/questions/786 ... -disposals
Мобильная версия