यहां समाधान दो टेक्स्ट क्षेत्र और एक डिफ़ॉल्ट बटन प्रदर्शित करता है। जब उपयोगकर्ता टैब कुंजी दबाता है, तो फोकस अगले नियंत्रण में नीचे चला जाता है। जब उपयोगकर्ता एंटर कुंजी दबाता है, तो डिफ़ॉल्ट बटन निकाल दिया जाता है।
इस व्यवहार को प्राप्त करने के लिए:
- प्रत्येक पाठ क्षेत्र, एक घटना फ़िल्टर द्वारा पकड़ ली की नकल की और पाठ क्षेत्र की मूल नोड (जो डिफ़ॉल्ट ठीक बटन शामिल हैं) के लिए लक्षित है के लिए कुंजी दबाएँ दर्ज करें। जब फॉर्म पर कहीं भी दबाया जाता है तो यह डिफ़ॉल्ट ओके बटन को निकाल दिया जाता है। मूल प्रविष्टि कुंजी प्रेस का उपभोग किया जाता है ताकि यह टेक्स्ट क्षेत्र के टेक्स्ट में एक नई लाइन को जोड़ा न जाए।
- प्रत्येक टेक्स्ट क्षेत्र के लिए टैब कुंजी प्रेस फ़िल्टर में पकड़ा जाता है और माता-पिता की फोकस ट्रैवर्सबल सूची को अगले फोकस करने योग्य नियंत्रण को खोजने के लिए संसाधित किया जाता है और उस नियंत्रण के लिए फोकस का अनुरोध किया जाता है। मूल टैब कुंजी प्रेस का उपभोग किया जाता है ताकि यह टेक्स्ट एरिया टेक्स्ट में नया टैब स्पेसिंग जोड़ा जा सके।
कोड जावा 8 में लागू सुविधाओं का उपयोग करता है, इसलिए Java 8 इसे निष्पादित करने की आवश्यकता है।
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.beans.value.*;
import javafx.collections.ObservableList;
import javafx.event.*;
import javafx.scene.*;
import javafx.scene.control.*;
import static javafx.scene.input.KeyCode.ENTER;
import static javafx.scene.input.KeyCode.TAB;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.VBox;
import javafx.stage.*;
public class TextAreaTabAndEnterHandler extends Application {
final Label status = new Label();
public static void main(String[] args) { launch(args); }
@Override public void start(final Stage stage) {
final TextArea textArea1 = new TabAndEnterIgnoringTextArea();
final TextArea textArea2 = new TabAndEnterIgnoringTextArea();
final Button defaultButton = new Button("OK");
defaultButton.setDefaultButton(true);
defaultButton.setOnAction(new EventHandler<ActionEvent>() {
@Override public void handle(ActionEvent event) {
status.setText("Default Button Pressed");
}
});
textArea1.textProperty().addListener(new ClearStatusListener());
textArea2.textProperty().addListener(new ClearStatusListener());
VBox layout = new VBox(10);
layout.setStyle("-fx-background-color: cornsilk; -fx-padding: 10px;");
layout.getChildren().setAll(
textArea1,
textArea2,
defaultButton,
status
);
stage.setScene(
new Scene(layout)
);
stage.show();
}
class ClearStatusListener implements ChangeListener<String> {
@Override public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
status.setText("");
}
}
class TabAndEnterIgnoringTextArea extends TextArea {
final TextArea myTextArea = this;
TabAndEnterIgnoringTextArea() {
addEventFilter(KeyEvent.KEY_PRESSED, new TabAndEnterHandler());
}
class TabAndEnterHandler implements EventHandler<KeyEvent> {
private KeyEvent recodedEvent;
@Override public void handle(KeyEvent event) {
if (recodedEvent != null) {
recodedEvent = null;
return;
}
Parent parent = myTextArea.getParent();
if (parent != null) {
switch (event.getCode()) {
case ENTER:
if (event.isControlDown()) {
recodedEvent = recodeWithoutControlDown(event);
myTextArea.fireEvent(recodedEvent);
} else {
Event parentEvent = event.copyFor(parent, parent);
myTextArea.getParent().fireEvent(parentEvent);
}
event.consume();
break;
case TAB:
if (event.isControlDown()) {
recodedEvent = recodeWithoutControlDown(event);
myTextArea.fireEvent(recodedEvent);
} else {
ObservableList<Node> children = parent.getChildrenUnmodifiable();
int idx = children.indexOf(myTextArea);
if (idx >= 0) {
for (int i = idx + 1; i < children.size(); i++) {
if (children.get(i).isFocusTraversable()) {
children.get(i).requestFocus();
break;
}
}
for (int i = 0; i < idx; i++) {
if (children.get(i).isFocusTraversable()) {
children.get(i).requestFocus();
break;
}
}
}
}
event.consume();
break;
}
}
}
private KeyEvent recodeWithoutControlDown(KeyEvent event) {
return new KeyEvent(
event.getEventType(),
event.getCharacter(),
event.getText(),
event.getCode(),
event.isShiftDown(),
false,
event.isAltDown(),
event.isMetaDown()
);
}
}
}
}
एक वैकल्पिक समाधान TextArea जो नया कुंजी हैंडलिंग व्यवहार शामिल है के लिए अपने खुद के अनुकूलित त्वचा को लागू करने के लिए होगा। मेरा मानना है कि इस तरह की एक प्रक्रिया यहां प्रस्तुत समाधान से अधिक जटिल होगी।
अद्यतन
एक बात मैं वास्तव में इस समस्या का अपने मूल समाधान के बारे में पसंद नहीं आया एक बार टैब या Enter कुंजी भस्म हो गया था, वहाँ उनके डिफ़ॉल्ट संसाधन ट्रिगर करने कोई रास्ता नहीं था कि था। इसलिए मैंने समाधान को अद्यतन किया कि यदि टैब या एंटर दबाते समय उपयोगकर्ता नियंत्रण कुंजी दबाता है, तो डिफ़ॉल्ट टैब या एंटर ऑपरेशन किया जाएगा। यह अद्यतन तर्क उपयोगकर्ता को CTRL + Enter या CTRL + Tab दबाकर टेक्स्ट क्षेत्र में एक नई पंक्ति या टैब स्थान डालने की अनुमति देता है।
एक शानदार ढंग से सुरुचिपूर्ण समाधान। इस पोस्ट के लिए समय निकालने के लिए धन्यवाद। – scottb
बहुत अच्छा। मेरी राय में, टेक्स्टएरिया एपीआई में एक डिफ़ॉल्ट हैंडलिंग संपत्ति होनी चाहिए। मेरा मानना है कि जिस तरह से TextAreas एंटर और टैब को डिफ़ॉल्ट व्यवहार के रूप में संभालता है, कई स्थितियों के लिए वांछनीय नहीं है। आपका समाधान, जबकि शानदार, अब व्यापक रूप से उपलब्ध नहीं है और क्लाइंट कोड का एक लंबा हिस्सा आवश्यक है। – scottb
@scottb आप [JavaFX समस्या ट्रैकर] (https://javafx-jira.kenai.com) में इस व्यवहार के लिए JavaFX प्लेटफ़ॉर्म सुविधा अनुरोध लॉग करना चाहते हैं। – jewelsea