Can someone explain me the CDC::SelectObject to me? - mfc

http://msdn.microsoft.com/en-us/library/sa8ahz7h(v=vs.80).aspx
//Border
CPen pen;
pen.CreatePen(PS_DASH, 20, RGB(0, 0, 0));
CPen* penOld = dc.SelectObject(&pen);
dc.Rectangle(rect);
dc.FillRect(rect, &brush);
How does this code work? It draws a rectangle and then a border around it. I just can't get my head around it.

When you ask the device context to draw a rectangle, it will use the current Pen.
You can set the current Pen, Brush, clipping region or whatever using the SelectObject() method. You're basically saying "use this Pen from now on".
SelectObject() also returns the item it was using before, so that it doesn't get lost and leak memory, and you can put it back later if you want. This is why penOld is being saved to a variable in your code. It will probably be selected back again later on.
CPen pen; //declare a new Pen object
pen.CreatePen(PS_DASH, 20, RGB(0, 0, 0)); //Create the GDI Pen, dashed, 20 pixels wide, black.
CPen* penOld = dc.SelectObject(&pen); //Tell the DC to use this pen from now on.
dc.Rectangle(rect); //Draw a rectangle (using the current pen)
dc.FillRect(rect, &brush); //Fill a rectangle (using the current brush)

It creates a pen, selects it into the DC, and then instructs the DC to use the pen (which is 20 pixels wide) to draw a rectangle at the specified coordinates. It then fills in the inside of that rectangle with a brush.

Related

MFC DrawText, vertical, DT_CALCRECT with lf_escapement = 900

I'm working on a MFC project with some GDI drawings.
I use DC.DrawText to draw a vertical text into a DC using a LOGFONT with lfEscapement = 900.
The text is output when i use DT_NOCLIP in the desired vertical formatting.
However to center this text i used a call to DC.DrawText with the DT_CALCRECT argument.
I recognized that, despite the text is indeed drawn vertically, the CRect has a larger width
than height.
My intuition says me that a vertical drawn text should have a larger height than width.
I did not include the calculation for centering the text. The question is just about what i can rely upon when i implement that vertical centering.
Does DC.DrawText with DT_CALCRECT ignore escapement?
void CMFCFontTestDlg::OnPaint()
{
CPaintDC dc(this); // Gerätekontext zum Zeichnen
if (IsIconic())
{
...
}
else
{
CDialogEx::OnPaint();
CRect clTextRect;
CFont myFont;
myFont.CreateFont(12, 0, 900, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _T("Tahoma"));
CFont* oldFont = dc.SelectObject(&myFont);
dc.DrawText(_T("000000"), clTextRect, DT_CALCRECT);
clTextRect.MoveToXY(100, 100);
dc.DrawText(_T("000000"), clTextRect, DT_NOCLIP);
dc.SelectObject(oldFont);
}
}
I found out about it in the remarks to the DrawTextEx function
https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-drawtextexa.
However, please note that neither the documentation of DrawText does say anything about this nor the documentation of the DT_CALCRECT flag.
This is likely to be overseen if one uses DrawText and not DrawTextEx.
I informed MS about this via "Is this page helpful?" feedback possibility.
Remarks
The DrawTextEx function supports only fonts whose escapement and
orientation are both zero.
The text alignment mode for the device context must include the
TA_LEFT, TA_TOP, and TA_NOUPDATECP flags.
Considering this the solution is to use some trigonometric calculation starting from the size determined for escapement = 0 and then calculate the topleft and bottomright points of the rotated rect.

ExtFloodFill stuck with the Color white

So i have been trying to repaint a bitmap programatically when user pressed a button with ExtFloodFill with the code below
CDC* cdc = GetDlgItem(IDC_MAP_STATIC)->GetDC(); // Get the CStatic that contains the bitmap
cdc->SetDCBrushColor(COLOR_SKYBLUE); // constant for #00EEEE
SetDCBrushColor((HDC)cdc, COLOR_SKYBLUE); // Trying to change the cdc brush color
// Just for debugging, i have inspected it and the value is the same with the COLOR_SKYBLUE value
COLORREF cr = cdc->GetDCBrushColor();
cdc->ExtFloodFill(x,cdc->GetCurrentPosition().y+y, RGB(0, 0, 0), FLOODFILLBORDER);
But everytime that i call ExtFloodFill the FloodFill will only fill the area with white color and as per the doc
Fills an area of the display surface with the current brush.
I tried to change the current CDC brush color with the color skyblue. But it doesn't work at all.
IDC_MAP_STATIC is an usual CStatic object. I'm not using a subclassed CStatic for it.
So where did i do wrong that it caused the ExtFloodFill to keep Flood-filling my bitmap with white not skyblue?
Nevermind, solved it right away with this snippet. I don't know why but when i set the brush color using SetDCBrushColor it doesn't change the selected brush. So with codes based from this article i tried to declare a new brush and select it before i tried to FloodFill it
CDC* cdc = GetDlgItem(IDC_MAP_STATIC)->GetDC();
CBrush cb(RGB(255, 0, 0)); //Make a new CBrush (Red)
cdc->SelectObject(&cb); //Assign the CBrush to the CDC
cdc->ExtFloodFill(x,y, RGB(0, 0, 0), FLOODFILLBORDER);
DeleteObject(cb);
ReleaseDC(cdc);

Draw over Dialog Margins in an MFC Dialog

I want a dialog to be borderless and yet have a dialog shadow. I came across this solution Borderless Window Using Areo Snap, Shadow, Minimize Animation, and Shake which uses a workaround by making the Dialog having a Margin of 1 px and extending the Client Area to it.
MARGINS borderless = { 1, 1, 1, 1 };
DwmExtendFrameInfoClientArea(this->GetSafeHwnd(), &borderless);
The post mentioned that the Client Area is literally being extended and Transparent drawing makes the Dialog edges of 1px each visible again.
Now this is exactly what happened, when I tried to paint a Solid Rectangle onto the whole dialog:
// getting the client area
CRect clientRect;
GetClientRect(&clientRect);
// expanding it to the new margins
clientRect.left -= 1;
clientRect.top -= 1;
clientRect.right += 2;
clientRect.bottom += 2;
// set the Device Context to draw non transparent and with a black background
pDC->SetBkMode(OPAQUE);
pDC->SetBkColor(RGB(0, 0, 0));
// finally draw a rectangle to it
CBrush brush_back_ground(RGB(0, 0, 0));
pDC->FillRect(clientRect, &brush_back_ground);
But the dialog is still drawn with its margins:
How would it be possible to draw something stretched on the margins? Later I'm going to use pictures as dialog Background which should be drawn on the margins aswell.
Thanks to Hans Passant for his comment. The solution is to use GDI+ drawing instead of GDI drawing
// making a Gdi+ graphics object from my CDC*
Graphics g(*pDC);
// getting the client area
CRect clientRect;
GetClientRect(&clientRect);
// making a Gdi+ rect
Rect bkRect(0,0,clientRect.Width(), clientRect.Height());
// making a pen for the Rect Drawing
Pen bkPen(Color(255,0,0,0));
// draw the rectangle over the full dialog
g.DrawRectangle(&bkPen, bkRect);

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

Black border around characters when draw Image to a transparent Bitmap

I have to draw a String on a transparent bitmap at first, then draw A to destination canvas.
However on certain case, there is black border around the characters.
Bitmap* tempImg = new Bitmap(1000, 1000, PixelFormat32bppARGB);
Graphics tempGr(tempImg);
tempGr.Clear(Color(0, 255,255,255));
Gdiplus::SolidBrush* brush = new SolidBrush(Color(255, 255, 0, 0 ));
Gdiplus::FontFamily fontFamily(L"Times New Roman");
Gdiplus::Font* font = new Gdiplus::Font(&fontFamily, 19, FontStyleRegular, UnitPixel);
RectF rec(400, 400, 1000, 10000);
tempGr.DrawString(
L"Merry Chrismas",
-1,
font,
rec,
NULL,
brush
);
Graphics desGr(hdc);
desGr.Clear(Color::Gray);
desGr.DrawImage(tempImg , 0,0, 1000, 1000);
The character draw on desGr have black board for some fontsize.
How can I avoid this problem?
Many thanks!
I think the problem here is that you are drawing the text onto a transparent background.
You could try adding this line after the call to tempGr.Clear...
tempGr.TextRenderingHint = TextRenderingHint.AntiAlias;
ps - sorry not sure the exact syntax in C++ ;)
I just solved this problem in XNA:
Clear background to the same as the foreground color. The only difference is that the background should have Alpha=0, and the foreground with Alpha >> 0
The black border comes from blending of your background and foreground of different colors. Try to clear the background to some contrasting color to fully appreciate the phenomenon.