Как обновить jframe java
Перейти к содержимому

Как обновить jframe java

  • автор:

[java] Обновление jPanel

Допустим я в NetBeans посадил на форму панельку jPanel и нарисовал на ней с помощью java.awt.Graphics некоторые штуковины, например так:

Graphics g = jPanel1.getGraphics(); g.setColor(Color.white); g.fillRect(0, 0, 100, 100); 

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

tr0ll ★
21.04.11 15:59:09 MSK

P.S.: отнаследуйся от JPanel и в методе paintComponent рисуй всё, что захочешь.

anonymous
( 21.04.11 16:22:34 MSK )

1) Картинку нужно рисовать на невидимом объекте java.awt.Image offscreen;
2) В методе прорисовки paint(Graphics g) визуального компонента быстро перенести содержимое невидимого компонента на канву.

Методы рисования и прорисовки должны быть синхронными, чтобы избежать порчи изображения, если метод рисования вызывает другая нить.

iZEN ★★★★★
( 21.04.11 17:46:14 MSK )
Ответ на: комментарий от iZEN 21.04.11 17:46:14 MSK

Это будет двойная буферизация на коленке. У Java2D лучше получится

vertexua ★★★★★
( 21.04.11 19:34:00 MSK )
Ответ на: комментарий от vertexua 21.04.11 19:34:00 MSK

Это не двойная буферизация, а использование бэк-буфера для рукопашной.

И как же она тут поможет?

Java/Первое окно

Так как в большинстве своем сегодняшние начинающие программисты не любят окно командной строки — приведу пример оконного приложения.

Начнем с простого [ править ]

import javax.swing.JFrame; public class MyWindowApp extends JFrame  //Наследуя от JFrame мы получаем всю функциональность окна public MyWindowApp() super("My First Window"); //Заголовок окна setBounds(100, 100, 200, 200); //Если не выставить //размер и положение //то окно будет мелкое и незаметное setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //это нужно для того чтобы при //закрытии окна закрывалась и программа, //иначе она останется висеть в процессах > public static void main(String[] args)  //эта функция может быть и в другом классе MyWindowApp app = new MyWindowApp(); //Создаем экземпляр нашего приложения app.setVisible(true); //С этого момента приложение запущено! > > 

Вот у нас и получилось ничего не делающее приложение!

Делаем что-то полезное [ править ]

Это конечно замечательно уметь показывать пустое окно, но мы хотим, чтобы оно приносило пользу! Создадим форму для подсчета ворон на заборе. Для этого будем отображать текущее количество ворон и с помощью двух кнопок добавлять или вычитать по одной.

Дизайн [ править ]

Это то, что мы примерно хотим увидеть:

Вороносчет
Ворон на заборе : 666
Ворона прилетела Ворона улетела

Скелет программы [ править ]

import java.awt.*; import java.awt.event.*; import javax.swing.*; public class VoronCalc extends JFrame  private int voron = 0; private JLabel countLabel; private JButton addCrow; private JButton removeCrow; public VoronCalc() super("Crow calculator"); //Подготавливаем компоненты объекта countLabel = new JLabel("Crows:" + voron); addCrow = new JButton("Add Crow"); removeCrow = new JButton("Remove Crow"); //Подготавливаем временные компоненты JPanel buttonsPanel = new JPanel(new FlowLayout()); //Расставляем компоненты по местам buttonsPanel.add(countLabel, BorderLayout.NORTH); //О размещении компонент поговорим позже buttonsPanel.add(addCrow); buttonsPanel.add(removeCrow); add(buttonsPanel, BorderLayout.SOUTH); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); > public static void main(String[] args)  VoronCalc app = new VoronCalc(); app.setVisible(true); app.pack(); //Эта команда подбирает оптимальный размер в зависимости от содержимого окна > > 

После компиляции и запуска — получится что-то такое:

Добавляем функциональность [ править ]

Пришло время добавить немного интерактивности. Нам нужно сделать 3 вещи:

  1. Научить кнопку addCrow добавлять 1 к переменной voron.
  2. Научить кнопку removeCrow вычитать 1 из переменной voron.
  3. Научить countLabel — обновлять свое значение в зависимости от содержимого переменной voron.
addCrow [ править ]

Добавляем listener для кнопки addCrow.

addCrow.addActionListener(new ActionListener() public void actionPerformed(ActionEvent e)  voron = voron+1; //Добавляем одну ворону countLabel.setText("Crows:" + voron); //Сообщаем приложению, что количество ворон изменилось > >); 
removeCrow [ править ]

Добавляем listener для кнопки removeCrow.

removeCrow.addActionListener(new ActionListener() public void actionPerformed(ActionEvent e)  if( voron > 0 )  voron = voron - 1; countLabel.setText("Crows:" + voron); //Сообщаем приложению, что количество ворон изменилось > > >); 
updateCrowCounter [ править ]
private void updateCrowCounter()  countLabel.setText("Crows:" + voron); > 

Конечный результат [ править ]

  • VoronCalc.java — главный класс программы

Как обновить jframe java

Регистрация: 02.10.2019

Сообщений: 2

Обновление JLabel при нажатии JButton

Укажите на ошибку, при нажатии на кнопку необходимо в окне обновить текст. Проверяю выводом в консоль, данные меняются, но в окне изменений не происходит.Как исправить данную ситуацию?
Использую класс JFrameTest:

public class JFrameTest < String [] arrayQuestion=< "11","22","33" >; int i=0; String a = arrayQuestion[i]; public class TestListener implements ActionListener < @Override public void actionPerformed(ActionEvent e) < >> public void createGUI() < JFrame frame = new JFrame("Test frame");//Создаем окно приложения frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//указываем действие при нажатии на Крест frame.setSize(1000,700);//задаю размер окна frame.setLocationRelativeTo(null);//центрирую окно frame.setResizable(false);//запрет на изменение размера окна frame.setVisible(true);//Видимость окна JPanel questionPanel = new JPanel(); frame.getContentPane().add(questionPanel); questionPanel.setBackground(Color.CYAN); questionPanel.setLayout(null);//для выставления ручного позицианирования элементов questionPanel.setVisible(true); JButton btnOne = new JButton("Первый вопрос"); JButton btnTwo = new JButton("Второй вопрос"); JButton btnThree = new JButton("Третий вопрос"); JButton btnFour = new JButton("Не знаю"); btnOne.setActionCommand("one"); btnOne.setBounds(560,220,400,50); questionPanel.add(btnOne); JLabel questionLabel = new JLabel(a); questionLabel.setBounds(10,10,950,180); //questionLabel.setOpaque(true);//для включения цвета фона questionLabel.setBackground(Color.green);//цвет фона заметки (использовал для настройки разположения) questionLabel.setVerticalAlignment(SwingConstants.BOTTOM);//расположение по вертикали текста в заметке questionLabel.setHorizontalAlignment(SwingConstants.LEFT);//расположение по горизонтали текста в заметке Font font = new Font("Courier New", Font.PLAIN, 16);//создаем обьект, что бы передать его в заметку questionLabel.setFont(font); questionPanel.add(questionLabel); ActionListener actionListener = new TestListener(); btnOne.addActionListener(new ActionListener() < @Override public void actionPerformed(ActionEvent e) < if(e.getActionCommand() == "one")< i++; questionLabel.setText(a); System.out.println(arrayQuestion[i]); System.out.println(e.getActionCommand()); >; > >); > public void main() < //обозначает специальное оформление JFrame.setDefaultLookAndFeelDecorated(false); SwingUtilities.invokeLater(new Runnable() < public void run() < createGUI(); >>); > >

И класс Main:

public class Main < public static void main(String[] args)< JFrameTest j = new JFrameTest(); j.createGUI(); >>

swing и обновление панели

подскажите, пожалуйста. стоит такая задача: при некотором событии панель должна обновляться и на ней появляются новые компоненты.Сначала она вообще пустая.
Изначально у меня была панель PanelBuilder builder, лежащая на JPanel content.
при обновлении принцип действия был такой:
1. builder.getPanel.removeAll;
2. добавление новых компонентов
3. builder.getPanel.validate;
builder.getPanel.repaint;
content.validate;
и все было хорошо. Но понадобилось положить builder.getPanel на JScrollPane, в результате теперь я просто не вижу никаких обновлений. Панель с компонентами как была пуста, такой и остается.
Какие есть методы борьбы с такой штуковиной? Почему скролл так плохо влияет на панель?
Хотя при обновлении панели я пыталась обновлять и сам скролл.
Люди, знающие swing, помогите пожалуйста.

И что такое PanelBuilder? Это ваш класс или какой-то сторонний? В спецификации J2SE (5-й и 6-й) такого класса нет ни в одном пакете. Стоило бы указать, что за библиотека используется (да и сказать, что в ней есть такого, что долго и неудобно делать стандартными средствами).
Далее, принцип обновления какой-то странный. Должно быть достаточно

public void revalidate
Supports deferred automatic layout.
Calls invalidate and then adds this component’s validateRoot to a list of components that need to be validated. Validation will occur after all currently pending events have been dispatched. In other words after this method is called, the first validateRoot (if any) found when walking up the containment hierarchy of this component will be validated. By default, JRootPane, JScrollPane, and JTextField return true from isValidateRoot.
This method will automatically be called on this component when a property value changes such that size, location, or internal layout of this component has been affected. This automatic updating differs from the AWT because programs generally no longer need to invoke validate to get the contents of the GUI to update.

Выделение мое. Т.е. 3-й пункт вообще лишний. У меня все работает и в варианте с JScrollPane и с обычной панелью (все компоненты нормально отрисовываются и обновляются). Пример (естественно без PanelBuilder, так как не известно, что это такое):

 
package test;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;

public class GuiTest private static final boolean USE_SP = true;

int count;
JPanel content;
JScrollPane jsp;
JPanel builder;
JButton goButton;

void invokeAndShowGui JFrame mainFrame = new JFrame("MainFrame");
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.setLayout(new BorderLayout;


builder = new JPanel;
builder.setLayout(null);

if (USE_SP) jsp = new JScrollPane;
mainFrame.add(jsp, BorderLayout.CENTER);
jsp.setViewportView(builder);
> else content = new JPanel(new BorderLayout;
mainFrame.add(content, BorderLayout.CENTER);
content.add(builder, BorderLayout.CENTER);
>


goButton = new JButton("Add");
mainFrame.add(goButton, BorderLayout.PAGE_END);
goButton.addActionListener(new ActionListener public void actionPerformed(ActionEvent e) builder.removeAll;
count++;
builder.setMinimumSize(new Dimension(30 * count, 30 * count;
builder.setSize(new Dimension(30 * count, 30 * count;
for (int i = 0; i < count; i++) JButton tmp = new JButton(Integer.toString(i;
tmp.setBounds(i * 30, i * 30, 30, 30);
builder.add(tmp);
>
builder.setPreferredSize(new Dimension(30 * count, 30 * count;
builder.setMinimumSize(new Dimension(30 * count, 30 * count;
// builder.validate;
//builder.repaint;

// if (USE_SP)
// jsp.validate;
// else
// content.validate;
>
>);

mainFrame.pack;
mainFrame.setSize(new Dimension(640, 480;
mainFrame.setVisible(true);
>

public static void main(String [] args) final GuiTest gui = new GuiTest;
SwingUtilities.invokeLater(new Runnable public void run gui.invokeAndShowGui;
>
>);
>
>

Так что стоило бы Вам привести еще и минимальный пример, демонстрирующий проблему.

Какие есть методы борьбы с такой штуковиной? Почему скролл так плохо влияет на панель?
Хотя при обновлении панели я пыталась обновлять и сам скролл.

Методов борьбы два: использовать метод fixPanelBuilder класса MegaBugFixer либо начать корректно использовать компоненты swing (в том числе, панель). Выбор метода зависит от причины. Скролл не плохо влияет на панель, вероятно панель написана без выполеннения контрактов для компонентов swing или используется неправильно.
А как скролл обновлялся? Может быть, стоило обновить его Viewport?
P.S. А вообще, этот ваш PanelBuilder поддерживает отчуждение его панели getPanel? А то на content по Вашим словам лежал PanelBuilder, а на JScrollPane вы его внутреннюю панель класть пытаетесь.

PanelBuilder это компонент библиотеки jgoodies( web-страница ). В вашем примере PanelBuilder тоже работает. Я использую эту библиотеку,так как ее layout кажется мне наиболее удобным.
Сейчас путем некоторых изменений я добилась того, что вижу обновление страницы, но пока проблема с размером скролла .

В вашем примере PanelBuilder тоже работает. Сейчас путем некоторых изменений я добилась того, что вижу обновление страницы, но пока проблема с размером скролла .

А пример кода, который не работает, увидеть можно? По нему хоть можно было бы сказать, где ошибка. А так — только гадать: ошибка вроде бы есть, а вот где — не понятно.

Я использую эту библиотеку,так как ее layout кажется мне наиболее удобным.

В качестве оффтопика — а что не получилось сделать стандартными Layout Manager’ами?

FormLayout layout = new FormLayout(«LN ,10px,FN»);- разметка для трех столбцов
PanelBuilder builder = new PanelBuilder(layout);
JScrollPane pane = new JScrollPane;
pane.setViewportView(builder.getPanel;
Основная панель
JPanel content = new JPanel(new BorderLayout;
content.add(pane, BorderLayout.CENTER);
вот метод который обновляет содержимое панели. раскладку компонент максимально упростила, но суть остается та же.
private void showCharacteristics(ArrayList data) RowSpec rowSpec = new RowSpec(«FN»);
CellConstraints cc = new CellConstraints;
int line = 0;
builder.getPanel.removeAll;
for (int i = 0; i < data.size; i++) builder.appendRow(rowSpec);
line++;
builder.addLabel(«Label » + i, cc.xy(1, line;
builder.add(new JTextField cc.xy(3, line;
>
//здесь пыталась устанавливать размер скролла, но он принимал нужный размер только в первый раз, при появлении.

content.validate;
>
Стандартные лэауты я тоже использую, но очень не люблю GridBagLayout. а FormLayout по моему тоже обладает неплохими возможностями, а вот в использовании мне он кажется удобнее.

С примером кода стало гораздо лучше, но все еще не совсем понятно. Скачал библиотеку JGoodies Forms со страницы http://www.jgoodies.com/downloads/libraries.html. В нем как раз определены все необходимые в вашем примере классы.
Для запуска пришлось изменить строки
FormLayout layout = new FormLayout(«LN ,10px,FN») и
RowSpec rowSpec = new RowSpec(«FN»)
так как при запуске программы происходил IllegalArgumentException: Invalid unit name ‘ln’. Must be one of: px, dlu, pt, mm, cm, in, пришлось посмотреть документацию и немного изменить строку инициализации. Возможно, Вы используете немного другую библиотеку (например, из коммерческой версии, если такая есть, или другой версии в которой возможности класса немного расширены.
В результате получился код, который все равно работает

 
package test;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

import com.jgoodies.forms.builder.PanelBuilder;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;
import com.jgoodies.forms.layout.RowSpec;

public class GuiTest private static final boolean USE_SP = true;

int count;
JPanel content;
JScrollPane jsp;
JButton goButton;
FormLayout layout;
PanelBuilder builder;

void invokeAndShowGui JFrame mainFrame = new JFrame("MainFrame");
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.setLayout(new BorderLayout;
layout = new FormLayout("L:D, 10px, F:D");
builder = new PanelBuilder(layout);

content = new JPanel(new BorderLayout;
mainFrame.add(content, BorderLayout.CENTER);

jsp = new JScrollPane;
jsp.setViewportView(builder.getPanel;
content.add(jsp, BorderLayout.CENTER);

goButton = new JButton("Add");
mainFrame.add(goButton, BorderLayout.PAGE_END);
goButton.addActionListener(new ActionListener public void actionPerformed(ActionEvent e) builder.getPanel.removeAll;
RowSpec rowSpec = new RowSpec("F:D");
CellConstraints cc = new CellConstraints;

int line = 0;

count++;
if (count > 30)
count = 10;
for (int i = 0; i < count; i++) builder.appendRow(rowSpec);
line++;
builder.addLabel("Label " + i, cc.xy(1, line;
builder.add(new JTextField(20 cc.xy(3, line;
>
content.validate;
//WORKAROUND for invalid repaint, don't disable ;):
content.repaint;
>
>);

mainFrame.pack;
mainFrame.setSize(new Dimension(640, 480;
mainFrame.setVisible(true);
>

public static void main(String [] args) final GuiTest gui = new GuiTest;
SwingUtilities.invokeLater(new Runnable public void run gui.invokeAndShowGui;
>
>);
>
>

Специально сделал не только увеличение, но и уменьшение количества элементов. JTextField’у указывается длина, чтобы он был чуть больше, чем для нуля символов, но код будет работать нормально и без указания аргумента конструктора.
Вы в

//здесь пыталась устанавливать размер скролла, но он принимал нужный размер только в первый раз, при появлении.

пытаетесь изменить размер самого JScrollPane, либо сделать, чтобы обновилось его содержимое?
Может быть, в параметрах что-то не то приходит и в результате отображается не то, что предполагалось?
Кстати, глючок маленький был замечен — не совсем корректно перерисовывается панель при добавлении новых компонентов. Workaround в коде помечен, можно попробовать без него и увидеть, что происходит. Глючок в библиотеке, так как аналогичный код с GridBagLayout работает без Workaround’а:

 
void invokeAndShowGui1 JFrame mainFrame = new JFrame("MainFrame");
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.setLayout(new BorderLayout;
layout = new FormLayout("L:D, 10px, F:D");
builder = new PanelBuilder(layout);

content = new JPanel(new BorderLayout;
mainFrame.add(content, BorderLayout.CENTER);

jsp = new JScrollPane;
jsp.setViewportView(builder.getPanel;
content.add(jsp, BorderLayout.CENTER);

goButton = new JButton("Add");
mainFrame.add(goButton, BorderLayout.PAGE_END);
goButton.addActionListener(new ActionListener public void actionPerformed(ActionEvent e) builder.getPanel.removeAll;
RowSpec rowSpec = new RowSpec("F:D");
CellConstraints cc = new CellConstraints;

int line = 0;

count++;
if (count > 30)
count = 10;
for (int i = 0; i < count; i++) builder.appendRow(rowSpec);
line++;
builder.addLabel("Label " + i, cc.xy(1, line;
builder.add(new JTextField(20 cc.xy(3, line;
>
content.validate;
//WORKAROUND for invalid repaint, don't disable ;):
content.repaint;
>
>);

mainFrame.pack;
mainFrame.setSize(new Dimension(640, 480;
mainFrame.setVisible(true);
>

Посмотрел возможности библиотеки, в принципе, при регулярном размещении FormLayout действительно будет удобнее в использовании да и кода в типичных случаях (для форм и т.п.) получается меньше. Просто с подозрением отношусь к нестандартным библиотекам которые делают вещи, которые можно сделать и стандартными средствами, при этом имеют большой объем, что приводит к большой вероятности ошибки. В данном же случае библиотечка оказалась маленькой и с открытым кодом, что для нее является большим плюсом.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *