Страницы

Поиск по вопросам

Показаны сообщения с ярлыком swing. Показать все сообщения
Показаны сообщения с ярлыком swing. Показать все сообщения

суббота, 8 февраля 2020 г.

Разработка настольного приложения для анализа данных

#c_sharp #wpf #java #swing


Доброго времени суток.
У меня на работе начинается новый проект по разработке приложения для анализа статистических
данных. Приложение будет работать с базой данных sql server. ОС Windows. Но есть нюанс... 
Мое место работы - это государственное учреждение, где требуется работа с информацией,
имеющей гриф секретности. Устанавливаться и использоваться ПО будет у нас.
Все бы ничего, но на рабочих машинах будущих пользователей будет установлено ПО Страж
3 и проведена аттестация рабочих мест на работу с секретными данными. Эта аттестация
пройдет в ближайшее время, и как мне объяснили, после данного мероприятия изменять
конфигурацию рабочих машин пользователей не будет возможным (показания, правда, расходятся
- я спрашивал троих человек, и трое дали разные варианты ответов). 
Суть такая - после аттестации менять железо и ПО на машинах будет нельзя (это худший
вариант ответа). 
И тут возникает вопрос: а что лучше выбрать для разработки. Хочется устанавливать
ПО пользователям с периодом в 2 недели, но там возникают трудности... для запуска java
приложения необходимо дать права только на jre и потом не напрягать IT с просьбой установки
или изменения паспорта компьютера и т.д. А вот для запуска wpf приложения потребуется
каждый раз искать этих неуловимых товарищей и привлекать к обновлению ПО у пользователя
на машине.
Что посоветуете выбрать java swing или wpf? Трудности я приблизительно постарался
описать. Опыт есть с обоими платформами.    


Ответы

Ответ 1



Из моего опыта -- Swing намного неудобнее, нелогичнее, медленнее и просто хуже WPF, что вопросов вообще никогда не возникало. Хотя на Swing'е в принципе можно создать нормально выглядящее приложение, по факту нативные виджеты выглядят в стиле Motif/CDE, layout manager отвратителен (некоторые свойства действуют в одном случае и не действуют в другом, простое выравнивание вправо/влево сопряжено с нетривиальными танцами с бубном), визуальный редактор производит код, глядя в который хочется плакать, нету XAML, binding'ов, стилей, анимации, кодировать приходится в стиле WinForms, 19 век, в общем. Кроме того, ваш опыт разработчика на WPF пригодятся на рынке труда существенно больше, чем опыт в Swing, всё же Java не снискала славы десктопного языка. Резюме: если есть возможность, выбирайте WPF. А вот для запуска wpf приложения потребуется каждый раз искать этих неуловимых товарищей и привлекать к обновлению ПО у пользователя на машине. Ы? Один раз устанавливаете .NET 4.5 и всё. Если вы говорите об обновлениях, то обновляются все -- и .NET, и Java, и эти обновления при необходимости вполне можно отключить на уровне групповых политик (спросите вашего админа, он знает лучше).

Ответ 2



Если честно, не понял, почему с WPF сложней. Мне кажется, стоит выбрать WPF.

понедельник, 3 февраля 2020 г.

Ищу аналог функции WebBrowser из WindowsForms (С#) в Intellij Idea, в Swing редакторе

#java #c_sharp #swing #webbrowser


Ищу аналог функции WebBrowser из WindowsForms (С#) в Intellij Idea (Java), в Swing
редакторе, из предустановленных ничего нет, вот я думаю может есть какие-нибудь модуль
расширения для этого, в частности мне нужно создать форму содержащее информацию из
интернета. Ядро любое можно (не только IE6 как там ^_^), просто не могу найти подобного
в сети, плохо ищу, может кто-нибудь посоветует?)
    


Ответы

Ответ 1



Например: JxBrowser (на движке Chromium) Браузер из состава DJProject

Ответ 2



Тоже советую насчет DJProject, в отличие от JxBrowser, они бесплатны. И легко вставляются в swing приложение: JWerBrowser webBrowser = new JWebBrowser(); webBrowser.navigate(WebServer.getDefaultWebServer().getClassPathResourceURL(getClass().getName(), "start.html")); webBrowser.setBarsVisible(false); add(webBrowser, BorderLayout.CENTER); Если будут проблемы с js - для таких случаев есть Rhino.

Ответ 3



Как вариант, в JavaFX есть WebView. Вот ссылка на хабр, где довольно подробно показаны примеры его использования. Входит в Java SE.

воскресенье, 26 января 2020 г.

Проблема с обновлением компонентов

#java #swing


Хочу создать анимацию во фрейме, которой можно управлять. Создаю класс AnimatedComponent:

class AnimatedComponent extends JComponent
{
    private static final long serialVersionUID = 1L;

    public AnimatedComponent()
    {
        Timer timer = new Timer( 30, action -> repaint() );
        timer.start();
    }

    @Override public Dimension getPreferredSize()
    {
        return new Dimension( 300, 200 );
    }

    @Override public void paintComponent( Graphics g )
    {
        // animation
    }
}


Во фрейм я введу экземпляр класса AnimatedComponent и другие компоненты, которые
будут влиять на его отображение:

class AnimatedFrame extends JFrame
{
    private static final long serialVersionUID = 1L;

    private AnimatedComponent animatedComponent = new AnimatedComponent();
    private JCheckBox check1 = new JCheckBox("check1");
    private JCheckBox check2 = new JCheckBox("check2");
    private JSlider slider1 = new JSlider( 0, 200, 50 );
    private JSlider slider2 = new JSlider( 0, 200, 50 );
    private JSlider slider3 = new JSlider( 0, 200, 50 );

    public AnimatedFrame()
    {
        setLayout( new GridBagLayout() );
        add( animatedComponent, new GBC(0,0,1,5).setFill(GBC.BOTH).setWeight(0.5, 0.5) );
        add( check1, new GBC(1,0,2,1).setAnchor(GBC.CENTER) );
        add( check2, new GBC(1,1,2,1).setAnchor(GBC.CENTER) );
        add( new JLabel("SLider1"), new GBC(1,2).setAnchor(GBC.EAST) );
        add( slider1, new GBC(2,2).setFill(GBC.BOTH).setWeight(0.1, 0.5) );
        add( new JLabel("Slider2"), new GBC(1,3).setAnchor(GBC.EAST) );
        add( slider2, new GBC(2,3).setFill(GBC.BOTH).setWeight(0.1, 0.5) );
        add( new JLabel("Slider3:"), new GBC(1,4).setAnchor(GBC.EAST) );
        add( slider3, new GBC(2,4).setFill(GBC.BOTH).setWeight(0.1, 0.5) );
    }

    public static void main(String... args)
    {
        EventQueue.invokeLater(new Runnable(){
            @Override public void run()
            {
                AnimatedFrame frame = new AnimatedFrame();
                frame.pack();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setVisible(true);
            }
        });
    }
}


Код класса GBC:

class GBC extends GridBagConstraints
{
    private static final long serialVersionUID = 1L;

    public GBC(int gridx, int gridy)
    {
        this.gridx = gridx;
        this.gridy = gridy;
    }

    public GBC(int gridx, int gridy, int gridwidth, int gridheight)
    {
        this.gridx = gridx;
        this.gridy = gridy;
        this.gridwidth = gridwidth;
        this.gridheight = gridheight;
    }

    public GBC setAnchor(int anchor)
    {
        this.anchor = anchor;
        return this;
    }

    public GBC setFill(int fill)
    {
        this.fill = fill;
        return this;
    }

    public GBC setWeight(double weightx, double weighty)
    {
        this.weightx = weightx;
        this.weighty = weighty;
        return this;
    }
}


Можете сами убедиться, что программа работает некорректно. Запустите код на выполнение.
Не растягивайте окно по вертикали и растяните по горизонтали. Сейчас попробуйте изменить
состояние JSlider-ов или JCheckBox-ов. Они начинают отображаться неправильно. Если
после этого опять изменить размер фрейма, то компоненты перерисуются правильно.

Если же изменить расположение компонентов, то проблема исчезнет:

public AnimatedFrame()
{
    setLayout( new GridBagLayout() );
    add( animatedComponent, new GBC(2,0,1,5).setFill(GBC.BOTH).setWeight(0.5, 0.5) );
    add( check1, new GBC(0,0,2,1).setAnchor(GBC.CENTER) );
    add( check2, new GBC(0,1,2,1).setAnchor(GBC.CENTER) );
    add( new JLabel("SLider1"), new GBC(0,2).setAnchor(GBC.EAST) );
    add( slider1, new GBC(1,2).setFill(GBC.BOTH).setWeight(0.1, 0.5) );
    add( new JLabel("Slider2"), new GBC(0,3).setAnchor(GBC.EAST) );
    add( slider2, new GBC(1,3).setFill(GBC.BOTH).setWeight(0.1, 0.5) );
    add( new JLabel("Slider3:"), new GBC(0,4).setAnchor(GBC.EAST) );
    add( slider3, new GBC(1,4).setFill(GBC.BOTH).setWeight(0.1, 0.5) );
}


Кажется мне, что это как-то связано с постоянной перерисовкой компонента animatedComponent.
Объясните, пожалуйста, подробно, почему так происходит, и как правильно обойти эту
проблему?
    


Ответы

Ответ 1



Добавьте в конец конструктора AnimatedFrame() код: check1.setMinimumSize( check1.getPreferredSize() ); check2.setMinimumSize( check2.getPreferredSize() ); slider1.setMinimumSize( slider1.getPreferredSize() ); slider2.setMinimumSize( slider2.getPreferredSize() ); slider3.setMinimumSize( slider3.getPreferredSize() ); Компоненты перестают схлопываться и ресайзинг происходит довольно прилично IMHO.

пятница, 24 января 2020 г.

Можно ли использовать MVVM там, где нет data binding?

#java #swing #mvvm


На Википедии про MVVM написано:


  MVVM удобно использовать вместо классического MVC и ему подобных в тех случаях,
когда в платформе, на которой ведётся разработка, присутствует «связывание данных».



Объясните, пожалуйста, что такое связывание данных? В сети совсем
мало информации. Я могу привести свои догадки на примере Delphi. Там
можно поместить на форму DBGrid, и данные из базы будут попадать в
него. То есть, они будут как бы привязаны к нему. Но, если, конечно, в
настройках правильно все прописать. Это и есть связывание данных?
Тогда, как я понимаю, в Java Swing нет никакого data binding. Можно ли там использовать
MVVM? В принципе, можно, наверное, просто самому написать функции bind и backBind,
в которых нужные данные туда-сюда передавать?
Если можно, то стоит ли? Или лучше MVC или MVP? Понимаю, что так однозначно сказать
нельзя, от ситуации, наверное, зависит. У меня десктопный проект с небольшой базой
данных (JDBC и MySql), но графический интерфейс довольно объемный и сложный, с большим
количеством функций. Предметная область для моего приложения — сложная алгоритмическая
задача (задача о ранце, кому интересно). Подскажите пожалуйста, что в моей ситуации
лучше использовать — MVC, MVP или MVVM (опыта ни в чем из этого не имею).

    


Ответы

Ответ 1



Шаблон MVVM больше ориентирован на технологии .Net от Microsoft, в частности под язык разметки XAML. В WPF или Silverlight привязка данных имеет большое значение, трудно представить серьёзное приложение без механизма привязок (bindings). Есть альтернатива на Java - платформа JavaFX. Привязка подразумевает взаимодействие двух объектов: источника и приемника. Объект-приемник создает привязку к определенному свойству объекта-источника. В случае модификации объекта-источника, объект-приемник также будет модифицирован (поведение зависит от типа привязки). Всего есть 4 типа привязок. • OneWay: свойство объекта-приемника изменяется после модификации свойства объекта-источника. • OneTime: свойство объекта-приемника устанавливается по свойству объекта-источника только один раз. В дальнейшем изменения в источнике никак не влияют на объект-приемник. • TwoWay: оба объекта - применки и источник могут изменять привязанные свойства друг друга. • OneWayToSource: объект-приемник, в котором объявлена привязка, меняет объект-источник. • Default: по умолчанию (если меняется свойство TextBox.Text, то имеет значение TwoWay, в остальных случаях OneWay). Пример Самому написать механизм с такой функциональностью будет не просто. Смотрите на платформу JavaFX, если выберите MVVM и Java. Если .Net то WPF или универсальные приложения под windows 10. Делая Web приложение посоветую Spring MVC.

Ответ 2



На счет какой того какой паттерн использовать я особо ничего сказать не могу. Если нужен красивый, высоконагруженный интерфейс, я бы использовал JavaFX, а там классический паттерн MVC. А на счет связывания данных, такую фичу я встречал в NetBeans'е (как в старом добром дельфи - "без единной строчки кода"), там есть связывание с помощью своих библиотек (они потом прикрепляются к проекту).

Динамическое построение GUI

#java #swing


Здравствуйте! Не знаю, правильно ли я подобрал термин "динамическое построение",
но суть вот в чём.

Необходимо реализовать метод, который бы через цикл выводил компоненты различных
типов в определённом порядке. Скажем, сначала идут 3 JTextField (Имя, Фамилия, Отчество)
- потом два JComboBox (Пол, Страна) и дальше другие текстовые поля. Метка и текстовое
поле (или список) заворачиваются в JPanel. Каждой метке присваивается имя и текст.
Текстовому полю или списку присваивается имя.



Для начала, я думаю, нужно где то сохранить имена меток и текстовых полей. А также
текст меток:

Multimap labels;
List componentsName;
List componentsList //список выводимых компонентов: "JTextField","JTextField","JComboBox"
etc.. 

public void drawComponents(Multimap labels, List componentsName,
List componentsList ) {
            /*do something*/
        }


Как создать красивый цикл перебора элементов и вывести компоненты на форму?
    


Ответы

Ответ 1



Предложу вам такой вариант: создайте класс описывающий этап(сократите с 3х коллекций до одной мапы). Он будет содержать поля описывающие каждый этап (имя + элемент который надо создать + можно добавить поле для результата) занести в мапу номер этапа - ключ, объект этапа - значение в цикле по индексу этапа вытаскивать объект из мапы, инициализировать все элементы (label, JTextField ...), сделать их видимыми ждать ввода от пользователя, нажатия кнопки "далее", заносить результат ввода в объект этапа делать невидимыми все элементы GUI. По итогу вы получите мапу, со всеми этапами + результатами ввода на этих этапах.

Ответ 2



Думаю, можно попробовать просто показывать компоненты по очереди - объявляешь все, потом задаёшь размеры и свойства, а при добавлении на форму дописываешь component.setVisible(false); где component - интересующий компонент. Потом, в конце каждой проверки, если данные верны - вызываешь у всех предыдущих компонентов component.setVisible(false), а у следующих - component.setVisible(true)

суббота, 11 января 2020 г.

Стоит ли сейчас использовать Java Swing в новых проектах

#java #javafx #swing


Коллеги, добрый день. 
Посоветуйте, стоит ли сейчас использовать Java Swing в новых проектах. Проект уже
пишется, но он будет переписан в ближайшем будущем вероятно всего на JavaFX. Сейчас
вообще в мире Java много изменений происходит, даже JavaFX хотят выпилить из Java SE,
не ясна судьба данных технологий в будущем. 
    


Ответы

Ответ 1



Тому, кто распространяет эту байку про выпиливание JavaFX, надо в голову гвоздь забить! Сейчас идёт процесс модуляризации стандартной библиотеки. Чтобы в будущем программисты могли поставлять с приложением компактную версию виртуальной машины с минимально необходимым набором библиотек. В рамках этого процесса JavaFX вынесли в отдельный модуль. Так же, как например JAXB - средства для работы с XML и JSON. В одной из следующих версий в отдельный модуль вынесут и Swing. По сути вопроса: Swing вполне пригоден и достаточен для разработки программ с оконным графическим интерфейсом, поэтому нет причин бросаться переписывать существующий код на JavaFX. Но для новых проектов стоит предпочесть более современную и более функциональную библиотека JavaFX.

пятница, 10 января 2020 г.

Как правильно использовать AbstractTableModel и DefaultTableColumnModel

#java #swing #jtable


Имеется задача, построить таблицу, столбцы которой являются полями в классе CustomItem.

package com.kolos.Table;

import java.util.Date;

public class CustomItem {
    public Integer id;
    public String name;
    public Date date;
    public CustomItem(Integer id, String name, Date date) {
        this.id = id;
        this.name = name;
        this.date = date;
    }
}


Класс CustomColumnModel:

package com.kolos.Table;

import javax.swing.table.DefaultTableColumnModel;
import javax.swing.table.TableColumn;
import java.lang.reflect.Field;

public class CustomColumnModel extends DefaultTableColumnModel{
    public CustomColumnModel(Class tClass) {
        for (Field tField : tClass.getDeclaredFields()){
            TableColumn tColumn = new TableColumn();
            tColumn.setHeaderValue(tField.getName());
            tColumn.setModelIndex(getColumnCount());
            tColumn.setIdentifier(tField);
            tField.setAccessible(true);
            this.addColumn(tColumn);
        }
    }
}


Модель таблицы:

package com.kolos.Table;

import javax.swing.table.AbstractTableModel;
import java.lang.reflect.Field;
import java.util.Date;

public class CustomDataModel extends AbstractTableModel{

    private CustomColumnModel columnModel;
    private CustomItem[] dataList = new CustomItem[3];

    public CustomDataModel(CustomColumnModel columnModel) {
        this.dataList = new CustomItem[3];
        this.dataList[0] = new CustomItem(1, "Fist", new Date());
        this.dataList[1] = new CustomItem(2, "Second", new Date());
        this.dataList[2] = new CustomItem(3, "Third", new Date());
        this.columnModel = columnModel;
    }

    @Override
    public int getRowCount() {
        return this.dataList.length;
    }

    @Override
    public int getColumnCount() {
        return this.columnModel.getColumnCount();
    }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        try {
            Field tField = ((Field)     columnModel.getColumn(columnIndex).getIdentifier());
            return tField.get(dataList[rowIndex]);
        } catch (IllegalAccessException e) {
            return "IllegalAccessExeption";
        }
    }
}


Класс CustomTable:

package com.kolos.Table;

import javax.swing.*;

public class CustomTable extends JTable{
    private CustomDataModel dataModel;
    private CustomColumnModel columnModel;
    public CustomTable() {
        setAutoCreateColumnsFromModel(false);
        columnModel = new CustomColumnModel(CustomItem.class);
        setColumnModel(columnModel);
        dataModel = new CustomDataModel(columnModel);
        setModel(dataModel);
    }
}


Фрейм:

package com.kolos;

import com.kolos.Table.CustomTable;
import javax.swing.*;
import java.awt.*;

public class MainFrame extends JFrame{
    public MainFrame() {
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        this.setSize(new Dimension(800, 600));
        this.setLayout(new GridBagLayout());

        //create table
        JScrollPane scrollPane = new JScrollPane();
        CustomTable table = new CustomTable();
        scrollPane.setViewportView(table);

        this.add(scrollPane, new GridBagConstraints(
                0, 0, 1, 1, 1, 1, GridBagConstraints.NORTH, GridBagConstraints.BOTH,
new Insets(0, 0, 0, 0), 0, 0
        ));

    }
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                MainFrame mainFrame = new MainFrame();
                mainFrame.setVisible(true);
            }
        });
    }

}


Проблема в том что при перетаскивании столбцов (например 2 -> 0) заголовки переносятся,
а значения из модели (получаемые методом getValueAt ) переносятся  непонятным образом.




Собственно почему так и как исправить?
    


Ответы

Ответ 1



Дело в том, что когда вы перемещаете столбцы, они реально меняются местами в списке столбцов ColumnModel, при этом в TableModel.getValueAt координаты ячейки приходят уже пересчитанными в пространство модели (значение поля TableColumn.modelIndex) Поэтому когда вы ставите третью колонку на место первой, для показа первой колонки вызывается getValueAt( rowIndex, 2 ), вы берете у модели столбцов колонку по индексу 2, но туда уже сдвинулась средняя колонка, которая отвечала за вывод имени. Мне кажется, лучше всего держать получение данных по номеру столбца прямо в модели таблицы. Заведите список Field для доступа к данным, заполните его в конструкторе модели, как вы сейчас делаете в CustomColumnModel, и возвращайте имя колонки в TableModel.getColumnName(int). А TableColumnModel вообще не трогать. public class CustomDataModel extends AbstractTableModel { private CustomItem[] dataList = new CustomItem[3]; private List fields = new ArrayList<>(); public CustomDataModel( Class tClass ) { this.dataList = new CustomItem[3]; this.dataList[0] = new CustomItem(1, "Fist", new Date()); this.dataList[1] = new CustomItem(2, "Second", new Date()); this.dataList[2] = new CustomItem(3, "Third", new Date()); for (Field tField : tClass.getDeclaredFields()){ tField.setAccessible(true); fields.add( tField ); } } @Override public int getRowCount() { return this.dataList.length; } @Override public int getColumnCount() { return this.fields.size(); } @Override public String getColumnName( int column ) { return fields.get( column ).getName(); } // можно возвращать тип столбца, тогда JTable будет выбирать соотв. TableCellRenderer // @Override // public Class getColumnClass( int column ) { // return fields.get( column ).getType(); // } @Override public Object getValueAt(int rowIndex, int columnIndex) { try { Field tField = fields.get( columnIndex ); return tField.get(dataList[rowIndex]); } catch (IllegalAccessException e) { return "IllegalAccessExeption"; } } } public class CustomTable extends JTable{ private CustomDataModel dataModel; public CustomTable() { setAutoCreateColumnsFromModel( true ); // не забудьте вернуть автосоздание dataModel = new CustomDataModel( CustomItem.class ); setModel( dataModel ); } } Либо вы можете в getValueAt искать нужную колонку по совпадению columnIndex и tableColumn.getModelIndex(), или воспользоваться методами jTable.convertColumnIndexToView( columnIndex ) (но нужно держать в модели ссылку на таблицу), или sun.swing.SwingUtilities2.convertColumnIndexToView( columnModel, columnIndex ), которые делают то же самое.

воскресенье, 29 декабря 2019 г.

Изменение цвета JProgressBar

#java #swing


Нужно изменить цвет полоски прогресса. Метод setBackground не помогает.

UIManager.put("ProgressBar.background", Color.ORANGE);
UIManager.put("ProgressBar.foreground", Color.BLUE);
UIManager.put("ProgressBar.selectionBackground", Color.RED);
UIManager.put("ProgressBar.selectionForeground", Color.GREEN);


Это тоже не оказывает никакого эффекта.
Как можно изменить цвет полосы прогресса?
Предполагаю, что нужно изменить метод, в котором происходит отрисовка, но найти этот
метод не могу.
    


Ответы

Ответ 1



Метод setBackground изменяет цвет фона. Для того чтобы изменить цвет самой полосы прогресса нужно использовать метод setForeground. Например: jProgressBar1.setForeground(Color.YELLOW);

Ответ 2



Вариант с UIManager, описанный в англоязычном Stack Overflow, отлично работает. Скорее всего вы что-то не так делаете. Вот пример: import java.awt.BorderLayout; import java.awt.Color; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import javax.swing.JFrame; import javax.swing.JProgressBar; import javax.swing.SwingUtilities; import javax.swing.UIManager; public class Main extends JFrame { private int counter = 0; private JProgressBar progressBar; public Main() { super("JProgressBar"); setSize(300, 50); UIManager.put("ProgressBar.background", Color.ORANGE); UIManager.put("ProgressBar.foreground", Color.BLUE); UIManager.put("ProgressBar.selectionBackground", Color.RED); UIManager.put("ProgressBar.selectionForeground", Color.GREEN); progressBar = new JProgressBar(); getContentPane().add(progressBar, BorderLayout.CENTER); WindowListener wndCloser = new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }; addWindowListener(wndCloser); setVisible(true); while (counter <= 100) { Runnable runme = () -> progressBar.setValue(counter); SwingUtilities.invokeLater(runme); counter++; try { Thread.sleep(100); } catch (Exception ignored) {} } } public static void main(String[] args) { new Main(); } } Модифицировал пример JProgressBar по ссылке.

среда, 18 декабря 2019 г.

Таймер в Java Swing

#java #swing


Как создать таймер, который по прошествии заданного времени выполнит какое-либо действие?

Например, нужно сказать System.out.print("Hi!"); через 4 секунды
    


Ответы

Ответ 1



Смотрим на javax.swing.Timer Пример: import javax.swing.Timer; //Будет вызыватся каждую секунду timer = new Timer(1000, new ActionListener( public void actionPerformed(ActionEvent ev) { System.out.println("WOW!"); })); timer.start();

Ответ 2



Как альтернативный вариант (хотя Timer тут удобнее) с помощью стороннего Thread'a, чтобы не мешал основному: public class Test { public static void main(String args[]) { new Thread(new Runnable() { public void run() { while(true) { //бесконечно крутим try { Thread.sleep(4000); // 4 секунды в милисекундах System.out.println("Hi!"); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); } } Либо, конечно, с помощью Таймера - переписать метод run(): import java.util.*; public class Test { public static void main(String args[]) { Timer timer = new Timer(); timer.schedule(new SayHello(), 0, 4000); // ставим по расписанию выполнять SayHello каждые 4 секунды } } class SayHello extends TimerTask { public void run() { System.out.println("Hi!"); } }

Ответ 3



Вот написал вам хороший пример package javaapplication24; import java.util.Timer; import java.util.TimerTask; public class JavaApplication24 { public static void main(String[] args) { final Timer time = new Timer(); time.schedule(new TimerTask() { int i = 0; @Override public void run() { //ПЕРЕЗАГРУЖАЕМ МЕТОД RUN В КОТОРОМ ДЕЛАЕТЕ ТО ЧТО ВАМ НАДО if(i>=2){ System.out.println("Таймер завершил свою работу"); time.cancel(); return; } System.out.println("Прошло 4 секунды"); i = i + 1; } }, 4000, 4000); //(4000 - ПОДОЖДАТЬ ПЕРЕД НАЧАЛОМ В МИЛИСЕК, ПОВТОРЯТСЯ 4 СЕКУНДЫ (1 СЕК = 1000 МИЛИСЕК)) } }

суббота, 30 ноября 2019 г.

Тяжелые и легкие компоненты в Java

#java #swing #awt


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


Ответы

Ответ 1



Если очень коротко, то: Тяжелые компоненты - это компоненты, которые имеют платформенно-зависимую реализацию. Легкие компоненты - это компоненты, полностью написанные на Java и не зависящие от peer-интерфейсов. Пояснение Приложения Java должны работать в любой, или хотя бы во многих графических средах. В связи с этим, требуется библиотека классов, независимая от конкретной графической системы, поэтому в JDK задачу решили следующим образом: были разработаны интерфейсы (также называются peer-интерфейсами), содержащие методы работы с графическими объектами. Классы библиотеки AWT (Abstract Window Toolkit) реализуют эти интерфейсы для создания приложений. Приложения Java используют данные методы для размещения и перемещения графических объектов, изменения их размеров, взаимодействия объектов. Для работы с экраном в конкретной графической среде эти интерфейсы реализуются отдельно для каждой. В каждой графической среде это делается по-своему: средствами этой оболочки (с помощью графических библиотек данной операционной системы). При выводе объекта, созданного в приложении Java и основанного на peer-интерфейсе, на экране создается парный ему (peer-to-peer) объект графической подсистемы операционной системы, который и отображается на экране. Эти объекты тесно взаимодействуют во время работы приложения. Поэтому графические объекты AWT в каждой графической среде имеют вид, характерный для этой среды и выглядят как "родные" окна. Начиная с версии JDK 1.1 библиотека AWT была переработана. В нее добавлена возможность создания компонентов, полностью написанных на Java и не зависящих от peer-интерфейсов. Такие компоненты стали называть "легкими" (lightweight) в отличие от компонентов, реализованных через peer-интерфейсы, названных "тяжелыми" (heavy). "Легкие" компоненты везде выглядят одинаково, сохраняют заданный при создании вид (look and feel). Более того, приложение можно разработать таким образом, чтобы после его запуска можно было выбрать какой-то определенный вид: Motif, Metal, Windows 95 или какой-нибудь другой, и сменить этот вид в любой момент работы. Эта интересная особенность "легких" компонентов получила название PL&F (Pluggable Look and Feel) или plaf. Была создана обширная библиотека "легких" компонентов Java, названная Swing. В ней были переписаны все компоненты библиотеки AWT, так что библиотека Swing может использоваться самостоятельно, несмотря на то, что все классы из нее расширяют классы библиотеки AWT. В данный момент Swing является основной библиотекой пользовательского интерфейса в Java, AWT - не дорабатывается. Использование библиотеки Swing - почти всегда предпочтительнее чем AWT, за исключением тех случаев, когда нужна обратная совместимость с Java 1.

Потеря точности Bigdecimal

#java #swing #bigdecimal


Создается переменная BigDecimal bet = new BigDecimal(0.00000010) и передается на
сервер и он возвращает значение отличное от ожидаемого.
Не понятно почему так.
    


Ответы

Ответ 1



При использовании конструктора, принимающего на вход double, возникает неприятная особенность, отмеченная в документации. Поскольку вещественное число при переводе в двоичную форму представляется, как правило, бесконечной двоичной дробью, то при создании объекта, например, BigDecimal(0.1), мантисса, хранящаяся в объекте, окажется очень большой. (ссылка на статью) Поэтому число будет сохранено неточно. В связи с этим лучше используйте конструктор, принимающий на вход строку: Bigdecimal bet = new Bigdecimal("0.00000010");

вторник, 16 июля 2019 г.

Работа с графикой

Добрый день. Наткнулся на вот такой пример в учебнике:
public class Tester { public static void main(String[] args) { Frame frame = new Frame(); frame.start(); } } class Frame { private JFrame frame; private Paint oval; private int x,y; Frame(){ x = y = 120; frame = new JFrame(); oval = new Paint(); } public void start() { frame.getContentPane().add(oval); frame.setSize(700, 700); frame.setVisible(true);
for(int count = 0;count <400;count++) { x++; y++; oval.repaint();
try { Thread.sleep(25); } catch (Exception ex) {
} } } class Paint extends JPanel { public void paintComponent(Graphics g) { g.setColor(Color.WHITE); g.fillRect(0, 0, this.getWidth(), this.getHeight()); g.setColor(Color.ORANGE); g.fillOval(x,y, 100, 100); } } }
Данный код рисует окружность в окне и используя цикл перерисовывает её, перемещая по диагонали. Так вот, изначально автор не добавлял эти две строки кода:
g.setColor(Color.WHITE); g.fillRect(0, 0, this.getWidth(), this.getHeight());
То есть не зарисовывал всё окно белым цветом перед рисованием фигуры на новой позиции. В результате фигура расплывалась. Как по мне это костыль. Когда я писал этот пример, я в учебник не смотрел, и метод repaint(); вызывал не у класса Paint, а у формы JFrame, у меня сразу всё нормально отображалось. Так вот собственно вопрос, какой из методов вы считаете целесообразней использовать? Вот мой код:
public class Tester { public static void main(String[] args) { Frame frame = new Frame(); frame.start(); } } class Frame { private JFrame frame; private Paint oval; private int x,y; Frame() { x = y = 120; frame = new JFrame(); oval = new Paint(); } public void start() { frame.getContentPane().add(oval); frame.setSize(700, 700); frame.setVisible(true);
for (int count = 0;count <400;count++) { x++; y++; **frame.repaint();**
try { Thread.sleep(25); } catch (Exception ex) {
} } } class Paint extends JPanel { public void paintComponent(Graphics g) { g.setColor(Color.ORANGE); g.fillOval(x,y, 100, 100); } } }


Ответ

Вообще ошибка в том, что в переопределённом методе paintComponent необходимо вызвать родительский метод:
public void paintComponent(Graphics g){ super.paintComponent(g); // <<< g.setColor(Color.ORANGE); g.fillOval(x,y, 100, 100); }
Он в частности и очистит фон и тогда вызов oval.repaint() будет работать как положено. Про это хорошо написано в документации к родительскому методу:
Further, if you do not invoke super's implementation you must honor the opaque property, that is if this component is opaque, you must completely fill in the background in a non-opaque color. If you do not honor the opaque property you will likely see visual artifacts.
Что примерно переводится как:
Далее, если вы не вызовете родительскую реализацию, вы должны учесть непрозрачность компонента, а именно, если он непрозрачный, вам необходимо полностью залить фон непрозрачным цветом. Если вы этого не сделаете, вы увидите визуальные артефакты.
Что мы и наблюдаем. Так что либо вызвать super.paintComponent(g), либо залить вручную (как у вас в коде). А как раз замена на frame.repaint() — это костыль, который скрывает истинную проблему и делает лишнюю работу (вам же не нужно перерисовывать всё окошко, нужно только содержимое перерисовать).

Логика построения MVP приложения с несколькими View-Presenter

К сожалению, все примеры из сети, которые я нашел, содержат примитивную логику построения MVP. Все компоненты инициализируются и связываются в main-методе. А как быть если пар View-Presenter N-ое число? Например, это могут быть модальные окна, или вкладки. Кому, с точки зрения архитектуры, будет правильно делегировать логику создания и инциализации нового View и связи его с Presenter ? Фабрике ?
DI использовать не получается, поскольку возникает круговая зависимость. View нужна ссылка на Presenter, а Presenter нужна ссылка на View.
Буду признателен за пример, или ссылку на рабочее swing приложение, использующее MVP.


Ответ

Я нашел ответ свой вопрос. Логика инциализации может быть передана View или Presenter, в зависимости от выбранного паттерна: Supervising Controller или Passive View. Тут подробное описание. Всем спасибо.

понедельник, 15 июля 2019 г.

swing KeyListener не отлавливает нажатие

import javax.swing.*; import java.awt.*;
public class Main { public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() { public void run() {
JFrame frameMain = new JFrame(); frameMain.setLayout(new BorderLayout()); JPanel label = new JPanel(); JButton button = new JButton("Button"); label.add(button); // Вопрос 3
frameMain.add(label, BorderLayout.NORTH); HelloComponent helloComponent = new HelloComponent(); frameMain.add(helloComponent, BorderLayout.CENTER); frameMain.addKeyListener(helloComponent); // Вопрос 2
frameMain.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frameMain.setSize(400, 400); frameMain.setVisible(true);
} });
} }

import javax.swing.*; import java.awt.*; import java.awt.event.*;
public class HelloComponent extends JComponent implements KeyListener, MouseMotionListener {
String theMessage = "Hello"; int x = 10; int y = 10;
public HelloComponent() {
//addKeyListener(this); // Вопрос 1 addMouseMotionListener(this); }
public void paintComponent (Graphics g){ g.drawString(theMessage, x, y); }
@Override public void keyTyped(KeyEvent e) { }
@Override public void keyPressed(KeyEvent e) { }
@Override public void keyReleased(KeyEvent e) { if(e.getKeyCode() == KeyEvent.VK_LEFT){ theMessage = "olleH"; repaint(); } else if(e.getKeyCode() == KeyEvent.VK_RIGHT){ theMessage = "Hello"; repaint(); } }
@Override public void mouseDragged(MouseEvent e) { x = e.getX(); y = e.getY(); repaint();
}
@Override public void mouseMoved(MouseEvent e) { } }
Вопрос 1
Если в конструкторе добавлять addKeyListener(this), то он не работает и при этом addMouseMotionListener(this) работает нормально.
Вопрос 2
Если добавлять во Farame frameMain.addKeyListener(helloComponent); все работает, но перестает если добавлять кнопку.
Вопрос 3
Потом не удается установить фокус. При этом мышка перерисовывает как нужно.
Подскажите где и что не так?


Ответ

Компонент порождает KeyEventы, только когда находится в фокусе. Чтобы ваш компонент мог получить фокус автоматически, нужно вызвать для него setFocusable( true ), или сделать привязку клавиш через Input Map (да, isFocusable() возвращает true, но фокус не передается, так задумано (JDK-6530201)). Поскольку окно не содержит компонентов, которым может отдать фокус, оно оставляет его себе, поэтому ваш компонент получает события, порождаемые окном. Кнопка может получить фокус и получает, а ваш компонент снова не видит нажатия.
Небольшие доработки для иллюстрации:
public HelloComponent() { setFocusable( true );
addKeyListener(this); // Вопрос 1 addMouseMotionListener(this);
addFocusListener( new FocusListener() { // перерисовка при получении и потере фокуса @Override public void focusLost(FocusEvent e) { repaint(); } @Override public void focusGained(FocusEvent e) { repaint(); } });
addMouseListener( new MouseAdapter() { // запрос фокуса при нажатии мыши @Override public void mousePressed( MouseEvent e ) { requestFocusInWindow(); } }); }
public void paintComponent (Graphics g){ g.setColor( isFocusOwner() ? Color.RED : Color.ORANGE ); g.fillRect(0, 0, getWidth(), getHeight() ); g.setColor( Color.BLACK ); g.drawString(theMessage, x, y); }
Java Turtorials: How to use focus subsystem

пятница, 12 июля 2019 г.

Где лежат стандарные картинки JTree Java

Создаю программу на Java. Рисую Jtree - дерево. Для родительских элементов - он подставляет значок папок, а для дочерних элементов - значок файла. Вопрос. Где лежат данные стандартные картинки icons? Используемая ОС на всякий случай WinXP.


Ответ

В директории JRE (C:\Java\your.jre.dir) есть библиотека resources.jar с пакетами javax.swing.plaf и com.sun.java.swing.plaf - посмотрите там. В случае дополнительных L&F комплектов надо смотреть, конечно, в соответствующих jar-файлах.

суббота, 6 июля 2019 г.

Стоит ли сейчас использовать Java Swing в новых проектах

Коллеги, добрый день. Посоветуйте, стоит ли сейчас использовать Java Swing в новых проектах. Проект уже пишется, но он будет переписан в ближайшем будущем вероятно всего на JavaFX. Сейчас вообще в мире Java много изменений происходит, даже JavaFX хотят выпилить из Java SE, не ясна судьба данных технологий в будущем.


Ответ

Тому, кто распространяет эту байку про выпиливание JavaFX, надо в голову гвоздь забить! Сейчас идёт процесс модуляризации стандартной библиотеки. Чтобы в будущем программисты могли поставлять с приложением компактную версию виртуальной машины с минимально необходимым набором библиотек. В рамках этого процесса JavaFX вынесли в отдельный модуль. Так же, как например JAXB - средства для работы с XML и JSON. В одной из следующих версий в отдельный модуль вынесут и Swing.
По сути вопроса: Swing вполне пригоден и достаточен для разработки программ с оконным графическим интерфейсом, поэтому нет причин бросаться переписывать существующий код на JavaFX. Но для новых проектов стоит предпочесть более современную и более функциональную библиотека JavaFX.

воскресенье, 30 июня 2019 г.

Java, скроллинг

Пытаюсь с помощью функции setValue заставить вставать verticalScrollBar в нужное положение, все работает. Но в цикле почему-то нет.
JScrollPane sp = new JScrollPane(); JScrollBar verticalScrollBar = sp.getVerticalScrollBar(); while(iМожет, нужно как то обновлять полосу прокрутки?


Ответ

Попробуйте устанавливать положение скролла вот так:
sp.getViewport().setViewPosition(...);
И я рекомендую Вам почитать про создание анимации в Swing.
UPDATE: Вы что-то делаете не так, вот я не поленился, этот способ - работает:
import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener;
public class Main extends JFrame {
public static void main(String[] args) throws Exception{ Main main = new Main(); main.setVisible(true); Thread.sleep(1000); main.animateScrollDown(); }
private final JScrollPane scrollPane = new JScrollPane(new SimpleComponent(750,1200));
private final Timer scrollTimer = new Timer(10, new TimerListener());
{ add(scrollPane); setDefaultCloseOperation(EXIT_ON_CLOSE); setSize(new Dimension(800, 600)); setLocationRelativeTo(null); }
private void animateScrollDown() { scrollTimer.start(); }
private class TimerListener implements ActionListener { @Override public void actionPerformed(ActionEvent e) { JViewport viewport = scrollPane.getViewport(); Point viewPosition = viewport.getViewPosition(); viewPosition.y += 1; if (viewPosition.y > viewport.getView().getHeight() - viewport.getHeight()){ scrollTimer.stop(); } else { viewport.setViewPosition(viewPosition); } } }
private class SimpleComponent extends JComponent{
Dimension size;
public SimpleComponent(int width, int height){ size = new Dimension(width, height); setSize(size); setMinimumSize(size); setPreferredSize(size); setMaximumSize(size); }
@Override protected void paintComponent(Graphics g) { g.drawLine(0, 0, size.width, size.height); } } }

среда, 19 июня 2019 г.

Использование Google Guava

Пытаюсь разобраться с EventBus из библиотеки Google Guava. Хотелось бы посмотреть пример его использования относительно моей задачи. Другими словами, не могли вы показать пример использования ?
Допустим у меня есть некий класс, в котором есть вот такой вот внутренний класс-слушатель:
private class StopScanButtonListener implements ActionListener { @Override public void actionPerformed(ActionEvent e) { try { portConnection.writeByte((byte) 0xFF); portConnection.writeByte((byte) 0x05); portConnection.writeByte((byte) 0xFF); } catch (SerialPortException | NullPointerException e1) { labelState.setText("Ошибка! Возможно вы не подключились к устройству!"); labelState.repaint(); } } }
Как я могу его вынести на шину?
P.S. Было бы еще лучше, если бы вы показали пример применения относительного этого класса. Но за пример относительно класса выше тоже буду очень признателен.


Ответ

Для начала, нужно создать класс описывающий событие:
public class TestEvent {
private final String message;
public TestEvent(String message) { this.message = message; }
public String getMessage() { return message; } }
и обработчик события, ключевой тут является аннотация @Subscribe, при помощи нее шина и понимает, какое же событие мы собираемся слушать:
public class EventListener { @Subscribe public void listen(TestEvent event) { System.out.println(event.getMessage()); } }
Затем нужно где-то в приложении инициализировать экземпляр EventBus, например как общедоступное статическое поле в вашем главном классе:
public static final EventBus bus = new EventBus();
После чего зарегистрировать слушатель(слушатели) на шине:
bus.register(new EventListener());
Теперь, где бы ты ни было(у вас - внутри ActionListener для JButton) при вызове:
bus.post(new TestEvent("message"));
все слушатели этого типа события, получат его

понедельник, 10 июня 2019 г.

Локализация JFileChooser через UIManager. Где найти ключи локализации?

Пытаю локализовать JFileChooser через UIManager. Делаю это вот так:`
UIManager.put("FileChooser.saveButtonText", "Сохранить"); UIManager.put("FileChooser.cancelButtonText", "Отмена"); UIManager.put("FileChooser.fileNameLabelText", "Наименование файла"); UIManager.put("FileChooser.filesOfTypeLabelText", "Типы файлов"); UIManager.put("FileChooser.lookInLabelText", "Директория"); UIManager.put("FileChooser.saveInLabelText", "Сохранить в директории"); UIManager.put("FileChooser.folderNameLabelText", "Путь директории");
И далее, где то 20 строк. Но не могу найти всех ключей к FileChooser. Кто-нибудь знает где они?


Ответ

Список можно получить из из ресурсов Swing в зависимости от используемого Look&Fill.
Например: basic
В пакете com.sun.java.swing.plaf есть пакеты под различные локали различных look&fill. Открыв их можно собрать все ресурсы начинающиеся с FileChooser.
Кроме того там есть ресурсы и для прочих стандартных диалогов.

суббота, 1 июня 2019 г.

Как правильно использовать AbstractTableModel и DefaultTableColumnModel

Имеется задача, построить таблицу, столбцы которой являются полями в классе CustomItem
package com.kolos.Table;
import java.util.Date;
public class CustomItem { public Integer id; public String name; public Date date; public CustomItem(Integer id, String name, Date date) { this.id = id; this.name = name; this.date = date; } }
Класс CustomColumnModel
package com.kolos.Table;
import javax.swing.table.DefaultTableColumnModel; import javax.swing.table.TableColumn; import java.lang.reflect.Field;
public class CustomColumnModel extends DefaultTableColumnModel{ public CustomColumnModel(Class tClass) { for (Field tField : tClass.getDeclaredFields()){ TableColumn tColumn = new TableColumn(); tColumn.setHeaderValue(tField.getName()); tColumn.setModelIndex(getColumnCount()); tColumn.setIdentifier(tField); tField.setAccessible(true); this.addColumn(tColumn); } } }
Модель таблицы:
package com.kolos.Table;
import javax.swing.table.AbstractTableModel; import java.lang.reflect.Field; import java.util.Date;
public class CustomDataModel extends AbstractTableModel{
private CustomColumnModel columnModel; private CustomItem[] dataList = new CustomItem[3];
public CustomDataModel(CustomColumnModel columnModel) { this.dataList = new CustomItem[3]; this.dataList[0] = new CustomItem(1, "Fist", new Date()); this.dataList[1] = new CustomItem(2, "Second", new Date()); this.dataList[2] = new CustomItem(3, "Third", new Date()); this.columnModel = columnModel; }
@Override public int getRowCount() { return this.dataList.length; }
@Override public int getColumnCount() { return this.columnModel.getColumnCount(); }
@Override public Object getValueAt(int rowIndex, int columnIndex) { try { Field tField = ((Field) columnModel.getColumn(columnIndex).getIdentifier()); return tField.get(dataList[rowIndex]); } catch (IllegalAccessException e) { return "IllegalAccessExeption"; } } }
Класс CustomTable
package com.kolos.Table;
import javax.swing.*;
public class CustomTable extends JTable{ private CustomDataModel dataModel; private CustomColumnModel columnModel; public CustomTable() { setAutoCreateColumnsFromModel(false); columnModel = new CustomColumnModel(CustomItem.class); setColumnModel(columnModel); dataModel = new CustomDataModel(columnModel); setModel(dataModel); } }
Фрейм:
package com.kolos;
import com.kolos.Table.CustomTable; import javax.swing.*; import java.awt.*;
public class MainFrame extends JFrame{ public MainFrame() { this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); this.setSize(new Dimension(800, 600)); this.setLayout(new GridBagLayout());
//create table JScrollPane scrollPane = new JScrollPane(); CustomTable table = new CustomTable(); scrollPane.setViewportView(table);
this.add(scrollPane, new GridBagConstraints( 0, 0, 1, 1, 1, 1, GridBagConstraints.NORTH, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0 ));
} public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { MainFrame mainFrame = new MainFrame(); mainFrame.setVisible(true); } }); }
}
Проблема в том что при перетаскивании столбцов (например 2 -> 0) заголовки переносятся, а значения из модели (получаемые методом getValueAt ) переносятся непонятным образом.

Собственно почему так и как исправить?


Ответ

Дело в том, что когда вы перемещаете столбцы, они реально меняются местами в списке столбцов ColumnModel, при этом в TableModel.getValueAt координаты ячейки приходят уже пересчитанными в пространство модели (значение поля TableColumn.modelIndex) Поэтому когда вы ставите третью колонку на место первой, для показа первой колонки вызывается getValueAt( rowIndex, 2 ), вы берете у модели столбцов колонку по индексу 2, но туда уже сдвинулась средняя колонка, которая отвечала за вывод имени.
Мне кажется, лучше всего держать получение данных по номеру столбца прямо в модели таблицы. Заведите список Field для доступа к данным, заполните его в конструкторе модели, как вы сейчас делаете в CustomColumnModel, и возвращайте имя колонки в TableModel.getColumnName(int). А TableColumnModel вообще не трогать.
public class CustomDataModel extends AbstractTableModel {
private CustomItem[] dataList = new CustomItem[3];
private List fields = new ArrayList<>();
public CustomDataModel( Class tClass ) { this.dataList = new CustomItem[3]; this.dataList[0] = new CustomItem(1, "Fist", new Date()); this.dataList[1] = new CustomItem(2, "Second", new Date()); this.dataList[2] = new CustomItem(3, "Third", new Date());
for (Field tField : tClass.getDeclaredFields()){ tField.setAccessible(true); fields.add( tField ); } }
@Override public int getRowCount() { return this.dataList.length; }
@Override public int getColumnCount() { return this.fields.size(); }
@Override public String getColumnName( int column ) { return fields.get( column ).getName(); }
// можно возвращать тип столбца, тогда JTable будет выбирать соотв. TableCellRenderer // @Override // public Class getColumnClass( int column ) { // return fields.get( column ).getType(); // }
@Override public Object getValueAt(int rowIndex, int columnIndex) { try { Field tField = fields.get( columnIndex );
return tField.get(dataList[rowIndex]); } catch (IllegalAccessException e) { return "IllegalAccessExeption"; } } }
public class CustomTable extends JTable{ private CustomDataModel dataModel; public CustomTable() { setAutoCreateColumnsFromModel( true ); // не забудьте вернуть автосоздание dataModel = new CustomDataModel( CustomItem.class ); setModel( dataModel ); } }
Либо вы можете в getValueAt искать нужную колонку по совпадению columnIndex и tableColumn.getModelIndex(), или воспользоваться методами jTable.convertColumnIndexToView( columnIndex ) (но нужно держать в модели ссылку на таблицу), или sun.swing.SwingUtilities2.convertColumnIndexToView( columnModel, columnIndex ), которые делают то же самое.