![]() |
Delphi mit Java komunizieren
Guten Tag,
ich habe folgende Aufgabe. Es gibt ein fertiges JavaProgramm mit Klassen. Ich soll versuchen diese Klassen in Delphi zu importieren. Es soll sozusagen anhand von Delphi eine JavaPlattform erstellt werden und diese sollen miteinander komunizieren . So ganz habe ich das noch nicht verstanden aber vllt. kann mir einer helfen. Ich habe hier auch noch zwei links zum orientieren. Alternative wäre alles in Delphi u übersetzen .. aber das wäre die notlösung. Wie schwer ist es so etwas mit Delphi zu machen ?! .. also das komunizieren mit Java. ![]() ![]() |
Re: Delphi mit Java komunizieren
Hi,
erstmal herzlich Willkommen in der DP :dp: Deine Frage kann so pauschal gar nicht beantwortet werden. Es gibt wie du schon sagst/zeigst mindestens zwei Wege. Welcher Weg am Besten geeignet ist, hängt aber stark davon ab, was du genau machen möchtest. Hier ist es halt wichtig zu wissen, was du unter einer JavaPlattform verstehst? Es wird ja sicherlich einen Grund geben warum ein Programm in Java vorliegt. Genau so gibt es sicherlich auch einen Grund warum Delphi damit kommunizieren soll, doch welche? Also müssen Eigenschaften von Java erhalten bleiben? Hier natürlich insbesondere die Plattformunabhängigkeit? Das ginge auf diesem Wege nämlich nicht. Der in den Links vermerkte Weg ist einer, an den ich auch zuerst gedacht habe. Das JNI erlaubt es dir halt nativen Code (an die jeweilige Plattform gebunden) aufzurufen. Hier werden häufig Dlls eingebunden oder ähnliches. Was genau ist eigentlich das Ziel? Wenn du ein wenig genauer sagst, wie deine Programme aussehen und was die tun sollen, kann man dir sicherlich leichter helfen. Das komplette übersetzen in Delphi kann z.B. auch sinnvoll sein. Sollte dies das einzigste Java-Programm sein und ab sofort nur noch in Delphi gearbeitet werden, wäre es wohl wenig sinnvoll jedesmal ein Vertreter-Treiber Modell zu verwenden. Dies kostet natürlich zudem zusätzlichen Speicher und andere Ressourcen. Zudem ist es angenehmer in einer IDE debuggen zu können. Eine Möglichkeit die sich auch eventuell anbieten könnte ist die Kommunikation per Netzwerk. Sowohl Delphi als auch Java können sehr einfach über ein Netzwerk kommunizieren. Soll dein Java-Programm nur eine bestimmte Berechnung durchführen, kannst du es sehr leicht als eine Komponente betrachten. Du gibst ein paar Argumente rein und bekommst irgendein Ergebnis raus. Das rein und raus kann dann eine einfache TCP/IP Verbindung übernehmen. Arbeitest du damit auf einem Rechner, so kannst du immer die Loopback Adresse nehmen. Hier müsstest du nur dafür sorgen, dass das Java-Programm entsprechend erweitert wird. Ist eigentlich kein Problem (wenn du ein wenig Java kannst), denn für Netzwerke wurde Java nahezu gemacht (es spielt hier eine Menge stärken aus). Du brauchst nur einen sehr einfachen Java-Server, der auf einem definierten Port alle Parameter entgegen nimmt und auf einem anderen das Ergebnis ausgibt. In Delphi brauchst du natürlich die einfachen Gegenstücke. Hier hättest du den Vorteil, dass du die volle Plattformunabhängigkeit von Java behalten könntest (und alle anderen Eigenschaften). Zudem kannst du dir dann aussuchen, ob du den Aufruf lokal oder sogar über ein Netzwerk stattfinden lässt. Ein weiterer Vorteil wäre noch, dass du statt Delphi auch jede andere Sprache zum Aufruf verwenden könntest. Wie gesagt, es hängt sehr sehr stark davon ab, was genau du eigentlich machen möchtest und warum. Ohne etwas mehr Details ist es sehr schwer etwas als geeignet oder ungeeignet zu benennen. Und letztlich ist noch eine weitere wichtige Frage, was dir am leichtesten fällt! Gruß Der Unwissende |
Re: Delphi mit Java komunizieren
Ok .. also das mit dem übersetzen hat sich erledigt. :D
Zunächst mal was zu dem Programm. Ich kann Java NOCH nicht. natürlich muss ich mich darin einarbeiten um zu verstehen wie Java funktioniert. Vllt. wird mir dann klarer wie diese Sprachen miteinander komunizieren könnten Es ist ein Programm das Vermessene daten einliest und rendert. . also eine Digitale Karte. Da gibts fan proceduren wie ranzoomen wegzoomen. speichern ect. Also eine Klasse namens Flüsse. da kann man die daten der flüsse laden , rendern, zommen ect. Das ist also ein Fertiges programm . Ich soll jetzt ein Handbuch schreiben wie ich diese Klassen usw. Von Delphi aus steuer. da wurden mir auch die links empfohlen. leider versteh ich fast nur bahnhof. vllt weil ich kein java kann (hoffe ich :D ) ich soll also auf eigenschaften zugreifen können (wie positionen des Flusases) auf die proceduren render usw. das alles von Delphi aus. Das rendern soll aber von java erledigt werden. Also einfach nur klassen mit delphi steuern .. Aber ich frage morgen nochmal nach ob ich das so richtig verstanden habe. vllt. kann ja einer kommentar dazu geben ob das geht ?! .. und ob das mit der Methode bei den links geht |
Re: Delphi mit Java komunizieren
Möglich ist es mit den zwei Links, wobei für dich der Zweite der eigentlich wichtige wäre. Damit kannst du (soweit verspricht es der Link) Java Objekte über Delphi aufrufen. Dazu wird einfach ein einfaches Vertreter-Treiber (Proxy-Driver) Modell verwendet. Deine Java-Klasse ist dabei der schon fertige Treiber. Auf Delphi Seite wird ein Vertreter automatisch generiert. Alle Aufrufe die an diesen Vertreter gehen, werden dann für dich völlig transparent verarbeitet. Allerdings bist du auch stark von der dort genannanten Komponente Abhängig. Je nachdem wie gut die ist, wird es besser oder schlechter klappen.
Du solltest also erstmal schauen, wie gut du mit dieser Komponente klar kommst. Wenn du da arge Probleme hast, gibt es noch ein paar Alternativen, aber wie gesagt erstmal hieße die Lösung dann wohl Link 2 |
Re: Delphi mit Java komunizieren
baut der erste link nich auf den zweiten auf ???
am besten ist es erstmal java beizubringen ? wobei soviel muss es dann auch nich sein ?! es wird doch mehr in delphi gemacht oder ? |
Re: Delphi mit Java komunizieren
Zitat:
Der zweite zeigt wie du in Delphi etwas verwenden kannst, das in Java geschrieben wurde. Zitat:
Da würdest du (idealer Weise) gar kein Java sehen. Du bekommst einfach nur eine automatisch erzeugte Delphi-Klasse die du direkt verwendest. Warum und wie die funktioniert, dass ist dir egal (das ist der Sinn einer Klasse). Du weißt was du reinsteckst und was rauskommt. Das alles gilt natürlich nur, wenn die automatisch erstellten Klassen das alles richtig machen. Schau dir einfach den zweiten Link an und probier die dort genannte Komponente aus. Sollte die nicht wie erwartet funktionieren, frag noch einmal nach. |
Re: Delphi mit Java komunizieren
vielen vielen dank :)
|
Re: Delphi mit Java komunizieren
hm .. also ich bin grad dabei mir dieses Tut für Delphi (also zweiter Link anzuschauen). Leider verstehen ich nichts :D ..
was ist denn dieses Java D Tool .. kann mir vllt. einer einen kleinen einstieg schreiben ?! .. danke .. Simon |
Re: Delphi mit Java komunizieren
Liste der Anhänge anzeigen (Anzahl: 1)
ich nochmal .. ich hab jetzt einfach mal versucht JNI zu erzeugen .
und zwar mit Folgendem Befehl
Delphi-Quellcode:
aber irgendwie hält der dann das programm vor dem intialisieren an.
JavaVM := TJavaVM.Create;
Ich hab den Code mal hochgeladen. |
Re: Delphi mit Java komunizieren
Hi,
das liegt einfach nur daran, dass die jvm.dll nicht gefunden wird (ok, soweit warst du sicherlich auch schon). Die ist einfach nötig, um die Virtuelle Maschine von Java zu starten (die ja letztlich dann deinen Java-Code interpretiert). Es gibt hier (wieder) verschiedene Möglichkeiten das Problem zu lösen. Die eine ist es einfach diese Datei aus dem aktuellen JRE zu kopieren (sowas wie /programme/java/jre_..../bin/client/) und in den selben Ordner wie die .exe zu packen. Das ist aber eigentlich nichts anderes, als diese Datei in den Suchpfad aufzunehmen (was du eigentlich tun solltest). Am einfachsten ist es, wenn du immer kontrollierst, ob auf dem aktuellen System überhaupt ein JRE installiert ist. Dies ist das Java Runtime Enviroment, also wirklich nur die Laufzeitumgebung. Die ist dann auch deutlich kleiner als das JDK (Development Kit), dass du nur für die Entwicklung benötigst. Unter Windows trägt sich das JRE in der Registry ein. Da müsstest du dann mal gucken, wo genau der Schlüssel zur JRE liegt und diesen Pfad dann beim Start deines Programms abrufen. Hier wäre dann auch die Möglichkeit gegeben, dass Programm (ohne Exception) zu beenden, wenn kein JRE installiert ist (natürlich wäre dann ein Hinweis an den Benutzer auch nicht schlecht). Liegt die .dll im Pfad, läuft deine .exe erstmal. Gruß Der Unwissende |
Re: Delphi mit Java komunizieren
Der Anlaufpunkt fuer das JNI mit Delphi ist
![]() Es empfiehlt sich Eclipse zu installieren fuer die Java-Entwicklung. Das JNI zeigt auch wie man eine Java-Klasse in einer DLL implementiert. Die Implementierung kann dann in jeder beliebigen Sprache einschliesslich Delphi erfolgen. Bei Code Mercenaries machen wird das mit unserem DLL API. Die normalen Funktionen werden auch als Methoden einer Java-Klasse exportiert und damit kann Java die DLL direkt benutzen. Ein bischen Glue-Code in der Implementierung der Methode, der die Anpassung der Parameter handhabt und die Originalfunktion aufruft, genugt. Macht man die DLL in C, dann ist dieser Glue-Code auch noch portabel und funktioniert auch unter Linux. |
Re: Delphi mit Java komunizieren
hey,
ok .. soweit so gut. Jetzt hab ich noch eine frage zum nächsten Schritt. Ich kenne mich mit Java nicht sonderlich gut aus. Weiß also nicht welche Dateien man mit java erstellen kann (ob *.exe oder *.jar oder was auch immer ^^) Welches Dateiformat brauche ich denn jetzt um es in Delphi einbinden zu können ? und wo steht dann im Delphiquelltext der Pfad dieser Datei. Also das sollte ja in dem Link beschrieben sein. Aber ich finde den Pfad halt nicht |
Re: Delphi mit Java komunizieren
In Java gibt es eigentlich nur 3 wirklich wichtige Dateitypen.
Der Quellcode wird in .java Dateien abgelegt. Mittels javac können diese dann in .class Dateien Übersetzt werden. Eine .class Datei besteht aus einem Objektcode. Dieser ist auf einer Virtuellen Maschine (JVM) Lauffähig. Die .class Dateien enthalten nur den übersetzten Code und lassen damit keinen Rückschluß auf die eigentlichen Sourcen zu. Wichtig ist hier die Technik der JVM. Code wird immer so gelinkt, dass er von einer bestimmten Plattform ausgeführt werden kann. In diesem Fall gibt es halt eine virtuelle Plattform. .exe Dateien laufen halt unter einem bestimmten Windows. Bei 32-bit exen auf einem Win 3.0 dürftest du aber schon Probleme haben. Linux, Solaris, AIX, ... wüßten aber gar nichts mit einer solchen Datei anzufangen. Bei Java ist die Plattform genauso festgelegt, aber virtuell. Hast du eine JVM für deine eigentliche Zielplattform (z.B. Windows X, MacOS Y, ...) dann kannst du auf dieser den Objektcode ausführen. Die letzte wichtige Datei ist dann noch die .jar. Hierbei handelt es sich eigentlich nur um ein Archiv. Ein Projekt wird schnell größer als ein zwei Dateien. Zudem verwendest du sicherlich früher oder später Klassen, die du für ein anderes Projekt geschrieben hast. Um hier eine einzelne Datei weiterreichen zu können, hat man sich (sinnvoller Weise) für eine Archiv entschieden. Dieses kann in Java transparent eingebunden werden (die Struktur der .jar wird dann nicht von der entpackten auf deiner Platte unterschieden). Ein jar ist glaube ich in erster Linie wirklich an ein .tar angelehnt, es nimmt erstmal nur Dateien auf. Es gibt jedoch noch weitere Optionen. Die eine wichtige ist, dass du die Dateien mit einem zip Algorithmus packen lassen kannst (unterstütz jar aus deinem JDK). Die andere wichtige Option ist, dass du ein Manifest angeben kannst. Unteranderem kann in dieser Datei der Classpath gesetzt werden und wichtiger, du kannst eine zu startende Datei angeben. Startest du dann dein Programm mittels javaw -jar DeinJar.jar oder java -jar DeinJar.jar, so wird automatisch diese .class Datei ausgeführt. Um deine Frage zu beantworten, in Java werden ausführbar eigentlich nur .class Dateien erzeugt. Da eine .jar einfach transparent eingebunden werden kann, gibt es zwar startbare Archive, aber für die JVM ist es auch nur das starten einer .class in einem bestimmten Pfad. Zu der anderen Frage komme ich gleich (muss mir mal das Beispiel anschauen) |
Re: Delphi mit Java komunizieren
So, zu deiner Frage wo genau die Dateien liegen müssen:
Wie gesagt, es sind die .class Dateien, die Java sucht. Was hier das Schlüsselwort ist (und mit dem Wissen dass es .class Dateien sind ist es auch sofort klar) "ClassPath". Dies ist so zu sagen der Suchpfad von Java. Hier kannst du entweder den direkten Pfad zu den einzelnen Klassen oder halt zu einem .jar angeben. In diesen würde dann nach der jeweilige Klasse gesucht werden (also ein wenig wie PATH unter Windows). |
Re: Delphi mit Java komunizieren
gut. das heißt also ich brauch zu jeder klasse eine .class datei.
und geladen wird sie indem die Optionen für die JVM setzt Meine Datei heißt HelloWorld.class und liegt im gleichen Ordner.
Delphi-Quellcode:
jetzt kommt aber im direkten weiteren Verlauf des Quelltextes ein Fehler, was mich darauf schließen lässt, dass er die Datei "HelloWorld.class" nicht gefunden hat.
// Set the options for the VM
Options[0].optionString := './HelloWorld.class'; {den Pfad hab ich auch mal ohne Punkt ausprobiert} VM_args.version := JNI_VERSION_1_2; VM_args.options := @Options; VM_args.nOptions := 1;
Delphi-Quellcode:
Da wird eben die ShowMessage mit dem ErrorCode -1 ausgegeben
// Load the VM
Errcode := JavaVM.LoadVM(VM_args); if Errcode < 0 then begin ShowMessage(Format('Error loading JavaVM, error code = %d', [Errcode])); Exit; end; |
Re: Delphi mit Java komunizieren
Jede Klasse wird automatische in eine .class gepackt. Du solltest (einfach weil es sauber ist) für jede öffentliche Klasse auch immer eine eigene Datei verwenden (was anderes erlaubt Java auch gar nicht!). Mehrere Klassen in einer Datei macht keine Sinn. Zusammengehörigkeit sollte man ja durch das package erzeugen.
Was dein Problem angeht, so weiß ich nicht genau was du mit
Delphi-Quellcode:
genau erreichen willst.
Options[0] := './HelloWorld.class';
Ich glaube da kommen wir nicht um ein wenig mehr Theorie zur Vorgehensweise rum. Ich hoffe ich kann es halbwegs verständlich (und korrekt) erklären. Java läuft wie gesagt immer plattform-unabhängig in der virtuellen Maschine. Diese Virtuelle Maschine muss einmal für jede Plattform entwickelt werden, die Java unterstützen soll. Der Vorteil ist halt, dass du nur ein Programm (die virtuelle Maschine) für die Plattform schreiben musst. Genau genommen musst nicht mal du das tun, für die großen Plattformen macht das SUN. Du schreibst deine Programme nur einmal und sie laufen überall. Sprachen wie Delphi, C und C++ sind hingegen Plattformspezifisch. Das stimmt so auch nicht 100%ig. Eine C Datei kann so geschrieben werden, dass man Code für verschiedene Plattformen aus ihr ohne Änderung erzeugen kann, aber wenn sie werden halt für eine Plattform (gegen entsprechende Bibliotheken) gelinkt. Du bekommst halt unter Windows eine .exe. Bei den Unix Derivaten gibt es dann ausführbare Dateien (die Erweiterung ist egal). Bibliotheken unter Windows werden dann in .dlls gelinkt, unter Linux in .so usw. Code der so gelinkt wurde, kann nativ von der entsprechenden Plattform ausgeführt werden. Die JVM muss wie gesagt mind. einmal für jede Plattform geschrieben werden, die Java unterstützt. Die JVM besteht somit aus nativem Code. JNI ist jetzt eine Java Schnittstelle zur nativen Welt (also der Plattform auf dem die JVM läuft). Code der nativ aufgerufen wird, ist dann auch wirklich an die jeweilige Plattform gebunden! Die JVM ist jetzt sozusagen ein Vermittler. Java Code für die Virtuelle Maschine wird hier in native Befehle umgesetzt. In welche hängt von der Plattform ab, aber du musst dich eben nicht drum kümmern. Das Java Native Interface funktioniert jetzt aber in Beide Richtungen. Das heißt wenn du nativen Code in Java verwenden möchtest, wird der halt in der anderen Richtung umgewandelt. Du hast also etwas wie NATIV <--> JVM <--> Java Code Alles was gemacht wird, läuft also immer über die JVM. In deinem Fall ist die Native Aussenwelt dein Delphi. Delphi kann nichts mit Java Klassen anfangen und diese nichts mit Delphi. Bei der JVM sieht dass anders aus. Delphi kann hier auf native Schnittstellen zur JVM zugreifen und umgekehrt. Anders gesagt, Delphi kommuniziert jetzt mit der JVM, die arbeitet den Java Code ab und gibt das Ergebnis an Delphi weiter. Das sind nur grob die Grundlagen, warum du dir eine Instanz der JVM in Delphi holst. Unter Windows kennst du sicherlich Pfade. Der Suchpfad PATH z.B. enthält alle Ordner, die nach Anwendungen durchsucht werden. Tippst du einen Befehl auf der Konsole ein, so gibt es drei Möglichkeiten: 1) Er liegt im aktuellen Verzeichnis und wird ausgeführt 2) Windows findet ihn im Suchpfad und er wird ausgefürht 3) er wird nicht gefunden Das Windows einen solchen Suchpfad kennt ist zwar schön, hat aber wenig zu bedeuten. Einerseits soll ja Java auf allen Plattformen lauffähig sein (nicht jede muss einen Suchpfad haben) und ausserdem muss Java nur die Lage von .class und .jar Dateien kennen. Die kann Windows (oder eine andere Plattform) aber nicht ausführen. Also würde ein Suchpfad unnötig groß werden. Die Lösung ist einfach, die JVM schafft sich ihren eigenen Suchpfad. Dieser wird halt treffender Weise mit ClassPath bezeichnet. Du kannst den entweder global für deine jeweilige Plattform setzen oder als Argument beim Start mitgeben. Alle Klassen auf die Java zugreifen können soll, müssen im Classpath bekannt gemacht werden. Du kannst entweder alle Klassen einzeln angeben oder sie in ein .jar packen und dieses in den ClassPath einfügen. Steht eine Klasse nicht im Pfad, kann sie nicht gefunden werden. Ohne Angabe eines ClassPath wird (denke ich) die JVM nur im aktuellen Ordner (in ihrem Fall das bin Verzeichnis des JRE) nachschauen. Liegt hier keine .class, pech. So, damit wären wir auch schon bei deinem Aufruf. Hoffe hab dich nicht schon jetzt gelangweilt, ein klein wenig kommt noch. Dein Delphi Programm möchte auf Java-Code zugreifen, muss also den Weg über die Schnittstelle JNI gehen. Dies tust du, indem du dir eine Instanz der JVM holst. Wo diese Instanz genau herkommt weißt du eigentlich nicht so recht (rein aus Delphi Sicht). Die Frage ist, ob du es wissen musst. Eigentlich nein! Hast du die Java-Datei, die du ausführen möchtest, so kennst du auch ihren Pfad. Damit kannst du den einfach bekannt machen. Den Klassenpfad machst du der JVM bei ihrem Start bekannt. Hierzu musst einfach -Djava.class.path=<ClassPathEintrag> als Option mit an die JVM geben. Du solltest dich da echt an das Bsp. von der Seite 2 halten! Gibst du nur einen Klassennamen an, weiß die JVM nichts damit anzufangen. Klar, sie könnte die Klasse einfach einmal ausführen und fertig. Aber das möchtest du ja nicht, du möchtest ja, dass Delphi mit dieser Klasse kommunizieren kann. Diese Option solltest du also übergeben. Dann weiß die JVM, dass es eine solche Klasse im Suchpfad gibt. Hast du die JVM in Delphi gestartet, holst du dir von der jetzt einen Zugriff auf das JNI. Dies ist die Brücke über die nativ (Delphi) mit Java kommuniziert. Du holst dir eine Instanz von TJNIEnv. Über diese Instanz finden dann die Aufrufe statt (und werden entsprechend übersetzt). Alles was du nun machst entspricht so ziemlich dem, was du in den JNI Texten von Sun findest. Du hast natürlich statt C eine Delphi Kapselung, aber im Prinzip tust du das gleiche. Mittels FindClass kannst du dir die Klasse die du aufrufen möchtest zurückgeben lassen. Hierbei sucht das JNIEnv einfach im Classpath der JVM nach der entsprechenden Klasse und liefert dir eine Adresse über die du sie erreichst. Hast du eine Klasse, kannst du in dieser wiederum nach Methoden und Variablen suchen. Du bekommst (unter C zumindest) immer eine ID, die du für den entsprechenden Aufruf mit angeben musst. Wichtig ist hier immer zu schauen, dass du eine gültige Adresse bekommst. Wie das konkret für Delphi aussieht müsste auch ich erst nachlesen, denke aber das findest du schon! Grob gibt es halt die JNI Seiten von Sun an denen du dich orientieren kannst. Da werden Beispiele zwar in C (ausser man hat es geändert) angegeben, was die Syntax nicht sehr Delphi ähnlich macht, aber verstehen wirst du die schon! env* entspricht dann halt deiner Klasse TJNIEnv, ähnlich leicht sind andere Entsprechungen zu erkennen. Die Signatur der Methoden kann natürlich in der Delphi Kapselung exakt der von JNI entsprechen oder (da es eine Kapselung ist) auch abweichen. Deswegen möchte ich hier erstmal nichts falsches sagen. Hoffe du hast grob verstanden warum du wirklich den Klassenpfad setzten musst und nicht den Namen einer Datei angeben reicht. |
Re: Delphi mit Java komunizieren
hey. danke .. das war echt ne super erklärung . Jetzt hab ich das verstanden denk ich .. zumindest in der Theorie. in der Praxis sieht es ganz anders aus. Hier meine procedure, die ich geschrieben hab.
Eigentlich ist es ja zum größten Teil erstmal nur abgeschrieben aber egal :D .. Also ich habe in dem Order C:\Projekt Java\Delphi Code\ 2 Klassen. Einmal Main.class und einmal HelloWorld.class. in die InputBox habe ich nun diesen Pfad C:\Projekt Java\Delphi Code\ angegeben Aber bei dem Punkt //Load the VM bricht er ab. mit demm error -1
Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
Var ClassPath : string; begin try JavaVM := TJavaVM.Create; // Set the options for the VM ClassPath := InputBox('JavaD','Enter the Java classpath', 'C:\Projects\DJNI\classes'); FillChar(Options, SizeOf(Options), #0); Options[0].optionString := PChar('-Djava.class.path=' + ClassPath); VM_args.version := JNI_VERSION_1_2; VM_args.options := @Options; VM_args.nOptions := 1; {hier bricht er ab} // Load the VM Errcode := JavaVM.LoadVM(VM_args); if Errcode < 0 then begin ShowMessage(Format('Error loading JavaVM, error code = %d', [Errcode])); Exit; end; // Create a Java environment from the JVM's Env (another wrapper class) JNIEnv := TJNIEnv.Create(JavaVM.Env); // Find the class in the file system. This is why we added // the current directory to the Java classpath above. Cls := JNIEnv.FindClass('HWJava'); if Cls = nil then begin ShowMessage('Can''t find class: HWJava'); Exit; end; // Find the static method 'printHello' within the HWJava class Mid := JNIEnv.GetStaticMethodID(Cls, 'printHello', '()V'); if Mid = nil then begin ShowMessage('Can''t find method: printHello'); Exit; end; // Call the static method JNIEnv.CallStaticVoidMethod(Cls, Mid, []); except on E : Exception do ShowMessage('Error: ' + E.Message); end; end; |
Re: Delphi mit Java komunizieren
Hm, entschuldigst du dich gerade dafür, dass du einen (so unscheinbaren) Beitrag übersehen hast?
:wiejetzt: Wenn das mal nicht mir rausschmiss aus der DP geandet wird... :-D |
Re: Delphi mit Java komunizieren
:D sorry ,dass ichs erst übersehen habe :D .. tut mir leid. IHR DÜRFT MICH JETZT RAUSSCHMEIßEN :D (nein scherz .. tut das bitte nicht) ..aber die Erklärung vorhin zur JVM von dir war echt sehr gut..^^
aber das nächste prob hab ich schon gepostet .. da kommt immer noch der Errorcode -1 ^^ |
Re: Delphi mit Java komunizieren
Danke erstmal für die Blumen.
Ja, werd mal Daniel oder so bescheid sagen, denke da versteht der dann auch keinen Spaß! Was dein Problem angeht, so hab ich eine Vermutung woran das liegen könnte. Also für deine Testzwecke kannst du natürlich die Eingabebox weglassen. Du kannst erstmal einen Pfad statisch im Source setzen (oder halt die Eingabe nehmen, was für dich praktischer ist). Jedenfalls gibt es hier mehrere Fallen, in die du tappen kannst. Die eine (ich denke die ist hier das Problem) liegt darin, dass Leerzeichen im Pfad sich immer schlecht machen. Versuch es einfach mal mit den üblichen Verdächtigen, in dem Fall also "dein Pfad mit Leerzeichen" und / oder damit, dass du einfach einen Pfad ohne Leerzeichen nimmst (e.g. C:\Test). Die andere Sache (die hier aber nicht zu treffen dürfte) ist, dass Java das \ als Escape zeichen ansieht, da du hier aber nichts direkt an ein Programm übergibst, solltest das noch kein Problem sein. Liegt es nicht am Leerzeichen kannst du noch zusätzlich das Escapen von \ in \\ versuchen (also C:\\...) |
Re: Delphi mit Java komunizieren
Liste der Anhänge anzeigen (Anzahl: 1)
Hi,
ich glaube ich muss nochmal etwas korrigieren, was ich einst (lang lang ist's her) sagte. Dein Fehler liegt wahrscheinlich immer noch an der JVM.dll. Ich sagte damals etwas dumm, dass du auch nur die .dll kopieren kannst. Das stimmt so natürlich null! Das Problem ist, dass weitere Files benötigt werden, deren Pfad relativ zur .dll ist. An sich wäre es eh eine unschöne Lösung eine Datei in jeden Ornder zu kopieren, der diese benötigt (würde ihren Sinn stark in Frage stellen!). Ich hätte einfach deutlicher sagen sollen, dass es eigentlich keine ernsthafte Alternative ist (schätze du hast die Lösung gewählt). Es gibt aber weiterhin zwei Möglichkeiten, die die schon im alten Beitrag nannte gilt immer noch. Du musst einfach den Suchpfad unter Windows so setzen, dass die dll mit in diesem liegt. Das Problem ist allerdings, dass du damit natürlcih auf jedem Rechner auf dem dein Programm läuft den Pfad der jvm.dll ermitteln und in die PATH Variable aufnehmen musst. Gerade bei W2k und XP (und Nachfolger) heißt dass, das du dich wohl einmal als Admin anmelden musst, nicht sehr praktisch. Schöner ist es, wenn man die Dll einfach dynamisch lädt. Immerhin sind das dynamische Bibliotheken, ihr Sinn liegt also gerade darin. Dynamisch heißt hier einfach, dass du nicht statisch gegen eine dll linkst sondern die dll erst zur Laufzeit bekannt ist. Dann wird in dieser dll die Adresse des Einsprungpunktes (einer Funktion) gesucht und diese dann ausgeführt. Der Vorteil liegt klar auf der Hand, du kannst eine .exe direkt starten und musst dich nicht kümmern, wo die jvm.dll liegt. Genau gesagt kümmert sich dein Programm darum, also einmal (beim Programmieren) mussst du dich drum kümmern, aber eben nicht mehr bei der Ausführung. Bleibt also nur das Problem, wie du den Pfad der JVM.dll findest und wie deine TJavaVM von diesem Pfad erfährt. Letzteres (hab mir jetzt auch mal JavaD etwas näher angeschaut) ist gar kein Problem. Es gibt einen überladenen Konstruktor der TJavaVM. Diesem kannst du auch den Pfad zur JVM.dll übergeben. Wo also findet man diese Datei? Festplatte durchsuchen könnte ein Weilchen dauern und wäre kaum sinnvoll. Standardpfade sind etwas worauf man sich nie verlassen sollte (schon Programme die einen Ordner 'Program Files' anlegen nerven doch). Aber Suns JRE trägt sich ganz vorbildlich in die Registry ein. Hab mal geguckt, auf meinem Rechner stimmen Suns Angaben natürlich völlig mit der Position der Schlüssel überein. Deshalb häng ich dir jetzt auch mal einen kleine Wrapper an. Der erzeugt dir die TJavaVM und TJniEnv und sucht dabei automatisch den Pfad zur JVM.dll. Du kannst einfach eine neue Instanz mit TJvm.Create(<ClassPath>) erzeugen. In dem Pfad klappt dann auch ein '.' oder ähnliches. Schöner ist natürlich, wenn du für Java-Klassen einen eigenen Ordner anlegst. Mit dem Aufruf des Konstruktors wird jedenfalls eine TJavaVM angelegt (also die JVM.dll geladen). Treten keine Fehler auf, so hat alles geklappt (es gibt keine andere Rückmeldung). Ja, vielleicht hilft es dir erstmal weiter. Da mich das Thema auch gerade interessiert werde ich es mir mal noch näher angucken. Hatte bisher immer den umgekehrten Weg behandelt, dass ein Java-Programm nativen Code ausführen muss. Da sieht vieles natürlich ähnlich aus (immerhin läuft alles über die gleiche Schnittstelle), aber natürlich muss man sich da nicht um das Laden der JVM sondern um das laden der Biblitheken in Java kümmern (was recht einfach ist!). Also wenn ich jetzt so weiter mache, wie im angegebenen Beispiel bekomme ich noch Fehlermeldungen (bei Aufruf einer Methode), aber mal schauen, denke ich mach da nur noch was falsch. |
Re: Delphi mit Java komunizieren
das heißt wenn ich diese Unit einbeziehen und einfach den Befehl
TJvm.Create(<ClassPath>) aufrufe, erzeugt er mir gleich die JVM instanz ? .. also fürht sozusagen automatisch den befehl JavaVM := TJavaVM.Create; aus ?! erzeugt der befehl TJvm.Create(<ClassPath>) auch gleich ein Objekt der Klasse TJNIEnv ? Nochmal Vielen Dank. Hier bekommt man echt gute Hilfe :) . bin begeistert |
Re: Delphi mit Java komunizieren
Liste der Anhänge anzeigen (Anzahl: 1)
So,
hab mal ein kleines Beispielprojekt zusammengestellt. Ist sehr sehr einfach gehalten, sollte dir aber grob klar machen wie du dein Programm (das etwas mehr beihalten sollte als die Klasse hier) zum laufen bekommst. Der Java-Src liegt dann natürlich auch bei. Die Java Sachen liegen im Unterordner Java, der Delphicode direkt im Ordner. Du brauchst dir eigentlich nur das Formular anschauen, die andere .pas hast du schon. Das komplette Anlegen der JVM und TJNIEnv passiert im onCreate des Fomulars (ist nur der Aufruf von TJvm.Create (mit dem ClassPath), was deine Frage beantworten dürfte, ja legt Beides an. Dann hast du ein Formular mit vier Buttons. Die machen eigentlich genau das was drauf steht. Einmal wird eine statische Variable gelesen, einmal eine nicht statsiche, einmal eine statische Methode ausgeführt, einmal eine nicht-statische. Das ist alles. Hatte gerade ein paar Probleme mit dem korrekten Erzeugen einer neuen Instanz (übersehen, dass ich die Method-Id des Standardkonstruktors mit übergeben muss). Da ist halt wenn du andersrum arbeitest das schöne, dass du natürlich schon eine Instanz (als this Zeiger) hast. Ok, der Code mag im ersten Moment etwas kompliziert wirken (gerade was die Signaturen von Methoden angeht), ist aber super einfach. Muss hier auch sagen, die Kapselung von diesem JavaD ist super! Ist wirklich einfach wenn man berücksichtigt, dass hier eigentlich vollkommen verschiedene Systeme aufeinander treffen (auch ein Lob an das imho durchdachte JNI!) Hab ordentlich viele Kommentare geschrieben, hoffe die helfen dir weiter. Ja, wie gesagt damit solltest du eigentlich was zum Laufen bekommen. Viel Spaß + Erfolg! |
Re: Delphi mit Java komunizieren
hey. das TextProgramm ist gut. und behebt eig alle Fragen :)
also wie ich das sehe gibts Felder ?!!! und Methoden. Methoden sind wahrscheinlich eine Art proceduren?!! aber was sind Felder bzw. Field ^^. und dann ist das ganze einmal in statisch und nicht statisch geteilt. Bei dem einen wird eine Instanz erzeugt bei dem anderen nicht. was hat es damit aufsich ?! reichen mir diese 4 Teile um so auch komplexere JavaProgramme zu steuern. Oder gibt es noch weit aus mehr Befehle ? |
Re: Delphi mit Java komunizieren
Felder und Methoden, ja, dass sind einfach nur Bezeichnungen in der OOP. Ein Feld entspricht eigentlich einer normalen Variablen in einer Klasse, Methoden sind wiederum entweder Prozeduren oder Funktionen in einer Klasse. Das ist es grob gesagt auch schon.
Das Beispiel mit den Feldern solltest du eigentlich in sauberen Code so gut wie nie brauchen. Zwar unterstützt Java keine Properties, aber natürlich gibt es auch hier getter und setter (und bei Beans entspricht das den Properties). Jedenfalls gilt für guten Java Code, dass eigentlich alle Variablen private sind und du über Methoden auf diese zugreifst. Damit kann man schon eine unterschiedliche Sichtbarkeit (für's Schreiben und Lesen) ermöglichen (hat natürlich noch andere Vorteile). Andererseits kennt Java auch keine direkten Konstanten bzw. man hat kein const Präfix sondern setzt eine Variable static final (entspricht dem Konstanten). Ja, damit wären wir auch schon bei static. Statische Variablen und Methoden haben eine Besonderheit, sie werden an einer festen Adresse angelegt. Egal wer auf eine solche Methode/Variable zugreift, es handelt sich immer um die selbe!
Code:
Das wäre sehr einfaches Beispiel für static vs. non-static. Wichtig ist, dass du die nicht als sauberes Beispiel auffässt! Da sind einige Sachen nicht schön!
class TestClass {
static int staticFoo = 0; int foo = 0; } class Test { public static void main(String[] args) { TestClass tc1 = new TestClass(); TestClass tc2 = new TestClass(); tc1.foo++; // tc1.foo = 1, tc2.foo = 0 tc1.foo++; // tc1.foo = 2, tc2.foo = 0 tc1.staticFoo++; // tc1.staticFoo = 1, tc2.staticFoo = 1 tc2.staticFoo++; // tc1.staticFoo = 2, tc2.staticFoo = 2 TestClass.staticFoo++; // tc1.staticFoo = 3, tc2.staticFoo = 3 } } Bei statischen Variablen bzw. Methoden handelt es sich um Dinge, die für diese Klasse einzigartig sind. Legst du mit new eine neue Instanz einer Klasse an (oder nimm Create in Delphi), dann wird für diese neue Instanz eigener Speicher reserviert. Das ist auch in den meisten Fällen gewollt. Als gutes Beispiel bietet sich hier ein Bank an, es möchte sicherlich jeder Kunde auf sein Konto zugreifen und nicht alle auf eins (da würden die Staatsschulden wohl das Gemeinschaftskonto etwas tiefrot aussehen lassen). Das heißt, jede Variable (z.B. der Kontostand) wird einzeln für ein bestimmtes Objekt geändert und gespeichert. Wie gesagt, dass ist das was du normalerweise in Programmen hast. Deswegen benötigt man auch einen neue Instanz, hat man keine neue Instanz erzeugt, wurde noch gar kein Speicher reserviert, wo also sollen die Daten hin? Legt man keine Instanz an, erwartet einen unter Java die NullPointerException (EAccessViolation unter Delphi). Jetzt gibt es aber Dinge, die möchte man statisch haben. Statisch heißt, dass der Speicher automatisch beim Laden der Klasse angelegt wird und für diese Klasse eine feste Position hat. Es gibt auch hier zwei einfache Beispiele: 1) Die public static void main(String[] args), eine statische Methode. Warum ist die statisch? Nun ja, wenn du das Programm startest, kannst du ja noch keine Instanz von irgendwas erzeugt haben, da bietet sich also ein statischer Einsprungpunkt an. 2) Konstanten. Diese haben die Form final static <DatenTyp> <Name> = <Wert> Wenn ich eine Konstante habe, dann sollte sie für alle Instanzen gleich sein. Greifen wir nochmal das Beispiel des Kontos auf und sagen wir, dass ein Kontotyp als Zahl gespeichert wird. Dann steht die 1 immer für ein Girokonto und die 2 immer für ein Sparbuch, egal wessen Konto ich gerade betrachte. Der final Teil in der Konstante sorgt dafür, dass diese auch an einer festen Adresse im Speicher steht und nicht verändert werden kann (bringt auch einige Vorteile bei Zugriff auf diese Variable). Wichtig ist, dass man trotzdem statische Variablen/Methoden vermeidet. Man sollte sich immer überlegen, ob sie nötig sind. Es gibt wie gesagt Gründe für den Einsatz, aber man möchte ja auch nicht unnötig Speicher reserviert halten. Vorallem kann es auch zu Problemen kommen, wenn man nicht merkt dass eine Variable statisch ist (s.Bsp. Konto), würde hier versehentlich alles auf ein Konto geschrieben werden... Für statische Methoden/Variablen gilt auch, dass der Aufruf immer direkt mit dem vorangestellten Klassennamen erfolgt. Hier erkennt man dann schnell, ob es sich um eine statische oder nicht statische Variable handelt. Nochmal am Bsp. von oben:
Code:
Ja, was das Programm angeht, so denke ich solltest du damit eigentlich auf jedes (auch komplexe) Java Programm zugreifen können. Wie du siehst gibt es immer die Unterscheidung zwischen statisch und nicht statisch (die ich dir hoffentlich näher bringen konnte). Der Rest ist ja eigentlich nur dass Aufrufen einer Methode oder das Lesen einer Variable, aus mehr bestehen Programme ja eigentlich wieder nicht.
class TestClass {
static int staticFoo = 0; int foo = 0; } class Test { public static void main(String[] args) { // RICHTIG: // Vorangestellter Klassenname macht deutlich dass es um eine statische Variable geht TestClass.staticFoo++; // FALSCH: // sollte zwar klappen, führt aber zu einem Warning! // ausserdem kann keiner erkennen dass diese Variable statisch ist! TestClass tc1 = new TestClass(); tc1.staticFoo++; // AUCH FALSCH: // foo ist eine Instanz Variable, solch ein Aufruf ist also nicht möglich! TestClass.foo++; } } In meinem Beispiel ist es allerdings auf primitive Datentypen beschränkt. Natürlich kannst du auch Intanzen als Rückgabetyp bekommen. Wie man mit denen weiterarbeitet, findest du dann wiederum auf den JNI Seiten. Dort werden auch alle verwendeten Funktionen (ausser dem anlegen der JVM und JNIEnv in Delphi) erklärt. Beispielcode ist dort zwar in C, aber die Erklärungen sind auch immer ohne Code verständlich (soviel gibt es dort imho auch gar nicht). Eine Sache die noch ganz wichtig ist, Java-Strings sind Klassen! Wenn du einen String an Java übergeben willst bzw. umgekehrt, wirst du von der JNIEnv die Methoden JavaStringToString und StringToJavaString verwenden müssen (glaube die hießen so). Ja, wie gesagt, die Basis für das Arbeiten mit Java-Programmen solltest du haben, aber ein wenig musst du dann auch noch selbst machen ;-) Ausser du zahlst gut! :mrgreen: |
Re: Delphi mit Java komunizieren
Hey,
also nach deinem Genialen Textprogramm und deiner Hilfe mit statisch und nich statisch wurd mir jetzt einiges klar .. unter anderem auch, wie das tutorial aufgebaut ist und welche funktionen es gibt, wie sie aufgebaut sind ec.t Danke nochmal :) Eine frage hab ich aber dann doch noch. Ich soll ja am ende ein programm mit delphi steuern. In diesem Programm gibt es eine Klasse, die nennt sich renderszene oder so. dem objekt diese klasse kann man durch methoden daten zuweisen, wie er was rendert und mit der methode render malt er mir dann was auf diese Oberfläche. (Oberfläche ist die klasse) .. also so ungefähr . Ise es möglich diese Oberfläche auf mein Form1 zu bekommen ?! Brauchste noch irgendwelche Informationen zur Klasse ?! Wenn dass vllt. nicht geht wäre die alternative das GANZE programm im delphi fenster anzeigen zu können ?! |
Re: Delphi mit Java komunizieren
Zitat:
Am besten ist halt so viel Information wie möglich (wo ich natürlich nicht weiß, wieviel du davon rausgeben darfst/möchtest/kannst). An sich ist natürlich hauptsächlich die Methode die zeichnet wichtig. Sie wird ja irgendwelche Daten irgendwie darstellen. Wichtig sind hier natürlich nicht die Daten oder wo sie herkommen, sondern wo wird gezeichnet. Wenn du also die Zeichenmethode hast, dann wäre es auch wichtig zu wissen was für eine Klasse als Ziel für's zeichnen übergeben wird. Ist es eine eigene Klasse wäre halt der entsprechende Vorfahrtyp interessant. Ob und wenn ja wie man ein komplettes Java-Fenster in ein Delphi Programm einbettet ist mir komplett unbekannt (denke mal nicht dass das so ohne weiteres geht, sind einfach unterschiedliche Ansätze). Ich denke mal, dass es auf eine Art Adapter hinaus laufen dürfte. Also ich denke du musst auf jeden Fall das Java-Programm erweitern. Hier kannst du evtl. dafür sorgen, dass ein Format erstellt wird, dass Delphi auch versteht (z.B. eine Bitmap) oder du müsstest halt die Render-Methode nach Delphi übersetzen, so dass du einfach die Daten oder Zeichenbefehle an Delphi weiterreichst. Wenn es einen schöneren Weg gibt, ist er mir leider nicht bekannt. Wie gesagt, der Aufwand und Ähnliches hängt stark von deiner Klasse ab. |
Re: Delphi mit Java komunizieren
Hallo, ich war die letzte Woche leider im Urlaub. Ich versuche in den nächsten Tagen mehr über die Klasse und über den Rendervorgang zu erfahren ..
Simon |
Re: Delphi mit Java komunizieren
Hi,
dann hoffe ich doch mal, dass du einen schönen (und erholsamen) Urlaub hattest! Gruß Der Unwissende |
Re: Delphi mit Java komunizieren
Hey,
also bevor wir das mit dem rendern klären hab ich doch nochn paar fragen. Bin jetzt fast ganz mit allen befehlen durchgestiegen. Ich bin grad dabei eine Bibliohek an Befehlen zu erstellen. Will am ende auchn Tutorial dazu ins Netz stellen. Wenns geht auf diese Seite. 1. Also Je nachdem welchen Rückgabetyp ich habe benutze ich folgende Befehle CallObjectMethode CallIntMethode CallByteMethode usw. Dabei kann ich arrays übergeben und alles. Das is mit klar wie das geht. Was ist aber wenn ich einen array zurückbekomme ? also nicht nur einen einfachen Integertyp oder nen einfachen ByteTyp, sondern arrays. 2. Dann bin ich noch auf folgende Befehle gestoßen. Vielleicht ist das auch schon die Antwort zu meiner 1. frage. Es gibt für alle CallBlablubMethoden auch noch folgende Methoden CallObjectMethodeA CallIntMethodeA was bedeutet das A ? ebenso gibt es diese Funktionen auch noch mit einem V? 3. was bedeutet der Befehl ReleaseShortArrayElements .. also speziell das Release ^^ Diese 3 Sachen sind mir noch nicht so geheuer. ich brauch die um meine Bibliothek zu ende zu bringen Danke Simon |
Re: Delphi mit Java komunizieren
Also zu der Sache mit den Arrays: Arrays sind in Java Objekte, vielleicht kannst du dann mit dem CallObjectMethode was anfangen.
|
Re: Delphi mit Java komunizieren
Gut also zum Befehl ReleaseIntArrayElement.
Dieses Release heißt ja sowas wie freigabe. Was bedeutet das in Java ? Bin mir nicht ganz sicher, ob arrays einfach mit CallObjectMethode geholt werden können, denn sie sind in Delphi als JObjectArray deklariert. Vllt. können diese auch als einfache Objekte behandelt werden un mit CallObjectMethode geholt werden. Was aber hat es mit dem CallObjectMethodeA befehl oder dem CallObjectMethodeV Befehl auf sich. Welchen Unterschied hat dieser Befehl zum normalen CallObjectMethode? -------------------------------------------------------------------------------------------------- So ein großer Absatz und ein großer Sprung. Ich hab nun einiges an Informationen über die Klasse in Erfahrung gebracht. Also das mit der Bitmap variante ist möglich, hat aber den nachteil, dass ich den schon bestehenden Eventlistener in Delphi neu proggen muss. Mit diesem Eventlistener kann man zum Beispiel ein gebief mit der Maus markieren welches rangezoomt werden soll. Nun gut. Also zum Rendervorgang Grob gesagt gibt es eine Klasse, die nennt sich Map. Dort sind alle informationen über die Karte gespeichert, die später gerendert werden können. Mit Methoden kann ich diese Informationnen ändern. Das wirkt sich dann auf das späterer Rendern aus (z.b. Zoomen). Ich weiß nicht ob ich es ganz richtig verstanden habe, aber gerendert wird mit der Klasse graphics2D und es werden 4 ebenen als Bild gerendert. Einmal Geometrie, dann Text usw.. Geseichnet wird mit einfachen Vectoren dieser Klasse und ich glaub am ende wird diese alles auf einem JPanel gespeichert. Das zusammenfügen und alles macht eine eigens entwickelte Klasse namens MBView oder so. Der sag ich Renderkarte und alles geschieht automatisch. Die Klasse ruft Graphics2d usw. auf. Achso ich hab noch den Befehl PopLocalFrame und PushLocalFrame gefunden. Vielleicht ist der ja des Rätsels lösung. Gruß Simon |
Re: Delphi mit Java komunizieren
Zitat:
Mit CallObjectMethode werden die Parameter einfach Kommagetrennt (wie bei einem lokalen Aufruf üblich) übergeben. Eine CallObjectMethodeA würde hier ein Array erwarten, in dem alle Variablen stehen (so wie beim Format die Argumente übergeben werden) Und CallObjectMethodeV erwartet die Parameter als va_list. Du siehst letztlich ist es völlig äquivalent (ob intern nicht eh immer in die jeweils andere Form gewandelt wird, merkst du nicht einmal). [ADD1] Werde mich brav an die Forenregeln halten und ranhängen, solange hier keiner zwischendrin antwortet! Zitat:
Rufst du Release für dieses Array auf, so muss der Zustand des Arrays im Java-Programm nicht mehr konsistent mit dem in deinem nativen Teil übereinstimmen. Vielmehr würde es dazu kommen, dass die Änderungen nur noch lokal stattfinden und Java das "alte" Array wieder herstellt. [/ADD1] [ADD2] Sorry, hab gerade noch ein paar Dinge nebenbei zu erledigen und gleichzeitig immer ein paar Minuten die ich eh warten muss, so dass ich hier etwas sprunghaft schreibe. Deswegen kommen jetzt erstmal die Stellen, die ich sofort und/oder kurz beantworten kann. Zitat:
Ja, hier solltest du Frame wörtlich verstehen, es ist nur eine Rahmen. Genau genommen kannst du dir hier die Größe eines Rahmen, der x-Referenzen aufnimmt zusichern lassen. Mehr ist es nicht. Du kannst hier dann einfach bestimmen ob die Anzahl der Referenzen übergeben werden kann oder ob nicht genug Speicher zur Verfügung steht. Es bezieht sich alles auf die LocalReferences (auch das wäre wohl wieder ein Thema für sich). Ja, die Referenzen müssen auch (geht ja aus dem Namen der Methode hervor) localReferences sein. Die bekommst du wenn du die JNI newObject Methode verwendest (wie auch immer die heißt, weißt schon was ich meine). [/ADD2] [ADD3] Zitat:
Ich denke der Weg bürgt dann doch einige (mögliche) Probleme in sich. Da ist es dann doch besser, wenn du einfach einen anderen Weg wählst. Was die neuen Listener angeht, so hast du nicht unrecht. Ich denke man kann halt nicht mal eben ein Java Programm komplett in einer anderen Umgebung zum laufen bekommen. Dafür ist Java ja auch nie gedacht gewesen, deswegen muss ich hier sagen, dass JNI trotz allem schon bis zu diesem Punkt gezeigt hat, wie mächtig es trotz alledem ist! Damit du wenig Inkonsistenz zwischen dem Java Programm und dem Delphi-Code hast, würde ich dir ein raten, dass du hier eine Art Adapter baust. Du zeigst einfach das gerendert Bild an (wie ist jetzt erstmal egal). Um an dieses Bild zu kommen gibt es halt eine Schnittstelle, die dir das aktuelle Bild (das sonst auf einem Panel dargestellt werden würde) liefert. Dieses kannst du dann in Delphi anzeigen. Hier gibt es dann für alle implementierten Ereignisse einen Beobachter, der jedes dieser Ereignisse einfach an das Java-Programm weiterreicht. Also um es einfach zu sagen, um das Zoomen sollte sich dann weiterhin dass Java-Programm kümmern, nur der auslöser ist dann halt dein Delphi-Programm. Obwohl, hier kommt dann natürlich das Problem zu tragen, dass du einen Auswahlrahmen dann in Delphi zeichnen musst... Na ja, versuch einfach sowenig wie möglich nach Delphi zu übernehmen und weiterhin Java die Arbeit machen zu lassen, dann sind Änderungen leichter möglich (ohne dass es zu Inkonsistenzen kommt). Wie gesagt, es ist nur meine Meinung, dass das der beste Weg ist, vielleicht gibt es eine schöne Zusammenarbeit zwischen den beiden Welten. [/ADD3] |
Re: Delphi mit Java komunizieren
Gut also nochmal :)
Ich habe eine Klasse Namens Map. Die hat ganz viele eigenschaften. z.b. wie weit rangezoomt ist , welche elemente, wie gezeichnet werden. Diese Eigenschaften kann ich über Methoden ändern. d.h. diese Methoden kann ich über delphi steuern. Jetzt kommt es zum render. CallVoidMethod('render mir ein BITMAP'); so der spuckt mir jetzt ein Bitmap aus und ich lade diese Bitmap ganz einfach in Delphi. Da gibt es ja auch Komponenten zum laden. So. Jetzt is die Karte da. Wenn ich nun auf ranzoomen drücke dann werden die Eigenschaften der map via Methode geändern, dann ruf ich die Methode Render mir eine BitMap auf und lade sie neu in Delphi. So müsste es erstmal laufen oder ? Ich denke das ist eine gut lösung. und das markieren eines Bestimmten bereiches müsste dann wieder Delphi übernehmen und die Markierten bereichsdaten via Methode an Java übergeben. |
Re: Delphi mit Java komunizieren
Zitat:
Ja, etwas vorsichtig muss du nur mit dem Satz: Zitat:
Eine HBitmap könnte eher dass sein, was sich hier eignet. Diese kannst du direkt aus der Höhe, Breite, Farbinformation und den Pixeln erzeugen. Während die ersten Teile hierbei reine Metainfos sind (die sich bei verschiedenen Maps vielleicht nicht mal ändern?) ist letzteres nur ein Array. Also nur falls du den internen Aufbau einer Bitmap nicht kennst, der ist wirklich denkbar einfach. Sagen wir du hast ein Byte pro Pixel an Farbinformation, dann kannst du dir die Bitmap so vorstellen, wie es ihr Name schon vermuten lässt, es ist einfach eine Matrix (Höhe x Breite), in der jede Zelle den Wert des Pixels enthält. Ob man es nun als Matrix betrachtet oder als ein Array ist natürlich äquivalent. Beim Array musst du halt selbst schauen, wo eine Zeile endet (jede Zeile geht natürlich von i*Breite + 0 bis i*Breite + (Breite - 1), mit 0 <= i < Höhe). Jedenfalls hast du dann alles, was du leicht übergeben kannst. Ein Array von Bytes (du wirst sicherlich mindestens ein Byte pro Pixel an Informationen nehmen?), Höhe und Breite (Integer) und die Anzahl der BitsProPixel (ebenfalls Integer, wahrscheinlich konstant). Dein Renderer muss also nur die Pixel, die gesetzt werden in einem Array abspeichern und dieses zur Verfügung stellen. In Delphi solltest du dann keine Probleme haben, mit diesen Daten weiter zu arbeiten. Natürlich kann eine Bitmap (aus der Windows Unit) auch direkt gezeichnet werden (hat ja ein Handle), du kannst aber auch den Umweg über ein TBitmap gehen (achtung, glaube windows kennt auch ein TBitmap). |
Re: Delphi mit Java komunizieren
Also es ist möglich ein Bitmap von dem Objekt "Karte" zu erstellen. Von Java aus.
dann liegt das ding als karte.bmp in einem Ordner vor. dann kommt delphi: procedure TForm1.Render ; var x,y : integer; begin // 2. Objekt erzeugen bild := TBitMap.Create; // 3. BitMap aus Datei laden, damit wird Größe gesetzt bild.LoadFromFile('karte.bmp'); // 4. Eigenschaften einstellen bild.Transparent := true; // 5. Bitmap anzeigen. x und y sind Position Canvas.Draw(x,y,bild); end; so hab ich das grob verstanden. Oder gibt es in Java eine Klasse, die genau so funktioniert und dass man dann die daten direkt, ohne sie auf der Platte zu speichern, übergibt ? |
Re: Delphi mit Java komunizieren
Liste der Anhänge anzeigen (Anzahl: 1)
So, hab jetzt noch mal etwas zu dem Thema Arrays.
Der Umgang mit Arrays ist ähnlich einfach, wie der mit allem anderen. Solange du mit primitiven Datentypen arbeitest, hast du alle Freiheiten und eine einfache Anbindung. Möchtest du mit einer kompletten Klasse arbeiten, macht es die Sache um einiges schwieriger. Objekte folgen ein paar Besonderheiten, die nicht zuletzt von der Programmiersprache abhängen. JNI ist hauptsächlich für C geschaffen, hier gibt es nicht einmal eine Entsprechung der Klasse. Was Arrays angeht, so hat Chewie ja schon richtig gesagt, dass die in Java auch wieder Objekte sind. Aber für Delphi ist das so egal. JNI geht hier mal wieder von der kleinsten Gemeinsamkeit aus. Ein Array liegt irgendwo im Adressraum der JVM. Das Objekt direkt zu kopieren ist nicht möglich (C könnte nichts mit einem Objekt anfangen). Deshalb wird eine Kopie der Werte gemacht (gilt jetzt für ein Array von einem primitiven Datentyp!) und dir ein Zeiger auf diese Kopie gegeben. Auch hier muss man schauen, wie ein Array in C aussieht. C legt Arrays immer am Stück im Speicher an. Man bekommt einen Zeiger auf das erste Element und kann (da alles am Stück liegt) den Offset von dieser Adresse zu jedem Element im Array bestimmen. Das Problem ist, dass C nicht prüfen kann wie groß das Array ist. Übergibst du das Array als Argument an eine Methode, so übergibst du hier nur den Zeiger auf das erste Element (und i.d.R. noch die Länge des Arrays). Hier kann man aber auch beliebig weit springen und in einem völlig falschen Adressraum landen, der garnichts mehr mit dem eigentlichen Array zu tun hat! JNI ist wie gesagt auf C ausgelegt, was daran liegt, dass sich C Code leicht von sehr unterschiedlichen Sprachen (auch Delphi) verwenden lässt und C auch auf nahezu jeder Plattform verfügbar ist. Jedenfalls bekommst du ein PJINT, was nur ein Zeiger auf ein Integer ist. Diesen kannst du direkt in die Adresse für ein IntegerArray casten, solltest aber bedenken, dass die Länge hier nicht übergeben wird. Wenn du also die length-Funktion von Delphi bemühst, wäre ich mir nicht sicher was sie liefert. Sicherer (und der Weg den man gehen soll, egal ob was anderes klappt oder nicht) ist es, hier die JNI Funktion zu verwenden, die dir die Länge gibt. Wie gesagt, du arbeitest mit einer lokalen Kopie. Hast du die Werte dieses Arrays verändert, so müssen diese von JNI zurückgeschrieben werden (wenn die Änderung übernommen werden soll!). Wurden die Werte nur lokal verwendet, brauchst du sie nicht zurückzuschreiben, nur um sie zu löschen (obwohl auch die Möglichkeit existiert). Jedenfalls kannst du mit einem Flag angeben, ob du commiten möchtest (zurückschreiben, nichts freigeben), nur löschen möchtest oder zurückschreiben und dann löschen. Ist dein Array das Ergebnis einer Funktion, macht zurückschreiben natürlich keinen Sinn! Ich habe das Beispiel JavaGoesDelphi nochmal um ein einfaches Integer Array erweitert. Hoffe es hilft dir weiter mit deiner Frage nach Arrays. Zitat:
Zitat:
Jedenfalls war Sun etwas früh damit dran (Web 2.0 setzt schließlich auf ähnliche Ansätze), aber egal. Java ist jedenfalls eine Sprache die im/mit Netzwerk groß gewurden ist. Die bietet somit jede Menge Alternativen zum direkten Speichern auf einem Datenträger an. Nebenbei, ich glaube JNI ist auch nur ein Netzwerkdienst, der halt lokal läuft. Jedenfalls hast du alle möglichen Alternativen. Das Problem ist, dass die meisten dieser Alternativen das Problem der unterschiedlichen Plattformen haben. So sind Java Klassen komplett anders aufgebaut als die in Delphi. Du kannst nicht einfach einen Java-Stream in einem Delphi-Stream einlesen (da hättest du schon die Probleme, dass du nicht ohne weiteres auf Adressen der virtuellen Maschine zugreifen kannst). Der Einfachste Weg ist es imho, dass du dir einfach so primitiv wie möglich die Daten holst, die du brauchst. Wenn du ein Bitmap erzeugen kannst bzw. eine beliebige Rastergrafik (was mit Java2D schon klappt), dann besteht die eigentlich nur aus zwei Teilen. Das eine ist (wie bereits erwähnt) der Datenteil. Hierbei handelt es sich um ein einfaches Array vom Typ Byte. Das kannst du ohne Probleme übertragen (wie siehst du ja im aktuellen Beispiel). Der Rest sind Metainformationen. Bei einer Bitmap halten diese sich auch deutlich in Grenzen. Was du wirklich brauchst ist die Größe (Höhe und Breite) und die Anzahl der Bits pro Pixel (hier sind 1, 8, 24 und 32) die üblichsten. 1 für Schwarz oder Weiß, 8 für indexierte Farben (wobei du dann noch die Farbpalette bräuchtest) und 24 sowie 32 für Farbbilder, die je ein Byte für R, G und B speichern (plus ein Füllbyte bei 32 Bit). Diese Metadaten sind also eigentlich nicht mehr als ein paar primitive Datentypen. In Delphi kannst du aus ebend diesen Daten sehr leicht wieder eine Bitmap erzeugen. Das sollte (imho) der einfachste und schnellste Weg sein. Das mit dem Laden- und speichern der Datei führt dann natürlich zu höheren Zugriffszeiten (durch die Festplatte) und hier auch zu evtl. Problemen (Lese/Schreibrechte, Platz auf der Platte, existierende Dateien...) |
Re: Delphi mit Java komunizieren
Hey, das trifft sich gut mit den array. dieses Thema ist mir mit der JNI noch etwaqs suspekt ^^
1) Also erstemal gibt es ja befehle wie GetIntArrayElements GetByteArrayElements usw. Diese holen sich alle Elemente des arrays ?! oder ? dann gibt es noch den Befehl GetObjectArrayElement, der immer nur ein Element des Objekts holt ?! was macht das für einen Sinn ? 2) In dem Buffer werden ja alle array Elemente als JIntarray oder so gespeichert. buffer := JIntArray(self.jvm.JniEnv.CallObjectMethod(instanc e, mid, [])); was hat aber die Funktion JIntArray da zu suchen ? und warum wird dann später nochmal alles auf der variablen p gespeichert , die glaube ich ein array Pointer ist ?! p := PIntegerArray(self.jvm.JniEnv.GetIntArrayElements( buffer, isCopy)); 3) muhaha und mit Pointern kenn ich mich nich aus :D kann ich die behandeln wie ein array , sprich EinElement := p[5] ; ? 4) Zum letzten befehl self.jvm.JniEnv.ReleaseIntArrayElements(buffer, PJInt(p), JNI_ABORT); Welche Parameter müssen da übergeben werden. Klar erstmal der array, der im Buffer gespeichert ist. Was soll der zweite übergabewer`? das ist doch dann doppeltgemoppelt ^^. ist doch das gleiche wie der buffer nur als Pointer oder ? Gruß Simon :) Fragen über Fragen :D |
Re: Delphi mit Java komunizieren
Zitat:
Wichtig ist, dass du hier den Datentyp anpasst. Die Methode self.jvm.JniEnv.CallObjectMethod gibt dir ein JObject zurück. Dies liegt daran, dass jede Instanz ein Nachfahre von JObject sein muss. Da Arrays in Java Klassen sind und du hier die Instanz eines Arrays bekommst, ist dieses Array also ein Nachfahre von Object (in Java, entspricht JObject in Delphi). Nun möchtest du aber sagen, dass du ein bestimmten Typ von Objekt hast, nämlich ein Array, dazu castest du dieses einfach. Stimmt der Typ in den du castest, wird alles klappen (andernfalls gibt es einen Laufzeitfehler!) Hier weißt du ja, dass der eigentlich Rückgabetyp ein Int-Array ist. Zitat:
Jedenfalls legst du mit GetIntArrayElements eine Kopie an, die von einem C Programm verwendet werden kann. Wie auch schon gesagt, sind in C Arrays nur Zeiger auf das erste Element. Wenn du das Array A = [1,2,3,4,5] in C übergeben möchtest, es mit 4 Byte Werten gefüllt ist, so würdest du einfach die Adresse von A[0] übergeben (@A[0] in Delphi Syntax). Nun weißt du, dass A[i] einfach der Wert ist, der an @A[0] + (i * 4) liegt. 4 Bytes ist jedes Datum groß und bei @A[0] fängst du an. So einfach sind dann auch schon die Zeiger hier. Was dir GetIntArrayElements liefert ist nicht das komplette Arrays, sondern nur die Adresse @A[0]. In Delphi gibt es (anders als in C) die Möglichkeit direkt mit dyn. Arrays zu arbeiten, dass ist das was du hier siehst. Die gelieferte Adresse wird einfach gecastet (und der Datentyp dahinter als ein IntegerArray behandelt). Danach kannst du wie mit einem normalen Array of Integer damit arbeiten. Beim Zugriff p[i] wird automatisch dereferenziert (wenn ich mich nicht irre). Jedenfalls siehst du irgendwo im Beispiel wie man auf die Elemente zugreift (sorry, gerade viel zu arbeiten). Zitat:
Nimmst du nur einen kleinen Teil, so kostet das kopieren weniger Zeit. Würdest du die Werte verändern und zurückschreiben, muss Java aber wissen, dass es nur ein kleiner Teil war den du da hast. Sagen wir du hast in Java ein Array von 10.001 Elementen und veränderst nur die letzten 10. Dann möchtest du die sicher auch wieder an die Stellen 9.990 - 10.000 schreiben. Dafür ist der zweite Parameter gut! Hoffe ich konnte dir ein paar Fragen beantworten. |
Re: Delphi mit Java komunizieren
HI,
ich habe noch eine kleine Anmerkung zu den Beispielen zu machen. bucchi war so freundlich mich auf ein Problem aufmerksam zu machen. In den Beispielen liegen die .class Dateien als Java 1.5/5.0 Kompilate vor. Diese sind so leider nicht mit Java 1.4.x (und anderen) kompatibel. Führt man das Beispiel aus, so wird die Klasse nicht gefunden (entsprechende Fehlermeldung wird ausgelöst). Zur Umgehung dieses Problems reicht es die .java Datei (\java\src\package1\subpackage\TestClass.java) mit dem eingesetzten JDK zu kompilieren (oder z.B. mit einem Compilerschalter im Kompatiblitätsmodus). Die .class Datei muss entsprechend dem Classpath abgelegt werden (\java\bin\package1\subpackage\TestClass.class), dann klappt's auch mit der 1.4.x Danke nochmal an bucchi Gruß Der Unwissende |
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:38 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz