Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: GUI и Java FX приложения > Свой компонент в JScroolPane


Автор: Lisus 5.10.2008, 11:02
Вопрос собствеено уже задан.

Есть свой компонент наследуемый от JPanel. В процессе добавления новых данный он должен увеличиваться. Логично засунуть его в JScrollPane, а вот как обвёртку извещать о новых размерах?

Автор: dorogoyIV 5.10.2008, 12:25
хм, так не надо ничего делать, все само должно работать

Автор: Dims 5.10.2008, 18:30
А как оно само-то может отработать? Мало ли что я там нарисую?

Автор: Старовъръ 5.10.2008, 19:26
Т.к. наследуется компонент от JPanel, то последний сам все сообщает скроллу.

Автор: Dims 5.10.2008, 21:05
Цитата(Старовъръ @  5.10.2008,  19:26 Найти цитируемый пост)
Т.к. наследуется компонент от JPanel, то последний сам все сообщает скроллу. 

Как он может сообщить скроллу то, чего сам не знает? 

Допустим, я переопределил paintComponent и там нарисовал линию длиной в километр. Откуда базовый JPanel об этом узнает?

Автор: Старовъръ 5.10.2008, 21:54
Если ты нарисуешь линию в км, то компонент не изменит своих размеров, просто линию не будет видно и все. Размеры меняются в зависимости от preferred, minimum, maximum Sizes. На них смотрит менеджер компановки и составляет пропорции, относительно всех остальных компонентов. А вот как определяет размеры внутренних компонентов JScrollPane мне и самому интересно...

Автор: dorogoyIV 5.10.2008, 22:05
тогда устанавливай на свою панель новые размеры 
Код

myPanel.setPreferredSize(new Dimension(myPanel.getWidth()*2, myPanel.getHeight()*2));


Добавлено через 5 минут и 25 секунд
Цитата(Старовъръ @  5.10.2008,  21:54 Найти цитируемый пост)
А вот как определяет размеры внутренних компонентов JScrollPane мне и самому интересно...

JScrollPane как раз вот и берет PreferredSize компонента, а размер этого компонента знает LayoutManager

Автор: Dims 5.10.2008, 23:04
Цитата(dorogoyIV @  5.10.2008,  22:05 Найти цитируемый пост)
тогда устанавливай на свою панель новые размеры 

Мне кажется, что логичней переопределить getSize. То есть, я переопределяю рисование компонента и я же переопределяю понятие о его размерах.

Добавлено через 5 минут и 28 секунд
Цитата(Старовъръ @  5.10.2008,  21:54 Найти цитируемый пост)
На них смотрит менеджер компановки и составляет пропорции, относительно всех остальных компонентов.

Я так понимаю, что менеджер компоновки делает вот что: (1) смотрит на всякие подсказки, которые ему даёт компонент (сюда входят всякие getPreferred, getMaximum и так далее), (2) думает, как ему расположить компоненты, при этом он может проигнорировать подсказки, (3) вызывает у компонентов методы setSize, чтобы задать размер, (4) смотрит, что получилось при помощи getSize и (5) раскладывает.

Если мы вызовем setPreferredSize, то менеджер может его и проигнорировать. Хотя менеджер скролла (там какой-то свой) наверняка не проигнориует, но мне кажется, что это будет не очень коррекно. Ведь этот метод определяет лишь ЖЕЛАЕМЫЙ размер. А нам надо задать ФАКТИЧЕСКИЙ.

Автор: Старовъръ 6.10.2008, 06:30
Цитата

Мне кажется, что логичней переопределить getSize.
Какая-то дикость - getSize() должен выполнять свои функции и он их выполняет. Не нужно переопределять все на свете, не зря же создавались методы, предложенные Дорогим. Где-то говорили об антипаттернах, что-то мне их напомнило только что smile 
Цитата

Я так понимаю, что менеджер компоновки делает вот что: (1) смотрит на всякие подсказки, которые ему даёт компонент (сюда входят всякие getPreferred, getMaximum и так далее), (2) думает, как ему расположить компоненты, при этом он может проигнорировать подсказки, (3) вызывает у компонентов методы setSize, чтобы задать размер, (4) смотрит, что получилось при помощи getSize и (5) раскладывает.

Думаю лучше не гадать что делают менеджеры, а просто где-нибудь об этом почитать, если есть желание. И конечно же опубликовать выводы в данной теме.

Автор: Dims 6.10.2008, 10:25
Цитата(Старовъръ @  6.10.2008,  06:30 Найти цитируемый пост)
Какая-то дикость - getSize() должен выполнять свои функции и он их выполняет.

Его функция -- сообщать интересующимся о размере компонента. Почему Вы считаете дикостью переопределять его, если ответственность за размер уже переопределена?

Автор: Lisus 6.10.2008, 10:49
Прошу прощения, что обсуждение без меня проходит. Действительно все делается само.
Вот пример что примерно надо было сделать.
Сама панель-компонент
Код

import java.awt.LayoutManager;

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

public class MyPanel extends JPanel {
    ArrayList list = new ArrayList();
    int w = 500;

    public void addNewLine(String _s) {
        list.add(_s);
        this.setSize(w, 30 * list.size() + 10);
    }

    public Dimension getPreferredSize() {
        return new Dimension(w, 10 + 30 * list.size());
    }

    public void paintComponent(Graphics g) {
        int i_max = list.size();
        g.setColor(this.getBackground());
        g.clearRect(g.getClipBounds().x, g.getClipBounds().y,
                    g.getClipBounds().width, g.getClipBounds().height);

        for (int i = 0; i < i_max; i++) {
            g.setColor(Color.BLACK);
            g.drawRect(5, 5 + i * 30, w - 10, 25);
            g.drawString((String) list.get(i), 15, 30 * i + 22);
        }
    }
}


И пусковой фрейм.
Код

mport javax.swing.JFrame;
import javax.swing.*;

public class ResizedFrame extends JFrame {
    MyPanel mp = new MyPanel();
    JScrollPane jsp = new JScrollPane(mp);
    public ResizedFrame() {
    this.getContentPane().add(jsp);
    }

    public static void main(String[] args) {
        ResizedFrame t = new ResizedFrame();
        t.setBounds(20,20,600,600);
        t.mp.addNewLine("One String");
        t.setVisible(true);

        try {
            Thread.sleep(10000);
        } catch (InterruptedException ex) {
        }

        for(int y=0; y<20; y++){
        t.mp.addNewLine("String s  number : "+y);
        }

    }
}


Запускаем фрейм и ждем немного. Скролл реагирует правильно. Спасибо.

Автор: Dims 6.10.2008, 12:45
А попробуйте переопределить не getPreferredSize, а getSize. Будет работать?

Автор: Старовъръ 6.10.2008, 13:59
Цитата

Его функция -- сообщать интересующимся о размере компонента. Почему Вы считаете дикостью переопределять его, если ответственность за размер уже переопределена?
Зачем нарушать инкапсуляцию родителя, если можно просто установить preferredSize()? Такие вещи, как переопределение методов делаются, если метод родителя совсем не подходит сыну! Тем более это не просто метод, а метод обращения к переменной класса! То есть вместо того, чтоб мы установили переменную в нужное значение, мы изменим метод-обращения к ней, который вобще теперь к ней не будет обращаться, а вместо этого - самовольничать? И потом - все, что мы установим с помощью setPreferredSize() куда будет уходить? А если в том же классе тоже допустили ошибку проектирования и инкапсуляции: обращались не к методу getSize(), а напрямую к переменной, она, ведь, в классе видна всем методам? То есть getSize() и наша переменная будут показывать разные значения? Какие плюсы нам вобще даст это переопределение? На мой взгляд - никаких...

Автор: Lisus 6.10.2008, 14:15
Dims
Видете ли работать оно может и будет, но...

При проектировании систем (например GUI) обычно одни методы делаются специально для переопределения (иногда просто абстрагируют их), а другие - для внутренней работы системы (их трогать не полагается).

По мне getSize относится ко вторым, а getPreferredSize к первым. И на это есть свои причины:
*) в литературе в качестве примеров указывали для переопределения именно preferredSize
*) внутри компонента есть понятие size и getSize должен именно его возвращать (как бин-геттер) и ничего другого
*) size - возвращает размер (это ОБЪЕКТИВНЫЙ параметр компонента), а вот preferedSize - это Субъективный размер по мнению автора компонента. Согласитесь, что машина не может понять какой бы размер был самым лучшим. И без человека здесь никак.

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

Например в том же примере. Если скролл больше чем желаемый размер, то компонент получает весь размер скролла. (помойму) А если размер не влизает в отведённую область, то устанавливается именно желаемый размер.

Да и зачем переопределять getSize если размер можно самому задать через setSize?

Автор: Lisus 6.10.2008, 23:20
Народ, проблема осталась.
Если не добавлять СкроллПане, а выводить напрямую в фрейм мою панель, то при добавлении новых строк компонент ужимается.
Т.е. если сам фрейм растянуть на 700, а компонент в длину 500, то после принудительного задания размера получается, что компонент занимает всего 5\7 длинны фрейма. В то время как менеджер расскладок должен его вытягивать на всю длинну.
Значит должно быть событие, которое сообщает об изменении размера, но чтобы вызывался менеджер расскладки и уже сам дул какой размер назначить компоненту.

setSize - не подходит, он задаёт размер жестко.

Автор: Старовъръ 6.10.2008, 23:57
Ну вобщем-то size трогать, мне кажется, не следует. Может подобрать подходящий менеджер?

Автор: Dims 7.10.2008, 00:02
Вообще-то в инструкции предлагается переопределять действительно getPreferredSize: https://www.cs.auckland.ac.nz/references/java/java1.5/tutorial/uiswing/painting/practice.html

Но мне всё равно кажется это нелогичным.

Добавлено через 6 минут и 16 секунд
Цитата(Lisus @  6.10.2008,  14:15 Найти цитируемый пост)
*) внутри компонента есть понятие size и getSize должен именно его возвращать (как бин-геттер) и ничего другого

Зависит от того, насколько Вы решаете использовать функционал базового класса.


Цитата(Lisus @  6.10.2008,  14:15 Найти цитируемый пост)
size - возвращает размер (это ОБЪЕКТИВНЫЙ параметр компонента), а вот preferedSize - это Субъективный размер по мнению автора компонента. 

Я воспринимаю иначе. size -- это действительно объективный размер, а вот preferredSize -- это не субъективный, а желаемый размер. Если Вы переопределили paint и нарисовали в нём, допустим, квадрат размером 100х100, то у вас будет объективный размер 100х100. Это не желаемый размер, на который менеджер может наплевать, а именно реальный размер компонента. И тут уже неважно, что там хранится в переменных width и height. Их надо либо правильно заполнить, либо скрыть.

Добавлено через 9 минут и 24 секунды
Цитата(Lisus @  6.10.2008,  23:20 Найти цитируемый пост)
Если не добавлять СкроллПане, а выводить напрямую в фрейм мою панель, то при добавлении новых строк компонент ужимается.

Не совсем понятно, что происходит.

Цитата(Lisus @  6.10.2008,  23:20 Найти цитируемый пост)
setSize - не подходит, он задаёт размер жестко.

Наоборот, setSize задаёт размер нежёстко, так как после задания размера при помощи setSize, никто не мешает менеджеру раскладок задать другой размер. 

Вероятно, надо переопределить ещё и minimunSize и maximumSize

Автор: Dims 7.10.2008, 00:24
Вот кусочек кода BorderLayout:

Код

if ((c=getChild(NORTH,ltr)) != null) {
        c.setSize(right - left, c.height);
        Dimension d = c.getPreferredSize();
        c.setBounds(left, top, right - left, d.height);
        top += d.height + vgap;
    }



Видно, что он смотрит getPreferredSize, думает, а затем тупо вызывает setSize и setBounds.

Отсюда выводы:

1) getSize переопределять бессмысленно
2) нужно уметь реагировать на setSize

Иными словами, в общем случае, изнутри компонента никаким образом нельзя добиться, чтобы он имел какой-то заданный размер. Компонент должен подчиняться лэйаут менеджеру и может только скромно просить его о чём-то при помощи preferred.

Я был неправ, когда отождествлял размер рисунка с размером компонента. Размер рисунка, если можно так выразиться, это размер содержимого компонента. Отключить изменение размера компонента со стороны менеджера мы не можем, поэтому варианта только 2: либо рисовать рисунок такого размера, какой велит менеджер, либо рисовать свой размер, но тогда рисунок будет либо обрезан, либо будет болтаться в углу компонента.

Автор: Lisus 7.10.2008, 09:31
Цитата(Dims @  7.10.2008,  00:02 Найти цитируемый пост)
Не совсем понятно, что происходит.


У меня в большом фрейме после программного добавления размер становиться таким, каким я задал в setSize.
соответственно фон рисуется только в длину 500 пикселов, в то время как сам фрейм в длину 700, и поэтому разница 200 не перерисовывается (не заполняется фоном).
как только повести размер фрейма чуть-чуть , то компонент принимает уже нормальные размеры - во весь фрейм.

Вот и нужно чтобы он это делал уже при добавлении строк.
Корочве вот так получается:
+++++++++++++++++++++++++++
+@@@@@@@@@@@@@                 +
+@@@@@@@@@@@@@                 +
+@@@@@@@@@@@@@                 +
+@@@@@@@@@@@@@                 +
+@@@@@@@@@@@@@                 +
+++++++++++++++++++++++++++

А надо чтобы менеджер растягивал.
При вызове setSize - размеры устанавливаются жестко и никакой менеджер не вызывается.
А НАДОБЫ.

возможно стоит дополнить минимумом и максимумом.

Добавлено через 10 минут и 11 секунд
Цитата(Dims @  7.10.2008,  00:24 Найти цитируемый пост)
Иными словами, в общем случае, изнутри компонента никаким образом нельзя добиться, чтобы он имел какой-то заданный размер. Компонент должен подчиняться лэйаут менеджеру и может только скромно просить его о чём-то при помощи preferred.


Как заставить этот грёбанный менеджер врубиться? Пока для меня это главная проблема.


Цитата(Dims @  7.10.2008,  00:24 Найти цитируемый пост)
Отключить изменение размера компонента со стороны менеджера мы не можем, поэтому варианта только 2: либо рисовать рисунок такого размера, какой велит менеджер, либо рисовать свой размер, но тогда рисунок будет либо обрезан, либо будет болтаться в углу компонента. 


... либо добавлять свойство align, и рисовать Справа , в Центре, Слева компонента.

Насчёт субъективного, я имел в виду, что желания сами по себе субъективны.

Автор: Lisus 7.10.2008, 09:48
Цитата(Dims @  7.10.2008,  00:24 Найти цитируемый пост)
c.setSize(right - left, c.height);
        Dimension d = c.getPreferredSize();
        c.setBounds(left, top, right - left, d.height);


Странно, я всегда думал, что setBounds внутри себя должен сам вызывать setSize и setLocation.
Т.е. что размер, и расположение пользуются теме же переменными, что и Bounds?
Я считал, что setLocation и setSize - это обрезанный setBounds, когда надо переопределить только 2 размера из 4-х.

Автор: dorogoyIV 7.10.2008, 11:09
Цитата(Lisus @  7.10.2008,  09:31 Найти цитируемый пост)
Как заставить этот грёбанный менеджер врубиться? Пока для меня это главная проблема.

Код

  myPanel.getLayout().layoutContainer(myPanel);

Автор: Lisus 7.10.2008, 11:19
Блин, как всё просто...
А на Нулл проверять не надо? а то может нет менеджера.

Автор: dorogoyIV 7.10.2008, 11:29
Цитата(Lisus @  7.10.2008,  11:19 Найти цитируемый пост)
А на Нулл проверять не надо? а то может нет менеджера.

надо

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)