LINUX.ORG.RU

Java GUI

 


1

2

Вот программа (просто для примера):

import javax.swing.*;
import java.awt.event.*;

public class test {
	public static void main(String args[]){
		MainFrame m = new MainFrame();
		m.setVisible(true);
	}
}

class MainFrame extends JFrame implements WindowListener, ActionListener{
	private JLabel leabl1 = new JLabel("TEST", JLabel.CENTER);
	private JButton enter = new JButton("START");
	
	public MainFrame(){
		this.setSize(300,200);
		this.addWindowListener(this);
		JPanel p = new JPanel();
		this.setContentPane(p);
		p.setLayout(null);
		leabl1.setBounds(0,20,300,20);
		enter.setBounds(100,60,100,20);
		p.add(leabl1);
		p.add(enter);
		enter.addActionListener(this);
		
	}
	
	public void windowClosing(WindowEvent e){System.exit(0);}
	public void windowOpened(WindowEvent e){}
	public void windowClosed(WindowEvent e){}
	public void windowIconified(WindowEvent e){}
	public void windowDeiconified(WindowEvent e){}
	public void windowActivated(WindowEvent e){}
	public void windowDeactivated(WindowEvent e){}
	public void actionPerformed(ActionEvent e){
		try {
			leabl1.setText("TEST 1");
			Thread.currentThread().sleep(5000);
			leabl1.setText("TEST 2");
			Thread.currentThread().sleep(5000);
			leabl1.setText("TEST 3");
			Thread.currentThread().sleep(5000);
			leabl1.setText("TEST 4");
		} catch (InterruptedException e2) {
			e2.printStackTrace();
		}
	}
}

Вот эта часть:

			leabl1.setText("TEST 1");
			Thread.currentThread().sleep(5000);
			leabl1.setText("TEST 2");
			Thread.currentThread().sleep(5000);
			leabl1.setText("TEST 3");
			Thread.currentThread().sleep(5000);
			leabl1.setText("TEST 4");
Не работает. 15 секунд тикает, а надпись не меняется. Меняется только в самом конце. Почему так происходит и как исправить?

★★★★★

Не работает.

Используй SWING Timer.

Или посмотри, как устроен поток обработки событий SWING и как безопасно изменять состояние компонентов GUI.

oami ★★
()
Ответ на: комментарий от oami

Вот такой вариант:

import javax.swing.*;
import java.awt.event.*;

public class test {
	public static void main(String args[]){
		MainFrame m = new MainFrame();
		m.setVisible(true);
		try {
			m.leabl1.setText("TEST 1");
			Thread.currentThread().sleep(5000);
			m.leabl1.setText("TEST 2");
			Thread.currentThread().sleep(5000);
			m.leabl1.setText("TEST 3");
			Thread.currentThread().sleep(5000);
			m.leabl1.setText("TEST 4");
		} catch (InterruptedException e2) {
			e2.printStackTrace();
		}
	}
}

class MainFrame extends JFrame implements WindowListener{
	public JLabel leabl1 = new JLabel("TEST", JLabel.CENTER);
	
	public MainFrame(){
		this.setSize(300,200);
		this.addWindowListener(this);
		JPanel p = new JPanel();
		this.setContentPane(p);
		p.setLayout(null);
		leabl1.setBounds(0,20,300,20);
		p.add(leabl1);
	}
	
	public void windowClosing(WindowEvent e){System.exit(0);}
	public void windowOpened(WindowEvent e){}
	public void windowClosed(WindowEvent e){}
	public void windowIconified(WindowEvent e){}
	public void windowDeiconified(WindowEvent e){}
	public void windowActivated(WindowEvent e){}
	public void windowDeactivated(WindowEvent e){}
}
Работает без лишних телодвижений. В чем же принципиальная разница?

TDrive ★★★★★
() автор топика

Так делать не нужно - ты находишься в том треде в котором работает Swing, потому когда работает sleep у тебя интерфейс не перерисоввывается.

Там есть какой-то метод которым можно явно дернуть перерисовку (.validate() что-ли), но в целом нужно задачи выполнять в отдельном треде и модификации делать через SwingUtilities.invoke

maxcom ★★★★★
()
Ответ на: комментарий от maxcom

Слип это для примера, в реальности там у меня обращение к серверу, авторизация, получение данных... и необходимо выводить информацию о том как всё это продвигается.
Не буду же я на каждую кнопку свой Thread создавать. Или нужно создавать?

TDrive ★★★★★
() автор топика
Ответ на: комментарий от TDrive

Ну вообще по уму - создавать. NetBeans в свое время (сейчас не знаю) по созданию события на кнопку сразу в отдельную нить его пихал.

morse ★★★★★
()
Ответ на: комментарий от maxcom

validate() не помог, ещё repaint() пробовал, тоже без результатов.

TDrive ★★★★★
() автор топика
Ответ на: комментарий от TDrive

Заведи отдельный тред и закидывай в него задания на выполнение через очередь. Например можно использовать Executors.newSingleThreadExecutor()

maxcom ★★★★★
()

SwingUtilities.invokeLater. Да, курите потоки и swing.

Insomnium ★★★★
()

Да, по поводу

public void windowClosing(WindowEvent e){System.exit(0);}
	public void windowOpened(WindowEvent e){}
	public void windowClosed(WindowEvent e){}
	public void windowIconified(WindowEvent e){}
	public void windowDeiconified(WindowEvent e){}
	public void windowActivated(WindowEvent e){}
	public void windowDeactivated(WindowEvent e){}
	public void actionPerformed(ActionEvent e){
		try {
			leabl1.setText("TEST 1");
			Thread.currentThread().sleep(5000);
			leabl1.setText("TEST 2");
			Thread.currentThread().sleep(5000);
			leabl1.setText("TEST 3");
			Thread.currentThread().sleep(5000);
			leabl1.setText("TEST 4");
		} catch (InterruptedException e2) {
			e2.printStackTrace();
		}
	}

Откройте для себя классы-адаптеры, чтобы код не засорять. В данном случае WindowAdapter, например.

Insomnium ★★★★
()
Ответ на: комментарий от Insomnium

Знаю про адаптеры. С ними 100500 классов получается, а так несколько интерфейсов объявил для одного класса и всё.

TDrive ★★★★★
() автор топика
Ответ на: комментарий от maxcom

Спасибо, буду разбираться.

TDrive ★★★★★
() автор топика
Ответ на: комментарий от Insomnium

Ещё рекомендовал бы пользоваться аннотацией @Override

BattleCoder ★★★★★
()
Ответ на: комментарий от TDrive

Используй подкласс (анонимный или нет сам смотри), незачем твоему классу MainFrame реализоввывать Listener'ы

maxcom ★★★★★
()

Выше все правильно рассказали: у Swing есть один-единственный поток, в котором обрабатываются события и рисуется изображение.

Когда этот поток засыпает, то Swing больше не может ничего: ни поменять надпись, ни даже закрыть окно — можешь жмакнуть по крестику, и все равно придется дожидаться, пока метод-капуша доработает до конца.

Можно распечатать, какой тред собирает графическую малину, а какой впадает в спячку. В первом случае это будет один и тот же объект, во втором работающем примере - разные.

Так что проще всего в обработчик засунуть команду new Thread(...).start() — в общем-то, в этом и есть единственный смысл всех дальнейших ухищрений. Если по какой-либо причине понадобятся изменения — всегда можно шагнуть в сторону SwingWorker'ов или же ThreadPool'ов, по обстоятельствам.

Вот твоя прога: сперва все переименовывается, как во втором примере, а потом становятся доступны две кнопки. У одной обработчик правильный, у другой — не совсем.

import javax.swing.*;
import java.awt.event.*;
import java.util.*;


class MainFrame extends JFrame {
    private JLabel label1 = new JLabel("TEST", JLabel.CENTER);
    private JButton launchInSwingThread = new JButton("Same thread rename");
    private JButton launchInOtherThread = new JButton("Other thread rename");


    public static void main(String args[]) {
        printCurrentThread("Main");
        MainFrame m = new MainFrame();

        m.renameLabelFewTimes();
    }

    public MainFrame(){
        JPanel p = new JPanel();
        setContentPane(p);
        p.setLayout(null);
        
        
        label1.setBounds(0, 20, 300, 20);
        launchInSwingThread.setBounds(50, 60, 200, 20);
        launchInOtherThread.setBounds(50, 90, 200, 20);
        
        p.add(label1);
        p.add(launchInSwingThread);
        p.add(launchInOtherThread);

        addActionListeners();
        

        setSize(300,200);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setVisible(true);
    }

    private void addActionListeners() {
        launchInSwingThread.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                renameLabelFewTimes();
            }
        });

        launchInOtherThread.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        renameLabelFewTimes();
                    }
                }).start();
            }
        });
    }

    private void renameLabelFewTimes() {
        printCurrentThread("Renaming");
        List<String> messages = Arrays.asList(
                "TEST 1", "TEST 2", "TEST 3", "TEST 4");

        setEnabledButtons(false);

        for (final String s: messages) {
            renameLabelAndSleep(s);
        }

        setEnabledButtons(true);
    }

    private void renameLabelAndSleep(String name) {
        System.out.println("New name: " + name);
        label1.setText(name);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e2) {
            e2.printStackTrace();
        }
    }

    private void setEnabledButtons(boolean isEnabled) {
        launchInOtherThread.setEnabled(isEnabled);
        launchInSwingThread.setEnabled(isEnabled);
    }

    private static void printCurrentThread(String prefix) {
        System.out.println(
                prefix + " thread"+ " is " + Thread.currentThread());
    }
}
anonymous
()
Ответ на: комментарий от Insomnium

Класс уже отнаследован от JFrame, так что второй предок в виде класса-адаптера не подойдет. Но здесь даже интерфейсы, в общем-то, не нужны.

anonymous
()
Ответ на: комментарий от TDrive

Лучше сразу ставить Intellij Idea, Netbeans или Eclipse (в порядке убывания удобства). Разница с gedit+консоль разительная, один дебаг сэкономит такую тучу времени, что его можно будет грузить вагонами и пускать на другие полезные пути.

anonymous
()
Ответ на: комментарий от anonymous

Разница с gedit+консоль разительная

Я пользовался Netbeans и Eclipse знаю их плюсы. Просто, многие вещи стали понятны только когда перестал ими пользоваться.
У меня программы ограничиваются 1000-2000 строчек, будет что то серьёзное пересяду на IDE.

TDrive ★★★★★
() автор топика
Ответ на: комментарий от Insomnium

Я пока учусь, выбираю как мне удобнее, что бы самому не запутаться. Без расчёта на то, что это будут читать. В книгах по Java вообще какого то единого стиля нету, я бы даже сказал, что в каждой книге свой вариант написания практически идентичных программ.

TDrive ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.