I have a JNI function that can take a while to complete, and I want a JProgress bar in indeterminate mode running while it is finishing the function. I have read the tutorials provided by Oracle, but the nature of their tutorials doesn't seem to help me understand how to do it. I realize that I should be running this function in a background thread, but I'm not quite sure how to do it.
Here is relevant code. I have a button (runButton) that will call the function, mainCpp(), when pressed:
public class Foo extends javax.swing.JFrame
implements ActionListener,
PropertyChangeListener{
#Override
public void actionPerformed(ActionEvent ae){
//Don't know what goes here, I don't think it is necessary though because I do not intend to use a determinate progress bar
}
#Override
public void propertyChange(PropertyChangeEvent pce){
//I don't intend on using an determinate progress bar, so I also do not think this is necassary
}
class Task extends SwingWorker<Void, Void>{
#Override
public Void doInBackground{
Foo t = new Foo();
t.mainCpp();
System.out.println("Done...");
}
return null;
}
/*JNI Function Declaration*/
public native int mainCpp(); //The original function takes arguments, but I have ommitted them for simplicity. If they are part of the problem, I can put them back in.
...//some codes about GUI
private void runButtonActionPerformed(java.awt.event.ActionEvent evt) {
ProgressBar.setIndeterminate(true);
Task task = new Task();
task.execute();
ProgressBar.setIndeterminate(false);
}
/*Declarations*/
private javax.swing.JButton runButton;
}
Any help would be appreciated.
EDIT: Editted in an attempt to do what kiheru suggested, but still does not work.
Assuming you have a SwingWorker like this:
class Task extends SwingWorker<Void, Void>{
#Override
public Void doInBackground() {
// I'm not sure of the code snippets if you are already in a
// Foo instance; if this is internal to Foo then you obviously do
// not need to create another instance, but just call mainCpp().
Foo t = new Foo();
t.mainCpp();
return null;
}
#Override
public void done()
// Stop progress bar, etc
...
}
}
You can either keep an instance in a field of the containing object, and then using it would work like this:
private void runButtonActionPerformed(java.awt.event.ActionEvent evt) {
// Start progress bar, disable the button, etc.
...
// Task task has been created earlier, maybe in the constructor
task.execute();
}
, or you can create a worker in place:
private void runButtonActionPerformed(java.awt.event.ActionEvent evt) {
// Start progress bar, disable the button, etc.
...
new Task().execute();
}
Related
Testing my libGDX app in RoboVM, I have encountered a major problem. When I pause my app (by actually going to the Home screen or sending app invites via Facebook) and then return to my app, classes of my games disappear. As if it does not store data properly on the resume() method. First i though it there was a problem of my AssetLoader, but after some debugging I found that the situation is worse. Actual instances of classes and shapes disappear. As if they never existed.
After googling the issue, I found that it might be related to IOSGraphics, but I have not managed to fix the problem.
My IOSLauncher looks something like this, I have erased the Facebook & Google AdMob specific code.
protected IOSApplication createApplication() {
IOSApplicationConfiguration config = new IOSApplicationConfiguration();
config.useAccelerometer = true;
config.useCompass = true;
config.orientationPortrait = true;
config.orientationLandscape = false;
return new IOSApplication(new Game(this), config);
}
#Override
public boolean didFinishLaunching(UIApplication application,
UIApplicationLaunchOptions launchOptions) {
FBSDKApplicationDelegate.getSharedInstance().didFinishLaunching(application, launchOptions);
initialize();
return true;
}
public void initialize() {
//...
}
public static void main(String[] argv) {
NSAutoreleasePool pool = new NSAutoreleasePool();
UIApplication.main(argv, null, IOSLauncher.class);
pool.close();
}
#Override
public void showAds(boolean show) {
//...
}
#Override
public void shareOnFacebook() {
//...
}
#Override
public void inviteFriends() {
//....
}
#Override
public boolean openURL(UIApplication application, NSURL url,
String sourceApplication, NSPropertyList annotation) {
super.openURL(application, url, sourceApplication, annotation);
return FBSDKApplicationDelegate.getSharedInstance().openURL(
application, url, sourceApplication, annotation);
}
#Override
public void didBecomeActive(UIApplication application) {
super.didBecomeActive(application);
FBSDKAppEvents.activateApp();
}
#Override
public void willResignActive(UIApplication application) {
super.willResignActive(application);
}
#Override
public void willTerminate(UIApplication application) {
super.willTerminate(application);
}
}
This sounds similar to a threading bug I once encountered. I fixed it by deferring resize and resume but I'm not sure if it will help in your case. Something like this:
private boolean needResize, needResume;
private void resize (int width, int height){
needResize = true;
}
private void deferredResize ();
if (!needResize) return;
needResize = false;
int width = Gdx.graphics.getWidth();
int height = Gdx.graphics.getHeight();
//move your resize code here
}
private void resume (){
needResume = true;
}
private void deferredResume (){
if (!needResume) return;
needResume = false;
//move your resume code here
}
public void render (){
deferredResize();
deferredResume();
//...
}
I suggest that you start looking for an alternative to RoboVM to avoid more issues in the future, as Robovm was acquired by Microsoft Xamarin (sad but true) and the framework is no longer maintained. License keys (with Libgdx) will continue to work until the 17th of April 2017, there will be no further updates to RoboVM, be it new features or bug fixes.
As far as I know, Libgdx will switch to Multi-OS engine as the default iOS backend for newly created libGDX projects in the next couple of weeks.
After a couple of days filled with headache I found the solution!
LifeCycle methods like pause & resume, hide & show are not always called When they are supposed to be called, therefore data is not stored properly. This issue can completely break your game.
This thing only occurred when testing my game on the iOS platform, mainly when I opened a 3rd party app, Facebook in this case. No such thing found on Android, though.
The only thing I changed on the iOS version was calling the mentioned methods manually to make sure it always pauses and resumes when it has to.
I've searched around and haven't found anything related to what I'm trying to achieve.
To explain as simple as possible. My app stores various number of values, acting as settings for the user basically. Now what I want is for the user to have the ability to switch between different preference files. Like different profiles.
So on a click of a button all instances of Preferences through the app will start reading a different file with different values, for example:
main.preferences = Gdx.app.getPreferences("prefs_2");
where the first profile would be "prefs_1" instead which is loaded by default when the app starts. I don't know if just changing the preference file like shown above would work at all. But I hope it gives an idea of how I'm thinking.
And when clicking that button to change preference file, the app will read that file's values through out all classes in the app until it is restarted where it will go back to the default file:
public class Main extends Game {
public SpriteBatch batch;
public ShapeRenderer renderer;
private Assets assets;
//Local Preferences
public Preferences preferences;
public Main(utilsInterface utils){
this.utils = utils;
}
#Override
public void create () {
batch = new SpriteBatch();
renderer = new ShapeRenderer();
assets = new Assets();
preferences = Gdx.app.getPreferences("prefs_1");
setScreen(new SplashScreen(this));
}
#Override
public void render () {
super.render();
}
#Override
public void resize(int width, int height) {
super.resize(width, height);
}
#Override
public void dispose() {
super.dispose();
assets.dispose();
batch.dispose();
renderer.dispose();
}
#Override
public void pause() {
// TODO Auto-generated method stub
super.pause();
// Logs 'app deactivate' App Event.
// AppEventsLogger.deactivateApp(this);
}
#Override
public void resume() {
// TODO Auto-generated method stub
super.resume();
//Assets.manager.finishLoading();
// Logs 'install' and 'app activate' App Events.
}
}
NOTE* I use the same instance of Preferences from the main class throughout the whole app.
Yes, this will work.
If you use a different settings file, it will use the settings of that file. Just make sure to have default values for all settings so that if a new file is created (when you open a file that does not exist, write to it and flush it) you can still use it without it having all settings written to it.
I realize the question may be confusing and the word "better" may be problematic, but I could not think of a, well, better way to ask.
Let's say you are writing an application that has a single entry point, like Main, which also serves as the composition root for IoC:
From outside, run application
Main or equivalent
var container = new AwesomeContainer();
container.Install(new CompositionRootInstaller(startArgs));
container.Register( ... );
ApplicationMiddleware = container.Resolve<IMiddleware>();
ApplicationMiddleware.SignalStart();
Here, ApplicationMiddleware might be a ControllerFactory in a web application, for instance.
Now, of course we will have lots of other services located by the container at the appropriate time (per request, for instance).
Sometimes we will run into situations where we don't feel like it's so bad to just assign, say, a default value to a field. But, in my view, this breaks IoC a little bit.
So, is it a true statement that (regardless of the marginal value of doing so) it is always better to avoid calling constructors or factories that call constructors or otherwise get components without calling the container once we leave the entry point?
Example: WinForms program
Here is the setup. It is a contrived example but I'm trying to focus on the issue at hand...
static class Program
{
[STAThread]
static void Main(string[] args)
{
using (var root = new AppCompositionRoot())
{
}
}
}
class AppCompositionRoot : IDisposable
{
private IWindsorContainer _container;
public AppCompositionRoot(IWindsorContainer container = null)
{
_container = container ?? new WindsorContainer();
}
public void Run()
{
var formFactory = _container.Resolve<DefaultFormFactory>();
Application.Idle += delegate
{
formFactory.ApplicationIsIdle();
};
Application.Run();
}
public void Dispose()
{
_container?.Dispose();
}
}
public interface IFormFactory
{
System.Windows.Forms.Form Create();
}
public class DefaultFormFactory : IFormFactory
{
private readonly IWindsorContainer _container;
private Form _lastForm;
public DefaultFormFactory(IWindsorContainer container)
{
_container = container;
}
public Form Create()
{
return _container.Resolve<AppForm>();
}
public void ApplicationIsIdle()
{
_lastForm = _lastForm ?? Create();
_lastForm.Show();
}
}
public class AppForm : Form
{
private readonly string _big; // sensible default is "Welcome!"
private readonly string _little; // sensible default is a string varying by form, time of day, factory
private readonly IList<object> _watched; // sensible default is list empty.
public AppForm(string bigMessage, string littleMessage, IList<object> watched)
{
_big = bigMessage;
_little = littleMessage;
_watched = watched;
}
public void Initialize()
{
// do something with bigMesaage, littleMessage, etc.
}
}
So let's start with concrete AppForm. It needs two strings and a List<object>.
Let's say for all of them there is a natural default that makes sense like 95% of the time, as in something that would be a const string on the class.
Regardless my question is - to really do IoC in the ideal sense, wouldn't it be true that you should always see constructors like these (clean constructors) and any defaults should be injected as well?
Inversion of Control simply states that control (whatever that is) is inverted. It doesn't mean that you have to invert everything; you should invert that which you want to vary.
If you're writing a Hello world application, and you don't want to vary anything, you can create the string within the implementation:
Console.WriteLine("Hello, world!");
On the other hand, if you want to be able to vary the message, you can pass it in as a Primitive Dependency:
public class Helo
{
private readonly string message;
public Helo(string message)
{
this.message = message;
}
public void SayHello()
{
Console.WriteLine(this.message);
}
}
If it helps, Miško Hevery makes the distinction between newables and injectables. On a different note, in my book, I've attempted to make a distinction between stable and volatile dependencies.
You can new up values that you don't need to be able to control from the outside. If you need to control them from the outside (Inversion of Control, remember), then you need to inject them.
I am working with some strange legacy code. They have a custom object which implements a JPanel. This JPanel object is a secondary popup screen within the main application. The issue I'm having is to detect when the secondary popup screen is closed.
I tried to implement a WindowListener for the class, but when I try to add it, there is no JFrame associated with this object. I am assuming this is because they are using a custom object and it is an embedded popup screen.
I tried to retrieve a JFrame using:
JFrame parentFrame = (JFrame) SwingUtilities.getWindowAncestor(this);
which fails on a NullPointerException. I have no idea why it's so difficult to detect the right hand corner "x" close button on this page! I should mention that they were able to add Mouse and Key Listeners to the table which is embedded within the JPanel. But the outside listener for the entire window is causing me troubles.
(Please bear with me, this is my first stackoverflow post and I am new to Swing.)
Thanks so very much!!
Try to call getParent() for that strange panel. It should return the parent GUI component. If this is still not your frame but some intermediate panel instead, call getParent() on it as well. The top level component returns null.
Component p = strangePanel;
while ( p != null && ! (p instanceof Window))
p = p.getParent();
((Window) p ).addWindowListener(..);
Cannot understand why you are getting "NullPointerException" at:
JFrame parentFrame = (JFrame) SwingUtilities.getWindowAncestor(this);
In two cases this can happen:
JFrame parentFrame = (JFrame) SwingUtilities.getWindowAncestor(null);
In your case, this is not possible as you have used this as a parameter.
Second, are you doing some other operations in above code line, like:
JFrame parentFrame = ((JFrame) SwingUtilities.getWindowAncestor(this)).someOperation();
In this case, if your this object represent the top window then you are supposed to get "NullPointerException" because ancestor of top parent is returned as "null". In other cases, I suspect you will get this exception.
Can you post a block of code where you are getting exception.
For this answer I'm making a minor assumption that the Nullpointer is not being thrown at the line that you mentioned, but rather when you attempt to add the WindowListener to the parentFrame. This is most likely because you're calling
JFrame parentFrame = (JFrame) SwingUtilities.getWindowAncestor(this);
before the JPanel has been added to the JFrame hierarchy.
Here's a rought code sample on how you could work around this. The thought it to wait for the panel to be notified that it has been attached to the JFrame somewhere in its hierarchy.
package test;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class HierarchyTest extends JPanel {
protected static void loadApp() {
HierarchyTest test = new HierarchyTest();
JFrame frame = new JFrame();
frame.add(test);
frame.setSize(200, 200);
frame.setVisible(true);
}
/**
* #param args
*/
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
loadApp();
}
});
}
public HierarchyTest() {
this.addHierarchyListener(new HierarchyListener() {
#Override
public void hierarchyChanged(HierarchyEvent e) {
// This can be optimized by checking the right flags, but I leave that up to you to look into
boolean connected = setupListenersWhenConnected();
if (connected) {
HierarchyTest.this.removeHierarchyListener(this);
}
}
});
}
protected boolean setupListenersWhenConnected() {
JFrame parentFrame = (JFrame) SwingUtilities.getWindowAncestor(this);
if (parentFrame == null) {
return false;
}
parentFrame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
// Implementation here
System.out.println("This window is closing!");
}
});
return true;
}
}
We're using #Before's all along the hierarchy to get some test data inserted into the database before tests execute. I want to commit all that data to the database just before the #Test starts running.
One way to do this would be to commit the data as the last step in this test class' #Before method. But we have hundreds of such classes, and don't want to go in and modify all of those.
I've played with ExternalResource #Rule and TestWatcher #Rule...but they don't afford a way to hook in after all the #Before's have happened.
I'm thinking I need to look at building a custom TestRunner to do this.
Is that the right track?
What you are looking for, seems inconsistent to me. Settind some data and committing them are very close operations and shouldn't belong to different places. On the contrary, I would rather put them into one function and call it with actual parameters set to values you want to insert. Or use SQL strings as actual parameters. And call this finction from #Before
If you are insisting, there is no problem to do it. Create descendant classes for your Junit classes:
package ...;
import org.junit.Before;
public class NewAndBetterYourTest1 extends YourTest1 {
#Override
#Before
public void setUp() {
super.setUp(); // this is where you are setting everything.
makeCommits();
}
}
Only don't forget to launch these new tests
While you can't do quite what you are asking without a custom Runner, you could ensure that all of the data created in the #Before methods is committed with a Rule:
public class LocalDatabase extends ExternalResource {
private DataSource dataSource;
#Override
protected void before() {
dataSource = createLocalDatabase();
}
#Override
protected void after() {
try {
destoyLocalDatabase(dataSource);
} finally {
dataSource = null;
}
}
public void run(Callback callback) {
if (dataSource == null) {
throw new IllegalStateException("No DataSource");
}
Collection con = null;
try {
con = ds.getConnection(DB_USERNAME, PASSWORD);
callback.execute(con);
con.commit();
} finally {
if (con != null) con.close();
}
}
You can have this as a Rule in your base class:
public DatabaseTest {
#Rule
public LocalDatabase final localDatabase = new LocalDatabase();
}
And could could use it in a #Before method in any subclass
public UserDaoTest extends DatabaseTest {
#Before
public void populateInitialData() {
localDatabase.run(new Callback() {
#Override
public void execute(Connection con) {
...
}
});
}
...
}