I made a small program to draw geometry figures on a D2DBox (with Direct2DCanvas and RenderTarget) and I need to be able to copy a rectangle from it to the clipboard. Tried this, but I'm stuck with the source handle parameter:
bm := TBitmap.Create;
try
bm.SetSize(maxx-minx, maxy-miny);
BitBlt(bm.Canvas.Handle, minx, miny, maxx, maxy, ??? , 0, 0, SRCCOPY);
Clipboard.Assign(bm);
finally
bm.Free;
end;
Any idea where to get a handle from? Or the whole thing is done a different way? Thanx!
BitBlt() requires a GDI HDC to copy from, but TDirect2DCanvas does not have an HDC of its own, and it cannot directly render to an off-screen HDC/TCanvas, such as TBitmap.Canvas, per its documentation:
TDirect2DCanvas will only work for on-screen device contexts. You cannot use the TDirect2DCanvas to draw on a printer device context, for example.
And you can't associate a custom RenderTarget (such as one created with ID2D1Factory.CreateDCRenderTarget() and ID2D1DCRenderTarget.BindDC()) since the TDirect2DCanvas.RenderTarget property is read-only.
So, you will likely have to go a long way to get what you want. Based on code I found in Direct2d Desktop printing C++, which demonstrates copying an arbitrary ID2D1RenderTarget to an arbitrary HDC, you can try the following:
Create a Direct2D ID2D1Bitmap that is bound to the canvas's current RenderTarget using one of the target's CreateBitmap() methods.
Copy pixels from the canvas into the bitmap using the bitmap's CopyFromRenderTarget() method.
Create an IWICBitmap (you can probably use the VCL's TWICImage for this) and render the Direct2D bitmap to it using one of the ID2D1Factory.CreateWicBitmapRenderTarget() methods with one of the ID2D1RenderTarget.DrawBitmap() methods.
Create a GDI DIB bitmap and render the IWICBitmap to it using the WIC bitmap's CopyPixels() method.
Finally, you use the DIB however you needed, such as select/copy it to your final HDC, or you can simply place its contents directly on the clipboard using the CF_DIB format.
Here is the code (sorry, it is in C++, I'm not going to translate it to Delphi):
void Direct2DRender::RenderToDC(HDC hDC, UINT uiWidth, UINT uiHeight)
{
HRESULT hr = S_OK;
IWICImagingFactory *pImageFactory = WICImagingFactory::GetInstance().GetFactory();
CComPtr<IWICBitmap> wicBitmap;
hr = pImageFactory->CreateBitmap( uiWidth, uiHeight, GUID_WICPixelFormat32bppBGR, WICBitmapCacheOnLoad, &wicBitmap);
D2D1_SIZE_U bitmapPixelSize = D2D1::SizeU( uiWidth, uiHeight);
float dpiX, dpiY;
m_pRenderTarget->GetDpi( &dpiX, &dpiY);
CComPtr<ID2D1Bitmap> d2dBitmap;
hr = m_pRenderTarget->CreateBitmap( bitmapPixelSize, D2D1::BitmapProperties(
D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE),
dpiX, dpiY), &d2dBitmap );
D2D1_POINT_2U dest = D2D1::Point2U(0,0);
D2D1_RECT_U src = D2D1::RectU(0, 0, uiWidth, uiHeight);
hr = d2dBitmap->CopyFromRenderTarget(&dest, m_pRenderTarget, &src);
D2D1_RENDER_TARGET_PROPERTIES rtProps = D2D1::RenderTargetProperties();
rtProps.pixelFormat = D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE);
rtProps.type = D2D1_RENDER_TARGET_TYPE_DEFAULT;
rtProps.usage = D2D1_RENDER_TARGET_USAGE_NONE;
CComPtr<ID2D1RenderTarget> wicRenderTarget;
hr = m_pDirect2dFactory->CreateWicBitmapRenderTarget( wicBitmap, rtProps, &wicRenderTarget);
wicRenderTarget->BeginDraw();
wicRenderTarget->DrawBitmap(d2dBitmap);
hr = wicRenderTarget->EndDraw();
// Render the image to a GDI device context
HBITMAP hDIBBitmap = NULL;
try
{
// Get a DC for the full screen
HDC hdcScreen = GetDC(NULL);
if (!hdcScreen)
throw 1;
BITMAPINFO bminfo;
ZeroMemory(&bminfo, sizeof(bminfo));
bminfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bminfo.bmiHeader.biWidth = uiWidth;
bminfo.bmiHeader.biHeight = -(LONG)uiHeight;
bminfo.bmiHeader.biPlanes = 1;
bminfo.bmiHeader.biBitCount = 32;
bminfo.bmiHeader.biCompression = BI_RGB;
void* pvImageBits = nullptr; // Freed with DeleteObject(hDIBBitmap)
hDIBBitmap = CreateDIBSection(hdcScreen, &bminfo, DIB_RGB_COLORS, &pvImageBits, NULL, 0);
if (!hDIBBitmap)
throw 2;
ReleaseDC(NULL, hdcScreen);
// Calculate the number of bytes in 1 scanline
UINT nStride = DIB_WIDTHBYTES(uiWidth * 32);
// Calculate the total size of the image
UINT nImage = nStride * uiHeight;
// Copy the pixels to the DIB section
hr = wicBitmap->CopyPixels(nullptr, nStride, nImage, reinterpret_cast<BYTE*>(pvImageBits));
// Copy the bitmap to the target device context
::SetDIBitsToDevice(hDC, 0, 0, uiWidth, uiHeight, 0, 0, 0, uiHeight, pvImageBits, &bminfo, DIB_RGB_COLORS);
DeleteObject(hDIBBitmap);
}
catch (...)
{
if (hDIBBitmap)
DeleteObject(hDIBBitmap);
// Rethrow the exception, so the client code can handle it
throw;
}
}
In that same discussion, another alternative is described:
Create a DIB section, and select it into a DC
Create a DC render target
Bind the render target to the DC that corresponds to the DIB section
Draw using Direct2D. After calling EndDraw the DIB contains what was rendered.
The final step is to draw the dib where you need it.
So, try moving your drawing code to its own function that takes an ID2D1RenderTarget as input and draws on it as needed. Then, you can create an HDC-based RenderTarget when you want to place a bitmap on the clipboard, and use TDirect2DCanvas.RenderTarget when you want to draw on your D2DBox.
I have two rectangles, one that is occasionally reset to some other rectangle. In C++ I'd just do:
_rect = _resetRect;
But in Dart that actually means that _rect now refers to the same object as _resetRect which is not what I want.
My current solution is this:
_rect.left = _resetRect.left;
_rect.width = _resetRect.width;
_rect.top = _resetRect.top;
_rect.height = _resetRect.height;
This is idiotic. Other questions suggest that there is no built-in way to copy objects (like there is in C++), and you have to rely on the object providing a clone() method. But Rectangle doesn't have one so what do I do?
Also even if it did have a clone() method, wouldn't that allocate an entirely new Rectangle rather than just setting the fields of the existing one (like C++'s operator=), and therefore be less efficient?
C++ also does not have a way to deep-copy an object which contains pointers/references to other objects. In Dart, all values are references, so that restriction applies to all objects.
I assume this is a MutableRectangle since the Rectange in dart:math is unmodifiable.
That class indeed does not have a way to clone the values of another rectangle, so you have to copy each of them. I would use a cascade for that:
_rect
..left = _resetRect.left
..top = _resetRect.top
..width = _resetRect.width
..height = _resetRect.height;
Alternatively, if it happens often enough, you can create a helper function:
void copyRectangle(MutableRectangle target, Rectangle source) {
target
..left = source.left
..top = source.top
..width = source.width
..height = source.height;
}
I can easily animate something like the position or size of a UIView. But how can I animate a "custom" variable (such as experiencePoints) to achieve interpolation of values that are not associated with a UIView.
// The variable being animated
CGFloat experiencePoints = 0;
// Pseudo-code
[experiencePoints animateTo:200 duration:2 timingFunction:someTimingFunction];
With this code, if I accessed experiencePoints while it was animating, I would get a value between 0 and 200 based on how long the animation has been going.
Bonus question: Is it possible to use a CAAnimation to do what I want?
You can go with Presentation layer with CADisplayLink and by adding observer on animation status you can increment the variable upto your final one. Observer will observe current status of Animation which will eventually provide you a way to get current value of that VAR.
Ended up using Facebook's POP animation library, which allows the animation of any property on an object. I recommend it!
Here is a quote from the readme, explaining how to do it:
The framework provides many common layer and view animatable properties out of box. You can animate a custom property by creating a new instance of the class. In this example, we declare a custom volume property:
prop = [POPAnimatableProperty propertyWithName:#"com.foo.radio.volume" initializer:^(POPMutableAnimatableProperty *prop) {
// read value
prop.readBlock = ^(id obj, CGFloat values[]) {
values[0] = [obj volume];
};
// write value
prop.writeBlock = ^(id obj, const CGFloat values[]) {
[obj setVolume:values[0]];
};
// dynamics threshold
prop.threshold = 0.01;
}];
anim.property = prop;
"Animating" something is simply moving a value from a starting position to an ending position over time. To "animate" a float from one value to another over a duration you could just run a timer and incrementally change it. Or possibly you could store the begin and end time of the "animation" and whenever the value is accessed, compare those to the actual time to come up with a value.
i make a PieChart at run time, and i want to interpolate data change, but i have some difficult.
The Code is here:
//Pie Chart
pieChart.dataProvider = expenses;
var pieSeries:PieSeries = new PieSeries();
pieSeries.nameField = "position";
pieSeries.field = "value";
pieSeries.explodeRadius = 0.08;
pieChart.series = null;
pieChart.series.push(pieSeries);
I found two method, but i don't know how to use that >.<:
pieSeries.beginInterpolation
pieSeries.interpolate
1) First create a SeriesInterpolate class instance and customize it however you want.
2) You can set the showDataEffect style of your pieSeries object to the interpolate object that you just created.
Whalah.. whenever your data changes the interpolator will get triggered.
See the code snippet below..
I've also created an example application with source enabled.
goto: http://befreestudiosllc.com/demos/flex4/charting/seriesInterpolate/ and right-click to view source.
// Create an interpolator and customize its properties
var interpolateDataIn:SeriesInterpolate = new SeriesInterpolate();
interpolateDataIn.duration = 1000;
var pieSeries:PieSeries = new PieSeries();
pieSeries.setStyle("showDataEffect", interpolateDataIn); // apply interpolators to your series through show/hide dataEffects
I have this piece of code:
TShape* T[256];
/* Other code ... */
for (int i = 255; i > 0; i--) {
T[i]->Brush->Color = T[i - 1]->Brush->Color;
T[i]->Pen->Color = T[i - 1]->Pen->Color;
};
The cycle is executed by a TTimer each 100 milliseconds and the Color of the first TShape change each 100 milliseconds.
During this cycle, I see a blinking white horizontal lines, because before receiving the color of the other TShape, each TShape is invalidated and becomes white.
Is there a way to avoid this behaviour?
Maybe, I must override some method?
I think double buffering is the key to your problem. If you are using C++Builder 2009 or newer probably setting property Controls::TWinControl::DoubleBuffered for your current frame will be enough.
TShape invalidates itself every time you change its Brush and Pen properties, so your loop is double-invalidating each TShape. As a workaround, try temporarily removing the OnChange event handlers that TShape assigns internally, and then Invalidate() the TShape only once after you have finished updating it. For example:
for (int i = 255; i > 0; i--)
{
TNotifyEvent OldBrushChange = T[i]->Brush->OnChange;
T[i]->Brush->OnChange = NULL;
TNotifyEvent OldPenChange = T[i]->Pen->OnChange;
T[i]->Pen->OnChange = NULL;
T[i]->Brush->Color = T[i - 1]->Brush->Color;
T[i]->Pen->Color = T[i - 1]->Pen->Color;
T[i]->Brush->OnChange = OldBrushChange;
T[i]->Pen->OnChange = OldPenChange;
T[i]->Invalidate();
};