0

Swingを使用してアプリを開発しています。ユーザーがアプリを操作しているときに、ヘルプデータが画面の閉じたセクションで利用できるようになる場合があります。その場合は、そのセクションを指す小さな矢印を描画したいと思います。

これを行うために、JPanelを拡張し、アプリjframeのガラス板として追加しました。カスタムガラスペインクラスの名前はAlertGlassPaneです。

AlertGlassPaneはこれを行います:新しいヘルプデータが利用可能になるまで待機します。これが発生してヘルプセクションが閉じられると、画面上のヘルプセクションの位置が検出され、その横にアニメーションの矢印が描画されます。

矢印を描画するために、ガラスペインのメソッドpaintComponentを拡張しました。

矢印をアニメーション化するために、100ミリ秒ごとにループする小さなスレッドを作成し、ガラスペインで再ペイントを呼び出しました。

問題:Javaは私の描画を無視します...トリガーがアニメーションの開始をトリガーして静止した場合、何も起こりません。アプリに描画は表示されません。

ループが実行され、paintComponentが呼び出されていることはわかっていますが、カスタムペイントが有効になっていません。

しかし、矢印を表示する領域にマウスを移動すると、表示されます。しかし、マウスが動いているとき。停止するとマウスが移動し、アニメーションも停止し、マウスが停止する(または領域を離れる)前の最後の位置で矢印がフリーズします。

多くのことを試しましたが(たとえば、図面のクリップ領域を設定するなど)、何も機能しないようです。動作するのは、paintComponent内から誤って再ペイントを呼び出したときだけでした。

現時点では、ガラス板のギブム領域を再ペイントする必要があることをレンダリングシステムに伝達する方法を探しています(repaint(x、y、w、h)は機能しませんでした...)。たぶん、カスタムレンダリングをJLabelに移動してから、このラベルをガラス板に追加しますか?私はこのアプローチが好きではありません...

ここにスニペットを投稿する前に、コードをクリーンアップしてみます。それが役立つだろう?

前もって感謝します!

snnipet:

package br.com.r4j.test;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.image.BufferedImage;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.text.JTextComponent;

/**
 *
 * @author 
 */
public class TestGlassPaneAnimation extends JPanel
{
    private static TestGlassPaneAnimation gvp = new TestGlassPaneAnimation();



    public static void main(String args[])
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                JFrame f = new JFrame("Anitest in glass");
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                //f.setResizable(false);
                f.setLayout(new GridLayout(5, 3));

                f.add(new JLabel("First Name :"));
                f.add(new JTextField(20));
                f.add(new JLabel("Last Name :"));
                f.add(new JTextField(20));
                f.add(new JLabel("Phone Number :"));
                f.add(new JTextField(20));
                f.add(new JLabel("Email:"));
                f.add(new JTextField(20));
                f.add(new JLabel("Address :"));
                f.add(new JTextField(20));
                JButton btnStart = new JButton("Click me, please!");
                f.add(btnStart);

                btnStart.addActionListener(new ActionListener()
                {
                    public void actionPerformed(ActionEvent e)
                    {
                        gvp.startAnimation();
                    }
                });

                f.setGlassPane(gvp);

                f.pack();
                f.setVisible(true);
                gvp.setVisible(true);
            }

        });
    }

    private BufferedImage icon;
    private boolean animate = false;
    private long timeStart = 0;
    private Thread thrLastActive = null;

    public TestGlassPaneAnimation()
    {
        setLayout(null);//this is the exception to the rule case a layoutmanager might make setting Jlabel co-ords harder
        setOpaque(false);
        Icon icon1 = UIManager.getIcon("OptionPane.warningIcon");
        int imgW = icon1.getIconWidth();
        int imgH = icon1.getIconHeight();
        this.icon = ImageUtilities.getBufferedImageOfIcon(icon1, imgW, imgH);
        this.animate = false;
    }


    public void startAnimation()
    {
        this.animate = true;
        this.timeStart = (new Date()).getTime();

        if (this.thrLastActive != null)
            this.thrLastActive.interrupt();

        this.thrLastActive = new Thread(new Runnable() 
        {
            public void run()
            {
                try
                {
                    while (true)
                    {
                        // int x = 250, y = 250;
                        // int width = 60, height = 60;

                        Thread.currentThread().sleep(100);

                        // frmRoot.invalidate();
                        // repaint(x, y, width, height);
                        repaint(new Rectangle(x, y, width, height));
                        // repaint(new Rectangle(10, 10, 2000, 2000));
                        // repaint();
                        // paintComponent(getGraphics());
                    }
                }
                catch (Exception e)
                {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });

        this.thrLastActive.start();
    }


    protected void paintComponent(Graphics g)
    {
      try
      {
            // enables anti-aliasing
            Graphics2D g2 = (Graphics2D) g;
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);


            java.awt.Composite composite = g2.getComposite();

            System.err.println("b1: " + g.getClipBounds());

            if (this.animate)
            {
                long timeSpent = (new Date()).getTime() - timeStart;

                int x = 10, y = 150;
                int width = 60, height = 60;
                float maxAlpha = 0.8f;
                x += (-100*Math.sin(5*2*Math.PI*timeSpent/10000)+50)/15;
                System.err.println("painting::x: " + x + ", y: " + y + ", sin: " + (Math.sin(6*2*Math.PI*timeSpent/10000)));

                // g.setClip(x-10, y-10, width, height);
                System.err.println("b2: " + g.getClipBounds());

                AlphaComposite alpha2 = AlphaComposite.SrcOver.derive(maxAlpha);
                g2.setComposite(alpha2);
                g2.drawImage(this.icon, x, y, null);
                g2.setComposite(composite);

                g2.setComposite(composite);
            }
      }
      catch (Throwable e)
      {
          System.err.println("Errr!");
          e.printStackTrace();
      }
    }

}

class ImageUtilities {

    public static BufferedImage resize(BufferedImage image, int width, int height) {
        BufferedImage bi = new BufferedImage(width, height, BufferedImage.TRANSLUCENT);
        Graphics2D g2d = (Graphics2D) bi.createGraphics();
        g2d.addRenderingHints(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));
        g2d.drawImage(image, 0, 0, width, height, null);
        g2d.dispose();
        return bi;
    }

    public static BufferedImage getBufferedImageOfIcon(Icon icon, int imgW, int imgH) {
        BufferedImage img = new BufferedImage(imgW, imgH, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2d = (Graphics2D) img.getGraphics();
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        icon.paintIcon(null, g2d, 0, 0);
        g2d.dispose();
        return img;
    }
}
4

1 に答える 1

1

うーん、あなたが与えたスニペットで何が起こっているのか正確にはわかりませんが、それは私のものから取ったように見えるので、私は別の例を書きました(1行または2行のコードshowWarningIcon(Component c)refreshLocations()メソッドを変更する必要がありましたが、大きなものは何もありません:

david以外のものを入力し、ボタン(クリックしてください)をクリックすると、次のように表示されます。

ここに画像の説明を入力してください

import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Map;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

public class TestGlassPaneAnimation {

    private static GlassValidationPane gvp = new GlassValidationPane();

    public static void main(String args[]) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame f = new JFrame("Anitest in glass");
                f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                //f.setResizable(false);
                f.setLayout(new GridBagLayout());

                GridBagConstraints gc = new GridBagConstraints();
                gc.fill = GridBagConstraints.HORIZONTAL;
                gc.weightx = 1;
                gc.weighty = 1;
                gc.insets = new Insets(15, 15, 15, 15);//give some space so icon doesnt cover components when shown

                gc.gridx = 0;
                gc.gridy = 0;
                f.add(new JLabel("First Name:"), gc);

                final JTextField jtf = new JTextField(20);
                gc.gridx = 1;
                f.add(jtf, gc);

                gc.gridx = 0;
                gc.gridy = 1;
                f.add(new JLabel("Surname:"), gc);

                final JTextField jtf2 = new JTextField(20);
                gc.gridx = 1;
                f.add(jtf2, gc);

                JButton btnStart = new JButton("Click me, please!");
                gc.gridx = 2;
                f.add(btnStart, gc);

                btnStart.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        if (!jtf.getText().equalsIgnoreCase("david")) {
                            gvp.showWarningIcon(jtf);
                        }
                    }
                });

                f.addComponentListener(new ComponentAdapter() {//so wjen frame is resized icons follow
                    @Override
                    public void componentResized(ComponentEvent ce) {
                        super.componentResized(ce);
                        gvp.refreshLocations();
                    }
                });
                f.setGlassPane(gvp);

                f.pack();
                f.setVisible(true);
                gvp.setVisible(true);
            }
        });
    }
}

class GlassValidationPane extends JPanel {

    private HashMap<Component, JLabel> warningLabels = new HashMap<>();
    private ImageIcon warningIcon;

    public GlassValidationPane() {
        setLayout(null);//this is the exception to the rule case a layoutmanager might make setting Jlabel co-ords harder
        setOpaque(false);
        Icon icon = UIManager.getIcon("OptionPane.warningIcon");
        int imgW = icon.getIconWidth();
        int imgH = icon.getIconHeight();
        BufferedImage img = ImageUtilities.getBufferedImageOfIcon(icon, imgW, imgH);
        warningIcon = new ImageIcon(ImageUtilities.resize(img, 24, 24));
    }

    void showWarningIcon(Component c) {
        if (warningLabels.containsKey(c)) {
            return;
        }

        JLabel label = new JLabel();
        label.setIcon(warningIcon);

        //int x=c.getX();//this will make it insode the component
        int x = c.getX() - warningIcon.getIconWidth();//this makes it appear outside/next to component if space
        int y = c.getY();

        label.setBounds(x, y, warningIcon.getIconWidth(), warningIcon.getIconHeight());
        add(label);
        revalidate();
        repaint();
        warningLabels.put(c, label);
    }

    public void removeWarningIcon(Component c) {
        for (Map.Entry<Component, JLabel> entry : warningLabels.entrySet()) {
            Component component = entry.getKey();
            JLabel jLabel = entry.getValue();
            if (component == c) {
                remove(jLabel);
                revalidate();
                repaint();
                break;
            }
        }
        warningLabels.remove(c);
    }

    public void refreshLocations() {
        for (Map.Entry<Component, JLabel> entry : warningLabels.entrySet()) {
            Component c = entry.getKey();
            JLabel label = entry.getValue();
            //int x=c.getX();//this will make it insode the component
            int x = c.getX() - label.getIcon().getIconWidth();//this makes it appear outside/next to component
            int y = c.getY();

            label.setBounds(x, y, label.getIcon().getIconWidth(), label.getIcon().getIconHeight());
            revalidate();
            repaint();
        }
    }
}

class ImageUtilities {

    public static BufferedImage resize(BufferedImage image, int width, int height) {
        BufferedImage bi = new BufferedImage(width, height, BufferedImage.TRANSLUCENT);
        Graphics2D g2d = (Graphics2D) bi.createGraphics();
        g2d.addRenderingHints(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));
        g2d.drawImage(image, 0, 0, width, height, null);
        g2d.dispose();
        return bi;
    }

    public static BufferedImage getBufferedImageOfIcon(Icon icon, int imgW, int imgH) {
        BufferedImage img = new BufferedImage(imgW, imgH, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2d = (Graphics2D) img.getGraphics();
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        icon.paintIcon(null, g2d, 0, 0);
        g2d.dispose();
        return img;
    }
}

より成熟したライブラリをお探しの場合は、JXLayer-検証オーバーレイガラスペインを使用した検証オーバーレイをご覧ください。

また、などのようなテキストフィールドデータ(ボタンを押す以外)を検証する多くの方法を示すここを読んでおくとよいでしょう。DocumentFilterInputVerifier

于 2013-02-15T20:59:41.290 に答える