优化游戏窗口大小选择功能 (#4234)

This commit is contained in:
Glavo
2025-08-14 16:32:14 +08:00
committed by GitHub
parent 10bda7e6f4
commit 4547448718
2 changed files with 158 additions and 37 deletions

View File

@@ -25,10 +25,7 @@ import javafx.beans.Observable;
import javafx.beans.WeakInvalidationListener;
import javafx.beans.WeakListener;
import javafx.beans.binding.Bindings;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.Property;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.*;
import javafx.beans.value.*;
import javafx.collections.ObservableMap;
import javafx.event.Event;
@@ -832,10 +829,144 @@ public final class FXUtils {
property.addListener(binding);
}
public static void unbindColorPicker(ColorPicker colorPicker, Property<Paint> property) {
PaintBidirectionalBinding binding = new PaintBidirectionalBinding(colorPicker, property);
colorPicker.valueProperty().removeListener(binding);
property.removeListener(binding);
private static final class WindowsSizeBidirectionalBinding implements InvalidationListener, WeakListener {
private final WeakReference<JFXComboBox<String>> comboBoxRef;
private final WeakReference<IntegerProperty> widthPropertyRef;
private final WeakReference<IntegerProperty> heightPropertyRef;
private final int hashCode;
private boolean updating = false;
private WindowsSizeBidirectionalBinding(JFXComboBox<String> comboBox,
IntegerProperty widthProperty,
IntegerProperty heightProperty) {
this.comboBoxRef = new WeakReference<>(comboBox);
this.widthPropertyRef = new WeakReference<>(widthProperty);
this.heightPropertyRef = new WeakReference<>(heightProperty);
this.hashCode = System.identityHashCode(comboBox)
^ System.identityHashCode(widthProperty)
^ System.identityHashCode(heightProperty);
}
@Override
public void invalidated(Observable observable) {
if (!updating) {
var comboBox = this.comboBoxRef.get();
var widthProperty = this.widthPropertyRef.get();
var heightProperty = this.heightPropertyRef.get();
if (comboBox == null || widthProperty == null || heightProperty == null) {
if (comboBox != null) {
comboBox.focusedProperty().removeListener(this);
comboBox.sceneProperty().removeListener(this);
}
if (widthProperty != null)
widthProperty.removeListener(this);
if (heightProperty != null)
heightProperty.removeListener(this);
} else {
updating = true;
try {
int width = widthProperty.get();
int height = heightProperty.get();
if (observable instanceof ReadOnlyProperty<?>
&& ((ReadOnlyProperty<?>) observable).getBean() == comboBox) {
String value = comboBox.valueProperty().get();
if (value == null)
value = "";
int idx = value.indexOf('x');
if (idx < 0)
idx = value.indexOf('*');
if (idx < 0) {
LOG.warning("Bad window size: " + value);
comboBox.setValue(width + "x" + height);
return;
}
String widthStr = value.substring(0, idx).trim();
String heightStr = value.substring(idx + 1).trim();
int newWidth;
int newHeight;
try {
newWidth = Integer.parseInt(widthStr);
newHeight = Integer.parseInt(heightStr);
} catch (NumberFormatException e) {
LOG.warning("Bad window size: " + value);
comboBox.setValue(width + "x" + height);
return;
}
widthProperty.set(newWidth);
heightProperty.set(newHeight);
} else {
comboBox.setValue(width + "x" + height);
}
} finally {
updating = false;
}
}
}
}
@Override
public boolean wasGarbageCollected() {
return this.comboBoxRef.get() == null
|| this.widthPropertyRef.get() == null
|| this.heightPropertyRef.get() == null;
}
@Override
public int hashCode() {
return hashCode;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!(obj instanceof WindowsSizeBidirectionalBinding))
return false;
var that = (WindowsSizeBidirectionalBinding) obj;
var comboBox = this.comboBoxRef.get();
var widthProperty = this.widthPropertyRef.get();
var heightProperty = this.heightPropertyRef.get();
var thatComboBox = that.comboBoxRef.get();
var thatWidthProperty = that.widthPropertyRef.get();
var thatHeightProperty = that.heightPropertyRef.get();
if (comboBox == null || widthProperty == null || heightProperty == null
|| thatComboBox == null || thatWidthProperty == null || thatHeightProperty == null) {
return false;
}
return comboBox == thatComboBox
&& widthProperty == thatWidthProperty
&& heightProperty == thatHeightProperty;
}
}
public static void bindWindowsSize(JFXComboBox<String> comboBox, IntegerProperty widthProperty, IntegerProperty heightProperty) {
comboBox.setValue(widthProperty.get() + "x" + heightProperty.get());
var binding = new WindowsSizeBidirectionalBinding(comboBox, widthProperty, heightProperty);
comboBox.focusedProperty().addListener(binding);
comboBox.sceneProperty().addListener(binding);
widthProperty.addListener(binding);
heightProperty.addListener(binding);
}
public static void unbindWindowsSize(JFXComboBox<String> comboBox, IntegerProperty widthProperty, IntegerProperty heightProperty) {
var binding = new WindowsSizeBidirectionalBinding(comboBox, widthProperty, heightProperty);
comboBox.focusedProperty().removeListener(binding);
comboBox.sceneProperty().removeListener(binding);
widthProperty.removeListener(binding);
heightProperty.removeListener(binding);
}
public static void bindAllEnabled(BooleanProperty allEnabled, BooleanProperty... children) {

View File

@@ -93,8 +93,7 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
private String versionId;
private final VBox rootPane;
private final JFXTextField txtWidth;
private final JFXTextField txtHeight;
private final JFXComboBox<String> cboWindowsSize;
private final JFXTextField txtServerIP;
private final ComponentList componentList;
private final JFXComboBox<LauncherVisibility> cboLauncherVisibility;
@@ -389,29 +388,20 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
BorderPane right = new BorderPane();
dimensionPane.setRight(right);
{
HBox hbox = new HBox();
right.setLeft(hbox);
hbox.setPrefWidth(210);
hbox.setSpacing(3);
hbox.setAlignment(Pos.CENTER);
BorderPane.setAlignment(hbox, Pos.CENTER);
{
txtWidth = new JFXTextField();
txtWidth.setPromptText("800");
txtWidth.setPrefWidth(100);
FXUtils.setValidateWhileTextChanged(txtWidth, true);
txtWidth.getValidators().setAll(new NumberValidator(i18n("input.number"), false));
Label x = new Label("x");
txtHeight = new JFXTextField();
txtHeight.setPromptText("480");
txtHeight.setPrefWidth(100);
FXUtils.setValidateWhileTextChanged(txtHeight, true);
txtHeight.getValidators().setAll(new NumberValidator(i18n("input.number"), false));
hbox.getChildren().setAll(txtWidth, x, txtHeight);
}
cboWindowsSize = new JFXComboBox<>();
cboWindowsSize.setPrefWidth(150);
right.setLeft(cboWindowsSize);
cboWindowsSize.setEditable(true);
cboWindowsSize.setStyle("-fx-padding: 4 4 4 16");
cboWindowsSize.setPromptText("854x480");
cboWindowsSize.getItems().addAll(
"854x480",
"1280x720",
"1600x900",
"1920x1080",
"2560x1440",
"3840x2160"
);
chkFullscreen = new JFXCheckBox();
right.setRight(chkFullscreen);
@@ -419,6 +409,8 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
chkFullscreen.setAlignment(Pos.CENTER);
BorderPane.setAlignment(chkFullscreen, Pos.CENTER);
BorderPane.setMargin(chkFullscreen, new Insets(0, 0, 0, 7));
cboWindowsSize.disableProperty().bind(chkFullscreen.selectedProperty());
}
}
@@ -559,8 +551,7 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
// unbind data fields
if (lastVersionSetting != null) {
FXUtils.unbind(txtWidth, lastVersionSetting.widthProperty());
FXUtils.unbind(txtHeight, lastVersionSetting.heightProperty());
FXUtils.unbindWindowsSize(cboWindowsSize, lastVersionSetting.widthProperty(), lastVersionSetting.heightProperty());
maxMemory.unbindBidirectional(lastVersionSetting.maxMemoryProperty());
javaCustomOption.valueProperty().unbindBidirectional(lastVersionSetting.javaDirProperty());
gameDirCustomOption.valueProperty().unbindBidirectional(lastVersionSetting.gameDirProperty());
@@ -593,8 +584,7 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
javaVersionOption.valueProperty().unbind();
// bind new data fields
FXUtils.bindInt(txtWidth, versionSetting.widthProperty());
FXUtils.bindInt(txtHeight, versionSetting.heightProperty());
FXUtils.bindWindowsSize(cboWindowsSize, versionSetting.widthProperty(), versionSetting.heightProperty());
maxMemory.bindBidirectional(versionSetting.maxMemoryProperty());
javaCustomOption.bindBidirectional(versionSetting.javaDirProperty());