java fx 如果 Swt 对话框更改位置,上下文菜单将显示在错误的位置

java fx Context menu will show in wrong position if the Swt dialog change the location

我有以下测试代码,运行 in linux 环境(如 ubuntu)。上下文菜单将显示在错误的位置而不是菜单按钮的邻居。 截图是这样的

import java.io.IOException;
import java.net.URL;
import java.util.function.Function;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;

import application.SWTTestUtil;
import javafx.embed.swt.FXCanvas;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;

public class ContextMenuTestingComposite extends Composite {
  private FXCanvas fxCanvas;

  public ContextMenuTestingComposite(Composite parent, int style) {
    super(parent, SWT.NONE);
    setLayout(new FillLayout());
    fxCanvas = new FXCanvas(this, SWT.NONE);
    Parent root = getRoot();
    if (root == null) {
      return;
    }
    Scene scene = new Scene(root);
    fxCanvas.setScene(scene);
  }

  protected Parent getRoot() {
    FXMLLoader fxmlLoader = new FXMLLoader(getURL());
    fxmlLoader.setController(this);

    Parent root = null;
    try {
      root = fxmlLoader.load();
    } catch (IOException e) {
      e.printStackTrace();
    }
    return root;
  }

  protected URL getURL() {
    return getClass().getResource("contextmenuTestingComposite.fxml");
  }

  public static void main(String[] args) {
    Display display = new Display();
    Shell shell = new Shell(display);
    shell.setSize(800, 600);
    shell.setText("test the context menu");
    shell.setLayout(new GridLayout(1, false));
    centerShellToPrimaryWindow(shell.getDisplay(), shell);
    ContextMenuTestingComposite composite = new ContextMenuTestingComposite(shell, SWT.NONE);
    composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
    shell.open();
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch()) {
        display.sleep();
      }
    }
    display.dispose();
  }

  public static void centerShellToPrimaryWindow(Display display, Shell shell) {
    Monitor primary = display.getPrimaryMonitor();
    Rectangle bounds = primary.getBounds();
    Rectangle rect = shell.getBounds();

    int x = bounds.x + (bounds.width - rect.width) / 2;
    int y = bounds.y + (bounds.height - rect.height) / 2;
    shell.setLocation(x, y);
  }

}

FXML

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.control.MenuButton?>
<?import javafx.scene.control.MenuItem?>
<?import javafx.scene.layout.VBox?>


<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1">
   <children>
      <ComboBox prefWidth="150.0" />
      <MenuButton mnemonicParsing="false" text="MenuButton">
        <items>
          <MenuItem mnemonicParsing="false" text="Action 1" />
          <MenuItem mnemonicParsing="false" text="Action 2" />
        </items>
         <VBox.margin>
            <Insets top="59.0" />
         </VBox.margin>
      </MenuButton>
   </children>
</VBox>

有人知道这个问题吗?这个问题将通过 shell 稍微移动 bit.therfore 来解决,如何通过程序解决?

我在 Linux 中遇到了同样的问题,这里是解决方法 - "shake" 激活 SWT 对话框 (shell) 一次。

shell.addShellListener(new ShellAdapter() {
   @Override
   public void shellActivated(ShellEvent e) {
       Point p = shell.getLocation();
       shell.setLocation(p.x, p.y - 1);
       shell.setLocation(p.x, p.y);

       shell.removeShellListener(this);
   }
});

希望对您有所帮助。