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);
Related
I'm want to make a flat design ComboBox which only shows a blue bottom border. But I can only change 4 borders' color. How to hide right,left and top border and show bottom border?
Finally I made it. Just rewrite OnPaint() function and use CDC::DrawEdge(CRect, BDR_RAISEDINNER, BF_BOTTOM) to drwa a bottom border.
void CCustomComboBox::OnPaint()
{
CPaintDC dc(this);
CRect rc;
GetClientRect(&rc);
dc.DrawEdge(rc, BDR_RAISEDINNER, BF_BOTTOM);
... //draw other parts of ComboBox
}
I want to customize the window frame using DWM in win32 to get an appearance like VS2022 (draw menu on title bar) or Chrome (draw tabs on title bar), so I use the function DwmExtendFrameIntoClientArea with margin {0, 0, caption height, 0}. Unfortunately, it shows a white window border with 1-pixel width and white title bar area. I use the function DwmDefWindowProc to handle the system messages and show the system control buttons (min, max, close button). But I have no idea how to change the color of the window border and title bar background. If I paint in WM_PAINT, it may cover the system control buttons and looks weird. If I paint in WM_NCPAINT, the window shadow with WS_THICKFRAME style may disappear and need to draw which I feel is difficult to do.
Additionally, the 1-pixel width border may come from the following code:
if (message == WM_NCCALCSIZE) {
auto client_area_needs_calculating = static_cast<bool>(wparam);
if (client_area_needs_calculating) {
auto parameters = reinterpret_cast<NCCALCSIZE_PARAMS*>(lparam);
auto& requested_client_area = parameters->rgrc[0];
requested_client_area.right -= GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER);
requested_client_area.left += GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER);
requested_client_area.bottom -= GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER);
return 0;
}
}
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);
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.
I have a program which draw a Rectangle under mouse cursor and show the pixel color, but I can't manage it to clear the shape inside the while loop, if I use 'InvalidateRect()' it clear rectangle too fast and flickering, if not use 'InvalidateRect()' then Rectangle keep duplicating like THIS, how to fix that?
HWND hwnd;
POINT p;
unsigned short R=0, G=0, B=0;
void drawRect()
{
GetCursorPos(&p);
HDC hdc = GetDC(NULL);
HPEN border = CreatePen(PS_SOLID, 2, RGB(0, 0, 0));
HBRUSH background = CreateSolidBrush(RGB(R, G, B));
SelectObject(hdc, border);
SelectObject(hdc, background);
Rectangle(hdc, p.x+10, p.y+10, p.x+40, p.y+40);
DeleteObject(border);
DeleteObject(background);
}
void init()
{
while (GetAsyncKeyState(VK_RBUTTON) & 0x8000)
{
grabPixel(); //get RGB color from cursor coordination
drawRect(); //draw preview rectangle under cursor
InvalidateRect(hwnd, NULL, true);
}
}
Note: it doesn't have WinMain() or WndProc()
There are all sorts of things wrong with this. What are you actually trying to do?
From the fact that you're using GetDC(NULL), it looks like this is supposed to be drawing a rectangle on the entire screen.
Where is the hwnd value coming from? If that window does have a message loop (and it probably does), then that's the window being invalidated and redrawing itself.
A note: InvalidateRect merely marks the rectangle as needing-to-be-painted the next time that that application's (actually thread's, more-or-less) message queue is empty. UpdateWindow will cause a WM_PAINT message to be sent immediately.
drawRect isn't cleaning up properly, either. It should call ReleaseDC when it's finished, and it ought to restore the previous drawing objects after it's finished (and most definitely before it deletes them) as well:
HBRUSH oldBackground = SelectObject(hDC, background);
// ...
SelectObject(hDC, oldBackground);
What you probably want to do is, when selection starts, create a window the size of the screen and copy the existing screen into it. Then you can draw all over that intelligently.
The DrawDragRect function (see my blog) is designed for this sort of thing.