JFrame in GUI class not updating - swing

I am very new to JAVA, and am attempting to write a pharmacokinetics calculation program for my students to use.
The program reads a database of plasma concentration vs time values and calculates a number of pharmacokinetic parameters and outputs these into a number of frames, as well as drawing linear and exponential curves which are also output into frames.
I wrote the program initially as a console based, to make sure everything worked as required, before moving to GUI. Now comes the difficult steps of GUI building. I realize my console code will change considerably, I'm looking forward to the learning curve.
I am now attempting to output results via a separate 'GUI' class, and so pass frames between classes before output. I have tried to pass a frame from my 'GUI' class to my other class, without success.
In my attempt to learn GUI, and the class structure of JAVA, I have two classes.
A ProjectChart Class, that contains all the calculation and graphing methods.
A ProjectChartGUI class, which will eventually be used to output all data.
ProjectChartGUI currently defines a number of InternalFrames. I have been trying to pass one such internalframe to a function in ProjectChart, OutputInputData(). This constructs a table of data, read by a separate function, and will output this table into a frame for user validation.
I am trying to pass a JInternalFrame from ProjectChartGUI to OutputInputData().
Initially I passed the JInternalFrame using a .getFrame() function using OutputInputData (JInternalFrame frame).
I also tried to pass a ProjectchartGUI object. OutputInputData (ProjectChartGUI tProjectChartGUI). This also did not work.
In both cases, the program runs, all calculations are performed successfully, however the frame which opens via ProjectChartGUI is empty.
Here is my main:
public static void main(String[] args) throws IOException, InterruptedException, URISyntaxException{
ProjectChartGUI tGUI = new ProjectChartGUI();
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
ActionPharmacokinetics(tGUI);
tGUI.setVisible(true);
}
});
}
Here is a snippet of the function ActionPharmacokinetics():
public static void ActionPharmacokinetics(ProjectChartGUI tGUI){
DetermineUserInput();
if(CHECK == IVBOLUS_TRUE)
{
// Read database to access main information
Access_IVBOLUS_DatabaseList();
// Read database again to allow user to select desired entry for calculation
Access_IVBOLUS_Database();
// Output CP and T values to a new window for confirmation
OutputInputData(tGUI);
//Diplay Linear chart of Data
Display_IVBOLUS_LinearGraph();
// Display exponential chart of Data
Display_IVBOLUS_ExponentialGraph();
// Calculate pharmacokinetic parameters
Calculate_IVBOLUS_PharmacokineticParameters();
// Output pharmacokinetic paramaters
OutputPharmacokineticParamaters();
}}
Here is outputInputData(): Cp, lnCp and T are declared variables in ProjectChart. Numberofpoints is the numberofdata points read from the database.
static public void OutputInputData(ProjectChartGUI tGUI){
//create table objects
String[] ColumnNames = new String[]{"Data Point", "CP"+Units_CP,"ln CP","Time"+Units_T};
double SetDecimalPoint = 0.0;
Object[][] Data = new Object[NumberofPoints][4];
for (int k=0;k<NumberofPoints;k++)
{
Data[k][0] = k+1;//index
Data[k][1] = Cp[k];//plasma
SetDecimalPoint = lnCp[k];//log plasma
BigDecimal bd = BigDecimal.valueOf(SetDecimalPoint);
bd = bd.setScale(2, BigDecimal.ROUND_FLOOR); // rounds ln cp to 2 decimal places for output
Data[k][2] = bd;
Data[k][3] = T[k];//time
}
//create table
JTable jtable = new JTable(Data, ColumnNames);
//Create frame
//JFrame jFrame = new JFrame("Input Data");
//jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//add table to frame
tGUI.getframe().add(new JScrollPane(jtable));
tGUI.getframe().pack(); //auto size
tGUI.getframe().setVisible(true);
}
.getframe() returns an internal frame from ProjectChartGUI
public javax.swing.JInternalFrame getframe(){
return jInternalFrame1;
}
I used Netbeans GUI builder to define a frame, with an internal frame
private javax.swing.JInternalFrame jInternalFrame1;
All other code in ProjectChartGUI was autogenerated by Netbeans.
Does anyone have any suggestions on where I may be going wrong?

Related

Messy diagram derives when it comes to printing it on pdf by using MS Windows 10 service

I've been writing Java SE 8 desktop application. I use Eclipse IDE, Oracle's JDK, and run it on MS Windows 10 OS.
My app draws diagrams, in short. I draw a diagram on JPanel which becomes part of JTabbedPane. It displays it well on GUI, and it is very responsive. The problem shows up when I pass the diagram on printing service. But instead of printing it on printer, I choose, "Microsoft print to PDF" service. What happens next, is that if the diagram is large, when you scroll it down, you will observe that its quality drops down. That is, grids start disappearing, new lines appear, etc.
The pic out here.
As you can see, eventually vertical grids vanish, diagonal line creeps in, and later gets even worse. And that is unwelcome.
Relevant code in here:
public final class GanttChartDiagram extends TopDiagram{
#Override
public void paintComponent(Graphics graph){
super.paintComponent(graph);
Graphics2D g2D = (Graphics2D)graph;
g2D.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
...........
#Override
public Dimension getPreferredSize(){
return new Dimension(this.diagramWidth + 20, this.diagramHeight + 20);
}
}
}
The getPreferredSize() method identifies the size of diagram, so that the app knows how to adjust the scroll-bars accordingly to fit the diagram in. Otherwise by default it return 0, if not overridden.
That is the class where I draw the diagram.
The super-class out here:
public abstract class TopDiagram extends JPanel implements Printable {
private static final long serialVersionUID = 1469816888488484L;
#Override
public void paintComponent(Graphics graph){
super.paintComponent(graph);
};
/**
* Prints selected diagram
*/
#Override
public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
Graphics2D dimension = (Graphics2D)graphics;
dimension.translate(pageFormat.getImageableX(), pageFormat.getImageableY());
if(pageIndex < PrintingImageBuffer.getImageBuffer().size()){
dimension.drawImage(PrintingImageBuffer.getImageBuffer().get(pageIndex), null, 0, 0);
return PAGE_EXISTS;
}
else{
return NO_SUCH_PAGE;
}
}
}
Now that is where I print the diagram:
public static void printDiagram(){
new Thread(new Runnable(){
public void run(){
TopDiagram diagram = null;
if(id.equalsIgnoreCase("GanttChart")){
diagram = ganttChartDiagram;
}
final PrinterJob printer = PrinterJob.getPrinte
rJob();
printer.setJobName("Printing the "+id+" Diagram");
PageFormat format = printer.pageDialog(page);
int nowWidth = (int)diagram.getPreferredSize().getWidth();
int nowHeight = (int)diagram.getPreferredSize().getHeight();
BufferedImage buffImg = new BufferedImage(nowWidth, nowHeight, BufferedImage.TYPE_INT_ARGB);//default type
Graphics2D d = (Graphics2D)buffImg.getGraphics();
....etc..................
}
}).start();
}
Now the interesting part is this:
int nowWidth = (int)diagram.getPreferredSize().getWidth();
int nowHeight = (int)diagram.getPreferredSize().getHeight();
On the same instance of diagram, on multiple invocations of print (or within the method), it may or may not return different values. So that it was causing me some sort of Raster exception. But I managed to get rid off of that exception by invoking size method only once and reusing that size value throughout the method. So that, the size value stays the same, cause it is read only once.
Bad solution, but it works.
I would like to solve this issue too. Firstly, how come that this invocation diagram.getPreferredSize().getWidth() on the same instance of diagram obj. returns different size value? One more thing, is that I overrode this method as has been presented above. And the diagram object is created only once, no recalculations.
This is where I create the diagram obj. on Swing Worker only once per application's life-cycle.
GanttChartSwingWorker ganttSwingWorker = new GanttChartSwingWorker(GanttChartDiagram::new, tabbedPane, showPerformanceDiagramTab, ganttChartDiagramTabReady);
ganttSwingWorker.execute();
new Thread(() -> {
try{
ganttChartDiagramTabReady.await();
ganttChartDiagram = ganttSwingWorker.getGanttChartDiagram();
}catch(InterruptedException ie){ie.printStackTrace();}
}
).start();
Swing Worker part:
diagram = this.get();
JScrollPane scrollPaneChart = addScrollPane(diagram);
tabbedPane.addTab("Gantt Chart", null, scrollPaneChart, "Displays Gantt Chart Diagram");
Some diagram objects can be time consuming to create, imposes delay, so I use Swing Worker to do that.
So, in summary:
How to make the diagram to appear clean when I print/save it on pdf file in the way that I explained?
How to make the diagram size to calculate consistently as per multiple invocations? What leads to different diagram size values retrieving it from the same diagram object instance on multiple calls?
I just figured out what the problem is.
I observed that when it comes to drawing the diagram, the
paintComponent(Graphics g) method has been invoked repeatedly. It keeps redrawing the diagram over and over again. It is invoked by the system implicitly, yet my implementation had been triggering it.
And that trigger comes in the form of this.setSize(width, height) method on derived JPanel object. So that each time the paintComponent(Graphics g) re-executes, it sets the size on JPanel which yet triggers additional execution of the painComponent method. In the end, it is an infinite loop.
And that infinite execution was the cause of the problem; it was producing distorted diagram image on pdf file.
Solution: execute the setSize method only when it is needed; on initial panel set-up, or resize.

Is it possible to remove an instance of an object from memory and restore it later in as3?

My question is a bit vague so let me elaborate. I'm a beginner programmer working on my first flash game which for the point of this question is a side-scrolling platformer like mario for example. Unlike a traditional platformer though, the level will continue indefinitely until a player dies or quits the game. The level is tilebased and will be generated automatically through a array which specifies what object is in each tile( or 0 if there is no object). In order to ensure my game doesn't automatically crash from excessive objects I will generate more of the map( by creating new instances of objects) as the player progresses so that as the player move right the map is generated just past the edge of the screen.
Now back to the matter at hand, I'm guessing that once the player gets to a certain point in the game it will start to slow down because more and more objects are being created.
I assume the solution to this problem would be to remove the instances to the left of the screen as the player progresses however the problem with this is I need the player to have the ability to go back through the level.
So my question is: how can i 'delete' or remove the instances from memory, so my game doesn't slow down, but also restore the instance when the player moves into a certain proximity of where that instance is (or was).
Note: Currently aside from the player the only object i have in the game is the 'Wall' object all instances of which are stored in the 'Wallarray' array which i currently only use to reference instances of a Wall for collision detection
See my comment, but either way it may be the same answer. Read up on the SharedObject class and do some simple experiments using SharedObjects to write info about objects to disk, and to read that info back.
My suggestion is to split game model from its view. You'll have the whole level model stored in a separate class and a view which renders visible model's part onto the stage. Rendering engine will remove visual objects that are out of the screen as well as create visual objects which become visible. Your model will dispatch some events to notify your view about its changes. Hope that will help.
I suggest you to use object pooling: When your objects are not visible anymore you can put them in a temporary array an when you need a new object, instead of create a new you can get one from this array.
here an example of object with his pool:
package
{
public class Pooled extends MovieClip
{
/** the array containg objects created and not used **/
protected static var _pool :Vector.<Pooled>;
/** the number of objects in the pool **/
protected static var _nbItems :int;
public function Pooled()
{
}
/** a function to dispose the object **/
public function dispose():void
{
// do what you want here for release memory
}
/** the function to call to release the object and return it to the pool **/
public function release():void
{
// do what you want here, stop animations, remove from parent, remove listeners ...
// put it in the pool
_pool[_nbItems++] = this;
}
/** a static function to initialize the object and to create the pool **/
public static function init():void
{
_pool = new Vector.<Pooled>();
_nbItems = 0;
}
/** a static function to get an object from the pool **/
public static function get():Pooled
{
var a :Pooled;
if( _nbItems > 0 )
{
a = _pool.pop();
_nbItems--;
}
else
{
a = new Pooled();
}
return a;
}
/** a static function to destroy objects and the pool **/
public static function dispose():void
{
for( var i:int = 0; i<_nbItems; ++i ) _pool[i].dispose();
_pool.length = 0;
_pool = null;
}
}
}
You have to call first the static init method to create the pool array.
After that instead of create object using new Pooled();, use Pooled.get();, it will return you item from the pool if available and if not, it will create a new one.
When you don't want your object anymore, you can call release() function and the object will be moved to the pool.
Using this technique, the maximum object in memory will be the maximum displayed object at the same time. And you avoid the time of creating new objects when your pool contain object.
Hope this could help you.

How to clone an object without knowing the exact type in AIR for iOS

I am writing an iOS game in Flash and I need a way to clone polymorphic objects.
I have BaseClass, SubClass1, SubClass2 (and so on...) and I need a clone() method in BaseClass, that will create a copy of the current object, without a conditional such as
var obj:BaseClass;
if(this is SubClass1) {
obj = new SubClass1();
}else if(this is SubClass2) {
obj = new SubClass2();
}else...
I need a way to create an object and create the exact bytes (yes, a shallow copy is enough for my purpose) of the object. I've looked at:
AS3 - Clone an object
As3 Copy object
http://actionscripthowto.com/how-to-clone-objects-in-as3/
But none seem to work. Probably not available in AIR 3.3 for iOS SDK. (they compile, but the code doesn't work in my case)
Is there any other way, or did anybody achieve to clone an object in AIR for iOS?
Thanks,
Can.
Bit-by-bit cloning cannot be done with ActionScript, unless your class only contains primitive values (i.e. a simple data structure). That's what the ByteArray approach you've linked to in this question's answer is used for - but when you're dealing with complex types, especially display objects, you'll soon come to the limits (as, I gather, you have already realized).
So this more or less leaves you with two options:
Create a new object and copy all of its fields and properties.
This is the way to go if you're going to need behavior and field values, and you didn't use any drawing methods (i.e., you can not copy vector graphics this way). Creating a new class instance without knowing its exact type can be done in a generalized way using reflections, getQualifiedClassName() and getDefinitionByName() will help you there, and if you need more than just the name, describeType(). This does have limits, too, though:private fields will not be available (they don't appear in the information provided by describeType()), and in order to not run into performance problems, you will have to use some sort of cacheing. Luckily, as3commons-reflect has already solved this, so implementing the rest of what you need for a fully functional shallow copy mechanism is not too complex.
Create a new instance like this:
var newObject:* = new Type.forInstance( myObject ).clazz();
Then iterate over all accessors, variables and dynamic properties and assign the old instance's values.
I have implemented a method like this myself, for an open source framework I am working on. You can download or fork it at github. There isn't any documentation yet, but its use is as simple as writing:
var myCopy:* = shallowCopy( myObject );
I also have a copy() method there, which creates a true deep copy. This, however, has not been tested with anything but data structures (albeit large ones), so use at your own risk ;)
Create a bitmap copy.
If you do have vector graphics in place, this is often easier than recreating an image: Simply draw the content of the object's graphics to a new Bitmap.
function bitmapCopy( source:Sprite ):Bitmap {
source.cacheAsBitmap = true;
var bitmapData:BitmapData = new BitmapData( source.width, source.height, true, 0xFFFFFF );
bitmapData.draw( source, new Matrix(), null, null, null, true );
return new Bitmap( bitmapData, PixelSnapping.AUTO, true );
}
You need to create an abstract clone method in the base class and implement it for each subclass. In the specific implementations, you would copy all of the properties of the object to the new one.
public class BaseClass {
public function clone():BaseClass
{
// throw an error so you quickly see the places where you forgot to override it
throw new Error("clone() should be overridden in subclasses!");
return null;
}
}
public class Subclass1 extends BaseClass {
public override function clone():BaseClass
{
var copy:Subclass1 = new Subclass1();
copy.prop1 = prop1;
copy.prop2 = prop2;
// .. etc
return copy;
}
}
If you wanted to create a generic default implementation of clone, you could use describeType to access the properties and copy them over:
public function clone():BaseClass
{
var defn:XML = describeType(this);
var clsName:String = defn.#name;
var cls:Class = getDefinitionByName(clsName) as Class;
var inst:* = new cls();
for each(var prop:String in (defn.variable + defn.accessor.(#access == 'readwrite')).#name )
{
inst[prop] = this[prop];
}
return inst;
}
The main issue with this is that the describeType XML can get quite large - especially if you are dealing with objects that extend DisplayObject. That could use a lot of memory and be slow on iOS.

Is it possible not to flush sharedobject on close?

I'm having a problem with the sharedObject flush method. Is it possible to not flush the new data when the swf is closed? My savegame function is the only function that calls the flush method and it also determines which array goes where in the sharedObject data.
parentMC.sharedObject.data.moveSpdUpgrade = parentMC.upgrades.tempMoveSpdUpgrade;
parentMC.sharedObject.flush();
However, when I modify the tempMoveSpdUpgrade array, it also saves the new data in the sharedObject even if the flush hasn't been called yet.
tempMoveSpdUpgrade[0][2] = 1;
trace(parentMC.sharedObject.data.moveSpdUpgrade);
This trace shows that the data has changed but I don't understand since the flush hasn't been called and the swf hasn't been closed. I'm wondering why the modifications made in the array automatically changes the sharedObject data.
Thank you for the help.
Edit:
public function saveGame(){
parentMC.sharedObject.data.money = parentMC.money;
parentMC.sharedObject.data.moveSpdUpgrade = parentMC.upgrades.tempMoveSpdUpgrade;
parentMC.sharedObject.flush();
}
Like I stated in the comments with hackattack, the money is the correct data when I don't save but the moveSpdUpgrade array is modified either way.
I think you are running into a bit confusing thing about arrays.
What is happening never saves any data by another function or has something to do with the rest of your code.
Simple the method how you try to copy the array of that Sharedobject doesnt create two seperate Obejcts. Instead you are always working live on the sharedObject-array.
package
{
import flash.display.Sprite;
public class arraytester extends Sprite
{
private var a:Array = new Array(1,2,3,4,5);
private var b:Array = new Array("a","b","c","d","e","f");
public function arraytester()
{
// Both arrays are different Objects
trace(a); // 1,2,3,4,5
trace (b); //a,b,c,d,e,f
// Both arrays are pointing to the same Object
a= b;
trace(a); //a,b,c,d,e,f
trace (b); //a,b,c,d,e,f
b[1] = 2;
trace(a); //a,2,c,d,e,f
trace (b); //a,2,c,d,e,f
// a is a copy of b while becoming a seperate Object
a = b.concat();
b[0]= 1;
trace(a); //a,2,c,d,e,f
trace (b); //1,2,c,d,e,f
}
}
}
What is in the sharedObject that is loaded into memory and what is saved to disc are separate things. You are tracing the sharedObject in memory. Until you flush this sharedObject it probably wont save its image to disc. Try creating a new SharedObject and tracing that, it should be different.
Edit:
I see an error in what i told you to do before (below in the comments). I told you to make a new instance of moveSpdUpgrade to place in your shared object with the .concat method. The reason this doesnt work is because moveSpdUpgrade is a 2d array, i missed this detail. So calling .concat creates a new instance, but the new instance is still filled with references to arrays and it those arrays that you are editing. So to solve this we have to do a deep copy of moveSpdUpgrade. Here is a function that will accomplish that
function array2DConcat(target : Array) : Array {
var buff : Array = new Array(target.length);
for(var i : int = 0;i < target.length;i++) }
buff[i] = target[i].concat();
}
return buff;
}
and then if you change your method to
public function saveGame(){
parentMC.sharedObject.data.money = parentMC.money;
parentMC.sharedObject.data.moveSpdUpgrade = array2DConcat(parentMC.upgrades.tempMoveSpdUpgrade);
parentMC.sharedObject.flush();
}
hopefully that will work.

ActionScript Basic Question

i've only ever created external .as files that extended a class such as sprite. now i just want to create one that doesn't extend anything and call it from a frame script.
package
{
public class Test
{
public function Test(val:Number, max:Number)
{
trace(val, max);
}
}
}
from my frame script of an .fla that is in the same folder as Test.as, i'll write this:
Test(50, 100);
this produces the following error:
1137: Incorrect number of arguments. Expected no more than 1.
Your code will be interpreted as cast to Test. It makes no sense to cast 2 numbers as a Test object.
What you want is an instance (an object) of the class Test.
For this, you need the new operator.
var testInstance:Test = new Test(50,100);
Then, you can use your object as needed, for example, calling methods, setting or getting values, etc.
testInstance.someMethod("hello");
testInstance.someNumber = 10;
var n:Number = testInstance.someNumber;
// etc...