Я хочу сделать следующее, и мне потребуются некоторые предложения о том, как лучше всего это сделать.
У меня есть JList, который отображает файлы, которые пользователь добавляет, нажав кнопку добавления (+), и удаляет файлы, когда пользователь нажимает кнопку удаления (-). С каждым добавленным файлом я хочу связать значок, который должен указывать на статус файла. Например, если пользователь только добавил файл и не запустил файл (у меня есть еще одна кнопка JButton для запуска приложения с выбранным файлом), то этот значок должен быть красным, и после того, как пользователь запустит его, этот значок должен измениться на зеленый. . Кроме того, если пользователь удаляет файл, щелкнув кнопку (-), он также должен удалить значок, связанный с этим конкретным файлом. Ниже представлено наглядное изображение того, что я хочу.
Я думал связать ImageIcon с каждым добавленным файлом, но я не уверен, как изменить его внешний вид для отображения статуса. Я также не уверен, как можно удалить ImageIcon при удалении файла. Есть ли другой способ (кроме ImageIcon) сделать это? Любая помощь / предложения приветствуются.
@Arvind Спасибо за предложение! Не могли бы вы уточнить / указать мне пример?
@Silvermoon Как пользоваться списками
@MadProgrammer Спасибо за предложение, но не думаю, что я последую за ним. Я только начал программировать на Java и Swing. Не могли бы вы уточнить?
@Stultuske Я знаю о JList, и у меня уже есть графический интерфейс, который добавляет и удаляет файлы. Мне просто было интересно реализовать это в качестве следующего шага
@Stultuske Я полностью согласен, но я думал, что хороший способ понять программирование - это реализовать его. Но я полностью согласен с вашим предложением.
В программировании данные - это король. То, как эти данные представлены, не должно иметь значения для данных, это область / ответственность слоев пользовательского интерфейса / представления.
Часто это модель-представление-контроллер
В вашем примере у вас есть две части (основной) информации. Файл и статус (не запущен, запущен, удален), вы хотите объединить эту информацию как «данные». В Java это обычно означает простой старый объект Java (или Pojo).
Поскольку статус имеет ограниченное количество возможностей, мы можем использовать enum
для его представления, тем самым ограничивая допустимые значения.
public enum FileStatus {
NOT_RUN, RUN, DELETED;
}
А потом мы можем создать собственное pojo ...
public class FileOperation {
private File file;
private FileStatus status;
public FileOperation(File file, FileStatus status) {
this.file = file;
this.status = status;
}
public FileOperation(File file) {
this(file, FileStatus.NOT_RUN);
}
public File getFile() {
return file;
}
public FileStatus getStatus() {
return status;
}
public void setStatus(FileStatus newStatus) {
if (status == newStatus) {
return;
}
this.status = newStatus;
}
}
Теперь, когда мы хотим узнать статус файла, мы знаем, где его взять.
А как насчет JList
? Вы спросите, хороший вопрос. Что нам действительно нужно, так это способ информирования JList
об изменении статуса любого объекта FileOperation
.
Теперь вы можете перебирать ListModel
, но это не очень чистое решение, лучшее решение - позволить FileOperation
генерировать события, когда они меняются, и заставить ListModel
прослушивать их и предпринимать собственные действия.
Это основная концепция образец наблюдателяƒ
Есть несколько способов сделать это, но я ленив, поэтому я просто воспользуюсь доступным API изменения свойств.
public class FileOperation {
private File file;
private FileStatus status;
private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
public FileOperation(File file, FileStatus status) {
this.file = file;
this.status = status;
}
public FileOperation(File file) {
this(file, FileStatus.NOT_RUN);
}
public File getFile() {
return file;
}
public FileStatus getStatus() {
return status;
}
public void setStatus(FileStatus newStatus) {
if (status == newStatus) {
return;
}
FileStatus oldStatus = status;
status = newStatus;
propertyChangeSupport.firePropertyChange("status", oldStatus, status);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
propertyChangeSupport.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
propertyChangeSupport.removePropertyChangeListener(listener);
}
}
А теперь нам нужен ListModel
, который может на него реагировать ...
public class FileOperationListModel extends AbstractListModel<FileOperation> {
private List<FileOperation> items = new ArrayList<FileOperation>(25);
private PropertyChangeListener handler = new PropertyChangeHandler();
public void add(FileOperation fo) {
fo.addPropertyChangeListener(handler);
int size = items.size();
items.add(fo);
fireIntervalAdded(this, size, size);
}
public void remove(FileOperation fo) {
int index = items.indexOf(fo);
if (index < 0) {
return;
}
fo.removePropertyChangeListener(handler);
items.remove(fo);
fireIntervalRemoved(this, index, index);
}
@Override
public int getSize() {
return items.size();
}
@Override
public FileOperation getElementAt(int index) {
return items.get(index);
}
public class PropertyChangeHandler implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (!(evt.getSource() instanceof FileOperation)) {
return;
}
FileOperation fo = (FileOperation) evt.getSource();
int index = items.indexOf(fo);
fireContentsChanged(FileOperationListModel.this, index, index);
}
}
}
Теперь, последний кусок головоломки, вам понадобится специальный ListCellRenderer
, который может отображать нужную вам информацию.
Для этого вам нужно начать с чтения Как пользоваться списками и Написание пользовательского средства визуализации ячеек.
ListCellRenderer
) для отображения состояния. Затем вы можете использоватьListModel
для генерации событий «изменения», когда когда-либо состояние менялось, или если вы использовали настраиваемыйListModel
, зарегистрируйте слушателя непосредственно в объекте «данные» и попросите его сообщить вам, когда оно изменилось.