2015-07-09 11 views
9

Ich möchte einen vollständig transparenten Hintergrund für einen Frame (oder JFrame) erstellen und eine transparente Animation anzeigen lassen. Ich habe es geschafft, es in Windows 7 x64 arbeiten, aber der gleiche Code läuft nicht auf meinem Linux (Lubuntu x64 15.04).Animation auf transparentem Hintergrund JFrame Linux

Der folgende Code zeigt, was ich versuche zu erreichen - kopieren Sie einfach & fügen Sie es ein. Ich möchte nur, dass sich das kleine Rechteck über den Bildschirm bewegt, ohne eine Spur zu hinterlassen.

static int a = 0; 

public static void main(String[] args) { 
    JFrame f = new JFrame(); 
    f.setUndecorated(true); 
    f.setBackground(new Color(0, 0, 0, 0)); 
    f.setVisible(true); 
    f.setSize(512, 512); 
    f.add(new JPanel() { 
     @Override 
     public void paintComponent(Graphics gr) { 
      Graphics2D g = (Graphics2D)gr; 
      g.setBackground(new Color(0, 0, 0, 0)); 
      g.clearRect(0, 0, 512, 512); 
      g.drawRect(a, a++, 2, 2); 
     } 
    }); 

    while(true) { 
     try { 
      Thread.sleep(30); 
     } catch(InterruptedException e) { 
      e.printStackTrace(); 
     } 
     f.repaint(); 
    } 
} 

Was ich erreichen möchte (wie in Windows gezeigt) und was ich mit Lubuntu 15.04:

Desired Animation                 Lubuntu Animation

Ich will nur sehen, Das kleine Quadrat bewegt sich genau wie bei Windows 7 - ich möchte keine Spur sehen.

Bitte geben Sie mir nicht den Link von Oracles Transparenz- und Fensterdokumentation - ich habe es dreimal gelesen.

Was ich versucht habe:

  • Graphics2D die 'copyArea()' aus einem transparenten Raum. (Diese verwendet AFAIK zu arbeiten, aber nicht tut mehr)
  • Glasspane
  • AlphaComposite
  • SetPaint()

Bitte bitte einfach Ihre Gedanken testen/Code zuerst. Viele der "das sollte funktionieren" Sachen, die ich bereits ausprobiert habe und nicht scheint ... Alle Hilfe wird sehr geschätzt.

+0

Nach vielen Stunden und Stunden, die ich habe es gefunden: Es ist ein Back-Puffer Problem. Ich habe einen Weg gefunden, es auch zu reparieren, aber ich habe jetzt nicht viel Zeit, also werde ich es heute später veröffentlichen. Trotzdem muss es auch unter Windows getestet werden. Meine Lösung scheint etwas zu flimmern, also werde ich wahrscheinlich sehen, ob ich das auch beheben kann. Wie auch immer, ich würde mich sehr über die neue Lösung freuen, da ich nur Windows 7 x64 und Lubuntu 15.04 zur Verfügung habe. Danke Leute. – Roland

+0

kann nicht auf die Antwort warten, und ich werde es auf meinen Computern versuchen: D – JetStream

+0

@JetStream Ich habe eine Antwort unten gepostet. Es funktioniert für Linux und Windows 7 für mich, aber ich besitze keinen Mac, also kann ich das nicht testen ... – Roland

Antwort

2

Im Grunde ist dieses Thema O bezogen. Was für Windows funktioniert, funktioniert nicht für Linux und umgekehrt.

Aus irgendeinem Grund erlaubt Linux nur animierte Per-Pixel-Transparenz beim Einrichten einer BufferStrategy. Diese Lösung schlägt jedoch unter Windows fehl. Als Ergebnis habe ich mit dem folgenden Code kommen, die den korrekten Algorithmus auf der OS-basierten nimmt:

static int a = 0; 

public static void main(String[] args) { 
    JFrame f = new JFrame(); 
    JPanel p = new JPanel() { 
     @Override 
     public void paintComponent(Graphics g) { 
      Graphics2D g2d = (Graphics2D) g; 
      g2d.setBackground(new Color(255, 255, 255, 0)); 
      g2d.clearRect(0, 0, f.getWidth(), f.getHeight()); 
      g2d.drawRect(a, a++, 2, 2); 
     } 
    }; 
    f.add(p); 
    f.setUndecorated(true); 
    f.setBackground(new Color(255, 255, 255, 0)); 
    f.setSize(512, 512); 
    f.setVisible(true); 
    f.createBufferStrategy(2); 

    BufferStrategy bs = f.getBufferStrategy(); 
    while (true) { 
     try { 
      Thread.sleep(33); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
     if (System.getProperty("os.name").contains("indows ")) { 
      p.repaint(); 
     } else { 
      Graphics g = null; 
      do { 
       try { 
        g = bs.getDrawGraphics(); 
        p.update(g); 
       } finally { 
        g.dispose(); 
       } 
       bs.show(); 
      } while (bs.contentsLost()); 
      Toolkit.getDefaultToolkit().sync(); 
     } 
    } 
} 

Dieser Code funktioniert für mein Windows 7 x64 und meine Lubuntu 15.04 x64. Bitte probieren Sie diesen Code selbst aus und sehen Sie, ob er für Sie funktioniert. Ich selbst besitze keinen Mac, also würde jemand, der es für mich testen würde, sehr dankbar sein. Wenn es für niemanden funktioniert, lass es mich wissen.

Dies ist, was man eigentlich sehen:

enter image description here

+0

Works on Mac OS X mit '.contains (" Mac ")', aber auch [* Initial Threads *] (http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html) – trashgod

+0

@trashgod Also muss Mac auch p.repaint() aufrufen? – Roland

+0

Ja, AFAIK; Ich rufe 'repaint() 'von einem' javax.swing.Timer', der Runnables auf dem EDT plant, in meinem [Beispiel] (http://stackoverflow.com/a/31328464/230513). – trashgod

2

Wenn wir JFrame erweitern, undecorated auf true setzen und Paint mit überschreiben, können wir einen transparenten JFrame erstellen.

dies versuchen,

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Graphics; 
import java.awt.Point; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import java.io.IOException; 
import java.net.MalformedURLException; 
import java.util.ArrayList; 
import java.util.List; 

import javax.swing.BorderFactory; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.SwingUtilities; 

public class TestTransparentFrame { 

private class PaintPanel extends JPanel { 
    private List<Point> points = new ArrayList<Point>(); 

    public PaintPanel() { 
     setOpaque(false); 
     MouseAdapter adapter = new MouseAdapter() { 
      @Override 
      public void mouseClicked(MouseEvent e) { 
       points.clear(); 
       repaint(); 
      } 

      @Override 
      public void mouseMoved(MouseEvent e) { 
       points.add(e.getPoint()); 
       repaint(); 
      } 
     }; 
     addMouseListener(adapter); 
     addMouseMotionListener(adapter); 
     setBorder(BorderFactory.createLineBorder(Color.GREEN)); 
    } 

    @Override 
    protected void paintComponent(Graphics g) { 
     super.paintComponent(g); 
     if (points.size() > 1) { 
      g.setColor(Color.RED); 
      Point p1 = points.get(0); 

      for (int i = 1; i < points.size(); i++) { 
       Point p2 = points.get(i); 
       g.drawLine(p1.x, p1.y, p2.x, p2.y); 
       p1 = p2; 
      } 
     } 
    } 

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

protected void createAndShowGUI() throws MalformedURLException, IOException { 
    JFrame frame = new JFrame("Test transparent painting"); 
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    frame.setUndecorated(true); 
    frame.setBackground(new Color(0, 0, 0, 50)); 
    frame.add(new PaintPanel()); 
    frame.pack(); 
    frame.setVisible(true); 
} 

public static void main(String[] args) { 
    SwingUtilities.invokeLater(new Runnable() { 
     @Override 
     public void run() { 
      try { 
       new TestTransparentFrame().createAndShowGUI(); 
      } catch (MalformedURLException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } catch (IOException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
     } 
    }); 

} 

} 
+0

Thx für die Antwort, aber ich habe das schon ausprobiert. Wenn Sie Ihre Antwort bearbeiten und Arbeitscode einfügen könnten, wäre das großartig. – Roland

+0

Thx für die Buchung Ihres Codes, aber dieses spezielle Beispiel gilt nicht für das Problem, das ich habe. Ich möchte, dass die Linien/Spuren verschwinden, wenn Sie die Maus bewegen. Das Problem ist, dass der JFrame seinen Bildschirminhalt nicht löscht, bevor das JPanel neu gezeichnet wird. Mit anderen Worten, der JPanel bleibt über sich selbst gezeichnet ... das ist das Problem, das ich habe, aber danke für die Hilfe :) – Roland

3

Als Referenz ist hier ein minimales complete example, geeignet für die plattformübergreifende Tests. Man beachte, dass

  • Auf einigen Plattformen, z.B. Ubuntu, ein vollständig transparenten Hintergrund wird nicht als opaque gesehen; ein kleiner, nicht Null Alpha Wert ist ein typischer Work-around.

  • Swing-GUI-Objekte sollten nur auf dem event dispatch thread konstruiert und manipuliert werden.

  • Verwenden Sie java.swing.Timer, die auf dem Ereignisversendungsthread ausgeführt wird, um die Animation zu beschleunigen.

  • Verwenden Sie nicht setPreferredSize(), wenn Sie wirklich übersteuern wollen getPreferredSize().

image

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.event.ActionEvent; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.Timer; 

/** 
* @see https://stackoverflow.com/a/31328464/230513 
*/ 
public class TransparentAnimation { 

    private static final Color tranparentBlack = new Color(0, 0, 0, 1); 

    private void display() { 
     JFrame f = new JFrame("Test"); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     f.setUndecorated(true); 
     f.setBackground(tranparentBlack); 
     f.add(new JPanel() { 
      int x, y; 
      Timer t = new Timer(10, (ActionEvent e) -> { 
       x = (x + 1) % getWidth(); 
       y = (y + 1) % getHeight(); 
       repaint(); 
      }); 

      { 
       setBackground(tranparentBlack); 
       t.start(); 
      } 

      @Override 
      public void paintComponent(Graphics g) { 
       super.paintComponent(g); 
       g.drawRect(0, 0, getWidth() - 1, getHeight() - 1); 
       g.fillOval(x, y, 16, 16); 
      } 

      @Override 
      public Dimension getPreferredSize() { 
       return new Dimension(320, 240); 
      } 
     }); 
     f.add(new JLabel(System.getProperty("os.name") + "; v" 
      + System.getProperty("os.version")), BorderLayout.SOUTH); 
     f.pack(); 
     f.setLocationRelativeTo(null); 
     f.setVisible(true); 
    } 

    public static void main(String[] args) { 
     EventQueue.invokeLater(new TransparentAnimation()::display); 
    } 
} 
+0

[Screenshots] (http://meta.stackoverflow.com/questions/99734/how-do -i-create-a-screenshot-zu-illustrieren-a-post) für andere Plattformen/Versionen willkommen. – trashgod

+0

Thx für die Antwort, aber das beantwortet meine Frage nicht. Ich weiß, wie man einen transparenten Rahmen erstellt, den mein Beispielcode bereits erreicht. Ich möchte wissen, wie man eine Animation erstellt. Ich habe gerade den Code getestet, den ich auf einer Windows-Maschine veröffentlicht habe, und es sieht so aus, als ob mein Code gut läuft. Aus irgendeinem Grund möchte er nicht mit meinem Linux arbeiten. Nicht sicher, ob es sich um ein Linux-, Ubuntu- oder LXDE-Problem handelt ... – Roland

+0

@Roland: Ah, ich habe dein Beispiel falsch interpretiert, das anscheinend 'a' in einem Thread ändert und auf einem anderen zugreift. Mehr oben. – trashgod

Verwandte Themen