в чем разница между jpanel.updateUI() и jpanel.repaint() и toolkit.getDefultToolkit().sync() в java?

#java #swing #jframe #layout-manager #frame-rate

Вопрос:

Я создаю простое приложение и учусь, практикуясь в том, как методы, связанные с FPS, работают в Java, чтобы создать приложение с высокой скоростью, но я не знаю, какой из вышеперечисленных методов я должен использовать. в моем приложении есть кнопка, текстовое поле и простой менеджер компоновки, который я сделал, который должен изменять расположение компонентов в соответствии с размером основного кадра (используя соотношение). менеджер по компоновке должен иметь возможность обновлять панель (или мою рамку, я на самом деле не знаю) каждый раз, когда местоположение компонента меняется. кроме того, пока пользователь изменяет размер кадра, компоненты должны двигаться плавно и без задержек. как я могу выполнить все это? прямо сейчас моя проблема показана ниже, и кажется, что panel.updateUI() ничего не делает.

введите описание изображения здесь

как вы видите, есть черная линия, которая появится, когда вы медленно измените размер кадра, и она не исчезнет. когда вы делаете это быстро, он становится больше, и вы видите его ясно, но он исчезает, в то время как при частоте кадров выше 60 вы не должны видеть такую вещь.

вот как я сейчас это делаю:

 
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingWorker;

public class Test {

    private JFrame frame;
    private SwingWorker<Void, Void> sw;
    private JTextField txtGi;
    protected volatile static boolean b = false;
    private double FPS = 0;
    protected static volatile JButton btnStart;

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
                public void run() {
                    try {
                        Test window = new Test();
                        window.frame.setVisible(true);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            });
    }

    public Test() {
        initialize();
    }

    private void initialize() {
        frame = new JFrame();
        frame.setBounds(100, 100, 230, 230);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setMinimumSize(new Dimension(230, 230));

        JPanel panel = new JPanel();
        panel.setBounds(0, 0, 216, 193);
        panel.setBackground(Color.PINK);
        frame.getContentPane().add(panel);
        panel.setLayout(null);

        btnStart = new JButton("Start");
        btnStart.setName("btnStart");
        btnStart.setFont(new Font("Segoe Print", Font.BOLD | Font.ITALIC, 17));
        btnStart.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    System.out.println(frame.getMinimumSize());

                    System.out.println(
                        "#sw.isDone(): "   sw.isDone()   " sw.isCancelled(): "   sw.isCancelled()   " b: "   b);

                }
            });
        btnStart.setBounds(50, 120, 101, 33);
        panel.add(btnStart);
        System.out.println("1: "   Thread.currentThread().getName());
        frame.validate();
        panel.validate();
        sw = new SwingWorker<Void, Void>() {

            @Override
            protected Void doInBackground() throws Exception {

                b = true;
                System.out.println(Thread.currentThread().getName()   " is going to sleep for 250 millis.");
                System.out.println(frame.isShowing());
                while (frame.isShowing() == false) {
                    System.out.println("initializing the frame.");
                    Thread.sleep(320);
                }

                System.out.println(frame.isShowing());
                int cc = 0;
                int FC = 0;

                while (frame.isShowing()) {
                    Thread.sleep(1);
                    panel.updateUI();
                    long s = System.currentTimeMillis();
                    System.out.println("2: "   Thread.currentThread().getName());
                    cc  ;

                    Graphical_AI.setComponentLocationWithButton(btnStart);

                    System.out.println("3: "   Thread.currentThread().getName());
                    if (Graphical_AI.thread1.isAlive()) {
                        System.out.println();
                        System.out.println("waiting for "   Graphical_AI.thread1.getName()   " to finish!");
                        System.out.println();
                        Graphical_AI.thread1.join();
                        Thread.sleep(1);
                        panel.updateUI();

                    }

                    Graphical_AI.setComponentLocationWithButton(txtGi);

                    if (Graphical_AI.thread1.isAlive()) {
                        System.out.println();
                        System.out.println("waiting for "   Graphical_AI.thread1.getName()   " to finish!");
                        System.out.println();
                        Graphical_AI.thread1.join();
                        Thread.sleep(1);
                        panel.updateUI();

                    }

                    long e = System.currentTimeMillis();
                    FPS = 1.0 / ((e - s) / 1000.0);

                    FC  ;
                    if (FC == 60) {
                        txtGi.setText(String.valueOf("FPS: "   (int) FPS));
                        FC = 0;
                    }

                    System.out.println("FPS: "   (int) FPS);

                    if (cc == 1000) {
                        Thread.sleep(5);
                        cc = 0;
                        System.gc();
                        System.out.println("memory optimized.");

                    }

                }
                return null;
            }

            @Override
            protected void process(List<Void> chunks) {
                super.process(chunks);
            }

            @Override
            protected void done() {
                System.out.println("sw.isDone(): "   sw.isDone()   " b: "   b);
                super.done();
            }

        };
        sw.execute();

        txtGi = new JTextField();
        txtGi.setName("txtGi");
        txtGi.setFont(new Font("Segoe Script", Font.BOLD | Font.ITALIC, 21));
        txtGi.setBounds(50, 40, 134, 70);
        panel.add(txtGi);
        txtGi.setColumns(10);
    }
}

 

менеджер по компоновке:

 import java.awt.Container;
import java.util.ArrayList;
import javax.swing.JComponent;
import javax.swing.JFrame;

public class Graphical_AI {

    protected static volatile int count = 0;
    protected static volatile int C_X;
    protected static volatile int C_Y;
    protected static double x_C_To_E_ratio;
    protected static double y_C_To_E_ratio;
    protected static int C_WIDTH;
    protected static int C_HEIGHT;
    protected static int Con_WIDTH;
    protected static int Con_HEIGHT;
    protected static volatile int N_C_X;
    protected static volatile int N_C_Y;
    protected static Container con;
    protected volatile static boolean bool = false;
    protected static volatile ArrayList<Double> al = new ArrayList<Double>();
    protected static volatile ArrayList<String> al_for_O_names = new ArrayList<String>();
    protected static volatile String C_Name;
    protected static volatile String C_O_Name;
    protected volatile static boolean bool2 = false;
    protected static volatile Thread thread1;

    protected static void analyzeJComponentSize(JComponent comp) throws InterruptedException {
        System.out.println("W: "   comp.getWidth()   " H: "   comp.getHeight());
        Thread.sleep(30);
    }

    protected static void analyzeJFrameSize(JFrame frame) throws InterruptedException {
        System.out.println("W: "   frame.getWidth()   " H: "   frame.getHeight());
        Thread.sleep(30);
    }

    protected static void setComponentLocationWithButton(JComponent comp) throws InterruptedException {

        thread1 = Thread.currentThread();
        thread1 = new Thread(new Runnable() {

                @Override
                public void run() {

                    System.out.println("count: "   count);
                    C_Name = comp.getName();
                    System.out.println("C_Name: "   C_Name);

                    if (count == 0) {
                        C_O_Name = comp.getName();
                        System.out.println("C_O_Name: "   C_O_Name);

                        con = comp.getParent();

                        Con_WIDTH = con.getWidth();
                        Con_HEIGHT = con.getHeight();

                        System.out.println("** (double) Con_WIDTH: "   (double) Con_WIDTH);
                        System.out.println("** (double) Con_HEIGHT: "   (double) Con_HEIGHT);

                        x_C_To_E_ratio = (double) con.getWidth() / (double) comp.getX();
                        y_C_To_E_ratio = (double) con.getHeight() / (double) comp.getY();

                        if (bool2 == false) {
                            al.add(x_C_To_E_ratio);
                            al.add(y_C_To_E_ratio);
                            al_for_O_names.add(comp.getName());
                            bool2 = true;
                        }

                        System.out.println("** x_C_To_E_ratio: "   x_C_To_E_ratio);
                        System.out.println("** y_C_To_E_ratio: "   y_C_To_E_ratio);

                        System.out.println("** (double) con.getWidth() / (double) comp.getX(): "
                              (double) con.getWidth() / (double) comp.getX());

                        C_X = comp.getX();
                        C_Y = comp.getY();
                        C_WIDTH = comp.getWidth();
                        C_HEIGHT = comp.getHeight();

                        System.out.println("** C_WIDTH: "   C_WIDTH   ", "   C_HEIGHT);

                        System.out.println("** (double) con.getWidth() / (double) C_X): "   (double) con.getWidth()   " / "
                              (double) C_X);

                        count  ;
                    }

                    if (C_Name != al_for_O_names.get(0)) {
                        count = 0;
                        System.out.println("%% C_Name: "   C_Name);
                        System.out.println("%% C_O_Name: "   C_O_Name);
                        System.out.println("%% al_for_O_names.get(0): "   al_for_O_names.get(0));
                        System.out.println("%% count became to:"   count);
                        al_for_O_names.remove(0);
                        al_for_O_names.add(comp.getName());
                    } else {
                        System.out.println("*ELSE STATEMENT*");
                        count = 1;
                    }

                    if (count == 0) {
                        C_Name = comp.getName();
                        System.out.println("$ C_Name: "   C_Name);

                        con = comp.getParent();

                        Con_WIDTH = con.getWidth();
                        Con_HEIGHT = con.getHeight();

                        System.out.println("$ (double) Con_WIDTH: "   (double) Con_WIDTH);
                        System.out.println("$ (double) Con_HEIGHT: "   (double) Con_HEIGHT);

                        x_C_To_E_ratio = (double) con.getWidth() / (double) comp.getX();
                        y_C_To_E_ratio = (double) con.getHeight() / (double) comp.getY();

                        if (bool2 == false) {
                            al.add(x_C_To_E_ratio);
                            al.add(y_C_To_E_ratio);
                            bool2 = true;
                        }

                        System.out.println("$ x_C_To_E_ratio: "   x_C_To_E_ratio);
                        System.out.println("$ y_C_To_E_ratio: "   y_C_To_E_ratio);

                        System.out.println("$ (double) con.getWidth() / (double) comp.getX(): "
                              (double) con.getWidth() / (double) comp.getX());

                        C_X = comp.getX();
                        C_Y = comp.getY();
                        C_WIDTH = comp.getWidth();
                        C_HEIGHT = comp.getHeight();

                        System.out.println("$ C_WIDTH: "   C_WIDTH   ", "   C_HEIGHT);

                        System.out.println("$ (double) con.getWidth() / (double) C_X): "   (double) con.getWidth()   " / "
                              (double) C_X);

                        count  ;
                    }

                    try {
                        System.out.println("## after if count block ## comp W: "   comp.getWidth()   " comp H: "
                              comp.getHeight()   "ncomp.getLocation(): "   comp.getLocation()
                              " comp.getLocationOnScreen(): "   comp.getLocationOnScreen());
                        System.out.println("con W: "   con.getWidth()   ", con H: "   con.getHeight());

                        if (x_C_To_E_ratio != al.get(0) || y_C_To_E_ratio != al.get(1)) {
                            x_C_To_E_ratio = al.get(0);
                            y_C_To_E_ratio = al.get(1);
                            Thread.sleep(2);
                        }

                        if (((double) con.getWidth() / (double) C_X) > x_C_To_E_ratio   0.025) {
                            Thread.sleep(2);
                            System.out.println((((double) con.getWidth() / (double) C_X))   " ,,, "   x_C_To_E_ratio);
                            while (((double) con.getWidth() / (double) C_X) > x_C_To_E_ratio   0.025) {

                                C_X  = 1;
                                N_C_X = C_X;
                                if (((double) con.getWidth() / (double) C_X) < x_C_To_E_ratio   0.025) {
                                    System.out.println("## in if bigger ## ");
                                    break;
                                }

                                System.out.println("## in if bigger ## C_X: "   C_X   ", N_C_X "   N_C_X);

                                System.out.println("## in if bigger ## (double) con.getWidth() / (double) C_X: "
                                      (double) con.getWidth()   " / "   (double) C_X);
                                System.out.println("## in if bigger ## ((double) con.getWidth() / (double) C_X): "
                                      ((double) con.getWidth() / (double) C_X)   ", x_C_To_E_ratio:"   x_C_To_E_ratio
                                      ", ((double) con.getWidth() / (double) C_X) == x_C_To_E_ratio: "
                                      (((double) con.getWidth() / (double) C_X) == x_C_To_E_ratio));

                                if (((double) con.getWidth() / (double) C_X) == x_C_To_E_ratio
                                || ((double) con.getWidth() / (double) C_X) - x_C_To_E_ratio < 0.002) {
                                    bool = true;
                                    System.out.println("## in if bigger ## GI.bool: "   bool);
                                    System.out.println("## in if bigger ## W: "   comp.getWidth()   " H: "
                                          comp.getHeight()   "ncomp.getLocation(): "   comp.getLocation()
                                          " comp.getLocationOnScreen(): "   comp.getLocationOnScreen()   " Con_WIDTH: "
                                          Con_WIDTH   " Con_HEIGHT: "   Con_HEIGHT   " con.getWidth(): "
                                          con.getWidth()   " con.getHeight(): "   con.getHeight());
                                    System.out.println("## in if bigger ## $GI.bool: "   bool   " $Test.b: "   Test.b);
                                    break;
                                }

                                comp.setBounds(N_C_X, comp.getY(), C_WIDTH, C_HEIGHT);
                            }
                        }

                        else if (((double) con.getWidth() / (double) C_X) < x_C_To_E_ratio - 0.025) {

                            Thread.sleep(2);
                            System.out.println((((double) con.getWidth() / (double) C_X))   " *** "   x_C_To_E_ratio);
                            while (((double) con.getWidth() / (double) C_X) < x_C_To_E_ratio - 0.025) {

                                C_X -= 1;
                                N_C_X = C_X;

                                if (((double) con.getWidth() / (double) C_X) > x_C_To_E_ratio - 0.025) {
                                    break;
                                }

                                System.out.println("C_X: "   C_X   ", N_C_X "   N_C_X);

                                System.out.println("(double) con.getWidth() / (double) C_X): "   (double) con.getWidth()
                                      " / "   (double) C_X);
                                System.out.println("((double) con.getWidth() / (double) C_X): "
                                      ((double) con.getWidth() / (double) C_X)   ", x_C_To_E_ratio:"   x_C_To_E_ratio
                                      ", ((double) con.getWidth() / (double) C_X) == x_C_To_E_ratio: "
                                      (((double) con.getWidth() / (double) C_X) == x_C_To_E_ratio));

                                if (((double) con.getWidth() / (double) C_X) == x_C_To_E_ratio
                                || ((double) con.getWidth() / (double) C_X) - x_C_To_E_ratio > -0.002) {
                                    bool = true;
                                    System.out.println("GA.bool: "   bool);
                                    System.out.println("W: "   comp.getWidth()   " H: "   comp.getHeight()
                                          "ncomp.getLocation(): "   comp.getLocation()
                                          " comp.getLocationOnScreen(): "   comp.getLocationOnScreen()   " Con_WIDTH: "
                                          Con_WIDTH   " Con_HEIGHT: "   Con_HEIGHT   " con.getWidth(): "
                                          con.getWidth()   " con.getHeight(): "   con.getHeight());
                                    System.out.println("$GA.bool: "   bool   " $T.b: "   Test.b);
                                    break;
                                }

                                comp.setBounds(N_C_X, comp.getY(), C_WIDTH, C_HEIGHT);

                            }
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        thread1.start();
    }
}

 

** Теперь компоненты, похоже, не запаздывают при их перемещении, в то время как я ценю, если у вас есть какое-либо лучшее решение.

** Я не хочу использовать метод pack() или какой-либо встроенный менеджер макетов.

** Я уже читал много подобных вопросов, но не нашел своего ответа.

** Я использую eclipse windowbuilder.

Комментарии:

1. Какую версию Java вы используете и с какой операционной системой разрабатываете?

2. @GilbertLeBlanc OpenJDK 14, и я делаю это в Windows 10

3. Вы используете SwingWorker его неправильно. Вы не должны обновлять состояние панели в doInBackground() методе. Если вы хотите обновить графический интерфейс, вам нужно «опубликовать» результаты. Прочитайте учебник Swing по задачам с промежуточными результатами для рабочего примера. Если все, что вы пытаетесь сделать, это предоставить анимацию, то используйте таймер качания, чтобы запланировать анимацию. В учебнике также есть раздел, посвященный анимации. Использование вами статических переменных и методов указывает на неправильный дизайн.

4. Имена классов не должны содержать «_» в именах. Изучите на примере и следуйте соглашениям об именах, используемым в Java API.

5. @camickr Я сделал то, что ты сказал, но проблему не исправил, но я увидел кое-что новое. когда появляется эта черная линия, если вы получаете измерение с помощью panel.getBounds() или frame.getBounds() в прослушивателе действий кнопки, вы понимаете, что разницы нет, поэтому я предполагаю, что проблема не в методе panel.updateUI (). поэтому я предполагаю следующее: поскольку размер панелей и рамок может быть только целым числом, это небольшое изменение, внесенное в размер, не считается одним пикселем для java. поэтому он не будет обновлять панель до тех пор, пока размер не станет для нее чем-то значимым.

Ответ №1:

Я не задумывался об этом с тех пор, как вы сказали в своем вопросе,

Я не хочу использовать метод pack() или какой-либо встроенный менеджер макетов.

Этот комментарий сразу же дисквалифицировал ваш вопрос в моем сознании. Я никак не мог ответить на этот вопрос с таким ограничением.

Вот самый простой пример графического интерфейса для тестирования Swing FPS, который я мог придумать.

Пример теста FPS

Я использую этот pack метод. Я использую менеджеры макетов Swing. Если это проблема, продолжайте бороться самостоятельно.

Как я уже сказал в своем комментарии, у Oracle есть учебник по созданию графического интерфейса с помощью JFC/Swing, в котором вы пройдете через этапы создания графического интерфейса Swing. Пропустите раздел Netbeans.

Первое, что я сделал, это вызвал SwingUtilities invokeLater метод для запуска приложения Swing. Этот метод гарантирует, что компоненты Swing создаются и выполняются в потоке отправки событий.

Следующее, что я сделал, это сконструировал а JFrame . JFrame Методы должны вызываться в определенном порядке. Это порядок, который я использую для большинства моих приложений Swing.

Я соорудил пуговицу JPanel и рисунок JPanel . Кнопка JPanel удерживает старт JButton . Рисунок JPanel рисует кадры со скоростью в секунду.

Я использовал качели Timer , чтобы зафиксировать текущее время и количество кадров. Вы можете настроить скорость Timer , изменив int значение в Timer конструкторе. Я не рекомендую значение ниже 5.

Вот полный исполняемый код.

 import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.FontMetrics;
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.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class FPSTestExample implements Runnable {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new FPSTestExample());
    }
    
    private long startTime, endTime, countInterval;
    
    private final DrawingPanel drawingPanel;
    
    public FPSTestExample() {
        this.drawingPanel = new DrawingPanel();
    }

    @Override
    public void run() {
        JFrame frame = new JFrame("FPS Test Example");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        frame.add(drawingPanel, BorderLayout.CENTER);
        frame.add(createButtonPanel(), BorderLayout.AFTER_LAST_LINE);
        
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }
    
    private JPanel createButtonPanel() {
        JPanel panel = new JPanel(new FlowLayout());
        panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        
        JButton button = new JButton("Start");
        panel.add(button);
        
        button.addActionListener(new ActionListener() {
            private Timer timer;
            
            @Override
            public void actionPerformed(ActionEvent event) {
                if (timer == null) {
                    FPSTestExample.this.startTime = System.currentTimeMillis();
                    timer = new Timer(15, new FPSListener());
                    timer.start();
                } 
            }
        });
        
        return panel;
    }
    
    public class DrawingPanel extends JPanel {

        private static final long serialVersionUID = 1L;
        
        public DrawingPanel() {
            this.setPreferredSize(new Dimension(300, 200));
        }
        
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            
            if (FPSTestExample.this.endTime > 0L) {
                long elapsedTime = FPSTestExample.this.endTime - 
                        FPSTestExample.this.startTime;
                int fps = (int) (FPSTestExample.this.countInterval * 1000L / 
                        elapsedTime);
                String fpsString = "FPS: "   fps;
                
                Graphics2D g2d = (Graphics2D) g;
                g2d.setColor(Color.BLUE);
                g2d.setFont(getFont().deriveFont(48f));
                FontMetrics fm = g2d.getFontMetrics();
                Rectangle2D r2d = fm.getStringBounds(fpsString, g2d);
                
                int width = (int) Math.round(r2d.getWidth());
                int height = (int) Math.round(r2d.getHeight());
                int x = (getWidth() - width) / 2;
                int y = (getHeight() - height   fm.getAscent()) / 2;
                
                g2d.drawString(fpsString, x, y);
            }
        }
        
    }
    
    public class FPSListener implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent event) {
            FPSTestExample.this.endTime = System.currentTimeMillis();
            FPSTestExample.this.countInterval  ;
            FPSTestExample.this.drawingPanel.repaint();
        }
        
    }

}
 

Комментарии:

1. Как вы сказали, «У Swing в Windows есть проблема, когда масштабирование монитора Windows>100%», вы имеете в виду, что я должен игнорировать эту проблему и придерживаться принципов приложений swing, потому что это невозможно исправить, потому что даже в этом примере, который вы написали, Есть эта проблема со всем LayoutManager, Который вы использовали, и т. Д. это моя банка , если вы не смогли открыть, то в ней находятся коды(3 файла java). в масштабе 100% он работает нормально, но рекомендуемый масштаб некоторых компьютеров составляет 125%, и он должен работать на них, но это не так. ЭТО моя проблема.

2. мой файл jar содержит некоторую дополнительную информацию, которая мне была нужна, конечно, они вам не понадобятся, поэтому удалите их, также внесено много изменений из-за того, что «В вашем коде слишком много статических полей и методов, что является недостатком».

3. @хамид: Я не могу научить вас, как разрабатывать сложное программное обеспечение Java в ответе на переполнение стека. Все, что я могу сделать и сделал, — это привести пример свинга.

4. В любом случае, спасибо за все. Знаете ли вы какие-либо ресурсы, ссылки или учебные пособия, с помощью которых я могу решить эту конкретную проблему? Я не смог найти ничего полезного в этом случае в Oracle.