How to drag a rectangle using GDI+? - c++

I am trying to implement a dragging of a simple rectangle using GDI+. My code is simply working by translating the graphics object to the new position and to draw a new Rectangle.
TransllateRectangle is called frequently whenever OnMouseMove event occur.
void RectangleContainer::TranslateRectangle(CDC *pDC, CRect newR, CRect oldR)
{
Graphics graphics(pDC->m_hDC);
DWORD ole = m_FillColor;
BYTE rr = ((BYTE)(ole));
BYTE gg = ((BYTE)(((WORD)(ole)) >> 8));
BYTE bb = ((BYTE)((ole) >> 16));
SolidBrush linGrBrush(
Color(125, rr, gg, bb)
);
Rect newRectangle = Rect(newR.left, newR.top, newR.Width(), newR.Height());
Matrix matrix;
matrix.Translate(newR.left - oldR.left, 0);
graphics.SetTransform(&matrix);
graphics.FillRectangle(&linGrBrush, newRectangle);
graphics.~Graphics();
}
My problem is that I could not remove old rectangle drawn in the old position properly. How can I achieve this please?

Related

MFC GDI+ Text rendering issue

I'm currently using 5MP Camera, so I convert BYTE* to GDI+ Bitmap object and uses Graphics object to draw on picture control (all GDI+ objects)
and I want to draw a string on it and when I do so, resolution (quality or whatsoever) gets strange. here're the images.
this is the original image
this is the image with the text on it
And here's my code. it uses MFC's WM_MOUSEMOVE. and when mouse pointer gets on CRect(dispRC[array]), it renders string "aa" on the Bitmap object.
and when I do so, quality of image gets lower or I don't exactly know it changes the IMAGE. (You might not notice because those are captured images, but latter image's quality gets lower.)
void CSmall_StudioDlg::OnMouseMove(UINT nFlags, CPoint point)
{
CPoint insidePoint;
// MAXCAM is the number of bitmap objects.
for (int i = 0; i < MAXCAM; i++)
{
// m_pBitmap[MAXCAM] is array of Bitmap* which contains address of Gdiplus::Bitmap objects.
if (m_pBitmap[i] != NULL)
{
// m_rcDisp[MAXCAM] are CRect objects which has information of picture control.
// i.e. GetDlgItem(IDC_BIN_DISP)->GetWindowRect(m_rcDisp[BINARY_VID]);
if (point.x > m_rcDisp[i].TopLeft().x && point.y > m_rcDisp[i].TopLeft().y)
{
if (point.x < m_rcDisp[i].BottomRight().x && point.y < m_rcDisp[i].BottomRight().y)
{
StringFormat SF;
insidePoint.x = point.x - m_rcDisp[i].TopLeft().x;
insidePoint.y = point.y - m_rcDisp[i].TopLeft().y;
Graphics textG(m_pBitmap[i]);
textG.SetTextRenderingHint(TextRenderingHintSingleBitPerPixel);
Gdiplus::Font F(L"Palatino Linotype Bold", 10, FontStyleBold, UnitPixel);
RectF R(insidePoint.x, insidePoint.y, 20, 100);
SF.SetAlignment(StringAlignmentCenter);
SF.SetLineAlignment(StringAlignmentCenter);
SolidBrush B(Color(0, 0, 0));
textG.DrawString(_T("aa"), -1, &F, R, &SF, &B);
// m_pGraphics[MAXCAM] is made like this
// i.e.
// static CClientDC roiDc(GetDlgItem(IDC_ROI_DISP));
// m_hDC[ROI_VID] = roiDc.GetSafeHdc();
// m_pGraphics[ROI_VID] = Graphics::FromHDC(m_hDC[ROI_VID]);
m_pGraphics[i]->DrawImage(m_pBitmap[i], 0, 0, m_vidwidth[i], m_vidheight[i]);
}
}
}
}
CDialogEx::OnMouseMove(nFlags, point);
}
Hope I get a helpful answer.
Thanks!
I had a similar problem and solved it by creating the GDI+ font from a Windows font like this:
Gdiplus::Font font(hDc, hFont);
where hDc is a DC handle and hFont is a font handle.
Can you try if this helps?

CClientDC and DC not Drawing on ChtmlEditCtrl

Hi all I am working with a CHtmlEditCtrl in MFC. I want to draw some random rectangles and lines inside a function handling right click event.
The ChtmlEditCtrl control is created from static using this snippet:
bool CHtmlEditCtrlEx::CreateFromStatic( UINT nID, CWnd* pParent ) {
CStatic wndStatic;
if ( !wndStatic.SubclassDlgItem(nID, pParent)) {
return false;
}
CRect rc;
wndStatic.GetWindowRect( &rc );
pParent->ScreenToClient( &rc );
if (Create( 0, (WS_CHILD | WS_VISIBLE), rc, pParent, nID, 0 )) {
...
}
Then I override the CWnd::pretranslate() function as thus:
CClientDC dcc(this);
switch (pMsg->message) {
case WM_RBUTTONUP: // Right-click
// Just some dummy values
DrawSquigly(dcc, 600, 240, 20);
break;
}
the DrawSquigly() function is defined as thus:
void CHtmlEditCtrlEx::DrawSquigly(CDC &dcc, int iLeftX, int iWidth, int iY)
{
CAMTrace trace;
trace.Trace("Drawing Squiggly");
//dcc.TextOut(10, 10, CString(_T("I used a client DC!")));
CPen * oldPen;
CBrush * oldBrush;
oldPen = (CPen *) dc.SelectStockObject(WHITE_PEN);
dcc.MoveTo(5,10);
dcc.LineTo(80, 10);
dcc.SelectObject(oldPen);
//GDI 002_2: Create custom pen with different Line thickness.
CPen thick_pen(PS_SOLID, 3, RGB(0,255,0));
oldPen = dc.SelectObject(&thick_pen);
dcc.MoveTo(5, 20);
dcc.LineTo(80,20);
dcc.SelectObject(oldPen);
//GDI 002_3: Create a Rectangle now
dcc.Draw3dRect(5,30,80,70, RGB(25,25,255), RGB(120,120,120));
//GDI 002_4: Create a Brush that we can use for filling the
// closed surfaces
CBrush brush(RGB(255,0,255));
oldBrush = dc.SelectObject(&brush);
dcc.Rectangle(5,110,80,140);
dcc.SelectObject(oldBrush);
//GDI 002_5: Hatch Brush is useful to apply a pattern in stead
//of solid fill color
CBrush* hatBrush = new CBrush();
hatBrush->CreateHatchBrush(HS_CROSS, RGB(255,0,255));
oldBrush = dc.SelectObject(hatBrush);
dcc.FillRect(new CRect(5,160,80,190), hatBrush);
dcc.SelectObject(oldBrush);
}
but no drawing happens when I right click. I think I am missing something especially because I am new to MFC.
I have added a trace to the top of the event handler to be sure that the function is getting called and it is.
Can anyone please point me the right direction?
There are actually 2 device context in your code: one you pass as parameter in the call (we don't know where it comes from) and the other created locally in the drawing function.
Normally, when the systems gives you a DC it expects you draw something in it, not that you draw into something else.
If the window you are working on is layered, the system gives you a memory context you draw in that is - upon clearing - blit-ted onto the window itself with some window manager effect.
My suspect is that -by allocating a second dc- your drawing are ovewritten when the first one (you left blank) is cleared upon returning from the message handler.

How to shift the start coordinates of the client area on the window?

I have refereed below article to draw a custom frame area with DWM.
Custom Window Frame Using DWM
After removing the standard frame, non client area is not exist in the frame.
void CMainFrame::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp)
{
int nTHight = 30; /*The title bar height*/
RECT * rc;
RECT aRect;
RECT bRect;
RECT bcRect;
if(bCalcValidRects == TRUE)
{
CopyRect(&aRect,&lpncsp->rgrc[1]);
CopyRect(&bRect,&lpncsp->rgrc[0]);
bcRect.left = bRect.left;
bcRect.top = bRect.top - nTHight;
bcRect.right = bRect.right;
bcRect.bottom = bRect.bottom;
CopyRect(&lpncsp->rgrc[0],&bcRect);
CopyRect(&lpncsp->rgrc[1],&bRect);
CopyRect(&lpncsp->rgrc[2],&aRect);
}
else
{
rc = (RECT *)lpncsp;
rc->left = rc->left;
rc->top = rc->top - nTHight;
rc->right = rc->right;
rc->bottom = rc->bottom;
}
CFrameWnd::OnNcCalcSize(bCalcValidRects, lpncsp);
}
Because the entire window is client region, I have to adjust the UI control placement for the frame, but I don't know how to handle this problem.
For example, below red rectangle (all UI component) should be shifted into the original coordinate of the client area before removing the non client part.
CWnd::GetWindowRect gives you the rectangle of the window on screen. The dimensions of the caption, border, and scroll bars, if present, are included.
CWnd::GetClientRect gives you the client rectangel of the window. The left and top members will be 0. The right and bottom members will contain the width and height of the window.
CWnd::ScreenToClientand CWnd::ClientToScreen calculate a point or rectangle from the client area to screen coordinates and back to screen.
AdjustWindowRect calculates the required window rectangle, based on the client rectangle of the window.
Here is afunction which calcualtes the margins of a window:
void CalculateWndMargin( const CWnd &wnd, int &leftM, int &rightM , int &topM, int &bottomM )
{
CRect wndRect;
wnd.GetWindowRect( wndRect );
CRect screenRect;
wnd.GetClientRect( screenRect );
wnd.ClientToScreen( screenRect );
leftM = screenRect.left - wndRect.left;
rightM = wndRect.right - screenRect.right;
topM = screenRect.top - wndRect.top;
bottomM = wndRect.bottom - screenRect.bottom;
}

GDI Double Buffer Black Flicker

I am using this BitBlt wrapper:
http://www.codeproject.com/Articles/21426/Double-Buffering-in-a-Win-API-Program
I initialize it in main():
biop = new Bitmap_Operations();
biop->Initialize_Buffers(m_hDC, m_hWND, 1);
biop->Create_Buffer(0);
Helper Functions:
void CreateBuffer()
{
biop->Create_Buffer(0);
}
void Render()
{
biop->Copy_to_Screen(0);
}
void ClearBuffer()
{
biop->Free_Buffer(0);
}
void DrawBox(int x, int y, int r, int g, int b, int size, int thickness)
{
// Brush style to hollow
m_LogBrush.lbStyle = BS_NULL;
// Create a logical brush and select into the context
m_hBrush = CreateBrushIndirect(&m_LogBrush);
HBRUSH hbrOldBrush = (HBRUSH)SelectObject(biop->Get_DC_Buffer(0), m_hBrush);
// Create a logical pen and select into the context
m_hPen = CreatePen(PS_SOLID, thickness, RGB(r, g, b));
HPEN hpOldPen = (HPEN)SelectObject(biop->Get_DC_Buffer(0), m_hPen);
// Draw the rectangle
Rectangle(biop->Get_DC_Buffer(0), (x - size / 2), (y - size / 2), (x + size / 2), (y + size / 2));
// Remove the object
SelectObject(biop->Get_DC_Buffer(0), hbrOldBrush); // first you must restore DC to original state
SelectObject(biop->Get_DC_Buffer(0), hpOldPen); // same here
DeleteObject(m_hBrush);
DeleteObject(m_hPen);
}
I spawn a thread to render data:
// Inside a thread
while (1)
{
CreateBuffer();
for (int i = 0; i < 1028; i++)
{
//
DrawBox()
//
}
Render();
ClearBuffer();
}
I am using FindWindow() to render on top of another application. Everything works fine, the boxes get rendered, ect, but there is a crazy full-screen flicker that seems to have a black background. My guess its when I draw from memory to the application?
I am using double buffering to avoid a flicker, but it seems like it made it worse. Any ideas?
Thanks.
I would use UpdateLayeredWindow APIs instead, if you need to draw transparent things on top of existing windows.

C++ MFC How to Draw Alpha transparent Rectangle

in a C++ MFC application. using the dc of ( CPaintDC dc(this); )
How do i draw a rectangle ( LPRECT ) with an alpha transparency that i can adjust.?
Following is an example c# code which i need to convert into C++
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
Color color = Color.FromArgb(75,Color.Red); //sets color Red with 75% alpha transparency
Rectangle rectangle = new Rectangle(100,100,400,400);
g.FillRectangle(new SolidBrush(color), rectangle); //draws the rectangle with the color set.
}
You need to look into GDI+. Its a bit of a faff but you can create a "Graphics" object as follows:
Gdiplus::Graphics g( dc.GetSafeHdc() );
Gdiplus::Color color( 192, 255, 0, 0 );
Gdiplus::Rect rectangle( 100, 100, 400, 400 );
Gdiplus::SolidBrush solidBrush( color );
g.FillRectangle( &solidBrush, rectangle );
Don't forget to do
#include <gdiplus.h>
and to call
GdiplusStartup(...);
somewhere :)
You'll notice it's pretty damned similar to your C# code ;)
Its worth noting that the 75 you put in your FromArgb code doesn't set 75% alpha it actually sets 75/255 alpha or ~29% alpha.
GDI (and thus MFC) has no decent support for drawing with an alpha. But GDI+ is available in C++ code as well. Use #include <gdiplus.h> and initialize it with GdiplusStartup(). You can use the Graphics class, create one with its Graphics(HDC) constructor from your CPaintDC. And use its FillRectangle() method. The SDK docs are here.
int StartHoriz,StartVert,BarWidth,BarHeight; // rect start, width and height
StartHoriz=0;
StartVert=100;
width = 100;
height=120;
CDC* pCDC = GetDC(); // Get CDC pointer
CRect Rect(StartHoriz,StartVert,BarWidth,BarHeight); //create rectangle dimensions
pCDC->Rectangle(Rect); //draw rectangle