I am using label with OnCtrlcolor event:
I have set the background color of the label to be the same as the form,
if (iD == IDCmylabel)
{
pDC->SetTextColor(blue);
COLORREF normal = RGB(245, 245, 245);
pDC->SetBkColor(normal);
return (HBRUSH)GetStockObject(NULL_BRUSH);
}
So I was thinking to use toogle:
SetWindowTextW("abc..."); // will show the color as expected.
SetWindowTextW(nullptr); // will remove the text color.
However this is not working for me (the caption didn't redraw because it still there).
How do I fix this?
NULL_BRUSH is a brush that instructs the system to turn any painting operations that use that brush into no-ops. Using it doesn't actually make the control transparent. It just appears to be transparent until (part of it) has been painted.
If you want a control that has a particular background color, irrespective of the the size of text displayed, you're going to have to provide a solid color brush.
The easiest way to do this would be to return a DC_BRUSH, with an accompanying call to SetDCBrushColor to request the color, i.e.
if (iD == IDCmylabel) {
pDC->SetTextColor(blue);
COLORREF normal = RGB(245, 245, 245);
// Still required so that the text background matches that of the rest
pDC->SetBkColor(normal);
// Request brush color for the control background
pDC->SetDCBrushColor(normal);
// Note: Stock objects do not need to be freed by client code
return (HBRUSH)GetStockObject(DC_BRUSH);
}
With that you can call SetWindowText with arbitrary parameters and get the result you are looking for.
Someone needs to erase the background under the old text.
You are returning NULL_BRUSH, so "erase background" does nothing.
Return the solid brush of the color RGB(245, 245, 245). You may also need to call Invalidate for that window after setting new text.
Related
How Do I Set the Background Color of buttons including a Checkbox button?
I struggled to find the answer to this today - thinking it should be simple to answer this, but the information I stumbled on was less than helpful, so at the risk of duplicating stuff that's out there but I couldn't find, I'll make this quick'n'dirty how-to...
All 'Button' class windows send WM_CTLCOLORSTATIC to their parent window, which can then call ::SetBkColor((HDC)wParam, rgbBkColor), and return a brush for that color.
If this is all using system colors, then the brush handle doesn't need to be managed, you can simply ask for the ::GetSysColor(sysIndex), and return the ::GetSysColorBrush(sysIndex) for the returned brush.
If you're using a custom color, then you'll need to create your own brush and manage the handle for that.
I needed this code for a Message Box replacement, which has the upper part using a white background, and the lower part using a gray background, per the Windows standard message box. So my static control (icon) needed to be white, while my other buttons (including a "Don't ask again" checkbox) needed to have a gray background (checkboxes normally have a white background).
So, I handle WM_ERASEBKGND to paint the two portions of the background correctly, and then I handle WM_CLTLCOLORSTATIC to ensure that all buttons are properly "transparent" for the background that they appear on. In my case, the I used a "Static" control for the icon, which draws its background in gray, and a couple of push-buttons plus a checkbox button - which a checkbox button always paints its background in white, so both required a fix.
My example is using MFC, but hopefully you can translate that trivially enough for your purposes:
// add to the message map:
ON_MESSAGE(WM_CTLCOLORSTATIC, OnCtlColorStatic)
// create the implementation:
LRESULT CRTFMessageBox::OnCtlColorStatic(WPARAM wParam, LPARAM lParam)
{
// buttons and static controls (icon) send WM_CTLCOLORSTATIC, so we can force them to use the correct background color here...
const HDC hdc = (HDC)wParam;
const int idc = ::GetDlgCtrlID((HWND)lParam);
// choose a system color or brush based on if this is icon (static) or another control (a button)
const int idx = idc == IDC_STATIC ? COLOR_WINDOW : COLOR_3DFACE;
// select system color
::SetBkColor(hdc, GetSysColor(idx));
// return system brush (which we don't need to delete!)
return (LRESULT)GetSysColorBrush(idx);
}
How can I get the pressed background color of a QPushButton?
if (isDown())
_BGColor = <pressed background color>; // how to get this???
else
_BGColor = palette().color(QPalette::Background); // this is to get the idle backcolor
Thanks in advance!!!
It's very difficult (if not impossible) to find a way to get the backgound color of a button when it's pressed, because it depends on the style, and it's not guaranteed that the style respects the palette.
However I suggest two different approaches:
You can set you own background color using style sheets (simpler) or implement the painting of the button yourself, using styles or reimplementing paintEvent(). See Customizing QPushButton
To paint over the button with the inverse color, you can set a composition mode to the painter in order to get the inverse color.
For example:
painter.setPen(QColor(255, 255, 255));
painter.setCompositionMode(QPainter::RasterOp_SourceAndNotDestination);
(note that using this example, the inverse color of middle grey (128, 128, 128) is exactly the same color)
See QPainter::CompositionMode
I have an mfc application. I have some richedit controls on the dialog. I want to show a yellow colored filled frame around the controls. What is the way to do this?
I tried to create one more rich edit ctrl around the existing richedit ctrl and use SetBackgroundColor on its variable, but it colors the entire area and other richedit ctrls become invisible. Also, I want to change the surrounding color at run time.
Please help me. I am stuck with this.
There may be a better way to accomplish this, but, the following should work. If you derive your own class from CRichEditCtrl, you can leverage the WM_NCPAINT message to render the border. Something like…
void RichEdit::OnNcPaint()
{
CPaintDC dc(this); // device context for painting
CRect rect;
GetWindowRect(&rect);
ScreenToClient(rect);
CPen pen;
pen.CreatePen(PS_SOLID, 10, RGB(255, 255, 0));
dc.SelectObject(pen);
dc.Rectangle(&rect);
CHARFORMAT cf = { 0 };
int txtLen = GetTextLength();
cf.cbSize = sizeof(cf);
cf.dwMask = CFM_ITALIC;
SetSel(txtLen, -1); ReplaceSel("Some text");
// Apply formating to the just inserted text.
SetSel(txtLen, GetTextLength());
SetSelectionCharFormat(cf);
SetFocus();
// Do not call CRichEditCtrl::OnNcPaint() for painting messages
}
Will render the border as Yellow, and, write the corresponding text. Here’s what it will look like.
I am using custom draw to try and create transparent tree view ( for now I am testing when Visual Styles are enabled ).
My CDDS_PREPAINT handler works fine, tree has parent's background bitmap drawn properly.
I tried to add CDDS_ITEMPREPAINT handler where I use SetBkColor( ((LPNMCUSTOMDRAW)lParam)->hdc, TRANSPARENT ); and return CDRF_NEWFONT, but that failed. Node is drawn with default white background.
How can I make item's text background transparent?
Thank you.
Best regards.
Below is the illustrative code snippet:
switch( ((LPNMCUSTOMDRAW)lParam)->dwDrawStage )
{
case CDDS_PREPAINT:
{
DrawThemeParentBackground(
((LPNMCUSTOMDRAW)lParam)->hdr.hwndFrom,
((LPNMCUSTOMDRAW)lParam)->hdc,
&((LPNMCUSTOMDRAW)lParam)->rc );
// since tree is in dialog box we need below statement
SetWindowLongPtr( hDlg, DWLP_MSGRESULT, (LONG_PTR)CDRF_NOTIFYITEMDRAW );
return TRUE;
}
break;
case CDDS_ITEMPREPAINT : // how to properly handle this ???
{
SetBkMode( ((LPNMCUSTOMDRAW)lParam)->hdc, TRANSPARENT );
SetWindowLongPtr( hDlg, DWLP_MSGRESULT, (LONG_PTR)CDRF_NEWFONT );
return TRUE;
}
break;
}
Unfortunately, this is not easily possible without drawing the items yourself, sorry.
It turns out the Tree View Control has traditionally used ExtTextOut() function internally to draw the item titles. This function takes an explicit flags parameter, where value ETO_OPAQUE says that "the current background color should be used to fill the rectangle".
Because this option is passed as an extra flag and not determined by looking at the current GDI background mode, you can't use SetBkMode() in a custom draw handler to work around this. The background color property of a DC does not support alpha channel either, so it cannot be just set transparent.
Since Common Controls version 6.0 and themed window decorations, this is a bit different, but still not useful in this case: the control just calls DrawThemeBackground() with the TVP_TREEITEM part and the rest is handled according to the theme being used. I see e.g in the default Aero theme in Windows 8.1 that there is this entry:
ClassID | PartID | StateID | Property | Value
---------+--------------+--------------+-----------------+--------------
TreeView | TVP_TREEITEM | TREIS_NORMAL | FILLCOLOR:COLOR | 255, 255, 255
So, what are the alternatives?
There is always an option to return CDRF_SKIPDEFAULT for the CDDS_ITEMPREPAINT event and do all the display operations yourself. But then you need to take care of drawing even the lines, [+] boxes, selection and focus rectangles and everything else.
Another option might be to leave the title text stored in the control empty, then add it in CDDS_ITEMPOSTPAINT - i.e. use TVM_GETITEMRECT with wParam=TRUE to get the text rectangle and draw the real text there after everything else has been already painted by the control. But this method fails too, because some tiny opaque rectangle is apparently drawn even for empty text. You'd need to erase that artifact first, only then proceed with drawing the text youself. Coming up with a code which does work for all combinations of item state seemed tricky.
Currently i'm drawing the text from a textbox in my window. I successfully get the text i need to draw and it draws the text. It's ok.
Here's the problem: when i write something else in my input box and draw the text again (via button push), the new text is drawn right on top of the previous text as to be expected.
I'm new to all of this and i can't find a way to clear the previous text before drawing the new text.
Here's my code:
void DrawMyText(HWND hwnd) {
int iTextLength = GetWindowTextLength(hDrawInput) + 1;
char cDrawText[1000] = "";
HDC wdc = GetWindowDC(hwnd);
RECT canvas;
canvas.left = 168;
canvas.top = 108;
canvas.right = 500;
canvas.bottom = 500;
GetWindowText(hDrawInput, cDrawText, iTextLength);
SetTextColor(wdc, 0x00FF0066);
SetBkMode(wdc,TRANSPARENT);
DrawText(wdc, cDrawText, -1, &canvas, DT_LEFT);
DeleteDC(wdc);
}
Any tips on how to do this? I will gladly provide any additional information if needed. Thanks in advance!
DrawText is more like a spray can - it paints over top whatever is already there. I'd recommend switching to SetWindowText. The difference is DrawText is more like a canvas rendering call, and doesn't consider much about the type of control it's drawing to. SetWindowText is an explicit "set the text of this window to this specific value", and is specific to text-based controls. More to the point, it will replace the current text with the new text value.
If you absolutely must do it with DrawText (i.e. you prefer a canvas approach as above), then you'll have to manually clear the text area yourself with something like InvalidateRect() (using the RECT of the text area). Or, by drawing a rectangle equal in size to the text area and with the same color as the background. Let me know if that's not enough detail.
If some other window covers and then uncovers the place where you drew the text it will be gone! The illusion that windows can sit on top of each other is destroyed! Windows provides a scheme to overcome this problem but you are not cooperating with the scheme.
Paint your text only in response to the WM_PAINT message, using the BeginPaint and EndPaint API calls. On the button click just call InvalidateRect, which asks Windows to send you a WM_PAINT. BeginPaint erases your window just before you paint. So by putting your painting code in the right place - the WM_PAINT handler - you solve two problems: It erases any old text, and it repaints whenever your window is uncovered.