I have an Active Form, I made some years ago, compiled as an ocx. It is installed on the tool palette.
I've only used one instance of it on each main application, and it has worked fine.
Now I need to use many instances of this active form from the same main application. So I drop a couple of them from the tool palette to my main application. But no matter which of the active forms I use (it has an built in form I open) from the application, the same instance of it shows up. And this is not what I want.
I can't figure out if the active form should been created in a different way, or if I should use it different from the main application.
The active form is built with c++builder XE, and the main application is built with XE6.
This is the way I create the instances:
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
ActXList = new TList;
TMyActX *TempActX;
for(int i=0; i<10; i++)
{
TempActX = new TMyActX(Owner);
TempActX->Parent = this; //Tried also with NULL and a new TForm(this), same result
ActXList->Add(TempActX);
TempActX->Init(i); //This adds i to a string in the created instance
}
MyActX1->Init(20); //Adds 20 to a string in the design time created instance
MyActX2->Init(21); //Adds 21 to a string in the instance
}
And here I open the different instances:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TMyActX *TempActX;
//A Combobox chooses the instance to show
if(ComboBox1->ItemIndex < 10)
{
TempActX = (TMyActX *)ActXList->Items[ComboBox1->ItemIndex];
TempActX->ShowForm();
}
else if(ComboBoxTerminaler->ItemIndex == 10)
MyActX1->ShowForm();
else if(ComboBoxTerminaler->ItemIndex == 11)
MyActX2->ShowForm();
//No matter which instance is chosen to be shown,
//the label with the init-string shows "0 1 2 3...9 20 21" for all of them
}
For testing, the integer i is added to an Label in ->Init(). TMyActX has an internal form where the Label is shown. If I open this from (with any of the created instances), the Label shows "0 1 2 3 4...". Therefore I make the conclusion that ->Init() calls the same instance, and the same form is opened no matter which created instance I use to open it.
The same thing happens if I drop two instances to my main form at design time. The same Label is shown if I open the ocx-form.
The reason I use an ocx, is that the ocx is a part of a payment solution, that is certified by a external organization. So I don't want to not mess around with it, if possible. But I have access of the code for it, and for testing I can change it.
if you got access to the TForm class of your form then just create new instances on runtime like:
TForm *win[10];
for (int i=0;i<10;i++) win[i]=new TForm(this);
where this is pointer to parent VCL form created by IDE. This works for me but I do not use ocx instead I include the 3 files per window (*.h,*.cpp,*.dfm) however I am bound to BDS2006 so on newer versions of builder things may be a bit different ...
Do not forget that to make this work you can not have global variables in your form, and have proper close/destroy method of the win[] on apps close.
You can access your windows by their pointer (to show or hide them or whatever) also you should handle the manual close of window (so you do not access dead pointer latter on)
Related
For sample I have one order that my user can add one store and in each store a lot of itens:
Amazon
- cup - $ 1
- notebook - $ 3
- $ 4 Ebay
- bike - $ 10
- boat - $ 13
- $ 23
Total order: $ 27 [Button to send the order]
And in my project I have 3 components:
CartView - (show the total from order and a button)
- StoreView (show de Store name, and total)
---StoreitemView (show the item and the button to remove)
lets to the doubts:
1 - The best way to show thats lists are usingo a GRID with one ROW? some like this:
Grid<StoreView> myGrid = new Grid();
myGrid.addComponentColumn(this::createStoreView).setAutoWidth(true);
or Its best to use a for just like this:
Div myDiv = new Div();
for(Store store in StoreList){
muDiv.add(new StoreView(store);
}
2 - How can I pass event to parent? so when my user click a button at StoreItemView I need to emit that event to my CartView(passing to StorView, and go to CarView to update the values and recreate the cart)
tks
Layout
The layout depends on how many stores and items you expect. If the number is low, just looping through and adding components is a decent approach.
If you have many items, using a Grid with one column is a better approach, as all items aren't rendered at once. An even better approach might be the IronList, or since Vaadin 21 the VirtualList.
If your views are complex with a lot of components, it's a good idea to use a TemplateRenderer instead of a ComponentRenderer. If writing views in HTML instead of Java is not your cup of tea, you can keep on using the ComponentRenderer, especially if performance seems to be good.
If there are a lot of items per store, you can consider having a virtual list for the store items inside the store also. Especially if there are only a few stores.
Events
There is no correct answer here. It seems like your StoreView and StoreItemView are tightly coupled, so the communication can be tightly coupled too. For example, the StoreItemView can expose the button directly with a getRemoveButton() method.
I would use the ComponentEvent for the removal event, something like the code below. Your logic for how the StoreItemViews are created would be different, and you could add a method in the StoreView for adding the event listener. You might want to add some data to the event, too.
public class StoreView extends HorizontalLayout {
public StoreView() {
// Create your store items as you see fit
StoreItemView storeItemView = new StoreItemView();
storeItemView.getRemoveButton().addClickListener(e -> {
remove(storeItemView);
fireEvent(new StoreItemRemovedEvent(storeItemView));
});
add(storeItemView);
}
public static class StoreItemRemovedEvent extends
ComponentEvent<StoreItemView> {
public StoreItemRemovedEvent(StoreItemView source) {
super(source, false);
}
}
}
public class CartView extends VerticalLayout {
public CartView() {
StoreView storeView = new StoreView();
ComponentUtil.addListener(storeView, StoreView.StoreItemRemovedEvent.class, e ->
Notification.show("Store item removed"));
add(storeView);
}
}
I am using C++Builder 10.3 Rio and a VCL windows application. I am using the TScreen->Forms to get information about my programs open forms. This shows a higher FormCount than I expected. My application has two open forms (1)the main program form and (2)a data entry dialog box. When I check the Screen->FormCount it shows 6 forms. When I check the forms name and caption in the for loops below only my 2 forms have a name and caption. The other form names and captions are NULL. I can identify my forms using the dynamic_cast or the form name. What are the other extra forms? How can I identify the other forms?
UnicodeString MyName, MyCaption;
for(int j=0; j<Screen->FormCount; j++){
MyName = Screen->Forms[j]->Name;
MyCaption = Screen->Forms[j]->Caption;
TMyForm *MyLocal = dynamic_cast<TMyForm *>( Screen->Forms[j] );
}
for(int j=0; j<Screen->CustomFormCount; j++){
MyName = Screen->CustomForms[j]->Name;
MyCaption = Screen->CustomForms[j]->Caption;
}
You can use the ClassName property to find out a little more information.
But that might not reveal anything of use if, for instance, some of the forms are plain TForm, or you don't recognise the name. To truly work out what these forms are, set a breakpoint in TCustomForm.Create and inspect the call stack each time that breakpoint is triggered.
I am learning about fluid dynamics (and Haxe) and have come across this awesome project and thought I would try to extend to it to help me learn. A demo of the original project in action can be seen here.
So far, I have created a side menu of items containing different shapes. When the user clicks on one of the shapes, then, clicks onto the canvas, the image selected should be imprinted onto the dye. The user will then move the mouse and explore the art etc.
To try and achieve this I did the following:
import js.html.webgl.RenderingContext;
function imageSelection(): Void{
document.querySelector('.myscrollbar1').addEventListener('click', function() {
// twilight image clicked
closeNav();
reset();
var image:js.html.ImageElement = cast document.querySelector('img[src="images/twilight.jpg"]');
gl.current_context.texSubImage2D(cast fluid.dyeRenderTarget.writeToTexture, 0, Math.round(mouse.x), Math.round(mouse.y), RenderingContext.RGB, RenderingContext.UNSIGNED_BYTE, image);
TWILIGHT = true;
});
After this call, inside the update function, I have the following:
override function update( dt:Float ){
time = haxe.Timer.stamp() - initTime;
performanceMonitor.recordFrameTime(dt);
//Smaller number creates a bigger ripple, was 0.016
dt = 0.090;//#!
//Physics
//interaction
updateDyeShader.isMouseDown.set(isMouseDown && lastMousePointKnown);
mouseForceShader.isMouseDown.set(isMouseDown && lastMousePointKnown);
//step physics
fluid.step(dt);
particles.flowVelocityField = fluid.velocityRenderTarget.readFromTexture;
if(renderParticlesEnabled){
particles.step(dt);
}
//Below handles the cycling of colours once the mouse is moved and then the image should be disrupted into the set dye colours.
}
However, although the project builds, I can't seem to get the image imprinted onto the canvas. I have checked the console log and I can see the following error:
WebGL: INVALID_ENUM: texSubImage2D: invalid texture target
Is it safe to assume that my cast for the first param is not allowed?
I have read that the texture target is the first parameter and INVALID_ENUM in particular means that one of the gl.XXX parameters are just flat out wrong for that particular function.
Looking through to the file writeToTexture is declared as so: public var writeToTexture (default, null):GLTexture;. WriteToTexture is a wrapper around a regular webgl handle.
I am using Haxe version 3.2.1 and using Snow to build the project. WriteToTexture is defined inside HaxeToolkit\haxe\lib\gltoolbox\git\gltoolbox\render
writeToTexture in gltoolbox is a GLTexture. With snow and snow_web, this is defined in snow.modules.opengl.GL as:
typedef GLTexture = js.html.webgl.Texture;
So we're simply dealing with a js.html.webgl.Texture here, or WebGLTexture in native JS.
Which means that yes, this is definitely not a valid value for texSubImage2D()'s target, which is specified to take one of the gl.TEXTURE_* constants.
A GLenum specifying the binding point (target) of the active texture.
From this description it's obvious that the parameter isn't actually for the texture itself - it merely gives some info on how the active texture should be used.
The question then becomes how the "active" texture can be set. bindTexture() can be used for this.
I've written a console app using the Umbraco (7.1.4) contentService API to move some nodes and rename them in a site redesign. It all works fine except when I rename the document the 'Link to Document' doesn't change. The code is adapted from https://github.com/sitereactor/umbraco-console-example.
private static void MoveNode(IContentService contentService, int nodeId, int newParentId, string newname)
{
//Get the Root Content
var nodeContent = contentService.GetByIds(nodeId.AsEnumerableOfOne()).First();
nodeContent.Name = newname;
contentService.Move(nodeContent, newParentId);
var status = contentService.SaveAndPublishWithStatus(nodeContent);
Console.WriteLine(status);
}
Status is True and the page name is changed when I look at it in back office but the 'Link to Document' doesn't change. Now if I use
var status = contentService.PublishWithChildrenWithStatus(nodeContent);
Then it works but takes a lot longer (minutes), but if I change the name in back office then it only takes seconds but the links are updated correctly. Is there another way to rename a document without Publishing all the children?
(I've left out a bit of code in the above - sometimes it moves sometimes it just renames, but in either case I have to publish with the children to get it to work.)
It seems this happens because the XML cache file has not been updated.
Have a look here for a few ways of doing it
http://our.umbraco.org/wiki/reference/api-cheatsheet/publishing-and-republishing
Or the quickest is just delete APP_Data\umbraco.config - the XML cache file, probably not recommended for Prod but gets things working quickly in dev.
I've never used actionscript before, and but I've just had to dive into it in order to get a map working.
I'm using the following code to add a map marker, replacing a previous one if one exists:
public var tracer:Array = new Array();
public var tracerLng:Number = 0;
for ( var i : Number=1 ; i<64000 ; i++)
{
//Check if there is already a marker, if so get rid of it
if(tracerLng > 0) {
map.removeOverlay(tracer[0]);
tracer[0] = null;
tracer.pop();
}
// Set up a marker
var trackMrk:Marker = new Marker(
new LatLng(_lat, _lng),
new MarkerOptions({
strokeStyle: new StrokeStyle({color: 0x987654}),
fillStyle: new FillStyle({color: 0x223344, alpha: 0.8}),
radius: 12,
hasShadow: true
})
);
//Add the marker to the array and show it on the map
tracerLng = tracer.push(trackMrk);
map.addOverlay(tracer[0]);
}
My first problem is that running this code (The 64000 repeats are for testing, the final application won't need to be run quite THAT many times). Either way, memory usage increases by about 4kB/s - how do I avoid that happening?
Secondly - could anyone advise me on how to make that program more graceful?
Thanks in advance for advice
This isn't a memory leak, it's probably the result of created events - enter frames, mouse events, custom events etc. Provided that your memory doesn't keep going up and up forever, it's nothing to be worried about - it'll get garbage collected in due course.
Some points on your code:
The tracer Array doesn't seem to do anything - you only seem to be holding one thing in there at a time, so an array makes no sense. If you need an Array, use Vector instead. It's smaller and faster. More so if you create one with a specific length.
Don't create a new Marker unless you need one. Reuse old objects. Learn about object pooling: http://help.adobe.com/en_US/as3/mobile/WS948100b6829bd5a6-19cd3c2412513c24bce-8000.html or http://lostinactionscript.com/2008/10/30/object-pooling-in-as3/
The LatLng and MarkerOptions (including the stroke and fill objects) don't seem to change (I'm assuming the LatLng object lets you set a new position). If that's the case, don't create new ones when you don't need to. If you need to create new ones, StrokeStyle and FillStyle seem good candidates for a "create once, use everywhere" policy.
Create a destroy() function or similar in your Marker class and explicitly call it when you need to delete one (just before setting it to null or popping it from the array). In the destroy() function, null out any parameters to non-base classes (int, Number, String etc). Garbage collection runs using a reference counting method and a mark and sweep method. Ideally, you want to run everything using reference counting as it's collected quicker and stops any stalls in your program.
I explain memory management in AS3 a bit more here: http://divillysausages.com/blog/tracking_memory_leaks_in_as3
Also included is a class that helps you track down memory leaks if there are any