I write a GUI program in Vala. When I compile it, compiler produces this error:
The name e1 does not exist in the context of Subtract.minus
The code is:
using Gtk;
class Subtract:Window{
public Subtract(){
this.title="Subtract program";
this.destroy.connect(Gtk.main_quit);
var e1=new Entry();
var e2=new Entry();
var lbl=new Label("Result");
var btn=new Button.with_label("Subtract");
var box=new Box(Gtk.Orientation.VERTICAL,5);
box.add(e1);
box.add(e2);
box.add(lbl);
box.add(btn);
this.add(box);
btn.clicked.connect(minus);
}
public void minus(){
int a=int.parse(e1.get_text());
int b=int.parse(e2.get_text());
int result=a-b;
lbl.set_label(result.to_string());
}
public static int main(string[]args){
Gtk.init(ref args);
var win=new Subtract();
win.show_all();
Gtk.main();
return 0;
}
}
How can I make the variables accessible from the minus method.
You have to declare the variables for your widgets (at least e1, e2 and lbl) as fields:
using Gtk;
class Subtract: Window {
// Fields (sometimes also called "attributes")
private Entry e1;
private Entry e2;
private Label lbl;
private Button btn;
private Box box;
public Subtract () {
title = "Subtract program";
destroy.connect (Gtk.main_quit);
// You don't have to use "this." to access fields in Vala
// I.e. "this.e1" is equivalent to "e1" in the code below
e1 = new Entry ();
e2 = new Entry ();
lbl = new Label ("Result");
btn = new Button.with_label ("Subtract");
box = new Box (Gtk.Orientation.VERTICAL, 5);
box.add (e1);
box.add (e2);
box.add (lbl);
box.add (btn);
add (box);
btn.clicked.connect (minus);
}
public void minus () {
// The compiler happily accepts "e1" (etc.) here now
// since I have declared them as fields
int a = int.parse (e1.get_text ());
int b = int.parse (e2.get_text ());
int result = a - b;
lbl.set_label (result.to_string ());
}
public static int main (string[] args) {
Gtk.init (ref args);
var win = new Subtract ();
win.show_all ();
Gtk.main ();
return 0;
}
}
PS: The correct technical term is "scope" here. Your code had the variables at the scope of the constructor, my code as the variables as class scoped fields which makes them visible across all the methods of the class.
The Vala compiler calls it "context", which is roughly the same in this case.
Related
Let say we have an object:
#:checkDirty
class Test {
var a:Int;
var b(default, default):String;
var c(get, set):Array<Int>;
public function new() {
...
}
public function get_c() {
...
}
public function set_c(n) {
...
}
}
Could we write a macro checkDirty so that any change to field/properties would set property dirty to true. Macro would generate dirty field as Bool and clearDirty function to set it to false.
var test = new Test();
trace(test.dirty); // false
test.a = 12;
trace(test.dirty); // true
test.clearDirty();
trace(test.dirty); //false
test.b = "test"
trace(test.dirty); //true
test.clearDirty();
test.c = [1,2,3];
trace(test.dirty); //true
Just to note - whenever you consider proxying access to an object, in my experience, there are always hidden costs / added complexity. :)
That said, you have a few approaches:
First, if you want it to be pure Haxe, then either a macro or an abstract can get the job done. Either way, you're effectively transforming every property access into a function call that sets the value and also sets dirty.
For example, an abstract using the #:resolve getter and setter can be found in the NME source code, replicated here for convenience:
#:forward(decode,toString)
abstract URLVariables(URLVariablesBase)
{
public function new(?inEncoded:String)
{
this = new URLVariablesBase(inEncoded);
}
#:resolve
public function set(name:String, value:String) : String
{
return this.set(name,value);
}
#:resolve
public function get(name:String):String
{
return this.get(name);
}
}
This may be an older syntax, I'm not sure... also look at the operator overloading examples on the Haxe manual:
#:op(a.b) public function fieldRead(name:String)
return this.indexOf(name);
#:op(a.b) public function fieldWrite(name:String, value:String)
return this.split(name).join(value);
Second, I'd just point out that if the underlying language / runtime supports some kind of Proxy object (e.g. JavaScript Proxy), and macro / abstract isn't working as expected, then you could build your functionality on top of that.
I wrote a post (archive) about doing this kind of thing (except for emitting events) before - you can use a #:build macro to modify class members, be it appending an extra assignment into setter or replacing the field with a property.
So a modified version might look like so:
class Macro {
public static macro function build():Array<Field> {
var fields = Context.getBuildFields();
for (field in fields.copy()) { // (copy fields so that we don't go over freshly added ones)
switch (field.kind) {
case FVar(fieldType, fieldExpr), FProp("default", "default", fieldType, fieldExpr):
var fieldName = field.name;
if (fieldName == "dirty") continue;
var setterName = "set_" + fieldName;
var tmp_class = macro class {
public var $fieldName(default, set):$fieldType = $fieldExpr;
public function $setterName(v:$fieldType):$fieldType {
$i{fieldName} = v;
this.dirty = true;
return v;
}
};
for (mcf in tmp_class.fields) fields.push(mcf);
fields.remove(field);
case FProp(_, "set", t, e):
var setter = Lambda.find(fields, (f) -> f.name == "set_" + field.name);
if (setter == null) continue;
switch (setter.kind) {
case FFun(f):
f.expr = macro { dirty = true; ${f.expr}; };
default:
}
default:
}
}
if (Lambda.find(fields, (f) -> f.name == "dirty") == null) fields.push((macro class {
public var dirty:Bool = false;
}).fields[0]);
return fields;
}
}
which, if used as
#:build(Macro.build())
#:keep class Some {
public function new() {}
public var one:Int;
public var two(default, set):String;
function set_two(v:String):String {
two = v;
return v;
}
}
Would emit the following JS:
var Some = function() {
this.dirty = false;
};
Some.prototype = {
set_two: function(v) {
this.dirty = true;
this.two = v;
return v;
}
,set_one: function(v) {
this.one = v;
this.dirty = true;
return v;
}
};
I'm using Processing 3 to make a GUI for a servo controller instead of using a pre-made library. It's based on having a packaging class organize several subclasses which use registerMethod mouse events to operate (as opposed to the simpler use of mousePressed() in the main sketch). What I'm getting hung up on is the PApplet naming/terms for each class to ensure that they can function both inside a subclass as well as on their own when called from the main. In my example the package is just a single button, as well as a direct button call for comparison. I do know that most current Java-users consider Applet use outdated, but since I'm just using the Processing IDE, I'd like to understand this concept better as well as try to avoid using something more complicated (but maybe less confusing) like an Interface.
PackServ tryMe;
Butt bOne;
void setup() {
size(200, 150);
tryMe = new PackServ(this);
bOne = new Butt(this);
}
void draw() {
background (250);
tryMe.Add(20, 10, 50);
line(100,10,100,100);
fill(130,255,170);
rect(120,10,50,60,5);
bOne.Add("B2", 145,35,25);
stroke(20); textSize(14); fill(25);
text("single", 130,100);
text("package", 20,100);
}
public class PackServ extends PApplet {
PApplet SerApp;
Butt Butt1, Butt2;
String theName;
int pkX, pkY, pkW;
PackServ(PApplet pa) {
this.SerApp = pa;
theName = "The Slider";
pkX = 20;
pkY = 20;
pkW = 100;
}
void Add(int _x, int _y, int _w) {
pkX = _x; pkY = _y; pkW = _w;
Butt1 = new Butt (this);
drawIt();
}
void drawIt() {
SerApp.fill(200);
SerApp.strokeWeight(1);
SerApp.rect(pkX, pkY, pkW, 60, 5);
Butt1.Add("B1", pkX+25, pkY+25, 25);
}
}
public class Butt
{
PApplet butApp;
int theX, theY, theW, theH, bRad;
boolean pressed = false;
color n;
color h = color(240, 210, 10);
color f = color (40, 90, 190);
color a = color (240, 20, 20);
int oBb, li;
String theLabel;
Butt (PApplet butApplet) {
this.butApp = butApplet;
butApp.registerMethod("mouseEvent",this);
n = f;
}
void Add(String _myName, int x, int y, int siz) {
theLabel = _myName;
theX = x;
theY = y;
bRad = siz;
fill(75);
textSize(9);
buttonLook();
}
boolean overB(int mx, int my) {
if (dist (mx, my, theX, theY) <= bRad) {
return true;
} else {
return false;
}
}
void buttonLook() {
if (overB(mouseX, mouseY) && pressed) {
n = a;
oBb = 3; li = 100;
} else if (overB(mouseX, mouseY)) {
text(theLabel, theX-10, theY+25);
n = h;
} else {
n = f; oBb=1; li=25;
}
strokeWeight(oBb);
stroke(li);
fill(n);
ellipse(theX, theY, bRad, bRad);
}
void mouseEvent(MouseEvent e) {
pressed = false;
int mx = e.getX(), my = e.getY();
switch (e.getAction()) {
case MouseEvent.PRESS:
pressed = overB(mx, my);
break;
}
}
}
I'm not totally sure what you're asking, so let me try to answer a few different things that you seem a bit confused about.
I do know that most current Java-users consider Applet use outdated
Please note that other than its name, PApplet has nothing to do with applets. Historically a PApplet was an applet, but as of Processing 3 that's no longer the case. PApplet is its own thing and has nothing to do with applets.
Let's take a closer look at this code:
public class PackServ extends PApplet {
PApplet SerApp;
PackServ(PApplet pa) {
this.SerApp = pa;
...
It doesn't make a ton of sense to extend PApplet and also take a PApplet argument into the constructor. This means that you now have two PApplet instances, which is almost never what you want to do.
Instead, my guess is you probably want to get rid of the extends PApplet part and only use Processing's classes using your serApp variable.
I believe that's the crux of your confusion: the PApplet class offers a bunch of handy functions like draw() and ellipse(), basically most variables and functions in the Processing reference. So you do need an instance of PApplet, but that instance is created for you when you use the Processing editor. You don't need to create your own instance by extending the PApplet class.
i have a class in a cs file:
public class ThreadData
{
private int index;
public ThreadData(int index)
{
this.index = index;
}
public static ThreadDataOutput DoWork(ThreadDataInput input)
{
return new ThreadDataOutput();
}
}
now, i have c++ code that tries to init a new task and to us the above function:
int numOfThread = 2;
array<Task^>^ taskArr = gcnew array<Task^>(numOfThread);
for (int i = 0; i < numOfThread; i++)
{
ThreadData^ td = gcnew ThreadData(i);
ThreadDataInput^ input = gcnew ThreadDataInput(i);
Task<ThreadDataOutput^>^ task = gcnew Task<ThreadDataOutput^>(td->DoWork, input);
taskArr[i] = task;
taskArr[i]->Start();
}
Task::WaitAll(taskArr, 300 * 1000);
the following code return 2 errors at compile time:
can't take address of 'ThreadData::DoWork' unless creating delegate instance
cannot convert argument 1 from 'AmadeusWS::ThreadDataOutput ^(__clrcall *)(AmadeusWS::ThreadDataInput ^)' to 'System::Func ^
i also tried to declare a delegate like this in the cs file:
public static Func<ThreadDataInput, ThreadDataOutput> DoWork2 = delegate(ThreadDataInput taskDataInput)
{
return new ThreadDataOutput();
};
but i don't know how to call it from the c++\cli code
can anyone assist me to understand how to define cli delegate that can take parametr ?
thanks
In order to create a delegate instance in C++/CLI, you need to construct it explicitly, and specify the object that it will be called on separately from the class & method to be called.
gcnew Func<TInput, TOutput>(theObject, &TheClass::MethodToInvoke)
Note that the method to be called is specified in the C++ style.
Substituting that in to your task creation, I believe this statement will work for you:
Task<ThreadDataOutput^>^ task = gcnew Task<ThreadDataOutput^>(
gcnew Func<ThreadDataInput^, ThreadDataOutput^>(td, &ThreadData::DoWork),
input);
Edit
In the code you posted in your comment, you missed the object to invoke the delegate on.
gcnew Func<Object^, Object^>(td, &ThreadData::DoWork)
^^
How can I get width and height of a linear layout which is defined in xml as fill_parent both in height and width? I have tried onmeasure method but I dont know why it is not giving exact value. I need these values in an Activity before oncreate method finishes.
Suppose I have to get a LinearLayout width defined in XML. I have to get reference of it by XML. Define LinearLayout l as instance.
l = (LinearLayout)findviewbyid(R.id.l1);
ViewTreeObserver observer = l.getViewTreeObserver();
observer.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
// TODO Auto-generated method stub
init();
l.getViewTreeObserver().removeGlobalOnLayoutListener(
this);
}
});
protected void init() {
int a= l.getHeight();
int b = l.getWidth();
Toast.makeText(getActivity,""+a+" "+b,3000).show();
}
callfragment();
}
The width and height values are set after the layout has been created, when elements have been placed they then get measured. On the first call to onSizeChanged the parms will be 0 so if you use that check for it.
Little more detail here
https://groups.google.com/forum/?fromgroups=#!topic/android-developers/nNEp6xBnPiw
and here http://developer.android.com/reference/android/view/View.html#Layout
Here is how to use onLayout:
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int width = someView.getWidth();
int height = someView.getHeight();
}
To get it work, you need to check whether the desired height value is bigger than 0 - and first then remove the onGlobalLayout listener and do whatever you want with the height. The listener calls its method continuously and by the first call it is not guaranteed that the view is measured properly.
final LinearLayout parent = (LinearLayout) findViewById(R.id.parentView);
parent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
int availableHeight = parent.getMeasuredHeight();
if(availableHeight>0) {
parent.getViewTreeObserver().removeGlobalOnLayoutListener(this);
//save height here and do whatever you want with it
}
}
});
You could add on layout change listener to your layout and get the newest height and width or even the one before last change.
Added in API level 11
Add a listener that will be called when the bounds of the view change
due to layout processing.
LinearLayout myLinearLayout = (LinearLayout) findViewById(R.id.my_linear_layout);
myLinearLayout.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
#Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
// Preventing extra work because method will be called many times.
if(height == (bottom - top))
return;
height = (bottom - top);
// do something here...
}
});
A generic approach using Kotlin based on MGDroid's answer for API 16+.
/**
* Align height of a container from wrap-content to actual height at runtime.
* */
private fun <T: ViewGroup> alignContainerHeight(container: T) {
container.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
// Obtain runtime height
val availableHeight = container.measuredHeight
if (availableHeight > 0) {
container.viewTreeObserver.removeOnGlobalLayoutListener(this)
setContainerHeight(container, availableHeight)
}
}
})
}
/**
* Note: Assumes that the parent is a LinearLayout.
* */
private fun <T : ViewGroup> setContainerHeight(container: T, availableHeight: Int) {
val availableWidth = container.measuredWidth
val params = LinearLayout.LayoutParams(availableWidth, availableHeight)
// Note: getLayoutParams() returns null if no parent exists
if (container.layoutParams != null) {
container.layoutParams = params
}
}
So, I made a class that takes arrays and calculates a value from them. I then decided (unknowingly) to incorporate it into a GUI interface. All went well until I noticed this strange error; one of the jtextfields (prarie) would not store text while the other (yard) does.
I looked around and found my problem similiar to mine on this site;
Updating text in a JTextField
But he had one that doesn't work at all, where I have one that works and one that doesn't.
The Code is here (it's a bit long, but most of it is GUI), so hold your breath!:
import java.awt.GridLayout;
import javax.swing.Box;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class Window {
/**
* #param args
*/
private static int numb;
private static double micro, centi;
private static JTextField[] yard,prarie;
private static double[] charges,distances;
public static void main(String[] args)
{
//create a small dialog window to take in number of charged objects
JPanel startup = new JPanel();
JTextField many = new JTextField(5);
startup.add(many);
int result = JOptionPane.showConfirmDialog(null,startup , "Please Enter How Many Charged Objects are Being Evaluated", JOptionPane.OK_CANCEL_OPTION);
many.requestFocusInWindow();
//once ok is clicked, then the number input will be stored under 'numb'
//then proceed to inputFields
if (result == JOptionPane.OK_OPTION)
{
numb = Integer.parseInt(many.getText());
inputFields();
}
}
//this window opens the various JTextFields for input
public static void inputFields()
{
//top JTextFields
yard = new JTextField[numb];
JPanel chargePanel = new JPanel();
for(int x=0;x<numb;x++)
{
yard[x] =new JTextField(5);
chargePanel.add(new JLabel("Charge "+ Integer.toString(x+1)+":"));
chargePanel.add(yard[x]);
chargePanel.add(Box.createVerticalStrut(15)); // a spacer
}
//bottom JTextFields
prarie = new JTextField[numb-1];
JPanel meterPanel = new JPanel();
for(int x=0;x<numb-1;x++)
{
prarie[x]=new JTextField(5);
meterPanel.add(new JLabel("Meters "+ Integer.toString(x+1)+":"));
meterPanel.add(new JTextField(5));
meterPanel.add(Box.createVerticalStrut(15)); // a spacer
}
//JCheckBoxes
JCheckBox isMicro = new JCheckBox("Charges are in terms of microCoulombs");
JCheckBox isCm = new JCheckBox("Distances are in terms of centiMeters");
JPanel chechBox = new JPanel();
chechBox.add(isMicro);
chechBox.add(Box.createVerticalStrut(20));
chechBox.add(isCm);
//Paste them all together into one window
GridLayout gufi = new GridLayout(3,1);
JPanel host = new JPanel(gufi);
host.add(chargePanel);
host.add(meterPanel);
host.add(chechBox);
int result1 = JOptionPane.showConfirmDialog(null, host, "Please Enter Charge and Distance Values", JOptionPane.OK_CANCEL_OPTION);
//if ok is clicked, then go to 'printArr()' to print the JTextFields
//then go to assign the values from the JTextFields to private double arrays 'yard' and 'prarie'
if (result1 == JOptionPane.OK_OPTION)
{
micro = (isMicro.isSelected())? Math.pow(10, -6): 1;
centi = (isCm.isSelected())? .01: 1;
printArr();
assign();
}
}
//a makeshift method to print the value from the JTextFields
//to fix the problem of why prarie wouldn't store numbers
public static void printArr()
{
System.out.println("Charges are:");
for(int x=0;x<numb;x++)
System.out.print(yard[x].getText() + " ");
System.out.println("Distances are:");
for(int x=0;x<numb-1;x++)
System.out.print(prarie[x].getText() + " ");
}
//assigns values from JTextFields to the private double arrays 'yard' and 'prarie'
public static void assign()
{
try {
charges = new double[numb];
for(int x=0;x<numb;x++)
charges[x]=micro*Double.parseDouble(yard[x].getText().trim());
distances = new double[numb-1];
for(int x=0;x<numb-1;x++)
distances[x]=centi*Double.parseDouble(prarie[x].getText().trim());
} catch (NumberFormatException e) {
e.printStackTrace();
//inputFields();
}
calculate();
}
public static void calculate()
{
JPanel sample = new JPanel();
JTextField whichOne = new JTextField(5);
sample.add(whichOne);
int result = JOptionPane.showConfirmDialog(null,sample , "Please Enter Which Charged Object thy Wishs For", JOptionPane.OK_CANCEL_OPTION);
whichOne.requestFocusInWindow();
if (result == JOptionPane.OK_OPTION)
{
int target = Integer.parseInt(whichOne.getText());
}
}
}
Anyone who runs the code and takes the time to enter dummy values will see that 'yard' stores values while 'prarie' does not. Why is this?
*I'm pretty sure I'm overlooking obvious (as always).
Change:
meterPanel.add(new JTextField(5));
to:
meterPanel.add(prarie[x]);
in the for loop for the prarie textfields