Как не дать графической программе Java украсть фокус при обновлении окна?

В (встроенной) системе Ubuntu 12.04 у нас есть простая программа на Java, которая отображает некоторые графические шаблоны в окне, обновляя их каждую секунду или около того. Мы используем его для мониторинга некоторых процессов, работающих в системе. Проблема в том, что, хотя он активен и не свернут, он крадет фокус при каждом обновлении окна. Это делает невозможной работу с открытыми оконными окнами.

То же самое происходит при запуске командной строки формы приложения или из Eclipse IDE.

Та же проблема не возникает в Windows 7 при работе в среде IDE NetBeans.

Как мы можем помешать приложению Java сфокусироваться на машине с Ubuntu?


ОБНОВЛЕНИЕ 1: нашел этот вопрос, который, кажется, борется с той же самой проблемой: Как мне остановить / обойти приложения Java, крадущие фокус в менеджерах окон Linux. Прочитав его, я узнал, что проблема заключается в использовании JFrame в качестве контейнера, что мы и используем. Их решением было использование контейнера JWindow вместо контейнера JFrame. Однако, ища разницу, JWindow "голый" и не ведет себя как "реальное" окно, так как там нет декораций. Есть ли способ использовать JWindow внутри JFrame и, таким образом, устранить кражу фокуса?


ОБНОВЛЕНИЕ 2: Попытка запустить эту программу на виртуальной машине Ubuntu на ПК приводит к тому же неправильному поведению. Это говорит о том, что существует разница во времени выполнения Java в Windows 7 и Linux, и что проблема не является специфичной для встроенного Linux.


ОБНОВЛЕНИЕ 3: Вот SSCCE:

//package SSCCE;

import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;

public class MonitorSSCCE extends JFrame{

    public static void main(String[] args) 
    {
        // Set the frame
        JFrame ecoreFrame = new JFrame("SSCCE");
        ecoreFrame.setSize(120, 120);
        ecoreFrame.setVisible(true);

        // Refresh frame every 200 msec
        while (true) {
            GRFX grfx = new GRFX();
            ecoreFrame.add(grfx);
            ecoreFrame.setVisible(true);
            grfx = null;

            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {

            }
        }
    }


    static int clr = 0;

    public static class GRFX extends JPanel {

        public void paintComponent(Graphics comp) {
            Graphics2D comp2D = (Graphics2D) comp;

            // Draw a changin color rectangle
            comp2D.setColor(new Color(clr, 0, 0));
            Rectangle2D.Double rect = new Rectangle2D.Double(10, 10, 100, 100);
            comp2D.fill(rect);
            clr = clr + 10;
            if (clr > 255)
                clr = 0;
        }
    }
}

ОБНОВЛЕНИЕ 4: Во время подготовки SSCCE я немного прочитал и узнал о множестве методов обновления окна объекта JFrame. Случается, что проблема была setVisible() позвоните внутрь while петля. Решение состояло в том, чтобы заменить его repaint() метод.

2 ответа

Решение

Замена setVisible() вызов метода внутри while() цикл по repaint() устранена проблема:

    // Refresh frame every 200 msec
    while (true) {
        GRFX grfx = new GRFX();
        ecoreFrame.add(grfx);
        ecoreFrame.repaint();
        grfx = null;

        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {

        }
    }

В Ubuntu 12.04.2 с оконным менеджером Unity этот пример обычно анимируется на рабочем столе в фоновом режиме с частотой 1 Гц, когда также запущены обновление терминала и программного обеспечения. Несколько ориентиров для сравнения:

Приложение: Я пересмотрел ваш пример ниже, чтобы проиллюстрировать некоторые дополнительные моменты:

  • Не спи на EDT; действительно использовать javax.swing.Timer чтобы ускорить анимацию.

  • Override getPreferredSize() установить исходную геометрию графического компонента.

  • Профиль для проверки ожидаемого использования кучи.

образ

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

/**
 * @see https://stackru.com/a/18455006/230513
 */
public class TestGRFX {

    private static class GRFX extends JPanel {

        private static final int N = 256;
        private float clr = 0;
        private Rectangle2D.Double rect = new Rectangle2D.Double(0, 0, N, N);
        private Timer t = new Timer(100, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                GRFX.this.repaint();
            }
        });

        public void start() {
            t.start();
        }

        @Override
        public void paintComponent(Graphics g) {
            Graphics2D g2D = (Graphics2D) g;
            g2D.setColor(new Color(Color.HSBtoRGB(clr, 1, 1)));
            g2D.fill(rect);
            clr += .01;
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(N, N);
        }
    }

    private void display() {
        JFrame f = new JFrame("TestGRFX");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        GRFX g = new GRFX();
        f.add(g);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
        g.start();
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new TestGRFX().display();
            }
        });
    }
}
Другие вопросы по тегам