FAQ
Aus Salespoint
Lk (Diskussion | Beiträge) (→Wie aktiviere ich diese Interceptor?) |
Uwe (Diskussion | Beiträge) (→Desktop) |
||
(Der Versionsvergleich bezieht 2 dazwischenliegende Versionen mit ein.) | |||
Zeile 30: | Zeile 30: | ||
==Wie kann ich Kataloge/Stocks filtern?== | ==Wie kann ich Kataloge/Stocks filtern?== | ||
Dafür gibt es spezielle Catalog- und StockFilter (package data.filters). Zum Anzeigen der gefilterten Daten werden diese anstatt der originalen Stocks/Kataloge an die FormSheets übergeben. Es ist nicht möglich, die Filterung im TED vorzunehmen. Man kann zwar dort die Anzeige von Items unterdrücken, es würde aber dennoch eine leere Zeile angezeigt. | Dafür gibt es spezielle Catalog- und StockFilter (package data.filters). Zum Anzeigen der gefilterten Daten werden diese anstatt der originalen Stocks/Kataloge an die FormSheets übergeben. Es ist nicht möglich, die Filterung im TED vorzunehmen. Man kann zwar dort die Anzeige von Items unterdrücken, es würde aber dennoch eine leere Zeile angezeigt. | ||
+ | |||
+ | ==Wie kann ich mit Eclipse serialVersionUIDs generieren lassen?== | ||
+ | Wenn eine Klasse das Interface ''Serializable'' implementiert, sollte auch eine ''serialVersionUID'' angegeben werden. Eclipse bietet die Möglichkeit diese automatisch generieren zu lassen, indem man am linken Rand auf die Warnung. | ||
+ | |||
+ | ''The serializable class User does not declare a static final serialVersionUID field of type long'' | ||
+ | |||
+ | klickt und | ||
+ | |||
+ | ''Add generated serial version ID'' | ||
+ | |||
+ | wählt. | ||
=Desktop= | =Desktop= | ||
Zeile 77: | Zeile 88: | ||
==Der DataBasket in meinem Prozess ist null, obwohl ich einen DataBasket zugewiesen habe.== | ==Der DataBasket in meinem Prozess ist null, obwohl ich einen DataBasket zugewiesen habe.== | ||
- | Beim Starten eines Prozesses übernimmt der Prozess automatisch den DataBasket vom SalesPoint, auf dem er läuft. Der DataBasket sollte also schon an den SalesPoint gehängt worden sein. Falls der DataBasket im Prozess gesetzt werden muss, darf das nicht im Konstruktor passieren. Die Methode getInitialGate() bietet sich stattdessen an. | + | Beim Starten eines Prozesses übernimmt der Prozess automatisch den DataBasket vom SalesPoint, auf dem er läuft. Der DataBasket sollte also schon an den SalesPoint gehängt worden sein. Falls der DataBasket im Prozess gesetzt werden muss, darf das nicht im Konstruktor passieren. Die Methode getInitialGate() bietet sich stattdessen an. |
+ | |||
+ | ==Wie können Bilder über den Classpath geladen werden?== | ||
+ | Normalerweise muss für ein Bild (und Ressourcen allgemein) der Pfad relativ zur Main Class angegeben werden, um sie laden zu können. Wenn man ein JAR packt, ändert sich jedoch manchmal die Verzeichnisstruktur, sodass man hier ein Problem bekommt. | ||
+ | |||
+ | Mit folgender Klasse können Ressourcen aller Art über den Classpath geladen werden. Natürlich muss dann auch der entsprechende Ordner dem Classpath hinzugefügt werden: | ||
+ | <code java> | ||
+ | import java.net.URL; | ||
+ | import javax.swing.ImageIcon; | ||
+ | |||
+ | /** | ||
+ | * Lädt Ressourcen über den Classpath, ohne dass man die absolute URL kennen muss. | ||
+ | * | ||
+ | * Ressourcen, die so gefunden werden sollen, müssen demnach dem Classpath hinzugefügt werden. | ||
+ | * | ||
+ | * @author Hannes John | ||
+ | */ | ||
+ | public class ResourceLoader { | ||
+ | |||
+ | /** | ||
+ | * Lädt eine Ressource über den Classpath. | ||
+ | * | ||
+ | * @param url Die relative Ressourcen-URL | ||
+ | * @return Die absolute Ressourcen-URL | ||
+ | */ | ||
+ | public static URL loadResource(String url) { | ||
+ | return ResourceLoader.class.getClassLoader().getResource(url); | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * Lädt ein Bild über den Classpath. Wenn das Bild nicht gefunden wurde, wird ein Platzhalter zurück- | ||
+ | * gegeben. | ||
+ | * | ||
+ | * @param url Die relative Bild-URL | ||
+ | * @return Das geladene ImageIcon | ||
+ | */ | ||
+ | static public ImageIcon loadImageIcon(String url) { | ||
+ | try { | ||
+ | return new ImageIcon(loadResource(url)); | ||
+ | } catch(NullPointerException npe) { | ||
+ | /* Eine Platzhaltergrafik zurückgeben (diese muss existieren) */ | ||
+ | return new ImageIcon("res/img/error.png"); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | ==Warum kommt beim Speichern eine NotSerializableException?== | ||
+ | Objekte, die serialisiert werden können sollen, müssen das Interface '''Serializable''' implementieren. Das gilt nicht nur für das Objekt selbst, sondern auch für alle Attribute, die nicht als ''transient'' deklariert sind. | ||
+ | |||
+ | Bei GUI-Elementen treten die meisten Probleme auf. Diese sollten generell als ''transient'' deklariert werden, da sie nach dem Laden beim Anzeigen eines Dialogs vom ''FormSheetContentCreator'' neu erzeugt werden. | ||
+ | |||
=Web= | =Web= | ||
==Wie aktiviere ich diese Interceptor?== | ==Wie aktiviere ich diese Interceptor?== |
Aktuelle Version vom 08:22, 7. Okt. 2010
Diese FAQ beschäftigt sich ausschließlich mit Fragen zum Framework. Fragen zum Praktikum werden auf der entsprechenden FAQ-Seite zum Praktikum beantwortet. Außerdem findet man dort Hilfe bei allgemeinen Problemen mit Java und den Entwicklungswerkzeugen.
Core
Wo gibt es den Quellcode von SalesPoint?
Der Quellcode wird nicht zum Download bereitgestellt. Bei Interesse kann aber über die Javadoc auf ihn zugegriffen werden. In der Detailansicht einer Klasse klickt man dazu auf den Klassen- oder einen Methodennamen und gelangt an die entsprechende Stelle im Code.
Wie kann ich mit meiner Tabelle dies und jenes anzeigen lassen?
Die Darstellung von Tabellen wird vom TableEntryDescriptor gesteuert. Dieser ist dem sogenannten Tabellenmodell, welches für die originalen Swing-Tabellen benutzt wird, sehr änlich. Das auf den folgenden Seiten vermittelte Wissen lässt sich deshalb ohne größere Probleme für SalesPoint-Tabellen nutzen:
Wie kann ich CatalogItems editierbar machen?
Um sich ein editierbares CatalogItem zu holen, ist die get() Methode des Catalogs zu verwenden. Ist der dritte Parameter true, ist das zurückgegebene CatalogItem editierbar.
CatalogItem ciEditable = myCatalog.get("key1", db, true);
Dabei ist zu beachten, dass ein ShallowClone zurückgeliefert wird, nicht das originale CatalogItem. Der DataBasket darf nicht null sein.
Wie kann ich Kataloge schachteln?
Man kann einem Katalog mit der add() Methode einen anderen Katalog als "Kind" hinzufügen. Allerdings ist der Kindkatalog nicht editierbar und kann damit keine weiteren CatalogItems aufnehmen. Man kann den Kindkatalog wie ein gewöhnliches CatalogItem editerbar machen (#Wie kann ich CatalogItems editierbar machen?) oder die Methode getEditableCopy(DataBasket db) verwenden. Der DataBasket darf dabei nicht null sein.
Die Methode getCatalog() liefert mir null zurück, obwohl ich den Catalog gesetzt habe.
Ein oft gemachter Fehler ist, die Kataloge am Shop anzumelden bevor der Shop gesetzt wurde. Es ist wichtig, dass zuerst setTheShop() ausgeführt wird und erst danach Kataloge und Stocks gesetzt werden.
Beim Iterieren bekomme ich eine ConcurrentModificationException.
Das geschieht, wenn der Iterator feststellt, dass sich die Datenbasis, über die er iteriert, verändert hat. Um potentiell falsche Ergebnisse zu vermeiden wird lieber kontrolliert abgebrochen. Vermutlich wurde versucht, mit dem Iterator ein Objekt (z.B. CatalogItem) zu finden und dies dann aus dem Katalog zu löschen. Um den Fehler zu vermeiden, ist statt der remove() Methode des Kataloges (Stocks,...) die remove() Methode des Iterators zu benutzen.
Wie kann ich Kataloge/Stocks filtern?
Dafür gibt es spezielle Catalog- und StockFilter (package data.filters). Zum Anzeigen der gefilterten Daten werden diese anstatt der originalen Stocks/Kataloge an die FormSheets übergeben. Es ist nicht möglich, die Filterung im TED vorzunehmen. Man kann zwar dort die Anzeige von Items unterdrücken, es würde aber dennoch eine leere Zeile angezeigt.
Wie kann ich mit Eclipse serialVersionUIDs generieren lassen?
Wenn eine Klasse das Interface Serializable implementiert, sollte auch eine serialVersionUID angegeben werden. Eclipse bietet die Möglichkeit diese automatisch generieren zu lassen, indem man am linken Rand auf die Warnung.
The serializable class User does not declare a static final serialVersionUID field of type long
klickt und
Add generated serial version ID
wählt.
Desktop
Ich kann keine Items im DataExchangeFormSheet verschieben.
Wenn man sich ein DataExchangeFormSheet an einem Gate anzeigen lässt, muss man darauf achten, dass das Gate zum Zeitpunkt, zu dem das FormSheet erzeugt wird, bereits existiert. Folgender Code funktioniert:
Gate testGate = new UIGate(null, null);
DataExchangeFormSheet defs = DataExchangeFormSheet.create(. . .);
testGate.setFormSheet(defs);
Dieser dagegen nicht:
Gate testGate = null;
DataExchangeFormSheet defs = DataExchangeFormSheet.create(. . .);
testGate = new UIGate(defs, null);
Wie kann ich die Oberfläche meines Shops anpassen?
Erzeuge eine Unterklasse von sale.multiwindow.MultiWindow. Das ist die Klasse, die für die Shopoberfläche verantwortlich ist. In dieser Klasse überschreibe die Methode createFramePane(). Es muss ein JPanel zurückgeliefert werden, das JPanel wird die Shopoberfläche sein, es kann beliebig verschönert werden. In der Shop-Klasse überschreibe die Methode createShopFrame(), so dass sie das neue MultiWindow zurückliefert.
Klasse MyShop:
...
protected sale.multiwindow.MultiWindow createShopFrame() {
return new MyShopFrame(getTheShop());
}
...
Klasse MyShopFrame:
...
public MyShopFrame(Shop s) {
super(s, WINDOW_VIEW);
}
protected JPanel createFramePane() {
JPanel jp = new JPanel();
jp.add(new JLabel("Mein Shop"));
return jp;
}
...
Der DataBasket in meinem Prozess ist null, obwohl ich einen DataBasket zugewiesen habe.
Beim Starten eines Prozesses übernimmt der Prozess automatisch den DataBasket vom SalesPoint, auf dem er läuft. Der DataBasket sollte also schon an den SalesPoint gehängt worden sein. Falls der DataBasket im Prozess gesetzt werden muss, darf das nicht im Konstruktor passieren. Die Methode getInitialGate() bietet sich stattdessen an.
Wie können Bilder über den Classpath geladen werden?
Normalerweise muss für ein Bild (und Ressourcen allgemein) der Pfad relativ zur Main Class angegeben werden, um sie laden zu können. Wenn man ein JAR packt, ändert sich jedoch manchmal die Verzeichnisstruktur, sodass man hier ein Problem bekommt.
Mit folgender Klasse können Ressourcen aller Art über den Classpath geladen werden. Natürlich muss dann auch der entsprechende Ordner dem Classpath hinzugefügt werden:
import java.net.URL;
import javax.swing.ImageIcon;
/**
* Lädt Ressourcen über den Classpath, ohne dass man die absolute URL kennen muss.
*
* Ressourcen, die so gefunden werden sollen, müssen demnach dem Classpath hinzugefügt werden.
*
* @author Hannes John
*/
public class ResourceLoader {
/**
* Lädt eine Ressource über den Classpath.
*
* @param url Die relative Ressourcen-URL
* @return Die absolute Ressourcen-URL
*/
public static URL loadResource(String url) {
return ResourceLoader.class.getClassLoader().getResource(url);
}
/**
* Lädt ein Bild über den Classpath. Wenn das Bild nicht gefunden wurde, wird ein Platzhalter zurück-
* gegeben.
*
* @param url Die relative Bild-URL
* @return Das geladene ImageIcon
*/
static public ImageIcon loadImageIcon(String url) {
try {
return new ImageIcon(loadResource(url));
} catch(NullPointerException npe) {
/* Eine Platzhaltergrafik zurückgeben (diese muss existieren) */
return new ImageIcon("res/img/error.png");
}
}
}
Warum kommt beim Speichern eine NotSerializableException?
Objekte, die serialisiert werden können sollen, müssen das Interface Serializable implementieren. Das gilt nicht nur für das Objekt selbst, sondern auch für alle Attribute, die nicht als transient deklariert sind.
Bei GUI-Elementen treten die meisten Probleme auf. Diese sollten generell als transient deklariert werden, da sie nach dem Laden beim Anzeigen eines Dialogs vom FormSheetContentCreator neu erzeugt werden.
Web
Wie aktiviere ich diese Interceptor?
Interceptor können zusätzlich zu Actions(Methoden von Controllern, die eine Anfrage bearbeiten) ausgeführt werden. Verschiedene Funktionalitäten der Salespoint TagLibrary sind mittels Interceptor umgesetzt, die für einen Controller aktiviert werden müssen. Dies lässt sich mit der Standardkonfiguration der sp2010-blank.war besonders einfach mit der Annotation @Interceptors machen.
@Controller
@Interceptors({LoginInterceptor.class, SearchFieldInterceptor.class})
public class MyController {
.
.
}
Jede Action dieses Controllers wird von den angegebenen Interceptor unterbrochen. Im Falle der in diesem Beispiel angegebenen Interceptor passiert nichts, sobald keine LoginDaten bzw. Suchfeld-Angaben mitgesendet werden.