Форум программистов, компьютерный форум, киберфорум
Java: GUI, графика
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.54/83: Рейтинг темы: голосов - 83, средняя оценка - 4.54
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30

Не могу понять, как работать с графикой

22.01.2012, 14:24. Показов 17670. Ответов 53
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Есть примитивная программа. Создаётся Frame, в нём создаётся Panel, далее в методе paintComponent рисуется линия. Как теперь человеческими способами переписать программу так, чтобы то, что требуется нарисовать, рисовалось, к примеру, в функции main, потому что принятие решений о том, что рисовать, должно делаться НЕ внутри paintComponent. Как идеальный пример хотелось бы увидеть программу, которая нарисует одну линию, а через 5 секунд нарисует вторую линию

Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import java.awt.*;
import javax.swing.*;
 
public class Main {
  public static void main (String[] args)
  {
    MyFrame frame = new MyFrame ();
    frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
    frame.setVisible (true);
  }
}
 
class MyFrame extends JFrame
{
  public MyFrame()
  {
    this.setBounds (0, 0, 200, 200);
    
    MyPanel panel = new MyPanel();
    this.add (panel);
  }
}
 
class MyPanel extends JPanel
{
  public void paintComponent (Graphics g)
  {
    super.paintComponent (g);   
    g.drawLine (10, 10, 180, 180);  
  }
}
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
22.01.2012, 14:24
Ответы с готовыми решениями:

Не могу понять как работать с событиями
Здравствуйте. Подскажите пожалуйста такую вещь: У меня при нажатии на кнопку выбора файла , появляется лэйбл на форме и после выбора файла...

TStyleManager, не могу понять как работать с ним
Ребята! Помогите! Хочу сделать программу покрасивее, но я не могу понять как работать с ним. Класс создаю. Пишет ошибку: Undeclared...

Не могу понять, как должна работать модель
Не могу понять алгоритм работы модели, кто может, подскажите как данная модель должна функционировать. Что это за терминалы, где...

53
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
24.01.2012, 16:41  [ТС]
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от mutagen Посмотреть сообщение
у меня тоже линукс и OpenJDK такчто ищите пули у себя
Понятное дело, что если что-то не запускается у меня, то к вам претензий нет. Я вот только не могу понять, почему "java" не выдаёт никаких сообщений об ошибках или несовместимостях

Цитата Сообщение от mutagen Посмотреть сообщение
А вы не заметили у меня аж 3 класса и MyVcl какраз и является холстом для линий и помнит сколько вы их нарисовали??? И в чём проблема наследовать за ними и наращивать контейнеры для всех придуманных вами фигур?
Заметил. Только заметил я и ещё одну вещь. Если мне нужно "наверху" рисовать линии, то "внизу" мне над заводить массив для линий. Если мне теперь "наверху" захочется нарисовать круги, то "внизу" придётся добавлять данные и коды. Т.е. у меня нетникакой возможности добавить возможность нарисования круга только в одном месте. Это надо будет делать как минимум в трёх местах: в том месте, где мне реальнонало круг нарисовать, в классе MyVcl завести данные для круга, в классе MyVcl дописать код, который бы нарисовал круг. На мой взгляд это уже совсем никакое не ООП а геморрой на ровном месте в чистом виде

Добавлено через 2 минуты
Попросту говоря, из-за такой модели работы с графикой попросту пропадает такая вещь, как инкапсуляция. И вот когда я на первом же шаге столкнулся с этим, то побежал на форум, в надежду увидеть, что может быть есть какие-то приёмы, чтобы без подобных извращений код написать

Добавлено через 6 минут
По поводу JDK

Code
1
2
3
4
5
6
7
$ javac -version
javac 1.6.0_07
 
$ java -version
java version "1.6.0_07"
Java(TM) SE Runtime Environment (build 1.6.0_07-b06)
Java HotSpot(TM) Server VM (build 10.0-b23, mixed mode)
Я так понимаю, что это какое-то старьё?
0
 Аватар для mutagen
2587 / 2260 / 257
Регистрация: 14.09.2011
Сообщений: 5,185
Записей в блоге: 18
24.01.2012, 17:54
Ну нет множественного наследования, нет, поэтому именно такой путь и он вполне ООП. Мало того я подозреваю что vcl примерно по такому же способу построена, просто это сделали за вас.
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
24.01.2012, 18:23  [ТС]
Как сделано VCL внутри - это мало кого волнует. Людям интересно знать лишь то, что для рисования им не надо программу и данные размазывать по нескольким классам. В таких случаях простым решением было бы в экземпляре класса MyVcl запомнить hook (который физически находится "наверху") и вызывать этот hook с параметром g, чтобы всей логикой отрисовки занимались наверху. Но в java, насколько я понимаю, указателей на методы не существует?
0
636 / 528 / 165
Регистрация: 01.04.2010
Сообщений: 1,843
25.01.2012, 06:29
Цитата Сообщение от Evg Посмотреть сообщение
Как сделано VCL внутри - это мало кого волнует.
И это не есть хорошо, понимание внутреннего устройства и принципов работы используемой библиотеки, по-моему, является очень важным.

Цитата Сообщение от Evg Посмотреть сообщение
Людям интересно знать лишь то, что для рисования им не надо программу и данные размазывать по нескольким классам.
А не нужно ничего размазывать. Каждый должен делать свою работу. Холст должен просто уметь отрисовывать некие объекты, и ничего более.

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

Вообще весь Swing построен на MVC немного отличной от эталонной, но всё-таки основные принципы остались.
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
25.01.2012, 09:03  [ТС]
Цитата Сообщение от aleksandy Посмотреть сообщение
И это не есть хорошо, понимание внутреннего устройства и принципов работы используемой библиотеки, по-моему, является очень важным
Принципы работы VCL всем понятны. Техническое устройство при этом знать незачем, т.к. главное понимать принципы. Ты ведь умеешь работать с print'ом, но для этого вовсе незачем знать его внутреннее устройство

Цитата Сообщение от aleksandy Посмотреть сообщение
А не нужно ничего размазывать. Каждый должен делать свою работу. Холст должен просто уметь отрисовывать некие объекты, и ничего более
Неправильно. Рисовать должен художник. А холст должен быть только местом, где рисуют, и не более того.

Цитата Сообщение от aleksandy Посмотреть сообщение
Я приводил пример, при таком раскладе, если мне завтра потребуется рисовать на компоненте, например, звезды, то будет достаточно добавить 1 класс имплементирующий нужный интерфейс.
Так у тебя всё то же самое. Холст внутри себя содержит информацию о линиях и метод, который эти линии рисует. А если потребуется рисовать звёзды, то тебе как минимум в трёх местах править (в тех, о которых я писал в посте #21). В отличие от VCL, где действительно надо будет поправить только одно место. Ну и твой вриант страдает тем же самым, что для конкретной простой задачи ты свалил всё в одну большую кучу. Для серьёзных задач такая куча в общем-то непригодна

Насколько я понимаю, аккуратных способов работы с графикой нет. В любом случае всем спасибо за потраченное на меня время
0
636 / 528 / 165
Регистрация: 01.04.2010
Сообщений: 1,843
25.01.2012, 11:17
Цитата Сообщение от Evg Посмотреть сообщение
А если потребуется рисовать звёзды, то тебе как минимум в трёх местах править
Укажи мне эти 3 места. Единственное "узкое" место в моем примере - это combobox, который по-умному, должен использовать свою модель, загружающую в себя все известные имплементации Drawable самостоятельно.

Цитата Сообщение от Evg Посмотреть сообщение
для конкретной простой задачи ты свалил всё в одну большую кучу.
Где это одна большая куча? Статический класс включающий в себя все: и gui, и обработку событий, и пр. Так это пример, в реальном приложении, естественно, так не делается.

Цитата Сообщение от Evg Посмотреть сообщение
Насколько я понимаю, аккуратных способов работы с графикой нет.
По-моему, просто нет понимания философии языка.
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
25.01.2012, 13:46  [ТС]
Цитата Сообщение от aleksandy Посмотреть сообщение
Укажи мне эти 3 места. Единственное "узкое" место в моем примере - это combobox, который по-умному, должен использовать свою модель, загружающую в себя все известные имплементации Drawable самостоятельно
Да, что-то я погорячился. Если несложно, перепиши свой исходник так, что бы там просто рисовалось 5 линий и 5 овалов и чтобы это как бы было разнесено во времени. Убрав при этом все пимпочки, кнопочки, обработчики событий мыши и т.п. И если несложно, напиши программу в том виде, как я условно изобразил в посте #19

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

Цитата Сообщение от aleksandy Посмотреть сообщение
Где это одна большая куча? Статический класс включающий в себя все: и gui, и обработку событий, и пр. Так это пример, в реальном приложении, естественно, так не делается
Ну вот мне кажется, что рассчётная часть программы и графическая должны быть разнесены. Как минимум для того, чтобы на один и тот же расчётный код можно было сажать разные GUI (во всяком случае я всегда исхожу из такого проектирования)

Цитата Сообщение от aleksandy Посмотреть сообщение
По-моему, просто нет понимания философии языка.
Возможно. Я просто не понимаю философию языка, когда для аккуратного кода по прорисовке прямоугольника нужно в программу вносить класс "Прямоугольник", "наверху" создать экземпляр класса прямоугольник, засунуть его в список, вызвать чей-то метод repaint, чтобы "внизу" достать экземпляр класса из списка и нарисовать. Это сильно смахивает на ООП ради ООП

---------------------------------------------------

Исходя из всего этого я правильно понимаю, что если я, к примеру, нарисовал на экране 10 спрайтов, то для того, чтобы удалить с экрана один из спрайтов, мне надо по новой формировать список из 10 экземпляров класса, отвечающего за спрайт и затем картинка будет перерисовываться с нуля (т.е. рисоваться 9 спрайтов вместо 10). А если захочется сделать "классическим" способом (т.е. удалить спрайт простой заливкой области цветом фона), то никак не получится, потому что единственная возможность - это отрисовать картинку с нуля?
0
Эксперт JavaЭксперт С++
 Аватар для M128K145
8384 / 3617 / 419
Регистрация: 03.07.2009
Сообщений: 10,709
25.01.2012, 14:56
Цитата Сообщение от Evg Посмотреть сообщение
что бы там просто рисовалось 5 линий и 5 овалов и чтобы это как бы было разнесено во времени. Убрав при этом все пимпочки, кнопочки, обработчики событий мыши и т.п. И если несложно, напиши программу в том виде, как я условно изобразил в посте #19
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
 
public class MainForm {
 
   public MainForm() {
      JFrame mainForm = new JFrame("Main Form");
      mainForm.setSize(650, 600);
      mainForm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      mainForm.setVisible(true);
 
      final JPanel imagePanel = new JPanel();
      imagePanel.setVisible(true);
      mainForm.getContentPane().add(imagePanel);
 
      for (int i = 0; i < 10; ++i) {
         Graphics g = imagePanel.getGraphics();
         int x1 = i * 10 + i;
         int y1 = i * 20 + 5;
 
         int x2 = i + 100;
         int y2 = (i + 10) * i;
         if ((i & 1) == 0)
            g.drawLine(x1, y1, x2, y2);
         else
            g.drawRect(x1, y1, x2, y2);
         try {
            Thread.sleep(1000);
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
      }
 
   }
 
   public static void main(String[] args) {
      new MainForm();
   }
 
}
1
 Аватар для mutagen
2587 / 2260 / 257
Регистрация: 14.09.2011
Сообщений: 5,185
Записей в блоге: 18
25.01.2012, 15:06
Цитата Сообщение от Evg Посмотреть сообщение
нужно в программу вносить класс "Прямоугольник", "наверху" создать экземпляр класса прямоугольник, засунуть его в список, вызвать чей-то метод repaint, чтобы "внизу" достать экземпляр класса из списка и нарисовать.
Этот вариант не типичный, это я специально для вас соорудил аналог поведения VCL, но типично в java совсем не так и не ООП ради ООП, вот пример выше - это типично для java.
Именно как сказал aleksandy вопрос философии
1
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
25.01.2012, 16:26  [ТС]
Цитата Сообщение от M128K145 Посмотреть сообщение
Java
1
2
3
4
...
   public MainForm() {
...
         Graphics g = imagePanel.getGraphics(); <--------- AAAAAAAAAAAAAA
Солнышко ты моё ненаглядное, дай я тебя расцелую Что же вы, гады, сразу об этом-то и не сказали, ведь я ещё в посте #7 спрашивал. Правда у меня под линуксом по прежнему оно не работает (т.е. ничего не рисуется), но может оно просто рисуется цветом фона?

Цитата Сообщение от mutagen Посмотреть сообщение
Этот вариант не типичный, это я специально для вас соорудил аналог поведения VCL
А... понятно
0
 Аватар для mutagen
2587 / 2260 / 257
Регистрация: 14.09.2011
Сообщений: 5,185
Записей в блоге: 18
25.01.2012, 16:34
Цитата Сообщение от Evg Посмотреть сообщение
Правда у меня под линуксом по прежнему оно не работает
Создай в эклипсе новый проект.
Создай в нём класс с именем MainForm
и потом в него скопируй полностью с заменой того что в нём исходник
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
 
public class MainForm {
 
   public MainForm() {
      JFrame mainForm = new JFrame("Main Form");
      mainForm.setSize(650, 600);
      mainForm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      mainForm.setVisible(true);
 
      final JPanel imagePanel = new JPanel();
      imagePanel.setVisible(true);
      mainForm.getContentPane().add(imagePanel);
 
      for (int i = 0; i < 10; ++i) {
         Graphics g = imagePanel.getGraphics();
         int x1 = i * 10 + i;
         int y1 = i * 20 + 5;
 
         int x2 = i + 100;
         int y2 = (i + 10) * i;
         if ((i & 1) == 0)
            g.drawLine(x1, y1, x2, y2);
         else
            g.drawRect(x1, y1, x2, y2);
         try {
            Thread.sleep(1000);
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
      }
 
   }
 
   public static void main(String[] args) {
      new MainForm();
   }
 
}
потом правой кнопкой по классу и RunAs java app...
1
 Аватар для Skipy
2000 / 1427 / 92
Регистрация: 25.11.2010
Сообщений: 3,611
25.01.2012, 17:03
mutagen, с Вашим решением есть одна маленькая проблема. Вы рисуете на панели извне. Любое событие перерисовки, посланное во время этого рисования, убьет всё, что было нарисовано раньше. Минимизировать окно и вернуть назад, утащить за пределы экрана, перекрыть другим окном и вытащить на поверхность...

Я бы рисовал на BufferedImage, который бы передал панели, чтобы она его отрисовывала. В этом случае ничего никуда не исчезнет.
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
25.01.2012, 17:48  [ТС]
Цитата Сообщение от mutagen Посмотреть сообщение
Создай в эклипсе новый проект
я из консоли запускаю javac и java (о чём писал в посте #21):

Code
1
2
3
4
5
6
7
$ javac -version
javac 1.6.0_07
 
$ java -version
java version "1.6.0_07"
Java(TM) SE Runtime Environment (build 1.6.0_07-b06)
Java HotSpot(TM) Server VM (build 10.0-b23, mixed mode)
0
 Аватар для mutagen
2587 / 2260 / 257
Регистрация: 14.09.2011
Сообщений: 5,185
Записей в блоге: 18
25.01.2012, 18:46
Цитата Сообщение от Skipy Посмотреть сообщение
mutagen, с Вашим решением есть одна маленькая проблема. Вы рисуете на панели извне. Любое событие перерисовки, посланное во время этого рисования, убьет всё, что было нарисовано раньше. Минимизировать окно и вернуть назад, утащить за пределы экрана, перекрыть другим окном и вытащить на поверхность...
Не не скипи ты ошибаешься, я просто дал рекомендации как засунуть код MK в эклипс, "мопед не мой я только дал обьяву"
А так да я с BufferedImage вполне согласен )
Цитата Сообщение от Evg Посмотреть сообщение
я из консоли запускаю javac и java (о чём писал в посте #21):
занчит создай файл MainForm.java и туда скопипасть код полностью, потом javac MainForm.java и вуаля java MainForm

ЗЫЖ я надеюсь пути для java и либок прописаны
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
25.01.2012, 21:03  [ТС]
А про BufferedImage расскажите. А то я, по ходу дела, рано радоваться начал

Цитата Сообщение от mutagen Посмотреть сообщение
занчит создай файл MainForm.java и туда скопипасть код полностью, потом javac MainForm.java и вуаля java MainForm
Я знаю, как работать с java'ой из консоли Мой вариант программы у меня работает, а некоторые из последних - нет: вылезает окно приложения, но на нём никаких линий не рисуется
0
 Аватар для mutagen
2587 / 2260 / 257
Регистрация: 14.09.2011
Сообщений: 5,185
Записей в блоге: 18
25.01.2012, 21:26
Цитата Сообщение от Evg Посмотреть сообщение
про BufferedImage расскажите
кидаешь на панель BufferedImage и рисуешь на нём
а со своей явой уже разбирайся сам чё она там рисует а чо нет ))
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
25.01.2012, 22:23  [ТС]
Родил ещё один способ, при котором процесс прорисовки управляется изнутри рассчётного класса. Он несколько черезж...ый, но коэффициэнт черезж...сти намного меньше, чем когда рисовать внутри paintComponent.

Правда во всех подобных методах прорисовки есть нехороший геморой. Чтобы нарисовать, например, несколько линий, нужно завести массив с их координатами и счётчик количества линий, заполнить массив с координатами, а потом из метода Draw всю эту информацию подцепить. При этом метод paintComponent может вызваться асинхронно по отношению к коду, который формирует данные для отображения. В итоге может получиться так, что данные начнут читаться ещё до того, как их сформировали. Как с этим бороться?

Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
import java.awt.*;
import javax.swing.*;
 
public class Main
{
  public static void main (String[] args)
  {
    new MyProg();
  }
}
 
class MyProg
{
  int x1, y1, x2, y2;
 
  public MyProg()
  {
    MyFrame frame = new MyFrame (this);
    frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
    frame.setVisible (true);
      
    while (true)
    {
      x1 = 10; y1 = 10; x2 = 100; y2 = 100;
      frame.repaint();
 
      try {
        Thread.sleep(1000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
 
      x1 = 100; y1 = 10; x2 = 10; y2 = 100;
      frame.repaint();
 
      try {
        Thread.sleep(1000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }
  
  public void Draw (Graphics g)
  {
    g.drawLine (x1, y1, x2, y2);      
  }
}
 
class MyFrame extends JFrame
{
  public MyFrame (MyProg my_prog)
  {
    this.setBounds (0, 0, 200, 200);
    
    MyPanel panel = new MyPanel (my_prog);
    this.add (panel);
  }
 
  class MyPanel extends JPanel
  {
    MyProg m_MyProg;
 
    public MyPanel (MyProg my_prog)
    {
      m_MyProg = my_prog;
    }
 
    public void paintComponent (Graphics g)
    {
      super.paintComponent (g);
      m_MyProg.Draw (g);
    }
  }
}
C BufferedImage с ходу что-то не получилось разобраться. При его создании задаются размеры. Т.е. получается конструкция, которая в общем-то не растягивается при изменении размеров фрейма?
0
 Аватар для Skipy
2000 / 1427 / 92
Регистрация: 25.11.2010
Сообщений: 3,611
26.01.2012, 17:37
Цитата Сообщение от Evg Посмотреть сообщение
C BufferedImage с ходу что-то не получилось разобраться. При его создании задаются размеры. Т.е. получается конструкция, которая в общем-то не растягивается при изменении размеров фрейма?
Вы по ходу не смотрели ту ссылку, которую я привел. Привожу еще раз:

Там в числе прочего есть пример, как использовать BufferedImage как невидимый буфер, причем с изменением его вместе с размерами компоненты.

Добавлено через 1 час 14 минут
М-да, что-то я сегодня добрый.

В общем, Evg, ниже код канвы, работающей как Вам надо - нарисовали и забыли. Перед первым рисованием надо выставить размер внутреннего буфера - вызовом конструктора с параметрами или методом extendCanvasTo, это если хотите рисовать еще до того, как показали компоненту. Или это произойдет автоматически при изменении размера/отображении. Размер канвы подстраивается под размер компоненты - расширяется при увеличении размера и НЕ уменьшается. Тем самым гарантируется, что ничего не пропало из того, что нарисовали. Если вылезли при рисовании за пределы размера внутреннего буфера канвы - тут уж упс: операции рисования не отслеживаются и под них канва не подстраивается. Для рисования получается Graphics через createCanvasGraphics, его надо потом специально уничтожать через dispose, иначе может память потечь. При отрисовке учитывается рамка, отрисовываемые элементы на нее не налезают.

Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package ru.skipy.swing;
 
import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.image.BufferedImage;
 
/**
 * JCanvas - canvas implementation. Component works in paint-and-forget mode - all painting operations
 * are stored in the internal buffer. Because of this painting result will not be visible till component
 * repaint - {@link java.awt.Component#repaint()} should be called explicitly after painting on visible
 * canvas.
 *
 * @author Eugene Matyushkin aka Skipy
 * @since 26.01.12
 */
public class JCanvas extends JPanel {
 
    /**
     * Internal buffer
     */
    private BufferedImage offscreen = null;
 
    /**
     * Current canvas width
     */
    private int currentWidth = 0;
 
    /**
     * Current canvas height
     */
    private int currentHeight = 0;
 
    /**
     * Creates empty transparent canvas with zero size ({@link #createCanvasGraphics()} will return
     * <code>null</code>). Internal buffer will be created on the first resize, display or explicit call to
     * {@link #extendCanvasTo(int, int)};
     */
    public JCanvas() {
        addComponentListener(new SizeTracker());
    }
 
    /**
     * Creates empty transparent canvas with the size specified.
     *
     * @param startWidth  starting canvas width
     * @param startHeight starting canvas height
     */
    public JCanvas(int startWidth, int startHeight) {
        this();
        extendCanvasTo(startWidth, startHeight);
    }
 
    /**
     * <b>Extends</b> canvas to the new size. Size setting less then current will be ignored (current setting
     * will remain). Creates new internal buffer of the specified size and paints exiting buffer's (if any)
     * content on new one.
     *
     * @param newWidth  new width
     * @param newHeight new height
     */
    public void extendCanvasTo(int newWidth, int newHeight) {
        int oldW = currentWidth;
        int oldH = currentHeight;
        int w = Math.max(newWidth, getWidth());
        int h = Math.max(newHeight, getHeight());
        currentWidth = Math.max(currentWidth, w);
        currentHeight = Math.max(currentHeight, h);
        if (currentWidth > oldW || currentHeight > oldH || offscreen == null) {
            BufferedImage old = offscreen;
            offscreen = new BufferedImage(currentWidth, currentHeight, BufferedImage.TYPE_INT_ARGB);
            if (old != null) {
                Graphics2D g = offscreen.createGraphics();
                g.drawImage(old, 0, 0, this);
                g.dispose();
            }
        }
    }
 
    /**
     * Returns current canvas size. It can differ from component size
     *
     * @return canvas' internal buffer's size
     */
    public Dimension getCanvasSize() {
        return new Dimension(currentWidth, currentHeight);
    }
 
    /**
     * Creates <code>java.awt.Graphics2D</code> object to work with canvas. This object should be explicitly disposed
     * after use by calling {@link java.awt.Graphics#dispose()}
     *
     * @return created graphics or <code>null</code> if internal buffer is not created yet.
     * @see #extendCanvasTo(int, int)
     */
    public Graphics2D createCanvasGraphics() {
        return (offscreen == null) ? null : offscreen.createGraphics();
    }
 
    /**
     * Cleans internal buffer and repaints canvas.
     */
    public void cleanCanvas() {
        offscreen = null;
        extendCanvasTo(currentWidth, currentHeight);
        repaint();
    }
 
    /**
     * Paints canvas taking into account current border (canvas' origin is moved into the topmost-leftmost point
     * inside the border, painting area is clipped according to the border's internal area)
     *
     * @param g graphics to use for painting of internal buffer
     */
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (offscreen != null) {
            Border b = getBorder();
            Insets i = (b == null) ? null : b.getBorderInsets(this);
            Graphics copy = (i == null) ? g.create() :
                    g.create(i.left, i.top, getWidth() - i.left - i.right, getHeight() - i.top - i.bottom);
            copy.drawImage(offscreen, 0, 0, this);
            copy.dispose();
        }
    }
 
    /**
     * This class is intended to track size/visibility change in order to adjust internal buffer size.
     */
    private class SizeTracker extends ComponentAdapter {
 
        /**
         * Component was shown
         * @param e event object
         */
        @Override
        public void componentShown(ComponentEvent e) {
            extendCanvasTo(getWidth(), getHeight());
        }
 
        /**
         * Component was resized
         * @param e event object
         */
        @Override
        public void componentResized(ComponentEvent e) {
            extendCanvasTo(getWidth(), getHeight());
        }
    }
}
Работы на час, обсуждений на четверо суток...
1
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
26.01.2012, 18:53  [ТС]
Цитата Сообщение от Skipy Посмотреть сообщение
Вы по ходу не смотрели ту ссылку, которую я привел
Ссылка приводилась в несколько другом контексте, а потому я читал только начало, и увидел то, чего мне было не особенно интересно (в контексте моей постановки вопроса). Ща надо почитать

Кстати, если в примере из поста #31 код "Graphics g = imagePanel.getGraphics();" вынести из цикла (т.е. чтобы g инициализировалось только один раз), то программа перестаёт рисовать. Это так и должно быть?

Добавлено через 3 минуты
Цитата Сообщение от Skipy Посмотреть сообщение
В общем, Evg, ниже код канвы, работающей как Вам надо - нарисовали и забыли
А оценочно можешь сказать, насколько такой метод работы более медлительный, чем "обычный".

Не по теме:

МФТИ?

0
 Аватар для Skipy
2000 / 1427 / 92
Регистрация: 25.11.2010
Сообщений: 3,611
27.01.2012, 11:23
Цитата Сообщение от Evg Посмотреть сообщение
А оценочно можешь сказать, насколько такой метод работы более медлительный, чем "обычный".
Да ни насколько. Отрисовка буфера весьма быстрая. Я бы сказал, что это вообще один из самых быстрых методов. Другое дело, что он, на мой взгляд, расходится с принципом MVC - модель отсутствует. Именно потому применяется такое крайне редко и в стандартной библитеке не реализовано.

Не по теме:

МФТИ?

1998-й, ФУПМ/ФПФЭ
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
27.01.2012, 11:23
Помогаю со студенческими работами здесь

Не могу понять как работать с данным массивом
Добрый день форумчане! Имеется массив ...

длинная арифметика, не могу понять как с ней работать
необходимо написать программу которая могла бы найти остаток от деления, но проблема в том что числа могут быть до 10 в 100 степени. как...

Не могу понять как в Visual Studio (C#) работать с "ресурсами"
Начал программировать на C#, установил Visual Studio и встретил там такую графу как &quot;ресурсы&quot;.И у меня возник вопрос как с ними...

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

Програма не хочет работать. не могу понять что не так (
В панели интерфейса предусмотреть возможность выбора одной из трех функций sin(x), x^2, exp(x) unit laba2; interface uses...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Новые блоги и статьи
Переходник USB-CAN-GPIO
Eddy_Em 20.03.2026
Достаточно давно на работе возникла необходимость в переходнике CAN-USB с гальваноразвязкой, оный и был разработан. Однако, все меня терзала совесть, что аж 48-ногий МК используется так тупо: просто. . .
Оттенки серого
Argus19 18.03.2026
Оттенки серого Нашёл в интернете 3 прекрасных модуля: Модуль класса открытия диалога открытия/ сохранения файла на Win32 API; Модуль класса быстрого перекодирования цветного изображения в оттенки. . .
SDL3 для Desktop (MinGW): Рисуем цветные прямоугольники с помощью рисовальщика SDL3 на Си и C++
8Observer8 17.03.2026
Содержание блога Финальные проекты на Си и на C++: finish-rectangles-sdl3-c. zip finish-rectangles-sdl3-cpp. zip
Символические и жёсткие ссылки в Linux.
algri14 15.03.2026
Существует два типа ссылок — символические и жёсткие. Ссылка в Linux — это запись в каталоге, которая может указывать либо на inode «файла-ИСТОЧНИКА», тогда это будет «жёсткая ссылка» (hard link),. . .
[Owen Logic] Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора
ФедосеевПавел 14.03.2026
Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора ВВЕДЕНИЕ Выполняя задание на управление насосной группой заполнения резервуара,. . .
делаю науч статью по влиянию грибов на сукцессию
anaschu 13.03.2026
прикрепляю статью
SDL3 для Desktop (MinGW): Создаём пустое окно с нуля для 2D-графики на SDL3, Си и C++
8Observer8 10.03.2026
Содержание блога Финальные проекты на Си и на C++: hello-sdl3-c. zip hello-sdl3-cpp. zip Результат:
Установка CMake и MinGW 13.1 для сборки С и C++ приложений из консоли и из Qt Creator в EXE
8Observer8 10.03.2026
Содержание блога MinGW - это коллекция инструментов для сборки приложений в EXE. CMake - это система сборки приложений. Здесь описаны базовые шаги для старта программирования с помощью CMake и. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru