Это то, что вы ищете? Чтобы все бары были одинаковой ширины, мне пришлось заполнить data
дополнительной строкой, поскольку в Car == 'BMW X5'
нет Country == 'US'
. Канал подготовки данных %>%
был полностью вдохновлен в на этот ответ .
library(tidyverse)
library(ggplot2)
data %>%
spread(key = Car, value = Value, fill = NA) %>%
gather(key = Car, value = Value, -Country) %>%
ggplot(aes(x = Car, y = Value, fill = Country)) +
geom_col(position = position_dodge())
Данные.
data <- read.table(text = "
Car Country Value
'Audi A6' US 23
'Audi A6' UK 12
'Audi A6' DE 19
'BMW X5' UK 8
'BMW X5' DE 5
", header = TRUE)
Два решения по сути являются реализациями одного и того же корневого шаблона проектирования (шаблон «Наблюдатель», как определено Группой Четыре.) В первом случае вы делаете сам ArrayList «наблюдаемым», во втором вы делаете объект домена, который использует список массивов, «наблюдаемым».
Моя тенденция заключалась бы в том, чтобы сделать второй: сделать доменный объект наблюдаемый. Это в первую очередь потому, что у вас могут появиться другие вещи, которые могут измениться в доменном объекте (для которого GUI должен быть обновлен). Если он уже наблюдаемый, вы уже настроены.
Обратите внимание, что у вас нет строго расширить java.util.Observable
- вы можете реализовать шаблон проектирования без этого.
Реализация Observable
в Java редко используется и плохо взаимодействует с Качели. Вместо этого используйте EventListener
.
В частности, есть ли причина не расширять AbstractListModel
или даже не использовать DefaultListModel
непосредственно при управлении содержимым списка «в другом месте в GUI»? Тогда ваше поле со списком может использовать ComboBoxModel
, который делегирует тот же экземпляр ListModel
, добавляя свою собственную реализацию для отслеживания состояния выбора.
Я имею в виду нечто подобное (но Я не проверял это):
final class MyComboBoxModel
extends AbstractListModel
implements ComboBoxModel
{
private final ListModel data;
private volatile Object selection;
MyComboBoxModel(ListModel data) {
/*
* Construct this object with a reference to your list,
* which contents are managed somewhere else in the UI.
*/
this.data = data;
data.addListDataListener(new ListDataListener() {
public void contentsChanged(ListDataEvent evt) {
fireContentsChanged(this, evt.getIndex0(), evt.getIndex1());
}
public void intervalAdded(ListDataEvent evt) {
fireContentsChanged(this, evt.getIndex0(), evt.getIndex1());
}
public void intervalRemoved(ListDataEvent evt) {
fireContentsChanged(this, evt.getIndex0(), evt.getIndex1());
}
});
}
public void setSelectedItem(Object selection) {
this.selection = selection;
fireContentsChanged(this, 0, data.getSize() - 1);
}
public Object getSelectedItem() { return selection; }
public int getSize() { return data.getSize(); }
public Object getElementAt(int idx) { return data.getElementAt(idx); }
}
Почему бы не использовать привязки?
http://wiki.eclipse.org/index.php/JFace_Data_Binding
Свяжите свой графический виджет с вашим списком. Изменения будут распространяться между двумя объектами прозрачно. Обязательно оберните вашу модель подходящей наблюдаемой, например WritableList (если вы используете ArrayList напрямую).
Always prefer composition over extension (my reference is effective java and my personal experience). extending ArrayList is simply a promise that you will not violate any of the classes invariants. It also binds you to the specific list implementation you are extending.
Вы можете переключиться на использование шаблона проектирования GUI . Или создайте ограниченную реализацию.
Создайте интерфейс формы графического интерфейса, который имеет метод DrawXArrayList (где X - какое-то значимое имя. Он имеет параметры типа ArrayList
. Создайте новый класс с именем GUIView. Он имеет по крайней мере два метода. : UpdateXArrayList и RegisterForm
Когда вы инициализируете свое приложение, форма GUI зарегистрируется в классе, реализующем GUIView. Сделайте класс, реализующий GUIView, видимым для формы.
Когда что-либо в вашей форме GUI обновляет массив, его вызовите UpdateXArrayList - последнее, что он делает. Метод UpdateXArrayList в классе, реализующем GUIView, в свою очередь будет вызывать DrawXArrayList, передавая обновленный массив. DrawXArrayList в классе формы, реализующем GUIFormInterface, затем предпримет шаги, необходимые для обновления элемента управления, отображающего ArrayList.
Хотя это кажется большим количеством шагов по сравнению с настройкой наблюдателя и слушателя. Вы имеете больше контроля над тем, как различные пользовательские действия влияют на пользовательский интерфейс, чем шаблон наблюдателя-слушателя. Кроме того, вы задокументировали в коде взаимодействие между действием пользователя и обновлениями пользовательского интерфейса.
Если вы можете добавить новый jar в приложение, проверьте глазированные списки