代码之家  ›  专栏  ›  技术社区  ›  Thomas S.

如何在Linux上使用Java实现前端

  •  1
  • Thomas S.  · 技术社区  · 7 年前

    我们的基于Java/SWT的应用程序可以启动用户可编辑的第三方应用程序,例如编辑器。例如,在Linux(Centos7,gnome 3.28.2)上,当启动“gedit”时,它打开得很好,但在应用程序窗口的后面。奇怪的是,当从终端启动“gedit”时( gnome-terminal )Gedit作为最前面的窗口出现。

    如何告诉“gedit”(或其他人)作为最前端的应用程序启动?

    更新: 当我从IDE(IDEA)启动Java应用程序时,它像预期的一样工作(GeDIT在前面)。如果我从shell脚本启动应用程序,它将按预期工作。如果我从指向shell脚本的.desktop文件启动应用程序,gedit不仅仅打开该文件 但也会显示有关准备就绪的通知 . 也许这会混淆应用程序窗口的z顺序?或者它取决于环境变量:如果从.desktop文件启动,则环境变量 DESKTOP_STARTUP_ID , GIO_LAUNCHED_DESKTOP_FILE , GIO_LAUNCHED_DESKTOP_FILE_PID 可另外购买 HISTCONTROL 设置为 ignoredups 而不是 ignorespace , SHLVL 是 2 而不是 4 和 TERM 设置为 dump 而不是 xterm-256color .

    基于Stephan Schlecht的代码,我发现下面的Java代码应该重现这个问题:

    import java.io.*;
    import java.util.*;
    
    import org.eclipse.swt.*;
    import org.eclipse.swt.layout.*;
    import org.eclipse.swt.widgets.*;
    
    public class EditorOpener {
    
        public static void main(String[] args) {
            final Map<String, String> getenv = System.getenv();
            System.out.println(getenv);
    
            Display display = new Display();
            Shell shell = new Shell(display);
            shell.setSize(500, 200);
            shell.setText("Editor Opener");
            shell.setLayout(new RowLayout());
    
            final Button button = new Button(shell, SWT.PUSH);
            button.setText("open gedit");
    
            button.addListener(SWT.Selection, event -> new Thread(() -> {
                final ProcessBuilder processBuilder = new ProcessBuilder();
                processBuilder.command("/usr/bin/gedit");
                final Map<String, String> environment = processBuilder.environment();
                System.out.println(environment);
                try {
                    final Process process = processBuilder.start();
                    process.waitFor();
                }
                catch (IOException | InterruptedException ex) {
                    ex.printStackTrace();
                }
            }).start());
    
            shell.open();
            while (!shell.isDisposed()) {
                if (!display.readAndDispatch()) {
                    display.sleep();
                }
            }
            display.dispose();
        }
    }
    

    对环境变量的2次访问是必不可少的。

    3 回复  |  直到 7 年前
        1
  •  3
  •   Stephan Schlecht    7 年前

    现在人们可以做出许多假设(例如.desktop文件的内容),但也许最好有一个关于如何工作的逐步指南,例如:

    测试程序

    此SWT程序通过runtime.getRuntime().exec启动“gedit”。

    import java.io.IOException;
    import org.eclipse.swt.SWT;
    import org.eclipse.swt.events.SelectionEvent;
    import org.eclipse.swt.events.SelectionListener;
    import org.eclipse.swt.layout.RowLayout;
    import org.eclipse.swt.widgets.Button;
    import org.eclipse.swt.widgets.Display;
    import org.eclipse.swt.widgets.Shell;
    
    public class EditorOpener {
    
        public static void main(String[] args) {
            Display display = new Display();
            Shell shell = new Shell(display);
            shell.setSize(500, 200);
            shell.setText("Editor Opener");
            shell.setLayout(new RowLayout());
    
            final Button button = new Button(shell, SWT.PUSH);
            button.setText("open gedit");
    
            button.addSelectionListener(new SelectionListener() {
    
                public void widgetSelected(SelectionEvent event) {
                    String[] cmdArray = new String[] { "/usr/bin/gedit" };
                    try {
                        Runtime.getRuntime().exec(cmdArray);
                    }
                    catch(IOException ex) {
                        ex.printStackTrace();
                    }
                }
    
                public void widgetDefaultSelected(SelectionEvent event) {
                }
            });
    
            shell.open();
            while (!shell.isDisposed()) {
                if (!display.readAndDispatch())
                    display.sleep();
            }
            display.dispose();
        }
    }
    

    调用Java程序

    Java程序是从shell脚本调用的,它看起来像这样:

    #!/usr/bin/bash
    java -cp /path/to/swt.jar:/path/to/classes EditorOpener
    

    桌面文件

    指向shell文件的.desktop文件如下所示:

    [Desktop Entry]
    Type=Application
    Terminal=false
    Name=Opener
    Icon=utilities-terminal
    Exec='/home/stephan/Documents/opener.sh'
    Categories=Application;
    

    结果

    通过点击 打开Gedit 按钮,gedit在所有其他窗口上按预期启动。

    演示

    测试是在CentOS Linux 7上完成的:

    gnome-shell --version
    

    给出输出:

    GNOME Shell 3.28.3
    

    gedit demo

        2
  •  1
  •   rodrigo    7 年前

    有这个实用工具 wmctrl 你想做什么就做什么。

    对于您的用例,您将使用 wmctrl -a "gedit" 或者类似的东西。从手册页:

    -A

    Switch to the desktop containing the window <WIN>, raise the window, and give it focus.
    

    或者,您可以将程序最小化,然后在 gedit 完成。

        3
  •  0
  •   Thomas S.    7 年前

    原因是我们的 .desktop 包含行的文件

    StartupNotify=true
    StartupWMClass=<main-class>
    

    移除这些线会导致问题消失。