好吧,我是java和fxml的初学者。
我创建了一个应用程序,需要更改屏幕的语言。我有国际化的密钥文件,但我不知道用更改的语言重新加载屏幕。 该应用程序有一个菜单,其中有可用的语言。我只想在用户更改语言时刷新屏幕。
更改仍然是手动的,您可以在代码中看到:(Main.java):
public class Main extends Application {
private Locale locale = new Locale("en", "US");
private Image icon = new Image("picture.jpg");
@Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("Home.fxml"), ResourceBundle.getBundle("label", locale));
Scene scene = new Scene(root);
stage.setTitle("GUI");
stage.getIcons().add(icon);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
当更改语言时,此代码在控制器上:
@FXML
private void btnMenuLanguageEnglishAction(ActionEvent event) {
this.locale = new Locale("en", "US");
}
@FXML
private void btnMenuLanguagePortuguesAction(ActionEvent event) {
this.locale = new Locale("pt", "BR");
}
如何将此区域设置发送到main并刷新屏幕? 我将使用哪种方法?我尝试了一些我在网站上看到的,但没有人回答我的问题。
答案 0 :(得分:5)
这是我的实施:
import javafx.fxml.FXMLLoader;
import javafx.geometry.NodeOrientation;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
/**
* Created by Fouad on 3/20/2015.
*/
public abstract class I18NController
{
private Stage primaryStage;
public void setPrimaryStage(Stage primaryStage){this.primaryStage = primaryStage;}
public Stage getPrimaryStage(){return primaryStage;}
public final void changeLanguage(I18NLanguage language) throws IOException
{
StateBundle stateBundle = new StateBundle();
onSaveState(stateBundle);
Locale locale = language.getLocale();
Locale.setDefault(locale);
ResourceBundle resourceBundle = getResourceBundle(locale);
URL fxml = getFXMLResource();
FXMLLoader loader = new FXMLLoader(fxml, resourceBundle);
Parent root = loader.load();
NodeOrientation nodeOrientation = language.getNodeOrientation();
root.setNodeOrientation(nodeOrientation);
primaryStage.setScene(new Scene(root));
primaryStage.sizeToScene();
I18NController newController = loader.getController();
newController.setPrimaryStage(primaryStage);
onLoadState(newController, language, resourceBundle, stateBundle);
}
protected abstract ResourceBundle getResourceBundle(Locale locale);
protected abstract URL getFXMLResource();
protected abstract void onSaveState(StateBundle stateBundle);
protected abstract void onLoadState(I18NController newController, I18NLanguage newLanguage, ResourceBundle resourceBundle, StateBundle stateBundle);
public static interface I18NLanguage
{
Locale getLocale();
NodeOrientation getNodeOrientation();
}
public static class StateBundle
{
private Map<String, Object> sMap = new HashMap<>();
StateBundle(){}
public void putData(String key, Object value)
{
sMap.put(key, value);
}
public <T> T getDate(String key, Class<T> type)
{
return type.cast(sMap.get(key));
}
}
}
您可以将此类用作控制器的基类,如下所示:
<强> JavaFXController.java:强>
public class JavaFXController extends I18NController implements Initializable
{
@FXML private DatePicker dpDate;
@FXML private RadioButton rdoArabic;
@FXML private RadioButton rdoEnglish;
// ...
@Override
public void initialize(URL location, ResourceBundle resources)
{
// ...
rdoEnglish.setOnAction(e ->
{
try
{
changeLanguage(AppSettings.Language.ENGLISH);
}
catch(IOException e1)
{
e1.printStackTrace();
}
});
rdoArabic.setOnAction(e ->
{
try
{
changeLanguage(AppSettings.Language.ARABIC);
}
catch(IOException e1)
{
e1.printStackTrace();
}
});
}
// ...
@Override
protected ResourceBundle getResourceBundle(Locale locale)
{
return ResourceBundle.getBundle("com/stackoverflow/gui/resources/JavaFXResourceBundle", locale, new UTF8Control());
}
@Override
protected URL getFXMLResource()
{
return getClass().getResource("resources/JavaFXDocument.fxml");
}
@Override
protected void onSaveState(StateBundle stateBundle)
{
LocalDate localDate = dpDate.getValue();
boolean isRdoArabicSelected = rdoArabic.isSelected();
boolean isRdoEnglishSelected = rdoEnglish.isSelected();
stateBundle.putData("localDate", localDate);
stateBundle.putData("isRdoArabicSelected", isRdoArabicSelected);
stateBundle.putData("isRdoEnglishSelected", isRdoEnglishSelected);
}
@Override
protected void onLoadState(I18NController newController, I18NLanguage newLanguage, ResourceBundle resourceBundle, StateBundle stateBundle)
{
JavaFXController controller = (JavaFXController) newController;
controller.getPrimaryStage().setTitle(resourceBundle.getString("window.title"));
NodeOrientation nodeOrientation = newLanguage.getNodeOrientation();
LocalDate localDate = stateBundle.getDate("localDate", LocalDate.class);
boolean isRdoArabicSelected = stateBundle.getDate("isRdoArabicSelected", Boolean.class);
boolean isRdoEnglishSelected = stateBundle.getDate("isRdoEnglishSelected", Boolean.class);
controller.dpDate.setValue(localDate);
controller.rdoArabic.setSelected(isRdoArabicSelected);
controller.rdoEnglish.setSelected(isRdoEnglishSelected);
}
}
<强> AppSettings.java:强>
import com.parmajeyat.autobooking.gui.I18NController;
import javafx.geometry.NodeOrientation;
import java.util.Locale;
/**
* Created by Fouad on 2/7/2015.
*/
public final class AppSettings
{
private static final class Locales
{
public static final Locale SAUDI_AR_LOCALE = new Locale.Builder().setLanguageTag("ar-SA-u-nu-arab").build(); // nu is for numbers
public static final Locale SAUDI_EN_LOCALE = new Locale("en", "SA");
}
public static enum Language implements I18NController.I18NLanguage
{
ARABIC(Locales.SAUDI_AR_LOCALE, NodeOrientation.RIGHT_TO_LEFT),
ENGLISH(Locales.SAUDI_EN_LOCALE, NodeOrientation.LEFT_TO_RIGHT);
private Locale locale;
private NodeOrientation nodeOrientation;
Language(Locale locale, NodeOrientation nodeOrientation)
{
this.locale = locale;
this.nodeOrientation = nodeOrientation;
}
public Locale getLocale(){return locale;}
public NodeOrientation getNodeOrientation(){return nodeOrientation;}
}
}
<强> UTF8Control.java:强>
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.Locale;
import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;
/**
* Created by Fouad on 2/1/2015.
*/
public class UTF8Control extends ResourceBundle.Control
{
public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) throws IllegalAccessException, InstantiationException, IOException
{
// The below is a copy of the default implementation.
String bundleName = toBundleName(baseName, locale);
String resourceName = toResourceName(bundleName, "properties");
ResourceBundle bundle = null;
InputStream stream = null;
if(reload)
{
URL url = loader.getResource(resourceName);
if(url != null)
{
URLConnection connection = url.openConnection();
if(connection != null)
{
connection.setUseCaches(false);
stream = connection.getInputStream();
}
}
}
else
{
stream = loader.getResourceAsStream(resourceName);
}
if(stream != null)
{
try
{
// Only this line is changed to make it to read properties files as UTF-8.
bundle = new PropertyResourceBundle(new InputStreamReader(stream, "UTF-8"));
}
finally
{
stream.close();
}
}
return bundle;
}
}
答案 1 :(得分:2)
我知道,这是一个很老的问题,但我是JavaFX的新手,我遇到了同样的问题。 这是我在应用程序中更改语言的最终解决方案。它可能不太理想,但它对我有用。 在控制器中我有这种方法:
@FXML
private BorderPane root; //root pane
@FXML
private void changeLocale(ActionEvent event) throws IOException{
Scene scene = root.getScene();
if(event.getSource().equals(lang_en)){
scene.setRoot(FXMLLoader.load(getClass().getResource("Layout.fxml"),ResourceBundle.getBundle("resources/Bundle", Locale.ENGLISH))); // = new Locale("en")
}else if(event.getSource().equals(lang_cs)){
scene.setRoot(FXMLLoader.load(getClass().getResource("Layout.fxml"),ResourceBundle.getBundle("resources/Bundle", new Locale("cs", "CZ"))));
}else{
}
}
该方法将新加载器加载到我的场景中(加载到舞台也可以)。
对于完整的场景......我可以在菜单中用两个放射性设备更改当前语言,因此在加载新的加载器后(在控制器中的方法“public void initialize(URL location,ResourceBundle resources)”中)我改变了放射对准的选择这个开关:
switch(resources.getLocale().getLanguage()){
case "en":
lang_en.setSelected(true);
break;
case "cs":
lang_cs.setSelected(true);
break;
default:
break;
}
这很简单,对于有这个问题的其他人可能会有用。
答案 2 :(得分:0)
我设法解决了代码:
主:
public class Main extends Application {
private static Locale locale = new Locale("pt", "BR");
private static Image icone = new Image("picture.jpg");
private Scene scene;
public static Stage stage;
/**
*
* @param st
* @throws Exception
*/
@Override
public void start(Stage st) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("Home.fxml"), ResourceBundle.getBundle("label", locale));
stage = st;
scene = new Scene(root);
stage.setTitle("GUI");
stage.getIcons().add(icone);
stage.setScene(scene);
stage.show();
}
public static Image getIcone() {
return icone;
}
public static Locale getLocale() {
return locale;
}
public static void setLocale(Locale locale) {
Main.locale = locale;
}
public void reload() throws IOException {
Parent root = FXMLLoader.load(getClass().getResource("Home.fxml"), ResourceBundle.getBundle("label", locale));
scene = new Scene(root);
stage.setTitle("GUI");
stage.getIcons().add(icone);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
控制器:
@FXML
private void btnMenuLanguageEnglishAction(ActionEvent event) throws IOException {
Main.setLocale(new Locale("en", "US")); // change to english
Main.stage.close();
Main reload = new Main();
reload.reload();
}
@FXML
private void btnMenuLanguagePortuguesAction(ActionEvent event) throws IOException {
Main.setLocale(new Locale("pt", "BR")); // change to Portuguese;
Main.stage.close();
Main reload = new Main();
reload.reload();
}
但仍有问题:语言更改只能发生一次,第二次发出致命错误...希望能帮助某人。
答案 3 :(得分:0)
与您的Labeled(Label,Text,TitledPane等)一起使用绑定。