I have a TCL file which uses Tcl's BWidget package that I've been using as a GUI for my program. I now want to be able to load up this GUI from a separate Java program. I've looked into Jacl and Swank, but they don't seem to do exactly what I want.
I've tried the following with Jacl but it's unable to evaluate the file. While debugging, I can see that it completes parsing my tcl file, but it throws an exception while parsing through the BWidget package tcl files. Here's my Java code:
Interp interp = new Interp();
try {
interp.evalFile("C:\\CTP\\Tcl\\LuxonCtp32.tcl");
} catch (TclException ex) {
int code = ex.getCompletionCode();
System.err.println("command returned bad error code: " + code);
} finally {
interp.dispose();
}
Any ideas on how I can accomplish what I want to do? Is it even possible?
Tcl itself can not display a GUI. It uses a plugin called Tk for that.
In the C reference implementation of Tcl you get Tk as well.
Tk has not been ported to Java, Tcl has.
You can not use Jacl to display Tk widgets, but TclBlend could do that, because TclBlend uses the C reference implementation of Tcl. That means that the user needs a working Tcl/Tk installation.
There are some problems with TclBlend and Tcl > 8.5 through, which result in a segfault.
IIRC you have to remove the conditional if around Tcl_FindNameOfExecutable in TclBlends C code (and compile it yourself).
Go to this site http://jtcl-project.github.io/jtcl/ and download now for the binary zip. Its a recent java tcl on github called Jtcl.
Unzip it and you will find a jar called jtcl-2.7.0.jar.
I am using Netbeans 8 my preference.
I add the jar into Project Library.
I create a java file called JTclHallo.java and this is the code.
package jtclhallo;
// import tcl.lang it belongs to jtcl-2.7.0 jar a must
import tcl.lang.*;
// Java wrapper to test JACL or JTCL.
public class JTclHallo {
public static void main(String []args) {
//Interp is a java class belonging to tcl.lang. Unrar the jtcl-2.7.0
Interp i = new Interp();
try {
//call your tcl file mine was swing.tcl from the E drive
i.eval("source E:/private/swing.tcl");
} catch (TclException e) {
System.out.println("Exception: " + e.getMessage());
}
}
}
For swing.tcl
package require java
set window [java::new javax.swing.JFrame]
$window setSize 600 400
$window setVisible true
Related
I wrote a Python program that consists out of five .py script files.
I want to execute the main of those python scripts from within a Java Application.
What are my options to do so? Using the PythonInterpreter doesn't work, as for example the datetime module can't be loaded from Jython (and I don't want the user to determine his Python path for those dependencies to work).
I compiled the whole folder to .class files using Jython's compileall. Can I embed these .class files somehow to execute the main file from within my Java Application, or how should I proceed?
Have a look at the ProcessBuilder class in java: https://docs.oracle.com/javase/7/docs/api/java/lang/ProcessBuilder.html.
The command used in the java constructor should be the same as what you would type in a command line. For example:
Process p = new ProcessBuilder("python", "myScript.py", "firstargument").start();
(the process builder does the same thing as the python subprocess module).
Have a look at running scripts through processbuilder
N.B. as for the Jython part of the question, if you go to the jython website (have a look at the FAQ section of their website www.jython.org). Check the entry "use jython from java".
I'm also interested in running Python code directly within Java, using Jython, and avoiding the need for an installed Python interpreter.
The article, 'Embedding Jython in Java Applications' explains how to reference an external *.py Python script, and pass it argument parameters, no installed Python interpreter necessary:
#pymodule.py - make this file accessible to your Java code
def square(value):
return value*value
This function can then be executed either by creating a string that
executes it, or by retrieving a pointer to the function and calling
its call method with the correct parameters:
//Java code implementing Jython and calling pymodule.py
import org.python.util.PythonInterpreter;
import org.python.core.*;
public class ImportExample {
public static void main(String [] args) throws PyException
{
PythonInterpreter pi = new PythonInterpreter();
pi.exec("from pymodule import square");
pi.set("integer", new PyInteger(42));
pi.exec("result = square(integer)");
pi.exec("print(result)");
PyInteger result = (PyInteger)pi.get("result");
System.out.println("result: "+ result.asInt());
PyFunction pf = (PyFunction)pi.get("square");
System.out.println(pf.__call__(new PyInteger(5)));
}
}
Jython's Maven/Gradle/etc dependency strings can be found at http://mvnrepository.com/artifact/org.python/jython-standalone/2.7.1
Jython JavaDoc
It is possible to load the other modules. You just need to specify the python path where your custom modules can be found. See the following test case and I am using the Python datatime/math modules inside my calling function (my_maths()) and I have multiple python files in the python.path which are imported by the main.py
#Test
public void testJython() {
Properties properties = System.getProperties();
properties.put("python.path", ".\\src\\test\\resources");
PythonInterpreter.initialize(System.getProperties(), properties, new String[0]);
PythonInterpreter interpreter = new PythonInterpreter();
interpreter.execfile(".\\src\\test\\resources\\main.py");
interpreter.set("id", 150); //set variable value
interpreter.exec("val = my_maths(id)"); //the calling function in main.py
Integer returnVal = (Integer) interpreter.eval("val").__tojava__(Integer.class);
System.out.println("return from python: " + returnVal);
}
I want to create a GUI app in java for signing j2me app which is done by JadTool.jar but it is a Command Line Interface Apps. So I just want to use it as library and pass the parameters in program. How it can be done?
Check out Runtime. It will allow you to execute a command. You can use this to start your command line interface library.
Edit:
Ah, I didn't read care carefully earlier. If you're using a Java library starting a separate process is not the best solution.
Just reference the JadTool jar from your project. If the functionality you need isn't accessible in the library, edit the source and recompile. Make sure JadTool's license allows this.
If you're against editing the source (or not allowed) try using reflection to invoke the private run method you need.
A jar is just a library of classes, the fact that it can be run from the command line is caused by the presence of a main method in a class. As jadtool's source is available it's easy to see its very simple main:
public static void main(String[] args) {
int exitStatus = -1;
try {
new JadTool().run(args);
exitStatus = 0;
} catch (Exception e) {
System.err.println("\n" + e.getMessage() + "\n");
}
System.exit(exitStatus);
}
Unfortunately, that run() method is private, so calling it directly from another class won't work, leading to a reduced set of options:
#WilliamMorrison 's solution of going via Runtime - not really a library call, but it would work.
see Any way to Invoke a private method?
Following code opens status very fine in notepad:
import java.util.*;
class test
{
public static void main(String args[])
{
try{
ProcessBuilder pb=new ProcessBuilder("notepad","F:/status");
pb.start();
}catch(Exception e)
{
System.out.println(e);
}
}
}
Following code does'not play the song:
import java.util.*;
class test
{
public static void main(String args[])
{
try{
ProcessBuilder pb=new ProcessBuilder("C:/Program Files (x86)/VideoLAN/VLC/vlc","D:/02 Tu Jaane Na");
pb.start();
}catch(Exception e)
{
System.out.println(e);
}
}
}
I think that the problem is that you're ignoring the fact that the files you're trying to open have filename extensions.
Windows Explorer doesn't display file extensions by default - that is probably why you are not aware of their existence.
The reason why notepad worked in your first example is that notepad automatically adds .txt extension to its filename parameter in case you didn't provide one yourself. So in reality the file that is being open is not status but status.txt.
VLC doesn't have this "advanced" functionality because there's no specific filename extension it is designed to work with.
So you will need to look up the dir command output and add the full file name as a parameter.
If that was the real issue - you might want to modify your Windows Explorer settings for it to display file extensions:
or, which is better, switch to a more programmer-friendly OS :)
For 1.6+ code, use Desktop.open(File) instead.
Of course, the sensible thing to do immediately before calling that is to check File.exists().
OTOH, Desktop.open(File) throws a slew of handy exceptions, including:
NullPointerException - if file is null
IllegalArgumentException - if the specified file doesn't exist
UnsupportedOperationException - if the current platform does not support the Desktop.Action.OPEN action
IOException - if the specified file has no associated application or the associated application fails to be launched
Properly handled, the exception would indicate the immediate problem.
As an aside, the Desktop class is designed to be cross-platform, and will handle any file type for which an association is defined. In that sense it is a lot more useful for something like this, than trying to use a Process.
It looks like I cannot use Desktop.open() on PDF files regardless of location. Here's a small test program:
package com.example.bugs;
import java.awt.Desktop;
import java.io.File;
import java.io.IOException;
public class DesktopOpenBug {
static public void main(String[] args)
{
try {
Desktop desktop = null;
// Before more Desktop API is used, first check
// whether the API is supported by this particular
// virtual machine (VM) on this particular host.
if (Desktop.isDesktopSupported()) {
desktop = Desktop.getDesktop();
for (String path : args)
{
File file = new File(path);
System.out.println("Opening "+file);
desktop.open(file);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
If I run DesktopOpenBug with arguments c:\tmp\zz1.txt c:\tmp\zz.xml c:\tmp\ss.pdf (3 files I happen to have lying around) I get this result: (the .txt and .xml files open up fine)
Opening c:\tmp\zz1.txt
Opening c:\tmp\zz.xml
Opening c:\tmp\ss.pdf
java.io.IOException: Failed to open file:/c:/tmp/ss.pdf. Error message:
The parameter is incorrect.
at sun.awt.windows.WDesktopPeer.ShellExecute(Unknown Source)
at sun.awt.windows.WDesktopPeer.open(Unknown Source)
at java.awt.Desktop.open(Unknown Source)
at com.example.bugs.DesktopOpenBug.main(DesktopOpenBug.java:21)
What the heck is going on? I'm running WinXP, I can type "c:\tmp\ss.pdf" at the command prompt and it opens up just fine.
edit: if this is an example of Sun Java bug #6764271 please help by voting for it. What a pain. >:(
I never knew about this Desktop command, untill recently through this post:
would Java's Runtime.getRuntime().exec() run on windows 7?
Previously i have been using:
Runtime.getRuntime().exec("rundll32 SHELL32.DLL,ShellExec_RunDLL "+ myfile);
And it has always worked for me. If your method does not work, may be you can think about try this command.
If you switch the order of your arugments does that cause one of the other files to get that same error. I wonder if you need to trim the end of the path before calling the File constructor.
umm...yeah ignore that... check the documentation of Desktop.open. open throws an IO exception "if the specified file has no associated application or the associated application fails to be launched " ... also from the top of the page... "The mechanism of registereing, accessing, and launching the associated application is platform-dependent. "
code for the Desktop class: http://fuseyism.com/classpath/doc/java/awt/Desktop-source.html
The open method calls DesktopPeer.open.
DesktopPeer source: http://www.jdocs.com/javase/7.b12/java/awt/peer/DesktopPeer.html
DesktopPeer is implementation specific.
Here is source for a Windows-specific implementation:
http://www.java2s.com/Open-Source/Java-Document/6.0-JDK-Platform/windows/sun/awt/windows/WDesktopPeer.java.htm
open->ShellExecute->(Native)ShellExecute
Native ShellExecute is a wrapper for Win32 ShellExecute. Here is info on the function.
http://msdn.microsoft.com/en-us/library/bb762153(VS.85).aspx
My suggestion for a work around would be to write your own implmentation of the ShellExecute function. Here is source from someone who did it. http://www.heimetli.ch/shellexec.html
I'm trying to figure out how to open the system preferred editor for a given file.
Say, we have a file manager, written in Java. User goes to folder and sees the list of files. And, for example, there is a file Icon.jpg. User double clicks on the filename and file opens in system's preferred editor (i.e. Gimp). The main issue is - how to do that?
We can do Runtime.getRuntime().exec("something file"), but this way you should know which program is preferred in user environment. But how?
We also are able to do Desktop.getDesktop().edit(File file), but this way we cannot track process and aren't able to know then this child process is closed. Other issue - function doesn't work on linux (at least on Ubuntu 8.10). There is also Desktop.getDesktop().open(File file), but it forces to open file viewer, instead of system viewer for that file type.
I am searching for a solution all week, but didn't got any suitable and generic one. Do you know the other approaches to this question? For my project it would be enough if it would work on Windows+Linux+Mac.
Thank you for your answers and advices.
Edit on 2009-02-08 23:04
Other suggestion: can I force "application selection" window in Windows and in Linux, as in Mac with "open file"? For example, then you trying to open file, you are being asked to choose application from list of system preferred ones? (something like "Open with..." in Windows explorer). Do you know?
Seems that if you can't use java.awt.Desktop you have to distinguish between the OSes:
Windows:
RUNDLL32.EXE SHELL32.DLL,OpenAs_RunDLL <file.ext>
Linux:
edit <file.ext>
Mac:
open <file.ext>
HTH. Obviously, that is not very portable...
Check out the java.awt.Desktop object. In your case, you want to invoke edit()
If you want to ensure that a given platform supports this call, then you can do something like the following (I have not tested this code):
public boolean editFile(final File file) {
if (!Desktop.isDesktopSupported()) {
return false;
}
Desktop desktop = Desktop.getDesktop();
if (!desktop.isSupported(Desktop.Action.EDIT)) {
return false;
}
try {
desktop.edit(file);
} catch (IOException e) {
// Log an error
return false;
}
return true;
}
This isn't cross-platform, but on Mac OS X you can do
Runtime.getRuntime().exec("open filename");
The open(1) executable uses LaunchServices to pick the right program to execute, and then uses that to open the file named filename.
This will work in windows
Runtime.getRuntime().exec( "CMD /C START filename.ext " );
For JavaFX applications, we can use HostServices. This question covers how to use HostServices. This should work on Ubuntu (tested)/Windows (not tested) and Mac (not tested).
import java.io.File;
import java.io.IOException;
public class App extends Application {
}
File file = new File("/your/file/path");
HostServices hostServices = getHostServices();
hostServices.showDocument(file.getAbsolutePath());
getHostServices() is a method of JavaFX Application class.