Change car size on runtime in AnyLogic - simulation

Cars are moving on the road, and I want to use a button to change the scale of the cars.
Once I press the button, the scale of all the cars that are in the system and are being produced by the source should change.
My approach
1. I make a variable "carSize" and put it in "car" 3Objact properties "Additional Scale." shown in image below.
2 Then in "Main" I put this code in a button.
LineCarAgent LineCar = new LineCarAgent();
LineCar.set_carSize(11);
traceln("New car size " + LineCar.carSize);
Now, when I run the model and press the button, I can see the new value printed in the console, but the size of the car does not change, neither for existing cars nor for upcoming cars.

If you know which car you want to have the shape scale change, use:
cars.get(i).car.setScale(s);

We can use a loop to go through "cars" population and change the scale of all the cars one by one.
The only issue is that if we include "loop" in the button, then only the scale of the existing population will change. So what we can do is put the loop in the cyclic event to keep changing the scale of the new coming car.
Step 1: Create an cyclic event and put this code in the action
for (int i = 0; i < cars.size(); i++) {
cars.get(i).car.setScale(0.9);
}
Step 2: We don't want the code in the event to start executing unless we press the button, so "on startup" write event.suspend(); and in the button action, write event.restart();.
Now event will only start once we press the button. Which means that all the cars scale will only change when we press the button.

Related

MAUI with MVVM - How Do I implement a Submit method in a 'details' page?

I am new to MVVM and MAUI, and I am quite a bit confused now.
This is the situation - I will explain it as well as I can:
In my main page I have a CollectionView with frames etc., and in each frame I show a picture of some CAR object. On clicking on a frame I execute the command
[RelayCommand]
private async Task GoToCarsDetails(Car car)
{
if (car == null)
return;
await Shell.Current.GoToAsync(nameof(CarPage), true, new Dictionary<string, object>
{
{"Car", car}
});
}
In my CarPage.xaml, which I reach with the method above, I have a grid which contains this xaml:
<Label
x:Name="Description"
Grid.Row="2"
Style="{StaticResource MediumLabelCentered}"
Text="{Binding Car.Description, StringFormat='Description: {0}'}" />
<Label
x:Name="Color"
Grid.Row="3"
Style="{StaticResource MediumLabelCentered}"
Text="{Binding Car.Color, StringFormat='Color: {0}'}" />
and also an Editor to be able to change the Description, a Picker to be able to change the Color, and a Submit button.
I want to allow the user to set some description and a color, and this should NOT immediately change the CAR object passed as param to the method Shell.Current.GoToAsync - they should only be changed when clicking on the submit button - if the user changes for instance the color from the initial Red to Blue, but does NOT click the Submit button and goes back to the previous screen (Main) instead, the property Color should NOT have changed - it should still show "Red".
So, for instance, let's say that for some car I have the
Color = RED, and
Description = "My Car"
Click on that car, go to the CarPage.xaml, see in the Picker the color set to RED and the description in the editor = "My Car", change those to BLUE and "Your Car", respectively, and navigate away without clicking on the Submit button. The initial car should still show
Color = RED, and
Description = "My Car"
(no change).
Do the same thing as above but this time click on the submit button. This should take us to the previous page (Main), and see that the initial car now shows
Description = "Your Car", and
Color = BLUE
My problem is this:
If I BIND the controls, as seen in the xaml above, then any change on those Editor and Picker will already change the underlying Car object, and then the Submit button has no meaning anymore. If I click on it or not, that makes no difference - the Car object already contains those changes.
If instead of opening the CarPage.xaml page with the Car object I open it with a clone, with the intention of allowing the user wo freely play on the clone object, by passing a clone object
car.Clone<Car>()
(I have created an extension method for that). I can now indeed change the Clone's properties all I want, but then how do I replace on Submit the object CAR with the object CARCLONE ? The code for that Submit button exists either in the code-behind of the CarPage.xaml object, either in the CarViewModel class. In neither object do I have access to both CAR and CARCLONE, to be able to switch them.
I cannot switch these two objects (the original CAR object with the changed CARCLONE object) in the MainViewModel's GoToCarsDetails method
private async Task GoToCarsDetails(Car car)
either, because this method calls Shell.Current.GoToAsync in an async way, and I cannot add the code which would switch objects after the Shell.Current.GoToAsync call, because the code will not wait for the CarPage to be closed.
I also thought of passing the real CAR object as param, NOT binding the two labels above, play with the controls, and populate the CAR object with the updated properties only in Submit_Click().... But how do I set, on opening the CarPage page, the Text of the two labels ? (Is there a Load() event ? I couldn't find one). Writing such code in the constructor does not work (it gives me a null reference).
So... I don't know how do do this seemingly very simple task:
Pass an object to a Details form, allow it to be changed, but actually update it to our collection in Main only if the user has clicked on the submit button in that Details page (CarPage, that is), all by not violating the MVVM ideas.
Thank you very much.
Alex
There is a standard mechanism, in any language, for dealing with situations like this: a "callback".
Think about "Responsibilities". The main page (and its viewmodel) is responsible for managing the Car objects.
You want somewhere else to work with a Car object, but that "somewhere else" [I'll call it CarEditor] isn't the place that should deal with the consequences of modifying a Car.
So what do you want to pass in? A Car. What do you want to do on Submit_Click? Something that CarEditor doesn't need to know about. It should hand all the information "back" (via the callback action) to somewhere that has the responsibility to act on the result.
As Jason suggested, one way to do this is to have a clone of Car. Then pass back both original and clone. This could be done as (Car original, Car clone).
Calling code:
Car original = ...;
Editor.EditThis(original, ProcessTheEdit);
...
void ProcessTheEdit(Car original, Car clone)
{
}
Editor code:
public delegate void CallbackDlg(Car original, Car clone);
public void EditThis(Car original, CallbackDlg callback)
{
Car clone = new Car();
//... do work.
callback(original, clone);
}
I have followed your advice, and here it is:
[RelayCommand]
private async Task GoToCarsDetails(Car car)
{
Car carClone = car.Clone();
await Shell.Current.GoToAsync(nameof(CarPage), true, new Dictionary<string, object>
{
{"Car", car},
{"CarClone", carClone}
});
}
CarPage has the controls bound to CarClone.
On the Submit button in the ViewModel I have:
[RelayCommand]
private void Submit()
{
Car = carClone.Clone();
Shell.Current.GoToAsync("../", true);
}
If I change the color from the initial RED to YELLOW and I set a breakpoint on the Shell line, I see that indeed Car now has the color property = YELLOW.
Good.
However, if I click again on the same car, the CarPage view opens again with Color = RED, which is not correct. I have changed that Car object to have the color set to Yellow, right ? The Cars collection in this MainViewModel shows as unchanged !
I don't understand - I have passed the Car object to the "Details" CarView page and I have changed it from Red to Yellow, and yet... it is still Red. It's like I have passed the Car object Byval and not Byref.... :-(
Thank you,
Alex

In LibreOffice Calc change the size of a shape by clicking it

I have several shapes in LO Calc and I need those shapes to change their sizes when they are mouse clicked: the first click enlarges the shape, the second click restores the original size.
I'm trying to do this with a macro assigned to those shapes. My problem and my question: how to determine within a macro which shape has been clicked?
I know how to get the current selected shape:
dim doc as object
doc = ThisComponent
someVar = doc.CurrentSelection...
But a shape when clicked is not getting selected and this method is not working.
I tried to add a parameter for the event object to the macro:
sub ChangeSize( oEvent )
But this produces a message about wrong number of parameters.
Is there a way to detect the caller of a macro in LO Basic? Or maybe another way to implement size changing with a mouse click?
P.S. One can use a separate button for calling the macro and click this button after selecting the needed shape, but this way is less convenient.
EDIT: As I guessed below in the comments, the described task can be solved via the mouse and shape coordinates. The key points for the solution I found here:
How to get Document-Coordinates from a Mouse Click in an OpenOffice BASIC Macro
Instead of detecting the caller, assign a different one-line macro for each shape clicked event.
Sub ShapeClickedA
ChangeSize("ShapeA")
End Sub
Sub ShapeClickedB
ChangeSize("ShapeB")
End Sub
Related: LibreOffice macro showing simple TextBox shape
P.S. After answering, I realized you asked the linked question as well. How is this different, and is the other answer not satisfactory?

LibreOffice macro showing simple TextBox shape

I cannot figure out (or find an example) how to perform the following simple thing in the LibreOffice Calc 6.2:
I have a drawing shape (e.g. a simple rectangle) in a sheet (call it ShapeA) and a textbox shape in another sheet (call it TextboxB). I want to do the following: when I click on the ShapeA, the TextboxB must appear on the screen (without changing the current sheet, maybe in a dialog box) and then be closed with a mouse click.
I guess the macro associated with ShapeA could look something like this:
Sub Main
oDrawPage = ThisComponent.getDrawPage()
oTb = oDrawPage.getByName("TextBoxB")
oTb.show()
End Sub
Could someone advise what I should put into this macro to accomplish the described task?
UPDATE: What I want to accomplish ( in reply to Jim K.).
I have a very cluttered diagram with many shapes. Each shape has some textual information associated with it. There is not enough space on each shape or around it to contain this info. So there is must be a way to display this info about each shape. Also this information should be displayed in a preformatted way (it contains code and other structured info).
My plan is to create a textbox with the relevant information for each diagram shape, place these textboxes in other sheet and have a possibility, when viewing diagram, to click on any shape and view the associated info in the poped up textbox without leaving the diagram, and then close the textbox with a simple action (e.g. by clicking on it).
Does this task sound feasible to be realized with the LO's shapes and macros?
How about this: Put everything on the same sheet but keep the text boxes hidden until needed.
Use the following code adapted from https://ask.libreoffice.org/en/question/93050/how-can-i-hideshow-a-shape-of-my-spreadsheet-using-a-macro/.
Sub ShapeClickedA
ShowHideShape("TextBoxA")
End Sub
Sub ShapeClickedB
ShowHideShape("TextBoxB")
End Sub
Sub ShowHideShape(shapeName As String)
oDrawPage = ThisComponent.getSheets().getByName("Sheet1").getDrawPage()
For iShape = 0 To oDrawPage.Count - 1
oShape = oDrawPage.getByIndex(iShape)
If oShape.Name = shapeName Then
If oShape.Visible Then
oShape.Visible = 0 'Not Visible
Else
oShape.Visible = 1 'Visible
End If
End If
Next iShape
End Sub
If you haven't yet, set the names of the text boxes by right-clicking and choosing Name... Then right click on both ShapeA and TextBoxA and assign the macro ShapeClickedA. Do likewise for other pairs of shapes. The result works like this:
Before anything is clicked.
Click on ShapeA. (To close it again, click on either ShapeA or TextBoxA). ShapeB functions similarly.
It's also possible to display both at the same time.

SAPUI5 VizFrame: How to get the selected data points

I used a VizFrame to display data in my project.
The normal behaviour of the VizFrame when you select data in the graph you see a popover with the data of the selected point. When you select more than one point the content of the popover is something like in the screenshot: popover content.
I tried using attaching myself to the SelectedData Event. The oControlEvent.mParameters contain the data nodes being currently selected for THAT event.
For example: I click node A => the node A is in the oControlEvent.mParameters. => OK
Then I click additionally on node B (so node A and B are selected) => only the node B is contained in the oControlEvent.mParameters. => not OK.
What I need is the set of all nodes that are currently selected in the graph, not just the one that triggered the event.
This information must be contained somewhere, as the Tooltip correctly shows "2 data nodes selected" after the user clicked B.
Thanks for your help.
the oControlEvent.mParameters.data, or oControlEvent.getParameter('data') will (correctly) only contain the elements that actually triggered the event. (may be more than one data point if you select several data points in one go by dragging a rectangular area over the data points)
if you need all currently selected data points, use oControlEvent.getSource().vizSelection() (here, getSource() will return the vizFrame)
Cheers, iPirat

Check if a record is selected from a dataPointGrid

I have a dataPointGrid and I want to check if a record from it is being selected (mouse clicked on)
Data point grid above. I want to check if a folder (record) is being selected.
Is there a method that does this?
Add ListGrid#addSelectionChangedHandler() on list grid that is called when (row-based) selection changes within this grid. Note this method fires for each record for which selection is modified - so when a user clicks inside a grid this method will typically fire twice (once for the old record being deselected, and once for the new record being selected).
Look at the ListGrid#setSelectionType() as well that defines a listGrid's clickable-selection behavior (MULTIPLE, SINGLE, SIMPLE or NONE)