i apologise for having posted a thread quite similar to this one. but still i am having some problems. thread can be seen here
i am applying a backfround to a jpanel. i need to have a loading gifthat changes later on for a ok or error image.
i load at the beginning a trasparent picture. it get replaced as soon as an action listener starts by the loading one and in the end of the code executed in the listener i change the figure with ok/error. the transparent, the ok and the error one get loaded perfectly but i did not manage to see the loading one.
here is my listener code:
void refreshButtonActionPerformed(java.awt.event.ActionEvent evt) {
// load loading icon
Image img = new ImageIcon(iconPath+"loading.gif").getImage();
this.iconPanel.replaceImage(img);
this.iconPanel.updateUI();
this.iconPanel.revalidate();
this.iconPanel.repaint();
// clear table contents
designValue.clear();
deployValue.clear();
// Fill class
diagnosticGenerator diagnostic = new diagnosticGenerator();
Vector<Integer> indexes;
// if modeCombo.getSelectedIndex() == 0 i show only data regarding the current user
if (modeCombo.getSelectedIndex() == 0) {
// receive Design Table
designValue.addAll(diagnostic.getDesignContents());
// receive Deploy Table
deployValue.addAll(diagnostic.getDeployContents());
// receive indexes of out-dated deploy
indexes = new Vector<Integer>(diagnostic.getOutdatedDeployIndexes());
}
// otherwise i show data of all the users
else {
// receive Design Table
designValue.addAll(diagnostic.getDesignContents_allUsers());
// receive Deploy Table
deployValue.addAll(diagnostic.getDeployContents_allUsers());
// receive indexes of out-dated deploy
indexes = new Vector<Integer>(diagnostic.getOutdatedDeployIndexes_allUsers());
}
// set default color to green
deployTable.resetColor(Color.white);
// set red background to the
for (Integer x : indexes)
deployTable.setRowColor(x, Color.red);
deployTable.repaint();
designTable.revalidate();
deployTable.revalidate();
//update refreshLabel with the new date
Date date = new Date();
refreshLabel.setText(date.toString());
//replace icon with different mark depending on the fact if we found an error or not
if(indexes.isEmpty())
img = new ImageIcon(iconPath+"ok.png").getImage();
else
img = new ImageIcon(iconPath+"error.png").getImage();
this.iconPanel.replaceImage(img);
this.iconPanel.repaint();
}
i think it's a matter of asyncronous messages because if i call a wait just after
this.iconPanel.repaint();
i can see the loading gif. but my code gets stuck there.
So i think i shoud find a way to force at that point to execute all the command in queue but i have no idea how to do it.
does anyone had a similar problem with swing?
Use a blocking method such as ImageIO.read(File/URL/InputStream) to get the Image. ImageIO has been introduced into the J2SE 'recently'.
Related
I have a slightly unusual situation with SharedObject:
The situation: where we have a SWF (browser) based application running on a single local machine. The SWF accesses local content and is reloaded every XX number of seconds/minutes/hours.
The state of application has to be stored within a single SharedObject (this is using the '/' parameter to force it to global) in a JSON style.
The SWF loads the SO before it makes any state updates and correctly calls flush() immediately after to save state.
The Problem: Everything runs fine BUT occasionally there is a situation where by 2 instances of the same SWF are existing at the same in different instances and both are accessing the same SharedObject.
The 2nd has to take control of the SO from the 1st, by each SWF instance setting it's instance state to an incremented number (SWF Idx) stored in the SO.
Both are loading the file before any update is made, version number checked, and will disable themselves if the saved SWF Idx is above it's own. Unfortunately the 1st SWF instance somehow isn't loading the latest version of the SharedObject because it traces out the original number (e.g. 22) instead of the now updated one (e.g. 23). While the 2nd SWF is tracing out 23 and the SO contains 23.
Is there any way that the browser could possibly be caching the SO?
Testing
I'm currently testing the situation by running one browser instance locally then launching a 2nd. Making copies of the SO before and after each state.
I've also run the 1st and 2nd via IntelliJ and can see that SharedObject.getLocal is being called and checked each time.
I've included the basics of the code I'm using below where:
__so = is the public SharedObject variable
_thisSWFIdx = is the private variable inside AS3 storing the current instances SWF Index
__so.data.activeSWFIdx = the latest SWF Index
The SO 'get' I'm using is:
SharedObject.getLocal(_SO_ID, "/");
The check i'm doing is:
if (_thisSWFIdx < __so.data.activeSWFIdx) {
__amActiveSWF = false;
}
The saving of the variable to SO:
__so.data.activeSWFIdx = _thisSWFIdx;
flush();
Additonal info:
This is running on both mac & windows
FlashPlayer 10.3
Pure AS3
compiled in IntelliJ
same issue in FF, Chrome and IE
primary machine Macbook
I can't find anything within the documentation or existing threads so any help will be much appreciated.
After a little test, I remarked the behavior that you've mentioned : after updating the SharedObject by a second SWF, the first one can't get the new value only after a reload.
To avoid that, I think, as a workaround, you can use a second SWF which will just work on the SharedObject by reading / writing data.
For that, take this example :
so.swf : the SWF which will read and write data.
var shared_object_name:String = 'so';
var shared_object:SharedObject = SharedObject.getLocal(shared_object_name, '/');
// get the id
function get_id(): int {
return shared_object.data.id ? shared_object.data.id : -1;
}
// set the id
function set_id(new_id:int): void {
shared_object.data.id = new_id;
shared_object.flush();
}
app.swf : your global app which will use the "so.swf" to do SharedObject's operations :
var init:Boolean = true;
var swf_id:int = 1;
var swf_disabled:Boolean = false;
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, on_SWFLoad);
loader.load(new URLRequest('so.swf'));
function on_SWFLoad(e:Event): void
{
var loaded_swf:MovieClip = MovieClip(loader.content);
var current_id:int = loaded_swf.get_id();
// if it's initial run
if(init){
init = false;
if(current_id > 0){
swf_id = current_id + 1;
}
loaded_swf.set_id(swf_id);
} else { // we are verifying if there is a new active SWF
if (swf_id <= current_id) {
swf_disabled = true;
}
}
}
function stage_onPress(e:MouseEvent){
// if this SWF is disabled, stop getting the "id"
if(swf_disabled){
stage.removeEventListener(MouseEvent.CLICK, stage_onPress);
return;
}
// otherwise, get the "id" to verify if there is another active SWF
loader.load(new URLRequest('so.swf'));
}
stage.addEventListener(MouseEvent.CLICK, stage_onPress);
I used MouseEvent.CLICK only for testing purposes, of course you have to use a Timer or something else to verify every n seconds (for example) that you have another active SWF to disable the current one...
Hope that can help.
I have a DataGrid on my main page that is full of Employees. Each Employee has an "in" status - this is modified based on whether the Employee is currently in the building or not.
I need to consistently update this DataGrid as people will be entering or leaving the building throughout the day. This means I will be sending MySQL queries somewhere between every 1-5 seconds until the user clicks on a button to navigate to another page.
I have tried the most simple and obvious solution, a While loop however this freezes and locks the UI. How can I create a loop that runs and queries MySQL without locking the UI?
EDIT: Attempted Answer
public void PeriodicCall()
{
var employeeDS = new EmployeeDataService();
int i = 1;
Timer timer = new Timer(
state => {
Employees = employeeDS.HandleEmployeeSelect();
FilteredView = CollectionViewSource.GetDefaultView(Employees);
Application.Current.Dispatcher.BeginInvoke(new Action(() => {
dataGrid.ItemsSource = FilteredView;
testLabel.Content = "Who's Who " + i;
i++;
}));
},
null, //no object as Callback parameter
TimeSpan.FromSeconds(0), //start in x millisec
TimeSpan.FromSeconds(1)); //time between call
}
You can use a Backgroundworker, hook to its .completed and there render (using
BackgroundWoker worker = new BackgroundWorker();
worker.DoWork += functioToDo
worker.Completed += functionWhere you update the UI
worker.runAsynchronous(); //actually starts the thread
In the function that updates the UI don't forget to use the dispatcher to access the UI thread:
dispatcher.invoke((Action) delegate { here your code})
to access the UI thread for elsewhere.
Other cooler approach is to take care of the propertyChanged and bind the changes to the UI. But this is a bit more complex and I don't know the details by head.
You can use a timer to start the whole thing every few seconds.
A third approach would be to have a trigger when you update the data base. We would need more details to know how to attach there. But from there you can also call some updates in the UI and then you don't need to use CPU to check every seconds (you know, work by interruption instead of by polling).
You should use a timer to periodically retrieve data from your DB and update data in your datagrid using the Dispatcher.BeginInvoke function.
Timer timer = new Timer(
state => {
//Callback function
Object yourData = GetDataFromDB();
Application.Current.Dispatcher.BeginInvoke(new Action(()=> {
YourUIProperty = yourData;
}));
},
null, //no object as Callback parameter
TimeSpan.FromSeconds(1), //start in x millisec
TimeSpan.FromSeconds(5) //time between call
);
I'm trying to integrate App42 Leaderboard Service to my Cocos2D-X Game. The core functionality (Sending Scores to Server and retrieving them, just the way shown on the App42 site...) is working fine.
Now i want to visualize my leaderboard data using a CCTableView.
So I got a Leaderboard class (inherited from CCLayer) and am doing something like this :
bool Leaderboard::init() {
...
// Initialize and send App42 Scoreboard API call
App42API::Initialize(API_KEY, SECRET_KEY);
ScoreBoardService *scoreBoardService = App42API::BuildScoreBoardService();
scoreBoardService->GetTopNRankers(gameName,MAX_SCORES, this,app42callfuncND_selector(Leaderboard::onGetTopNRankings));
// responseArrived is boolean, indicates if onGetTopRankings was called
while(!responseArrived);
CCTableView* tableView = CCTableView::create(this, CCSizeMake(400, 100));
tableView->setDirection(kCCScrollViewDirectionVertical);
tableView->setPosition(winSize.width/3 , winSize.height/2);
tableView->setDelegate(this);
tableView->setVerticalFillOrder(kCCTableViewFillTopDown);
this->addChild(tableView,5);
tableView->reloadData();
return true;
}
void HelloWorld::onGetTopNRankings(App42CallBack *sender, void *response){
App42GameResponse *scoreResponse = (App42GameResponse*)response;
if (scoreResponse->isSuccess)
{
// Save User scores to Array
responseScores = scoreResponse->scores;
}
else
{
printf("\nerrordetails:%s",scoreResponse->errorDetails.c_str());
printf("\nerrorMessage:%s",scoreResponse->errorMessage.c_str());
printf("\nappErrorCode:%d",scoreResponse->appErrorCode);
printf("\nhttpErrorCode:%d",scoreResponse->httpErrorCode);
}
// Response Data is saved, or Error occured, go back to init()
responseArrived = true;
}
So as you see, I am waiting for onGetTopNRankings to get called, because the data for my TableView would be empty else. But what happens is, that the I can't get back to init() when onGetTopNRankings returns, it gets stuck.
So anybody got an idea why i can't return to Leaderboard::init() or got any good idea to solve this in any other way, I am open for each suggestion ?
while(!responseArrived);
This blocks the thread (endless loop). You need to fill your table view in the callback method when you have actual data. It will be empty until then. That's something your app's design has to deal with. For instance you could display a "loading" animation in the meantime, with a cancel button on it.
I tested your code and it is working fine in my App42Cocos2dXSample
The only possible reason for the issue you are getting is the owner class name of callback method in your code snippet.
scoreBoardService->GetTopNRankers(gameName,MAX_SCORES,
this,app42callfuncND_selector(Leaderboard::onGetTopNRankings));
In the above statement, onGetTopNRankings belong to the class Leaderboard, but while defining the callback method, it belongs to the class Helloworld:
void HelloWorld::onGetTopNRankings(App42CallBack *sender, void *response){
So, try changing the class name from Helloworld to Leaderboard in the above statement. I hope it will work.
I have an issue with a function I use to delete an instance and replace it with another. Basically, it keeps the item in memory no matter what. Inside the object I have weak listeners and I null everything after it gets removed, but the function I run to check if it is still active tells me that it is (just an Event.ENTER_FRAME tracing some text, with a weak link).
Even when I removed everything from the instances I am loading, it still seems to stay in memory, according to my trace it still is. How do I completely delete something from memory more thoroughly than nulling it out after removing it from the stage? Am I not seeing something?
This is the function:
private function loadArea(inputArea:String)
{
//This is for a checker to make sure that areas only get loaded once.
currentRoom = inputArea;
//If the area currently loaded is not null, make it null now.
if(selectedArea != null) selectedArea = null;
//Null any data inside of the reference used to create the name of the new area.
areaReference = null;
//Grab the class using the input.
areaReference = getDefinitionByName(inputArea + "Area") as Class;
//Null the sprite used to house the class
areaSprite = null;
//Set the holder as a new instance of the desired class.
areaSprite = new areaReference() as Sprite;
//If the selected area is still not null for some reason,
if(selectedArea != null)
{
//Remove the area from the container...
areaContainer.removeChild(selectedArea);
//...and nullify it.
selectedArea = null;
}
//Set the current area as the newly created instance.
selectedArea = areaSprite;
//If the area is not the "Game", load in the assets one way,
if(inputArea != "Game") selectedArea.construct(areaAssets);
//otherwise do it another way.
else selectedArea.construct(newScreenData,apiServer,cdnServer,areaAssets);
//This is for a checker that fades out the screen, which it needs to fade back in soon.
newScreenData = null;
//While the container for areas has any areas inside of it, remove them.
while(areaContainer.numChildren) areaContainer.removeChildAt(0);
//...then add the new instance area to the container.
areaContainer.addChild(selectedArea);
//...then let all the parts of the game know that a new area has been laoded in.
Global.echoEvent.echo("gameBootUp","playAreaIn");
}
The memory is actually released when Garbage Collector will find and erase an orphaned instance of yours. Before that, your memory usage will state there is an instance in memory. There is no way to force garbage collection, calling System.gc() only "instructs" Flash to run it, it might not obey. So, you have done what you had to, let it be.
Removing all references including stage and nulling an object is all it takes to free up memory.
If the object is not being released then you are missing something or doing something incorrectly or out of sequence.
Carefully go through your code, making sure you identify where objects are being referenced so you can remove them.
Looking at your example code:
if(selectedArea != null) selectedArea = null;
Here you are making sure that the selectedArea is null.
But immediately after you are testing selectedArea again
(you know it is null so this block is never used)
if(selectedArea != null){
//Remove the area from the container...
areaContainer.removeChild(selectedArea);
//...and nullify it.
selectedArea = null;
}
In every language its VERY DIFFICULT to "clear" memory... even HTML. That being said... try to reduce your memory footprint.
Correct Null:
1. remove all event listeners
2. remove all children
3. remove all mapped/referenced methods/parameters
4. set the class object to null
In most cases this is all you need to do, the WAY you do it will determine if the object gets cleared. Consider the following situation.
You have a custom sprite class (MEMORY FOOTPRINT #1) that has a mapped property (mapping happen when one class object references another). Once you map/reference one object to another = MEMORY FOOTPRINT #2. Adding events = MEMORY FOOTPRINT #3, etc and so on.
Custom Sprite
import flash.display.Sprite;
class CustomSprite extends Sprite{
private var _mappedProperty:Object;
public function addMapping(map:Object):void{
_mappedProperty = map;
}
public function finalize():void{
_mappedProperty = null;
}
}
Assuming we're using CustomSprite in many other methods, lets look at some common ways of removing the ojbect.
INCORRECT - in this situation [objToRemove] was not set to null to free its memory:
var objToRemove:CustomSprite = new CustomSprite;
function doSomething(referenceObj:CustomSprite):void{
var methodObj:CustomSprite = referenceObj;
//CRAZY LINES OF CODE
methodObj = null; //frees memory from [doSomething::methodObj]
referenceObj = null; //frees memory from [doSomething::referenceObj]
//objToRemove is not cleared and will remain in memory
}
INCORRECT - in this situation [objToRemove] has a reference object so it will not clean until the reference is removed:
var objToRemove:CustomSprite = new CustomSprite;
var mappedObject:Sprite = new Sprite;
objToRemove.addMapping(mappedObject);
objToRemove.addEventListener(Event.ENTER_FRAME,onEnterFrame);
//CRAZY LINES OF CODE
//remove all children
while(objToRemove.numChildren > 0){
objToRemove.removeChildAt(0);
}
//remove all event listeners
objToRemove.removeEventListener(Event.ENTER_FRAME,onEnterFrame);
//this will NOT work
objToRemove = null;
//reason is objToRemove has a reference object of [mappedObject]
//[mappedObject] is not a child so it needs to be removed manually
//from WHITIN the CustomSprite class using [CustomSprite::finalize()]
Ok... breath... the correct way is actually simple.
CORRECT - here we are using [Dynamic] objects rather than [Static] class objects, this is considered Object Mapping:
//think of this as a global list of objects
var objPool:Dictionary = new Dictionary;
//create a pool reference
objPool['poolObj'] = new CustomSprite;
//CRAZY LINES OF CODE;
//do the normal [null] process
//both of these will work
objPool['poolObj'] = null;
//or
delete objPool['poolObj'];
SUPER ADVANCED CORRECT - no example provided, I have to get back to work lol...
1. Take a ByteArray clone of the class
2. User a Loader to construct the ByteArray as the class, rather than using "new"
3. When finished... unload/remove the loader
4. EVERYTHING will clear... thats how a Loader works!
(Not getting into why and how... too long of an explanation)
Although this works flawlessly... its not generally accepted or suggested in a work environment.
I'm currently enrolled in an ActionScript course, and cannot seem to get my progress bar to work correctly. We were tasked with creating a simple image loader application, which would access externally hosted images (through use of a PHP proxy script), and then spit the image onto the user's screen (with a progress event and progress bar to track the image's download progress).
However, when I run it, I get these mysterious black graphical glitches everywhere, as well as a non-functioning progress bar. In some browsers I get the following error: "ArgumentError: Error #2109: Frame label NaN not found in scene NaN. at flash.display.MovieClip/gotoAndStop() at Document/imageLoadProgress().
Here is my code - I cant for the life of me figure out what is wrong. I figure it has something to do with the imageLoadProgress() function, or my progress bar (which is just a simple 100-frame movie clip with a motion tween and a "stop()" command at the beginning).
public function loadImage()
{
var imageURL:String = imageArray[currentImageIndex];
if(loaderInfo.url.substr(0,4) == "http")
{
trace("we're online");
//use the proxy script
//escape() will replace spaces in file names with %20
imageURL = "./image_proxy.php?filename=" + escape(imageArray[currentImageIndex]);
}
var imageRequest:URLRequest = new URLRequest(imageURL);
this.imageLoader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, this.imageIOError);
this.imageLoader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, this.imageLoadProgress);
this.imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, this.imageLoadComplete);
this.imageLoader.load(imageRequest);
//end loadImage
}
public function imageIOError(e:Event)
{
trace("ImageIOError called. Error=" + e);
//end imageIOError
}
public function imageLoadProgress(e:ProgressEvent)
{
var percentLoaded:Number = e.bytesLoaded/e.bytesTotal;
percentLoaded = Math.round(percentLoaded * 100);
//this.progress_mc.scaleY = percentLoaded;
if (percentLoaded < 1)
{
this.progressBar.gotoAndStop(1);
}
else
{
this.progressBar.gotoAndStop(percentLoaded);
}
//end imageLoadProgress
}
Your loader script seems absolutely fine to me, except for a tiny flaw:
The only way the NaN(== not a Number) in your error message makes sense to me is if your ProgressEvent's bytesTotal property equals 0 - because division by zero doesn't produce valid results, as we all know.
I can't say for sure why this happens, not knowing any of your server-side code, but I assume it would occur if your PHP proxy script does not set the Content-Length HTTP response header correctly. If you were loading an actual image file, the web server would automatically set the header for you - in the case of your proxy script, it seems you have to take care of it yourself.
Anyway, you can make your loader script more error-proof by testing for NaN, and making sure the frame you jump to is never greater than 100:
var frame:int = isNaN (percentLoaded) || percentLoaded < 1 ? 1 :
percentLoaded > 100 ? 100 : percentLoaded;
progressBar.gotoAndStop(frame);
(I chose shorthand notation, but this is essentially the same as writing two if statements and an else).