执行脚本代码会将焦点移动到浏览器控件

时间:2016-04-05 06:49:00

标签: java browser swt

在SWT浏览器中执行脚本代码时,我发现了一个非常好奇的现象 我的窗口中有两个控件:一个列表和一个浏览器,并排放置(GridLayout.numColumns = 2)。

该列表包含一些标题,我希望稍后在HTML文档中导航。

private void setFocusToElement(String id) {
  StringBuilder sb = new StringBuilder();
  sb.append("var elem = document.getElementById('" + id + "');");
  sb.append("if (elem) {");
  sb.append("  elem.setAttribute('tabindex', '-1');");
  sb.append("  elem.focus();");
  sb.append("}");

  browser.execute(sb.toString());
}

每次单击列表中的项目时都会调用该方法 到目前为止,标题已正确选择,执行符合我的期望。

但是现在焦点移动而没有我从列表到浏览器的交互 这是一个SWT错误还是我的错误?如何防止移动焦点?

+++ UPDATED +++

我的列表控件包含我尝试查找的ID,并在浏览器的HTML文档中选择标题h1 ... h6。
我需要将焦点设置在这样的标题上,以便不能使用.scrollIntoView()。

示例:

我有一个名为" myHeading-1"的列表条目。我点击这个项目,想要在webview中选择相应的标题(h1,列表中有id)。为此,我使用上面的JavaScript代码" myHeading-1"作为输入参数。

结果是我的列表控件失去了焦点。这对我来说有点不合逻辑因为我从不使用browser.setFocus()。我只使用了JavaScript焦点功能,所以不应该发生。

我的期望是:

选择了webview中的标题,但焦点仍然放在列表控件上。

好的,这里有一些代码可以证明我的意思。也许那么重现效果会更好:

public class Main {
  private List list;
  private Browser browser;

  public Main() {
    Display display = new Display();
    Shell shell = new Shell(display);
    shell.setLayout(new GridLayout(2, false));
    shell.setSize(400, 200);
    shell.setText("Demo");

    list = new List(shell, SWT.BORDER | SWT.SINGLE);
    list.add("rtrx_001d");
    list.add("rtrx_003e");
    list.setSelection(0);
    list.addSelectionListener(new SelectionAdapter() {
      @Override
      public void widgetSelected(SelectionEvent e) {
        setFocusToElement(list.getSelection()[0]);
      }
    });

    browser = new Browser(shell, SWT.NONE);
    try {
      browser.setText(readAllLines(new File("C:\\workspace\\file.html")));
    } catch (IOException e) {
      System.err.println(e);
    }

    shell.open();
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch()) {
        display.sleep();
      }
    }
    display.dispose();
  }

  private String readAllLines(File file) throws IOException {
    return readAllLines(file, StandardCharsets.UTF_8);
  }

  private String readAllLines(File file, Charset charset) throws IOException {
    return readAllLines(new FileInputStream(file), charset);
  }

  private String readAllLines(InputStream istream, Charset charset) throws IOException {
    StringBuilder sb = new StringBuilder();
    BufferedReader reader = new BufferedReader(new InputStreamReader(istream, charset));
    try {
      String line;
      while ((line = reader.readLine()) != null) {
        sb.append(line);
        sb.append('\n');
      }
      return sb.toString();
    } finally {
      try {
        reader.close();
      } catch (IOException e) {
      }
    }
  }

  private void setFocusToElement(String id) {
    StringBuilder sb = new StringBuilder();
    sb.append("var elem = document.getElementById('" + id + "');");
    sb.append("if (elem) {");
    sb.append("  elem.setAttribute('tabindex', '-1');");
    sb.append("  elem.focus();");
    sb.append("}");
    browser.execute(sb.toString());
  }

  public static void main(String[] args) {
    new Main();
  }
}

这是我的HTML文档:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>My page</title>
    <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
  </head>
  <body>
    <h1 class="title" id="nlzt_0001">
      <a href="nlzt0002.smil#nlzt_0001">Introduction</a>
    </h1>
    <h1 id="rtrx_001d">
      <a href="nlzt000a.smil#rtrx_001d">Summary</a>
    </h1>
    <h1 id="rtrx_001e">
      <a href="nlzt000b.smil#rtrx_001e">First chapter</a>
    </h1>
    <h2 id="rtrx_001f">
      <a href="nlzt000c.smil#rtrx_001f">1</a>
    </h2>
    <h1 id="rtrx_003e">
      <a href="nlzt002b.smil#rtrx_003e">Second chapter</a>
    </h1>
  </body>
</html>

1 个答案:

答案 0 :(得分:0)

您的Javascript代码明确地将元素与elem.focus()集中在一起。这就是浏览器获得焦点的原因。

所有UI的共同之处在于,最多可以存在一个具有当前输入焦点的UI元素,即接收键盘事件的UI元素。浏览器中的HTML元素也是一个UI元素。如果您希望焦点与列表保持一致,则不得将HTML元素集中在浏览器中。

此外,我的实验表明,将焦点放在HTML元素(例如h1)上不一定会将元素滚动到视图中。

public static void main( String[] args ) {
  String html = "<html><head></head><body>";
  for( int i = 0; i < 100; i++ ) {
    html += "<h2 id=\"id" + i + "\">This is header " + i + "</h2>";
  }
  html += "</body></html>";
  Display display = new Display();
  Shell shell = new Shell( display );
  shell.setLayout( new GridLayout( 1, false ) );
  Button button = new Button( shell, SWT.PUSH );
  button.setText( "Focus header 17" );
  Browser browser = new Browser( shell, SWT.BORDER );
  browser.setText( html );
  browser.setLayoutData( new GridData( SWT.FILL, SWT.FILL, true, true ) );
  button.addListener( SWT.Selection, new Listener() {
    @Override
    public void handleEvent( Event event ) {
      if( !browser.execute( "document.getElementById( 'id17' ).focus();" ) ) {
        throw new RuntimeException( "Failed to execute Javascript" );
      }
    }
  } );
  shell.open();
  while( !shell.isDisposed() ) {
    if( !display.readAndDispatch() )
      display.sleep();
  }
  display.dispose();
}

要将元素滚动到视图中(不提供焦点),请参阅此处:How do I scroll to an element using JavaScript?