Правильный способ использования JLabels для обновления изображения

Я создаю графический интерфейс и новичок в качании и awt. Я пытаюсь создать графический интерфейс, который при запуске устанавливает фон для изображения, а затем использует метод для создания своего рода слайд-шоу. Я пытался это сделать, и я не привязан к коду, поэтому я могу вносить как изменения, так и/или совершенно новые концепции.

РЕДАКТИРОВАТЬ (15.09.13): У меня проблемы со слайд-шоу, я не могу заставить его работать.

Вот мой текущий код.

public class MainFrame extends JFrame{

JLabel backgroundL = null;
private JLabel bakckgroundL;
BufferedImage backimg;
Boolean busy;
double width;
double height;

public MainFrame() throws IOException {
    initMainframe();
}



public void initMainframe() throws IOException { 

//misc setup code, loads a default jpg as background

    setTitle("Pemin's Aura");
    busy = true;
    String backgroundDir = "resources/frame/background.jpg";

    backimg = ImageIO.read(new File(backgroundDir));
    backgroundL = new JLabel(new ImageIcon(backimg));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    refreshframe();
    setVisible(true);
    busy = false;
}
public void adjSize() { // the attempted start of a fullscreen mode
        GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().setFullScreenWindow(this);
    width = this.getWidth();
    height = this.getHeight();
    setVisible(true);
}

public void setmastheadText() {//unfinished code
busy = true;

busy = false;
}
public void setbackground() {
    add(backgroundL);
}
public void refreshframe() { //should refresh image?
    setSize(2049, 2049);
    setSize(2048, 2048);
}
public void loadingscreen() throws IOException, InterruptedException {

 //this is the code in question that is faulty.

    if (busy == false) {
    busy = true;

    String backgroundDir1 = "resources/frame/background.jpg";
    String backgroundDir2 = "resources/frame/scr1.jpg";
    String backgroundDir3 = "resources/frame/scr2.jpg";

    BufferedImage backimg1 = ImageIO.read(new File(backgroundDir1));
    BufferedImage backimg2 = ImageIO.read(new File(backgroundDir2));
    BufferedImage backimg3 = ImageIO.read(new File(backgroundDir3));

    backgroundL = new JLabel(new ImageIcon(backimg1));
    Thread.sleep(2000);
    setbackground();
    setVisible(true);
    backgroundL = new JLabel(new ImageIcon(backimg2));
    setbackground();
    setVisible(true);
    Thread.sleep(2000);
    bakckgroundL = new JLabel(new ImageIcon(backimg3));
    setbackground();
    setVisible(true);

    if(backimg != null) {
         backgroundL = new JLabel(new ImageIcon(backimg));;
        }
    }
    busy = false;
}//end of loading screen

person Aaron    schedule 16.09.2013    source источник
comment
где у тебя проблема? Или вы хотите код-ревью?   -  person nachokk    schedule 16.09.2013
comment
Я проясню это в своем вопросе, спасибо, что предупредили меня. Я хотел бы просмотреть код, но моя проблема в том, что я не могу заставить работать слайд-шоу.   -  person Aaron    schedule 16.09.2013
comment
Следуйте стандартным соглашениям об именах Java. Слова в именах методов должны быть написаны с заглавной буквы после первого слова. (т.е. все, что вам нужно сделать, это изучить имена методов, найденные в JDK). Метод refreshFrame() — ужасный кусок кода. Нет причин вызывать один и тот же метод дважды с двумя разными значениями. На самом деле обычный способ создать фрейм — это использовать метод pack() и позволить каждому компоненту отображаться в своем собственном размере.   -  person camickr    schedule 16.09.2013
comment
Лучший способ стать лучше — это получить правдивый и прямолинейный совет. @camickr, спасибо за это. Я понимаю, что pack() является наиболее распространенным способом, и я знаком с тем, что он делает. Однако, если я хочу иметь пустое пространство, ничего, кроме фона, я бы не использовал pack(). Когда я пробовал это раньше, это было бесполезно, так как рама стала самой маленькой, какой только могла быть, даже несмотря на то, что был JLable, поэтому, если вы хотите помочь мне с этим, сделайте это, пожалуйста, это было бы большим подспорьем.   -  person Aaron    schedule 16.09.2013
comment
the frame became the smallest it could possibly be even though there was a JLable – Вы прочитали JLabel API и перешли по ссылке на руководство по Swing на How to Use Labels? В нем есть рабочий пример того, как лучше структурировать вашу программу, и он показывает метки с изображениями, а код использует pack(), а фрейм имеет правильный размер. Я не могу предположить, что вы можете делать неправильно. Вот почему вы должны начать с рабочего примера и изменить его.   -  person camickr    schedule 16.09.2013
comment
хорошо, теперь я понимаю, что мой код все еще незрелый и действительно должен быть довольно болезненным для глаз более опытных программистов, поэтому с этого момента я буду работать с существующими примерами. Спасибо   -  person Aaron    schedule 16.09.2013


Ответы (2)


См. ImageViewer рабочий пример отображения изображений с использованием Timer.

См. также Как использовать таймеры Swing.


И пока я здесь, еще один (более красивый) пример анимации изображения. Он использует эту карту Меркатора земельных массивов. Изображение может быть разбито по горизонтали, и поэтому его можно прокручивать влево/вправо по мере необходимости.

Карта меркаторских массивов суши

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import javax.swing.*;

import java.net.URL;
import javax.imageio.ImageIO;

public class WorldView {

    public static void main(String[] args) throws Exception {
        URL url = new URL("http://i.stack.imgur.com/P59NF.png");
        final BufferedImage bi = ImageIO.read(url);
        Runnable r = new Runnable() {

            @Override
            public void run() {
                int width = 640;
                int height = 316;
                Graphics2D g = bi.createGraphics();

                float[] floats = new float[]{0f, .4f, .55f, 1f};
                Color[] colors = new Color[]{
                    new Color(20, 20, 20, 0),
                    new Color(0, 10, 20, 41),
                    new Color(0, 10, 20, 207),
                    new Color(0, 10, 20, 230),};
                final LinearGradientPaint gp2 = new LinearGradientPaint(
                        new Point2D.Double(320f, 0f),
                        new Point2D.Double(0f, 0f),
                        floats,
                        colors,
                        MultipleGradientPaint.CycleMethod.REFLECT);

                final BufferedImage canvas = new BufferedImage(
                        bi.getWidth(), bi.getHeight() + 60,
                        BufferedImage.TYPE_INT_RGB);

                final JLabel animationLabel = new JLabel(new ImageIcon(canvas));
                ActionListener animator = new ActionListener() {

                    int x = 0;
                    int y = 30;

                    @Override
                    public void actionPerformed(ActionEvent e) {
                        Graphics2D g = canvas.createGraphics();
                        g.setColor(new Color(55, 75, 125));

                        g.fillRect(0, 0, canvas.getWidth(), canvas.getHeight());

                        int offset = (x % bi.getWidth());
                        g.drawImage(bi, offset, y, null);
                        g.drawImage(bi, offset - bi.getWidth(), y, null);

                        g.setPaint(gp2);
                        g.fillRect(0, 0, canvas.getWidth(), canvas.getHeight());

                        g.dispose();

                        animationLabel.repaint();

                        x++;
                    }
                };
                Timer timer = new Timer(40, animator);
                timer.start();
                JOptionPane.showMessageDialog(null, animationLabel);
                timer.stop();
            }
        };
        // Swing GUIs should be created and updated on the EDT
        // http://docs.oracle.com/javase/tutorial/uiswing/concurrency
        SwingUtilities.invokeLater(r);
    }
}

Вот версия этого изображения с добавленным экватором (это 44 пикселя к югу от центра изображения).

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

person Andrew Thompson    schedule 16.09.2013
comment
Пожалуйста. Я добавил еще один (симпатичный, но более сложный) пример. ... В основном потому, что я создаю набор изображений, на которые код примера может ссылаться (точно так же, как код выше), и это изображение станет одним из них. ;) - person Andrew Thompson; 16.09.2013

Вы звоните Thread.sleep(...) и, вероятно, в потоке событий EDT или Swing (полное имя – поток Event Dispatch T). Этот поток отвечает за все рисование/рисование Swing и взаимодействие с пользователем, поэтому его спящий режим будет служить только для замораживания всего вашего графического интерфейса. Вместо этого вы должны использовать Swing Timer, чтобы позволить вам поменять местами ImageIcon JLabel.

Итак, кратко:

  • Не вызывайте Thread.sleep(...) в потоке событий Swing (поток отправки событий или EDT).
  • Используйте Swing Timer для повторяющихся отложенных действий.
  • Не создавайте и не добавляйте много JLabels. Просто сделайте и добавьте один.
  • Поменяйте местами ImageIcon, который отображает JLabel, вызвав setIcon(...) на метке.
  • Лучше (чище) писать if (busy == false) { как if (!busy) {

e.g.,

ImageIcon[] icons = {...}; // filled up with your ImageIcons

if (!busy) {
  int timerDelay = 2000;
  new Timer(timerDelay, new ActionListener() {
    private int i = 0;
    public void actionPerfomed(ActionEvent e) {
      myLabel.setIcon(icons(i));
      i++;
      if (i == icons.length) {
        ((Timer)e.getSource).stop();
      } 
    };
  }).start();
}
person Hovercraft Full Of Eels    schedule 16.09.2013
comment
Поскольку я не знаком с большей частью того, что вы написали, могу я спросить, что делает метод .start()? Кроме того, какая цель у ActionListener и actionPerformed соответственно в этом коде? пс: спасибо за советы - person Aaron; 16.09.2013
comment
Ознакомьтесь с руководством по Swing Как использовать таймеры, чтобы узнать об основах. . В учебнике также есть раздел Concurrency, о котором вам следует прочитать (он больше объясняет EDT). И вы должны загружать примеры из учебника, чтобы улучшить структуру вашей программы (т.е. код GUI должен выполняться в EDT). Вы не должны расширять JFrame. - person camickr; 16.09.2013
comment
@Hovercraft Full Of Eels Когда я пытаюсь написать ваш код, я вижу ошибку new Swing(timerDelay, что Swing «не может быть преобразован в тип». Вы знаете, что с этим делать? - person Aaron; 16.09.2013
comment
@ Аарон, он может захотеть сказать new javax.swing.Timer(..) или, если вы импортируете его, просто new Timer(..) - person nachokk; 16.09.2013
comment
@Aaron: не копируйте мой код (во-первых, я его не тестировал, а просто набирал на лету), а используйте его идеи. И да, вы должны импортировать любые классы, кроме самых основных, которые вы используете. - person Hovercraft Full Of Eels; 16.09.2013
comment
Я импортировал то, что было предложено мне моей IDE (да, у меня есть эта концепция). - person Aaron; 16.09.2013