我已經定義了一個class InfoAction implements java.swing.Action需要從其呼叫背景關系中檢索一些資訊才能執行自身的函式。為此,我定義了一個介面來提供這些資訊:
public interface InfoProvider {
Info getInfo();
}
InfoActionactionPerformed類中的看起來像
public void actionPerformed(ActionEvent e) {
Info info=e.getSource().getInfo();
// ... treat Info ...
}
然后我想使用這些動作創建各種 Swing 物件,每個 Swing 物件都為動作提供自己的背景關系。
InfoAction infoAction = MyApp.getInstance().getAction(MyApp.RENAME_ACTION); // Retrieving one action
JButton button = new JButton(infoAction); // TODO: inject the InfoProvider interface
JMenuItem menuItem = new JMenuItem(infoAction); // TODO: inject the InfoProvider interface
我被困在如何將 InfoProvider 介面添加到這些擺動物件中。
我天真地試著寫
InfoAction infoAction = MyApp.getInstance().getAction(MyApp.RENAME_ACTION);
JButton button = new JButton(infoAction) implements InfoProvider {
Info getInfo() {
return MyGui.this.getInfo();
}
};
JMenuItem menuItem = new JMenuItem(infoAction) implements InfoProvider {
Info getInfo() {
return MyGui.this.getInfo();
}
};
但這不是一個有效的代碼。
我想避免創建所有 Swing 片段的子類,例如
private class InfoButton extends JButton implements InfoProvider {...}, private class InfoMenuItem extends JMenuItem implements InfoProvider {...}.
所以我想知道在保持代碼干凈的同時還有哪些其他選擇可以做到這一點?
使用反射會是一個不錯的選擇嗎?擺脫介面并測驗 actionEvent.getSource() 是否有 getInfo() 方法?
PS:我正在使用 Java8
uj5u.com熱心網友回復:
您不需要專門化每個支持動作的組件(或計時器或其他動作事件源)。相反,創建一個專門Action的實作來在組件/事件源和實際操作之間進行調解。例如
public class InfoProviderAction implements Action, InfoProvider {
final PropertyChangeSupport listeners = new PropertyChangeSupport(this);
final PropertyChangeListener relay = ev -> listeners.firePropertyChange(
ev.getPropertyName(), ev.getOldValue(), ev.getNewValue());
final Action target;
final InfoProvider actualProvider;
public InfoProviderAction(Action target, InfoProvider actualProvider) {
this.target = target;
this.actualProvider = actualProvider;
}
@Override
public void actionPerformed(ActionEvent e) {
target.actionPerformed(new ActionEvent(
this, e.getID(), e.getActionCommand(), e.getWhen(), e.getModifiers()));
}
@Override
public Info getInfo() {
return actualProvider.getInfo();
}
@Override
public void addPropertyChangeListener(PropertyChangeListener listener) {
boolean hadListeners = listeners.hasListeners(null);
listeners.addPropertyChangeListener(listener);
if(!hadListeners) target.addPropertyChangeListener(relay);
}
@Override
public void removePropertyChangeListener(PropertyChangeListener listener) {
boolean hadListeners = listeners.hasListeners(null);
listeners.removePropertyChangeListener(listener);
if(hadListeners && !listeners.hasListeners(null))
target.removePropertyChangeListener(relay);
}
@Override
public boolean isEnabled() {
return target.isEnabled();
}
@Override
public void setEnabled(boolean b) {
target.setEnabled(b);
}
@Override
public Object getValue(String key) {
return target.getValue(key);
}
@Override
public void putValue(String key, Object value) {
target.putValue(key, value);
}
}
然后,您的MyGui班級可以像使用它一樣
InfoAction infoAction = MyApp.getInstance().getAction(MyApp.RENAME_ACTION);
infoAction = new InfoProviderAction(infoAction, this::getInfo);// inject the InfoProvider
JButton button = new JButton(infoAction);
JMenuItem menuItem = new JMenuItem(infoAction);
組件將InfoProviderAction視為它的動作,它將表現出與包裝動作相同的屬性和行為。而實際操作將InfoProviderAction視為偶數源,InfoProvider按預期實作介面。
如果操作期望源是組件,則可能會出現問題。但是操作不應該假設這一點,因為它會導致問題Timer或全域鍵系結作為事件源。
uj5u.com熱心網友回復:
您可以在 Swing 中使用一些東西:
- JComponent.putClientProperty
- JComponent.getClientProperty
構建物件時,可以對其進行配置:
class ComponentFactory {
public static <T extends JComponent> T configure(T component) {
// the MyGui.this won't compile here, but it is only to explain
// what you can do with your current code.
component.putClientProperty(InfoProvider.class, MyGui.this);
}
}
并構建物件,如下所示:
ComponentFactory.configure(new JButton(infoAction));
或者為它創建一個靜態方法ComponentFactory:
ComponentFactory.createButton(infoAction);
在您的操作中,您可以讀取該屬性:
public void actionPerformed(ActionEvent e) {
Object src = e.getSource();
if (src instanceof JComponent) {
JComponent c = (JComponent) src;
Info info = (Info) c.getClientProperty(InfoProvider.class);
...
}
}
筆記:
因為它是 Swing,所以有一定的機會需要它Serializable——我認為這在 2022 年不是問題。
并且該檔案putClientProperty說:
clientProperty 字典并非旨在支持對 JComponent 的大規模擴展,也不應在設計新組件時將其視為子類化的替代方案。
對于一個屬性應該沒問題,否則您將不得不為每個此類組件使用子類化并實作 InfoProvider。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/511834.html
標籤:爪哇摇摆
上一篇:使用BoyLayout管理器設定JTextField的大小。爪哇
下一篇:數獨Swing/AwtJava
