2015-04-28 6 views
5

में लॉगिन संवाद को कैसे हिलाएं, जब भी कोई उपयोगकर्ता गलत लॉगिन नाम/पासवर्ड जोड़ी इनपुट करता है तो मैं अपने जावाफ़ैक्स/8 संवाद बॉक्स को और अधिक सुन्दर तरीके से कैसे हिला सकता हूं?जावाएफ़एक्स/8

चूंकि java8u40 में संवाद में कोई नहीं है, इसलिए मैंने इसे स्वयं बनाने के लिए तैयार किया है। हालांकि, यह काफी अच्छा नहीं लग रहा है।

इसके साथ क्या गलत है? क्या कोई मदद कर सकता है? क्या ऐसा करने में कोई बेहतर तरीका है?


public void loginDialog() { 
    // Create the custom dialog. 
    Dialog<Pair<String, String>> dialog = new Dialog<>(); 
    dialog.setTitle("Mars Simulation Project"); 
    dialog.setHeaderText("Log in"); 
    dialog.setContentText("Enter your username and password : "); 
    dialog.initModality(Modality.NONE); 
    // Set the button types. 
    ButtonType loginButtonType = new ButtonType("Login", ButtonData.OK_DONE); 
    dialog.getDialogPane().getButtonTypes().addAll(loginButtonType, ButtonType.CANCEL); 

    // Create the username and password labels and fields. 
    GridPane grid = new GridPane(); 
    grid.setHgap(10); 
    grid.setVgap(10); 
    grid.setPadding(new Insets(20, 150, 10, 10)); 

    TextField tfPlayer = new TextField(); 
    tfPlayer.setPromptText("e.g. m03j"); 
    PasswordField tfPassword = new PasswordField(); 
    tfPassword.setPromptText("xxxx"); 

    Button defaultPWB = new Button("Use Default"); 
    Button guestB = new Button("As Guest"); 

    defaultPWB.setOnAction(event -> { 
     tfPassword.setText("msp0"); 
    }); 

    guestB.setOnAction(event -> { 
     tfPlayer.setText("Guest_"); 
     tfPassword.setText("msp0"); 
    }); 

    grid.add(new Label("Player Name :"), 0, 0); 
    grid.add(tfPlayer, 1, 0); 
    grid.add(guestB, 2, 0); 
    grid.add(new Label("Password :"), 0, 1); 
    grid.add(tfPassword, 1, 1); 
    grid.add(defaultPWB, 2, 1); 

    // Enable/Disable login button depending on whether a username was entered. 
    Node loginButton = dialog.getDialogPane().lookupButton(loginButtonType); 
    loginButton.setDisable(true); 

    // Do some validation (using the Java 8 lambda syntax). 
    tfPlayer.textProperty().addListener((observable, oldValue, newValue) -> { 
     loginButton.setDisable(newValue.trim().isEmpty()); 
    }); 

    dialog.getDialogPane().setContent(grid); 

    // Request focus on the player name field by default. 
    Platform.runLater(() -> tfPlayer.requestFocus()); 

    // Convert the result to a player name /host address pair when the login 
    // button is clicked. 
    dialog.setResultConverter(dialogButton -> { 
     if (dialogButton == loginButtonType) { 
      return new Pair<>(tfPlayer.getText(), tfPassword.getText()); 
     } 
     return null; 
    }); 

    Optional<Pair<String, String>> result = dialog.showAndWait(); 

    result.ifPresent(input -> { 
     playerName = tfPlayer.getText(); 
     logger.info("Player " + input.getKey() + " connecting to server at " + serverAddressStr); 

     try { 
      dialog.show(); 
      makeContact(serverAddressStr); 
      // obtain a client id 
      boolean isSuccessful = sendRegister(); 

      if (isSuccessful) { 
       dialog.close(); 
       // establish chat... 

      } else { 
       // shake the dialog or send an alert to inform the user the 
       // player name is NOT valid 
       DialogEarthquakeCenter dec = new DialogEarthquakeCenter(dialog); 
       dec.startTimer(); 

       try { 
        System.out.println("start sleeping "); 
        Thread.sleep(2000); 
        System.out.println("done sleeping "); 
       } 
       catch (InterruptedException e) {} 

       loginDialog(); 
      } 

     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    }); 

अब तक, मेरी समस्या यह है कि जैसे ही मैंने बटन "प्रवेश" मारा, संवाद डिफ़ॉल्ट रूप से बंद हो जाएगा है।

इसलिए मुझे इसे फिर से दिखाने के लिए dialog.show() का उपयोग करना होगा।

[संपादित करें] यह अभी भी क्षणिक अंतर को होने से रोक नहीं सकता है (संवाद गायब हो रहा है और फिर से दिखाई देता है)।

उसके बाद, मैं संवाद को हिलाकर डायलॉगइर्थक्वैक सेंटर का एक उदाहरण बना देता हूं।

ध्यान दें कि नीचे मेरी DialogEarthquakeCenter इस मूल का एक सीधा संशोधन है:

https://github.com/gigiigig/Java-Chat/blob/master/tag/FacebookChatCore_Original/src/facebookchat/ui/common/DialogEarthquakeCenter.java

import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import javax.swing.Timer; 
import javafx.animation.KeyFrame; 
import javafx.animation.Timeline; 
import javafx.application.Platform; 
import javafx.scene.control.Dialog; 
import javafx.util.Duration; 
import javafx.util.Pair; 

public class DialogEarthquakeCenter { 

public static final int SHAKE_DISTANCE = 10; 
public static final double SHAKE_CYCLE = 50; 
public static final int SHAKE_DURATION = 500; 
public static final int SHAKE_UPDATE = 5; 

private Dialog<Pair<String, String>> dialog; 
private int x, y; 
private long startTime; 
private Timer shakeTimer; 
private final double TWO_PI = Math.PI * 2.0; 
private Timeline timeline; 

public DialogEarthquakeCenter(Dialog<Pair<String, String>> parent) { 
    dialog = parent; 
} 

/** 
* Creates and starts the timer 
* 
* @return Scene 
*/ 
public void startTimer() { 
    x = (int) dialog.getX(); 
    y = (int) dialog.getY(); 
    startTime = System.currentTimeMillis(); 
    // Set up earth time text update 
    timeline = new Timeline(new KeyFrame(Duration.millis(SHAKE_DURATION), ae -> startNudging())); 
    //timeline.setCycleCount(javafx.animation.Animation.INDEFINITE); 
    timeline.play(); 
} 

public void startNudging() { 
    x = (int) dialog.getX(); 
    y = (int) dialog.getY(); 
    startTime = System.currentTimeMillis(); 
    shakeTimer = new Timer(SHAKE_UPDATE, new ActionListener() { 
     public void actionPerformed(ActionEvent e) { 
      shake(); 
     } 
    }); 

    shakeTimer.start(); 
} 

public void shake() { 
    // calculate elapsed time 
    long elapsed = System.currentTimeMillis() - startTime; 
    //System.out.println("elapsed is " + elapsed); 
    // use sin to calculate an x-offset 
    double waveOffset = (elapsed % SHAKE_CYCLE)/SHAKE_CYCLE; 
    double angle = waveOffset * TWO_PI; 
    // offset the x-location by an amount 
    // proportional to the sine, up to shake_distance 
    int shakenX = (int) ((Math.sin(angle) * SHAKE_DISTANCE) + x); 

    Platform.runLater(() -> { 
     //dialog.hide(); 
     dialog.setX(shakenX); 
     //System.out.println("set shakenX to " + shakenX); 
     dialog.setY(y); 
     dialog.show(); 
    }); 

    //try {Thread.sleep(20);} 
    //catch (InterruptedException ex) {} 

    // should we stop timer 
    if (elapsed >= SHAKE_DURATION) { 
     stopShake(); 

    } 
} 

public void stopShake() { 
    shakeTimer.stop(); 
    Platform.runLater(() -> { 
     timeline.stop(); 
     dialog.close(); 
    }); 
} 
} 

मैं सूचना है कि controlsfx संवाद एक शेक() विधि है किया था।

क्या किसी को पता है कि यह अच्छी तरह से काम करता है?

देख https://code.google.com/p/mqtt-spy/source/browse/mqtt-spy/src/main/java/org/controlsfx/dialog/CustomDialogs.java?r=6ec0240e4e64d1b8cc2b59bc77cd5902a68e0c81

धन्यवाद किसी भी टिप्पणी के लिए बहुत!

+1

आपको नियंत्रणों का प्रयास करना चाहिए संवाद नियंत्रण स्वयं को हिलाएं और देखें कि यह आपके लिए अच्छा काम करता है या नहीं। आप [fxexperience से डिब्बाबंद एनिमेशन] को भी देख सकते हैं (http://fxexperience.com/2012/03/canned-imimations/) - हालांकि वे नोड आधारित हैं और आपको उन्हें मंच के साथ काम करने के लिए अनुकूलित करना होगा । – jewelsea

+1

JavaFX अनुप्रयोग थ्रेड पर थ्रेड.sleep() को कभी भी कॉल न करें, इसके बजाए एक विराम चिह्न का उपयोग करें। – jewelsea

+0

ठीक है। controlfx संवाद को बहिष्कृत किया जाएगा और इसलिए मैं इसका उपयोग नहीं करता हूं। लेकिन यह मुझ पर डॉन करता है कि मैं वास्तव में देख सकता हूं कि वे कोड कैसे हिलाते हैं()। डिब्बाबंद एनिम देखेंगे। और मुझे रोकथाम के लिए स्विच करने के लिए याद दिलाने के लिए thx! आपके संशोधित शेकट्रांसशन के लिए – mk7

उत्तर

5

खिड़की बंद होने से पहले Dialog एपीआई का उपयोग कर उपयोगकर्ता ने लॉगिन बटन पर क्लिक करने के बाद एक संक्रमण जोड़ सकते हैं।

संवाद के बजाय dialog.show() का उपयोग करना .ShowAndWait() `, चाल बस बटन पर क्लिक कार्रवाई को फँस रही है, घटना का उपभोग करती है, और उसके बाद आवश्यक तर्क निष्पादित करती है।

dialog.initModality(Modality.APPLICATION_MODAL); 
dialog.show();    

loginButton.addEventFilter(EventType.ROOT, 
    e->{ 
     if(e.getEventType().equals(ActionEvent.ACTION)){     
      e.consume(); 
      // (hardcoded) Login Validation 
      boolean isSuccessful = false; 
      if (isSuccessful) { 
       dialog.close(); 
      } 
      else { 
       // perform animation and close the dialog (or any other action) 
       ShakeTransition anim = new ShakeTransition(dialog.getDialogPane(), t->dialog.close()); 
       anim.playFromStart(); 
      } 
     } 
    }); 

शेक एनीमेशन के लिए, मैं जैस्पर Potts से ShakeTransition संशोधित कर लिया है, ताकि संवाद विंडो ले जाने के लिए, के रूप में @jewelsea पहले ही बताया:

/** 
* Animate a shake effect on the given node 
* 
* Based on CachedTimelineTransition, a Transition that uses a Timeline internally 
* and turns SPEED caching on for the animated node during the animation. 
* 
* https://github.com/fxexperience/code/blob/master/FXExperienceControls/src/com/fxexperience/javafx/animation/CachedTimelineTransition.java 
* 
* and ShakeTransition 
* 
* https://github.com/fxexperience/code/blob/master/FXExperienceControls/src/com/fxexperience/javafx/animation/ShakeTransition.java 
* 
* @author Jasper Potts 
*/ 
class ShakeTransition extends Transition { 

    private final Interpolator WEB_EASE = Interpolator.SPLINE(0.25, 0.1, 0.25, 1); 
    private final Timeline timeline; 
    private final Node node; 
    private boolean oldCache = false; 
    private CacheHint oldCacheHint = CacheHint.DEFAULT; 
    private final boolean useCache=true; 
    private final double xIni; 

    private final DoubleProperty x = new SimpleDoubleProperty(); 

    /** 
    * Create new ShakeTransition 
    * 
    * @param node The node to affect 
    */ 
    public ShakeTransition(final Node node, EventHandler<ActionEvent> event) { 
     this.node=node; 
     statusProperty().addListener((ov, t, newStatus) -> { 
      switch(newStatus) { 
       case RUNNING: 
        starting(); 
        break; 
       default: 
        stopping(); 
        break; 
      } 
     }); 

     this.timeline= new Timeline(
       new KeyFrame(Duration.millis(0), new KeyValue(x, 0, WEB_EASE)), 
       new KeyFrame(Duration.millis(100), new KeyValue(x, -10, WEB_EASE)), 
       new KeyFrame(Duration.millis(200), new KeyValue(x, 10, WEB_EASE)), 
       new KeyFrame(Duration.millis(300), new KeyValue(x, -10, WEB_EASE)), 
       new KeyFrame(Duration.millis(400), new KeyValue(x, 10, WEB_EASE)), 
       new KeyFrame(Duration.millis(500), new KeyValue(x, -10, WEB_EASE)), 
       new KeyFrame(Duration.millis(600), new KeyValue(x, 10, WEB_EASE)), 
       new KeyFrame(Duration.millis(700), new KeyValue(x, -10, WEB_EASE)), 
       new KeyFrame(Duration.millis(800), new KeyValue(x, 10, WEB_EASE)), 
       new KeyFrame(Duration.millis(900), new KeyValue(x, -10, WEB_EASE)), 
       new KeyFrame(Duration.millis(1000), new KeyValue(x, 0, WEB_EASE)) 
      ); 
     xIni=node.getScene().getWindow().getX(); 
     x.addListener((ob,n,n1)->(node.getScene().getWindow()).setX(xIni+n1.doubleValue())); 

     setCycleDuration(Duration.seconds(1)); 
     setDelay(Duration.seconds(0.2)); 
     setOnFinished(event); 
    } 

    /** 
    * Called when the animation is starting 
    */ 
    protected final void starting() { 
     if (useCache) { 
      oldCache = node.isCache(); 
      oldCacheHint = node.getCacheHint(); 
      node.setCache(true); 
      node.setCacheHint(CacheHint.SPEED); 
     } 
    } 

    /** 
    * Called when the animation is stopping 
    */ 
    protected final void stopping() { 
     if (useCache) { 
      node.setCache(oldCache); 
      node.setCacheHint(oldCacheHint); 
     } 
    } 

    @Override 
    protected void interpolate(double d) { 
     timeline.playFrom(Duration.seconds(d)); 
     timeline.stop(); 
    } 
} 

और यह एक JavaFX आवेदन किया जाएगा अपने लॉगिन संवाद का उपयोग कर:

@Override 
public void start(Stage primaryStage) { 
    Button btn = new Button(); 
    btn.setText("Show Login Dialog"); 
    btn.setOnAction(mevent -> { 

     // Create the custom dialog. 
     Dialog<Pair<String, String>> dialog = new Dialog<>(); 
     dialog.setTitle("Mars Simulation Project"); 
     dialog.setHeaderText("Log in"); 
     dialog.setContentText("Enter your username and password : "); 
     dialog.initModality(Modality.NONE); 
     // Set the button types. 
     ButtonType loginButtonType = new ButtonType("Login", ButtonData.OK_DONE); 
     dialog.getDialogPane().getButtonTypes().addAll(loginButtonType, ButtonType.CANCEL); 

     // Create the username and password labels and fields. 
     GridPane grid = new GridPane(); 
     grid.setHgap(10); 
     grid.setVgap(10); 
     grid.setPadding(new Insets(20, 150, 10, 10)); 

     TextField tfPlayer = new TextField(); 
     tfPlayer.setPromptText("e.g. m03j"); 
     PasswordField tfPassword = new PasswordField(); 
     tfPassword.setPromptText("xxxx"); 

     Button defaultPWB = new Button("Use Default"); 
     Button guestB = new Button("As Guest"); 
     defaultPWB.setOnAction(event -> { 
      tfPassword.setText("msp0"); 
     }); 

     guestB.setOnAction(event -> { 
      tfPlayer.setText("Guest_"); 
      tfPassword.setText("msp0"); 
     }); 

     grid.add(new Label("Player Name :"), 0, 0); 
     grid.add(tfPlayer, 1, 0); 
     grid.add(guestB, 2, 0); 
     grid.add(new Label("Password :"), 0, 1); 
     grid.add(tfPassword, 1, 1); 
     grid.add(defaultPWB, 2, 1); 

     // Enable/Disable login button depending on whether a username was entered. 
     Node loginButton = dialog.getDialogPane().lookupButton(loginButtonType); 
     loginButton.setDisable(true); 

     // Do some validation (using the Java 8 lambda syntax). 
     tfPlayer.textProperty().addListener((observable, oldValue, newValue) -> { 
      loginButton.setDisable(newValue.trim().isEmpty()); 
     }); 

     dialog.getDialogPane().setContent(grid); 

     // Request focus on the player name field by default. 
     Platform.runLater(() -> tfPlayer.requestFocus()); 

     dialog.initModality(Modality.APPLICATION_MODAL); 
     dialog.show();    

     loginButton.addEventFilter(EventType.ROOT, 
      e->{ 
       if(e.getEventType().equals(ActionEvent.ACTION)){ 
        e.consume(); 
        // (hardcoded) Login Validation 
        boolean isSuccessful = false; 
        if (isSuccessful) { 
         dialog.close(); 
        } 
        else { 
         ShakeTransition anim = new ShakeTransition(dialog.getDialogPane(), t->dialog.close()); 
         anim.playFromStart(); 
        } 
       } 
      }); 
    }); 

    StackPane root = new StackPane(); 
    root.getChildren().add(btn); 

    Scene scene = new Scene(root, 300, 250); 

    primaryStage.setTitle("Shaky Login Dialog"); 
    primaryStage.setScene(scene); 
    primaryStage.show(); 
} 
+0

thx।यह इतना बेहतर हिलाता है! हां, मुझे वैकल्पिक <> और showAndWait() का उपयोग करने के डिफ़ॉल्ट तरीके पर भरोसा करने के बजाय बटन क्लिक को फंसाने में देखना चाहिए था! – mk7

+0

जोस, एकमात्र परिवर्तन जो मुझे ऊपर करने की आवश्यकता है, टी-> tfPlayer.requestFocus(), टी-> dialog.close() का intead का उपयोग कर रहा है। यदि गलत लॉगिन नाम/पीडी दर्ज किया गया था, तो अब मुझे कोड की लाइन के नीचे फिर से अपना लॉगिनडिअलॉग() दोबारा कॉल करने की आवश्यकता नहीं है: anim.playFromStart()। इसे फिर से काम करने के लिए धन्यवाद फिर से बेहतर! – mk7

+0

हां, मैंने एनीमेशन में 'इवेंट हैंडलर' जोड़ा जो कि पूर्ण घटना पर कुछ कार्रवाई की अनुमति देता है। संवाद बंद करने के बजाय, आप कोई अन्य क्रिया जोड़ सकते हैं। –