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.
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.
The title seems a little bit confusing, but I'll explain everything.
I'm developing a project where I show the image captured by a webcam in a JPanel, Java Swing. Now I have to integrate this with JavaFx.
I have a controller where I have the method startRecording, that would initialize the cameraThread and tell the class Camera to startRecording, inside Camera class a have a method DrawFrame(BufferedImage, JPanel panel) where I call the function drawImage from OpenCV to draw in the Panel:
Controller:
public void startRecording(){
cameraInstance.setCameraRGBPanel(windowsInstance.getCameraRGBPanel());
cameraInstance.setCameraHSVPanel(windowsInstance.getCameraHSVPanel());
cameraInstance.setCameraThresholdPanel(windowsInstance.getCameraThresholdPanel());
cameraInstance.setRecord(true);
cameraThread = new Thread(cameraInstance);
cameraThread.start();
}
Class camera:
private void drawFrame(BufferedImage buff, JPanel pane){
pane.getGraphics().drawImage(buff, 0, 0, null);
}
To start with, JavaFX has no JPanel and the Pane (an option) has no getGraphics, I've tried to use a SwingNode, add the JPanel and then do everything as usual, but the image simply won't be shown.
The following code was a test, that's why it seems to be so 'bad'.
public void start(Stage stage) throws Exception {
stage.setTitle("Tela Teste");
pCamera = new Pane();
SwingNode swing = new SwingNode();
pCamera.getChildren().add(swing);
createAndSetSeingContent(swing);
Group root = new Group();
root.getChildren().add(pCamera);
stage.setScene(new Scene(root , 500, 500));
stage.setResizable(true);
stage.show();
}
private void createAndSetSeingContent(SwingNode swing) {
ControllerCamera control = new ControllerCamera();
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
JPanel panel = new JPanel();
JLabel label = new JLabel("Abc");
//panel.add(label);
swing.setContent(panel);
Button teste = new Button("A");
pCamera.getChildren().add(teste);
teste.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
control.startRecording(panel);
System.out.println("abc");
}
});
}
I changed to method startRecording to something like:
public void startRecording(JPanel panel){
cameraInstance.setCameraRGBPanel(panel);
cameraInstance.setRecord(true);
cameraThread = new Thread(cameraInstance);
cameraThread.start();
}
Still nothing appears in the panel, but if I add a label or button, then it appear and works as intended to. The "abc" is always shown in the console.
I think that's all the code related to the problem. Something else I want to say is that yesterday was the first day I was dealing with FX, let's say the project is divided, the other guy is also working on the problem, but we haven't gotten anywhere so far, that's why I decided to ask you here.
Edit 1: everything was working perfectly before all this situation (everything works with Swing, but not in FX).
The simplest way to display an Image in JavaFX is with an ImageView. You can create a single ImageView and update its image by calling setImage(...), passing in a javafx.scene.image.Image. I don't know the camera API you are working with: you might be able to generate a JavaFX image directly, in which case your draw frame method looks as simple as:
private void drawFrame(Image image, ImageView imageView) {
imageView.setImage(image);
}
If you can only generate BufferedImages, you can do
private void drawFrame(BufferedImage buff, ImageView imageView) {
imageView.setImage(SwingFXUtils.toFXImage(buff, null));
}
In either case, you can just create the ImageView, put it in a Pane subclass of some kind, put the Pane in a scene and display it in the Stage:
public void start(Stage stage) throws Exception {
stage.setTitle("Tela Teste");
pCamera = new Pane();
ImageView imageView = new ImageView();
pCamera.getChildren().add(imageView);
Group root = new Group();
root.getChildren().add(pCamera);
stage.setScene(new Scene(root , 500, 500));
stage.setResizable(true);
stage.show();
}
Then just pass the imageView to your drawFrame method as needed.
I used the SimpleSwingBrowser example (http://docs.oracle.com/javafx/2/swing/SimpleSwingBrowser.java.htm) and added some code of my own for log tailing.
I wanted to add a search bar ability to it (Search and Highlight text).
After googling for hours and self experiments, I didn't find a way to do it.
Can someone give me a kick-off direction for writing such ability.
Suggestions for a JavaScript based solution
Use an existing JavaScript highlighting library such as jQuery highlight or hilitor.js.
Suggestions for a Java based solution
Use the Java w3c DOM API to perform operations on the WebEngine document object after the document has been loaded.
To get a Search API in the JavaFX WebView core implementation
I created feature request RT-23383 Text search support for WebView. The feature request is currently open and unactioned - you can create an account in the issue tracker and vote for or comment on the feature request.
Sample
This sample uses jQuery highlight. The user types the word to be highlighted into the text field, then presses the highlight button to highlight all occurrences of the word in the page or to remove highlight button to clear all marked highlights. You could modify the sample to allow further jQuery based searches to scroll to a next and previously highlighted word.
I tried to get it to work with any arbitrary web page, but that logic defeated me. If you control the source of the page you want to search and can add the reference to the jQuery highlight plugin and it's style class to your page, something like this sample program might be an option.
import javafx.application.Application;
import javafx.event.*;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.web.*;
import javafx.stage.Stage;
public class WebViewSearch extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
final WebView webView = new WebView();
final WebEngine engine = webView.getEngine();
engine.load("http://johannburkard.de/blog/programming/javascript/highlight-javascript-text-higlighting-jquery-plugin.html");
final TextField searchField = new TextField("light");
searchField.setPromptText("Enter the text you would like to highlight and press ENTER to highlight");
searchField.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
if (engine.getDocument() != null) {
highlight(
engine,
searchField.getText()
);
}
}
});
final Button highlightButton = new Button("Highlight");
highlightButton.setDefaultButton(true);
highlightButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
searchField.fireEvent(new ActionEvent());
}
});
final Button removeHighlightButton = new Button("Remove Highlight");
removeHighlightButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
removeHighlight(
engine
);
}
});
removeHighlightButton.setCancelButton(true);
HBox controls = new HBox(10);
controls.getChildren().setAll(
highlightButton,
removeHighlightButton
);
VBox layout = new VBox(10);
layout.getChildren().setAll(searchField, controls, webView);
searchField.setMinHeight(Control.USE_PREF_SIZE);
controls.setMinHeight(Control.USE_PREF_SIZE);
controls.disableProperty().bind(webView.getEngine().getLoadWorker().runningProperty());
searchField.disableProperty().bind(webView.getEngine().getLoadWorker().runningProperty());
primaryStage.setScene(new Scene(layout));
primaryStage.show();
webView.requestFocus();
}
private void highlight(WebEngine engine, String text) {
engine.executeScript("$('body').removeHighlight().highlight('" + text + "')");
}
private void removeHighlight(WebEngine engine) {
engine.executeScript("$('body').removeHighlight()");
}
}
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();
}
I am trying to use MvvmCross v3 in one of my applications which consists of activities, content providers and broadcast receivers. However, I am not quite succeeding.
The application consists of a Core PCL which contains logic, models and viewmodels and a Droid application which contains all MonoDroid-specific stuff.
In Core I have an App:MvxApplication class and in Droid I have a Setup:MvxSetup class which creates an App-instance and initialises stuff.
I can use the IOC parts with content providers, broadcast receivers and non-Mvx-activities without problems. When I now want to add an MvxActivity it falls apart.
When the Mvx Activity launches I get an exception "Cirrious.CrossCore.Exceptions.MvxException: MvxTrace already initialized".
Obviously I am initialising things in the wrong order / wrong place. But, I need a pointer in the right direction.
My App Class
public class App
: MvxApplication
{
public override void Initialize()
{
base.Initialize();
InitialisePlugins();
InitaliseServices();
InitialiseStartNavigation();
}
private void InitaliseServices()
{
CreatableTypes().EndingWith("Service").AsInterfaces().RegisterAsLazySingleton();
}
private void InitialiseStartNavigation()
{
}
private void InitialisePlugins()
{
// initialise any plugins where are required at app startup
// e.g. Cirrious.MvvmCross.Plugins.Visibility.PluginLoader.Instance.EnsureLoaded();
}
}
And my setup class
public class Setup
: MvxAndroidSetup
{
public Setup(Context applicationContext)
: base(applicationContext)
{
}
protected override IMvxApplication CreateApp()
{
return new App();
}
protected override IMvxNavigationSerializer CreateNavigationSerializer()
{
return new MvxJsonNavigationSerializer();
}
public override void LoadPlugins(Cirrious.CrossCore.Plugins.IMvxPluginManager pluginManager)
{
pluginManager.EnsurePluginLoaded<Cirrious.MvvmCross.Plugins.Json.PluginLoader>();
base.LoadPlugins(pluginManager);
}
public void RegisterServices()
{
// I register a bunch of singletons here
}
// The following is called from my content provider's OnCreate()
// Which is the first code that is run
public static void DoSetup(Context applicationContext)
{
var setup = new Setup(applicationContext);
setup.Initialize();
setup.RegisterServices();
}
My Content provider's OnCreate():
public override bool OnCreate()
{
Log.Debug(Tag, "OnCreate");
_context = Context;
Setup.DoSetup(_context);
return true;
}
My MvxActivity:
[Activity(Label = "#string/ApplicationName", MainLauncher = true)]
[IntentFilter(new[] { "Settings" })]
public class SettingsView
: MvxActivity
{
public new SettingsViewModel ViewModel
{
get { return (SettingsViewModel) base.ViewModel; }
set { base.ViewModel = value; }
}
protected override void OnViewModelSet()
{
SetContentView(Resource.Layout.Page_SettingsView);
}
}
Short answer (I'm in an airport on mobile)
all the mvx android views will check the setup singleton has been created - https://github.com/slodge/MvvmCross/blob/vnext/Cirrious/Cirrious.MvvmCross.Droid/Platform/MvxAndroidSetupSingleton.cs (vnext tree - but similar on v3)
so if you are creating a setup, but not setting this singleton, then you will get a second setup created when you first show a view
i suspect you can just get your setup created via the singleton class, but if this isn't flexible enough for your needs, then please log an issue on github
would also love to see some blogging about this - I've not used custom content providers much (at all!)