Dieses Video-Tutorial wurde auf Livestream gehostet und ist den Aufräum-Arbeiten zum Opfer gefallen. Die Original-Aufnahmen wurden von mir leider nicht archiviert und können nicht erneut hochgeladen werden. Daraus habe ich gelernt und werde in Zukunft eine lokale Kopie meiner Aufnahmen behalten. Das Endresultat, in Form eines vollständigem Codes, ist immer noch vorhanden und voll funktionsfähig. Er kann weiterhin hilfreich sein, daher wandert dieser Beitrag vorerst nicht in den Müll.
Diese Übung soll zeigen, wie sich ein einfaches Programm aufbauen lässt, in dem eine langlebige Aktion gestartet wird, ohne die Benutzeroberfläche zu blockieren. Der eigentliche Download wird nur simuliert, es werden also noch keine Daten bewegt. Hierbei handelt es sich um einen Aufgaben-Ausschnitt aus einer Vorlesung an meiner HS, der Lösungsweg ist mein eigener. Verbesserungsvorschläge sind erwünscht
Tutorial-Schritte:
- Leeres Fenster
- Das Layout
- Ereignisbehandlung
- JFace Tabelle mit Column- und Labelprovider
- Tabelle mit Downloads füllen
- Downloadthread und Beobachtungsmuster mit Beans
Programmcode:
- package downloadhelper;
-
- import org.eclipse.swt.widgets.Display;
- import org.eclipse.swt.widgets.Shell;
-
- public class Downloadhelper {
- Shell shell;
- Display display;
-
- public Downloadhelper(Display display) {
- this.display = display;
- shell = new Shell(display);
- shell.setText("Downloadhelper");
- }
-
- private void createGui() {
- new GUI(shell);
- }
-
- public void run() {
- createGui();
- shell.open();
-
- while(!shell.isDisposed()) {
- if(!display.readAndDispatch()) {
- display.sleep();
- }
- }
-
- display.dispose();
- }
-
- new Downloadhelper(Display.getDefault()).run();
- }
- }
- package downloadhelper;
-
- import org.eclipse.swt.SWT;
- import org.eclipse.swt.events.SelectionListener;
- import org.eclipse.swt.layout.FormAttachment;
- import org.eclipse.swt.layout.FormData;
- import org.eclipse.swt.layout.FormLayout;
- import org.eclipse.swt.widgets.Button;
- import org.eclipse.swt.widgets.Composite;
- import org.eclipse.swt.widgets.Control;
- import org.eclipse.swt.widgets.Display;
- import org.eclipse.swt.widgets.Label;
- import org.eclipse.swt.widgets.Shell;
- import org.eclipse.swt.widgets.Text;
-
- public class GUI {
-
- Shell shell;
- Display display;
- SelectionListener listener;
- Text url;
- DownloadTable table;
-
- public GUI(Shell shell) {
- this.shell = shell;
- try {
- this.display = shell.getDisplay();
- listener = new DownloadSelectionAdapter(this, shell);
- createGUI();
- }
-
- /**
- * Erzeugt die GUI
- */
- private void createGUI(){
- createMainwindow();
-
- //shell.pack();
- }
-
- /**
- * Ende Button
- * @return
- */
- buttonEnde.setText("Ende");
- FormData formData = new FormData();
- formData.right = new FormAttachment(100);
- formData.bottom = new FormAttachment(100);
- buttonEnde.setLayoutData(formData);
- buttonEnde.setData("button", "ende");
- buttonEnde.addSelectionListener(listener);
- return buttonEnde;
- }
-
- /**
- * Leeres Composite für die Tabelle
- * @param lad
- * @return
- */
- FormData formData = new FormData();
- formData.left = new FormAttachment(0);
- formData.right = new FormAttachment(100);
- formData.top = new FormAttachment(lad, 10);
- formData.bottom = new FormAttachment(be, -10);
- composite.setLayoutData(formData);
- return composite;
- }
-
- /**
- * Label Aktuelle Downloads
- * @param lnu
- * @return
- */
- label.setText("Aktuelle Downloads");
- FormData formData = new FormData();
- formData.left = new FormAttachment(0);
- formData.top = new FormAttachment(lnu, 10);
- formData.right = new FormAttachment(100);
- label.setLayoutData(formData);
- return label;
- }
-
- /**
- * Neue URL Text
- * @param lnu
- * @param bs
- * @param ldh
- * @return
- */
- url = new Text(shell, SWT.BORDER);
- FormData formData = new FormData();
- formData.left = new FormAttachment(lnu, 3);
- formData.right = new FormAttachment(bs, -3);
- formData.top = new FormAttachment(ldh, 10);
- url.setLayoutData(formData);
- return url;
- }
-
- /**
- * Leeres Fenster
- * @return
- */
- FormLayout f1 = new FormLayout();
-
- // Abstände zum Rand
- f1.marginHeight = 3;
- f1.marginWidth = 3;
-
- shell.setLayout(f1);
- shell.setSize(600, 400);
- return shell;
- }
-
- /**
- * Downloadhelper Label
- * @param string
- * @return
- */
- label.setText("Downloadhelper");
- FormData formData = new FormData();
- formData.left = new FormAttachment(0);
- formData.top = new FormAttachment(0);
- formData.right = new FormAttachment(100);
- label.setLayoutData(formData);
- return label;
- }
-
- /**
- * Nue Url Label
- * @param widget
- * @return
- */
- label.setText("Neue URL:");
- FormData formData = new FormData();
- formData.left = new FormAttachment(0);
- formData.top = new FormAttachment(widget, 10);
- label.setLayoutData(formData);
- return label;
- }
-
- /**
- * Start Button
- * @param widget
- * @return
- */
- buttonStart.setText("Start");
- FormData formData = new FormData();
- formData.top = new FormAttachment(widget, 10);
- formData.right = new FormAttachment(100);
- buttonStart.setLayoutData(formData);
- buttonStart.setData("button", "start");
- buttonStart.addSelectionListener(listener);
- return buttonStart;
- }
-
- /**
- * @return the url
- */
- public Text getUrl() {
- return url;
- }
-
- /**
- * @return the table
- */
- public DownloadTable getTable() {
- return table;
- }
-
- }
- package downloadhelper;
-
- import java.beans.PropertyChangeEvent;
- import java.beans.PropertyChangeListener;
-
- import org.eclipse.swt.events.SelectionAdapter;
- import org.eclipse.swt.events.SelectionEvent;
- import org.eclipse.swt.widgets.Display;
- import org.eclipse.swt.widgets.Shell;
-
- import downloadhelper.Download.STATE;
-
- public class DownloadSelectionAdapter extends SelectionAdapter{
-
-
- @Override
-
- if(evt.getPropertyName().equals("download")){
- if(!Display.getDefault().isDisposed()) {
-
- if(!gui.getTable().getDownloadsmodel().isEmpty()) {
-
- gui.getTable().getDownloadsmodel().set(count,
- (Download)evt.getNewValue());
-
- gui.getTable().update();
- }
-
- if(((Download)evt.getNewValue()).getState() == STATE.READY) {
- count++;
- }
- }
- }
- }
- }
-
- private GUI gui;
- private DownloadThread downloadThread;
- private int count = 0;
-
- public DownloadSelectionAdapter(GUI gui, Shell shell) {
- this.gui = gui;
- downloadThread = new DownloadThread(shell);
- downloadThread.addPropertyChangeListener(new ThreadListener());
- downloadThread.start();
- }
-
- @Override
- public void widgetSelected(SelectionEvent event) {
- if(event.widget.getData("button").equals("start")) {
- start();
- }
- else
- if(event.widget.getData("button").equals("ende")) {
- ende();
- }
- }
-
- private void start() {
- gui.getTable().addUrl(gui.getUrl().getText());
- downloadThread.addDownload(gui.getUrl().getText());
- }
-
- private void ende() {
- //TODO Ende
- }
-
- }
- package downloadhelper;
-
- public class Download {
- public enum STATE{ WAITING, READY, RUNNUNG};
-
- private STATE state;
-
- this.setState(state);
- this.setUrl(url);
- }
-
- /**
- * @param state the state to set
- */
- public void setState(STATE state) {
- this.state = state;
- }
-
- /**
- * @return the state
- */
- public STATE getState() {
- return state;
- }
-
- /**
- * @param url the url to set
- */
- this.url = url;
- }
-
- /**
- * @return the url
- */
- return url;
- }
-
- }
- package downloadhelper.common;
-
- import java.util.List;
-
- import org.eclipse.jface.viewers.IStructuredContentProvider;
- import org.eclipse.jface.viewers.Viewer;
-
- import downloadhelper.Download;
-
- public class DownloadContentProvider implements IStructuredContentProvider{
-
- @Override
- public void dispose() {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- // TODO Auto-generated method stub
-
- }
-
- @SuppressWarnings("unchecked")
- @Override
- return ((List<Download>)element).toArray();
- }
-
- }
- package downloadhelper;
-
- import java.util.ArrayList;
-
- import org.eclipse.jface.layout.TableColumnLayout;
- import org.eclipse.jface.viewers.ColumnWeightData;
- import org.eclipse.jface.viewers.TableViewer;
- import org.eclipse.jface.viewers.TableViewerColumn;
- import org.eclipse.swt.SWT;
- import org.eclipse.swt.widgets.Composite;
- import org.eclipse.swt.widgets.Table;
-
- import downloadhelper.Download.STATE;
- import downloadhelper.common.DownloadContentProvider;
- import downloadhelper.common.StatusLabelProvider;
- import downloadhelper.common.UrlLabelProvider;
-
- public class DownloadTable {
-
- private TableViewer tableViewer;
- private Table table;
- private ArrayList<Download> downloadsmodel = new ArrayList<Download>();
-
- this.composite = compositeTable;
- createTable();
- }
-
- private void createTable() {
- TableColumnLayout layout = new TableColumnLayout();
- composite.setLayout(layout);
-
- tableViewer = new TableViewer(composite, SWT.FULL_SELECTION);
- tableViewer.setContentProvider(new DownloadContentProvider());
-
- table = tableViewer.getTable();
-
- TableViewerColumn column = new TableViewerColumn(tableViewer, SWT.LEFT);
- layout.setColumnData(column.getColumn(), new ColumnWeightData(20, false));
- column.setLabelProvider(new StatusLabelProvider());
- column.getColumn().setText("Status");
-
- column = new TableViewerColumn(tableViewer, SWT.LEFT);
- layout.setColumnData(column.getColumn(), new ColumnWeightData(80, true));
- column.setLabelProvider(new UrlLabelProvider());
- column.getColumn().setText("URL");
-
- table.setHeaderVisible(true);
- table.setLinesVisible(true);
- tableViewer.setInput(downloadsmodel);
- table.getColumn(0).pack();
- }
-
- downloadsmodel.add(new Download(STATE.WAITING, url));
- tableViewer.refresh();
- table.getColumn(0).pack();
- }
-
- /**
- * @return the downloadsmodel
- */
- public ArrayList<Download> getDownloadsmodel() {
- return downloadsmodel;
- }
-
- /**
- * @param downloadsmodel the downloadsmodel to set
- */
- public void setDownloadsmodel(ArrayList<Download> downloadsmodel) {
- this.downloadsmodel = downloadsmodel;
- }
-
- public void update() {
- tableViewer.refresh();
- table.getColumn(0).pack();
- }
- }
- package downloadhelper;
-
- import java.beans.PropertyChangeListener;
- import java.beans.PropertyChangeSupport;
- import java.util.ArrayList;
- import org.eclipse.swt.widgets.Display;
- import org.eclipse.swt.widgets.Shell;
-
- import downloadhelper.Download.STATE;
-
-
- // Verwaltung der PropertyChangeListener
- private ArrayList<Download> downlModel = new ArrayList<Download>();
- private boolean running;
- private Display display;
-
- public DownloadThread(Shell shell) {
- running = true;
- try {
- display = shell.getDisplay();
- }
-
- /**
- * Listener hinzufügen
- * @param listener
- */
- support.addPropertyChangeListener(listener);
- }
-
- /**
- * Der Thread ruft es auf um sich auf eine Ereignis warten zu legen
- * Threadsicher mit synchronized, damit greift nur ein Thread auf einmal
- * darauf zu.
- * @throws InterruptedException
- */
- wait();
- }
-
- /**
- * Der Thread kann von außen wieder aufgeweckt werden
- */
- public synchronized void doNotify() {
- notify();
- }
-
- /**
- * Downloadsimulator blokiert die Anwendung für eine gewisse Zeit
- */
- try {
- sleep(10000);
- }
-
- /**
- * Methode, die aus der GUI aufgerufen wird
- * @param url
- */
- downlModel.add(new Download(STATE.WAITING, url));
- doNotify();
- }
-
- @Override
- public void run() {
-
- while(running) {
-
- if(display.isDisposed()) {
- running = false;
- }else
-
- if(!downlModel.isEmpty()) {
-
- Download oldState = downlModel.get(0);
- Download curState = new Download(STATE.WAITING,
- oldState.getUrl());
-
- curState.setState(STATE.RUNNUNG);
- tellUI(oldState, curState);
- download(curState.getUrl());
-
- oldState.setState(STATE.RUNNUNG);
- curState.setState(STATE.READY);
- tellUI(oldState, curState);
-
- downlModel.remove(0);
-
- } else {
- try {
- doWait();
- }
-
- }
- }
-
- private void tellUI(final Download oldState, final Download curState) {
- @Override
- public void run() {
- support.firePropertyChange("download", oldState, curState);
- }
- });
- }
- }
Es sind einige unnötige try-catches raus gefallen und das display wurde dem Thread direkt übergeben, mit dem Default-Display wurde der Task leider nicht richtig beendet.