te')); return $arr; } /* 遍历用户所有主题 * @param $uid 用户ID * @param int $page 页数 * @param int $pagesize 每页记录条数 * @param bool $desc 排序方式 TRUE降序 FALSE升序 * @param string $key 返回的数组用那一列的值作为 key * @param array $col 查询哪些列 */ function thread_tid_find_by_uid($uid, $page = 1, $pagesize = 1000, $desc = TRUE, $key = 'tid', $col = array()) { if (empty($uid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('uid' => $uid), array('tid' => $orderby), $page, $pagesize, $key, $col); return $arr; } // 遍历栏目下tid 支持数组 $fid = array(1,2,3) function thread_tid_find_by_fid($fid, $page = 1, $pagesize = 1000, $desc = TRUE) { if (empty($fid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('fid' => $fid), array('tid' => $orderby), $page, $pagesize, 'tid', array('tid', 'verify_date')); return $arr; } function thread_tid_delete($tid) { if (empty($tid)) return FALSE; $r = thread_tid__delete(array('tid' => $tid)); return $r; } function thread_tid_count() { $n = thread_tid__count(); return $n; } // 统计用户主题数 大数量下严谨使用非主键统计 function thread_uid_count($uid) { $n = thread_tid__count(array('uid' => $uid)); return $n; } // 统计栏目主题数 大数量下严谨使用非主键统计 function thread_fid_count($fid) { $n = thread_tid__count(array('fid' => $fid)); return $n; } ?>java - How to avoid flickering when painting an opaque filled circle inside a transparent JFrame? - Stack Overflow
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

java - How to avoid flickering when painting an opaque filled circle inside a transparent JFrame? - Stack Overflow

programmeradmin3浏览0评论

Consider a transparent JPanel with an overridden paintComponent(Graphics?) that fills an opaque green circle underneath the cursor's current position (it also fills an opaque red square, always at the panel's top-left). The panel has been added to a transparent, undecorated JFrame. Some random numbers are also written on-screen to indicate where and where not a repaint is happening. A stray Jbutton is also present.

Upon moving the cursor, lot of flickering is observed. How to remedy this?

Maybe there's a prototypical way seasoned coders implement simple but dynamic, opaque drawing on transparent JFrames.

code (kotlin) (java acceptable too)

import java.awt.Color
import java.awt.Dimension
import java.awt.Graphics
import java.awt.Point
import java.awt.event.MouseEvent
import java.awt.event.MouseMotionAdapter
import javax.swing.*
import kotlin.random.Random

fun main() {
    SwingUtilities.invokeLater {
        val pn = object : JPanel() {
            var pt: Point?=null
            val w=256
            val h=w
            init {
                addMouseMotionListener(object : MouseMotionAdapter() {
                    override fun mouseMoved(e: MouseEvent?) {
                        super.mouseMoved(e)
                        // efficient repainting from .html
                        var lpt=pt//make a local copy of a global nullable to keep compiler happy
                        if (lpt!=null)
                            repaint(lpt.x-w/2,lpt.y-h/2,w,h)
                        pt=e?.point
                        lpt=pt
                        if (lpt!=null)
                            repaint(lpt.x-w/2,lpt.y-h/2,w,h)
                    }
                })
            }
            //few random numbers to show that indeed only the square under the cursor is being repainted
            val rand= Random.Default
            override fun paintComponent(g: Graphics?) {
                super.paintComponent(g)
                if (g!=null){
                    g.color= Color.red
                    val pt=pt
                    g.color = Color.red
                    g.fillRect(10,10,100,100)
                    g.color=Color.black
                    g.drawString(rand.nextInt(1000).toString(),10+50,10+50,)
                    g.color = Color.green
                    pt?.also {
                        g.fillOval(pt.x-w/2,pt.y-h/2,w,h)
                        g.color=Color.black
                        g.drawString(rand.nextInt(1000).toString(),pt.x,pt.y)

                    }
                    
                }
                
            }
        }
        pn.add(JButton("hello"))
        pn.preferredSize = Dimension(500, 500)
        pn.isOpaque = false // panel must be transparent
        pn.border = BorderFactory.createLineBorder(Color.black,5)

        val fr = JFrame()
        fr.defaultCloseOperation = WindowConstants.EXIT_ON_CLOSE
        fr.isUndecorated = true
        fr.background=Color(0, 0, 0,0)//notice the 0 alpha
        fr.add(pn)
        fr.pack()
        fr.setLocationRelativeTo(null)
        fr.isVisible = true


    }
}

Environment
Linux 6.9.3-76060903-generic #202405300957~1738770968~22.04~d5f7c84 SMP PREEMPT_DYNAMIC Wed F x86_64 x86_64 x86_64 GNU/Linux
Pop!_OS 22.04 LTS
GNOME version 42.9
Windowing System X11
openjdk 21.0.6 2025-01-21
OpenJDK Runtime Environment (build 21.0.6+7-Ubuntu-122.04.1)
OpenJDK 64-Bit Server VM (build 21.0.6+7-Ubuntu-122.04.1, mixed mode, sharing)
Screen Refresh Rate: 60.01 Hz and 165.02 Hz (flicker seen in both)
Display scaling: 100% and 125% (flicker seen in both)

Edit(s):

  1. No flicker when run on Windows 11 instead of the original Linux operating system, with (Microsoft's build of) the same JDK and on same hardware with same screen resolution, refresh rate and scaling.
  2. No flicker when tested on a Windows 11 virtual machine running in the original Linux OS, using VirtualBox. The VM is pretty watered down compared to the native hardware and yet shows no flicker - may have to do with the JVM build difference.

Consider a transparent JPanel with an overridden paintComponent(Graphics?) that fills an opaque green circle underneath the cursor's current position (it also fills an opaque red square, always at the panel's top-left). The panel has been added to a transparent, undecorated JFrame. Some random numbers are also written on-screen to indicate where and where not a repaint is happening. A stray Jbutton is also present.

Upon moving the cursor, lot of flickering is observed. How to remedy this?

Maybe there's a prototypical way seasoned coders implement simple but dynamic, opaque drawing on transparent JFrames.

code (kotlin) (java acceptable too)

import java.awt.Color
import java.awt.Dimension
import java.awt.Graphics
import java.awt.Point
import java.awt.event.MouseEvent
import java.awt.event.MouseMotionAdapter
import javax.swing.*
import kotlin.random.Random

fun main() {
    SwingUtilities.invokeLater {
        val pn = object : JPanel() {
            var pt: Point?=null
            val w=256
            val h=w
            init {
                addMouseMotionListener(object : MouseMotionAdapter() {
                    override fun mouseMoved(e: MouseEvent?) {
                        super.mouseMoved(e)
                        // efficient repainting from https://docs.oracle/javase/tutorial/uiswing/painting/refining.html
                        var lpt=pt//make a local copy of a global nullable to keep compiler happy
                        if (lpt!=null)
                            repaint(lpt.x-w/2,lpt.y-h/2,w,h)
                        pt=e?.point
                        lpt=pt
                        if (lpt!=null)
                            repaint(lpt.x-w/2,lpt.y-h/2,w,h)
                    }
                })
            }
            //few random numbers to show that indeed only the square under the cursor is being repainted
            val rand= Random.Default
            override fun paintComponent(g: Graphics?) {
                super.paintComponent(g)
                if (g!=null){
                    g.color= Color.red
                    val pt=pt
                    g.color = Color.red
                    g.fillRect(10,10,100,100)
                    g.color=Color.black
                    g.drawString(rand.nextInt(1000).toString(),10+50,10+50,)
                    g.color = Color.green
                    pt?.also {
                        g.fillOval(pt.x-w/2,pt.y-h/2,w,h)
                        g.color=Color.black
                        g.drawString(rand.nextInt(1000).toString(),pt.x,pt.y)

                    }
                    
                }
                
            }
        }
        pn.add(JButton("hello"))
        pn.preferredSize = Dimension(500, 500)
        pn.isOpaque = false // panel must be transparent
        pn.border = BorderFactory.createLineBorder(Color.black,5)

        val fr = JFrame()
        fr.defaultCloseOperation = WindowConstants.EXIT_ON_CLOSE
        fr.isUndecorated = true
        fr.background=Color(0, 0, 0,0)//notice the 0 alpha
        fr.add(pn)
        fr.pack()
        fr.setLocationRelativeTo(null)
        fr.isVisible = true


    }
}

Environment
Linux 6.9.3-76060903-generic #202405300957~1738770968~22.04~d5f7c84 SMP PREEMPT_DYNAMIC Wed F x86_64 x86_64 x86_64 GNU/Linux
Pop!_OS 22.04 LTS
GNOME version 42.9
Windowing System X11
openjdk 21.0.6 2025-01-21
OpenJDK Runtime Environment (build 21.0.6+7-Ubuntu-122.04.1)
OpenJDK 64-Bit Server VM (build 21.0.6+7-Ubuntu-122.04.1, mixed mode, sharing)
Screen Refresh Rate: 60.01 Hz and 165.02 Hz (flicker seen in both)
Display scaling: 100% and 125% (flicker seen in both)

Edit(s):

  1. No flicker when run on Windows 11 instead of the original Linux operating system, with (Microsoft's build of) the same JDK and on same hardware with same screen resolution, refresh rate and scaling.
  2. No flicker when tested on a Windows 11 virtual machine running in the original Linux OS, using VirtualBox. The VM is pretty watered down compared to the native hardware and yet shows no flicker - may have to do with the JVM build difference.
Share Improve this question edited 2 days ago lineage asked Feb 17 at 14:06 lineagelineage 8951 gold badge12 silver badges21 bronze badges 7
  • AFAIR you need to enable double buffering somewhere. – talex Commented Feb 17 at 14:14
  • @talex enabling it in fr.rootPane and in pn (JPanel) by setting isDoubleBuffered to true has no effect (and was already true anyways) – lineage Commented Feb 17 at 14:18
  • I guess e?.point is null sometimes. – talex Commented Feb 17 at 14:25
  • Swing was not designed to paint with transparent backgrounds.. See the answer to How to make the JFrame contentPane transparent but the JFrame visible? – Gilbert Le Blanc Commented Feb 17 at 15:24
  • @talex e is nullable so pt=e?.point doesn't execute whenever e is null. Practically, I have never found e to be null – lineage Commented Feb 17 at 16:50
 |  Show 2 more comments

1 Answer 1

Reset to default 0

I gave it a try in java, and I merely replaced pt?.also { with a null check. Whether that was the cause I do not know. But the pure java version seems to work. I thought the JButton would have been a problem as this comes over the green circle.

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.util.Random;
import javax.swing.*;

public class Stov {

  public static void main(String[] args) {
    SwingUtilities.invokeLater(() -> {
      JPanel pn = new JPanel() {
        Point pt = null;
        int w = 256;
        int h = w;

        {
          addMouseMotionListener(new MouseMotionAdapter() {
            @Override
            public void mouseMoved(MouseEvent e) {
              super.mouseMoved(e);
              // efficient repainting from https://docs.oracle/javase/tutorial/uiswing/painting/refining.html
              Point lpt = pt; //make a local copy of a global nullable to keep compiler happy
              if (lpt != null)
                repaint(lpt.x - w / 2, lpt.y - h / 2, w, h);
              pt = e.getPoint();
              lpt = pt;
              if (lpt != null)
                repaint(lpt.x - w / 2, lpt.y - h / 2, w, h);
            }
          });
        }

        //few random numbers to show that indeed only the square under the cursor is being repainted
        Random rand = new Random();

        @Override
        public void paintComponent(Graphics g) {
          super.paintComponent(g);
          if (g != null) {
            g.setColor(Color.red);
            //val pt=pt;
            g.setColor(Color.red);
            g.fillRect(10, 10, 100, 100);
            g.setColor(Color.black);
            g.drawString(String.valueOf(rand.nextInt(1000)), 10 + 50, 10 + 50);
            g.setColor(Color.green);
            //pt?.also {
            if (pt != null) {
              g.fillOval(pt.x - w / 2, pt.y - h / 2, w, h);
              g.setColor(Color.black);
              g.drawString(String.valueOf(rand.nextInt(1000)), pt.x, pt.y);

            }

          }

        }
      };

      pn.add(new JButton("hello"));
      pn.setPreferredSize(new Dimension(500, 500));
      pn.setOpaque(false); // panel must be transparent
      pn.setBorder(BorderFactory.createLineBorder(Color.black, 5));

      JFrame fr = new JFrame();
      fr.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
      fr.setUndecorated(true);
      fr.setBackground(new Color(0, 0, 0, 0));//notice the 0 alpha
      fr.add(pn);
      fr.pack();
      fr.setLocationRelativeTo(null);
      fr.setVisible(true);
    });
  }
}
发布评论

评论列表(0)

  1. 暂无评论