Can't change edit text background when using Common Controls 6.0 - winapi

I'm working on a Win32 C++ GUI Desktop application.
All the edit text are created statically in the resource file and their background is changed in the DialogBox routine using the WM_CTLCOLOREDIT and WM_CTLCOLORSTATIC messages.
case WM_CTLCOLOREDIT:
if (lParam == (LPARAM)Edit1Hwnd)
return SetBkColor((HDC)wParam, GuiColors[RED]);
else if (lParam == (LPARAM)Edit2Hwnd)
return SetBkColor((HDC)wParam, GuiColors[GREEN]);
break;
case WM_CTLCOLORSTATIC:
if (lParam == (LPARAM)Edit3Hwnd)
return SetBkColor((HDC)wParam, GuiColors[BLUE]);
else if (lParam == (LPARAM)Edit4Hwnd)
return SetBkColor((HDC)wParam, GuiColors[YELLOW]);
break;
When the window loads I can see that all the edit have the correct background color.
The problem rises when I use Common Controls 6.0 (which I need in order to load a BMP as a list-view background).
In order to enable Common Controls 6.0 I do:
#pragma comment(linker,"\"/manifestdependency:type='win32' \name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
If I run the program with the Common Controls enabled, all the edit text appear with a white background. But I can change the edit color selecting it with the mouse cursor.
Searching on the site I found this question.
It confirms the behaviour I experience, but it doesn't give a solution for changing the edit background color when it doesn't have the focus.
Any help is appreciated.
EDIT:
Thanks RbMm for your answer, I changed the code to
case WM_CTLCOLOREDIT:
if (lParam == (LPARAM)Edit1Hwnd)
return (LRESULT)redBrush;
break;
Where redBrush is declared and created like this
static HBRUSH redBrush = NULL;
redBrush = CreateSolidBrush(GuiColors[RED]);
The edit background color is properly red painted at the start, but when the edit gets the focus it turns white again (it turns back to red when the focus is lost).
EDIT 2:
Thanks zett42, now it works!
case WM_CTLCOLOREDIT:
if (lParam == (LPARAM)Edit1Hwnd){
SetBkColor((HDC)wParam, GuiColors[RED]);
return (LRESULT)redBrush;
}
break;

Related

Any suggestions to effectively update the status bar of an application?

The status bar window of this program needs to be updated every time the user press a key that is likely to move the caret of the EDIT control, and the code below works like a charm! In a nutshell, pressing a key on the keyboard will update some values and send a message "ECM_GETLINEINFOS" that is next processed in the main window procedure (code below)
However, there is flickering that is not disturbing, of course, but I wonder if it's related to how I set the text on the status bar (maybe too many updates ?) or just a problem with the drawing part.
PS: The flickering occurs on the text, not the status bar in itself, so that is why I'm questioning how I should manage the update of my window.
constexpr int failed_val = -1;
LRESULT MainWindow::HandleMessage(UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
// Custom message sent by an EDIT control, I
// use this message to tell the status bar it must update its text.
case CEM_GETLINEINFO:
{
const size_t buffSz = 24;
std::wstring buffer(buffSz, L'\0');
int line = LOWORD(wParam);
int column = HIWORD(wParam);
int count = _snwprintf_s(buffer.data(), buffer.size(),
_TRUNCATE, L"Ln %d, Col %d", line, column);
if (count != failed_val) {
// Param 1 : The text to be displayed
// Param 2 : Which status bar part
m_statusBar->SetText(buffer, 0);
}
}
return 0;
}
}
Just as Flicker-Free Displays Using an Off-Screen DC directed by the answer said,
What makes this window flicker when we update it frequently? The
answer is that Windows asks the window procedure to repaint the window
as a two-step process. First, it sends a WM_ERASEBKGND message and
then a WM_PAINT message. The default handling for the WM_ERASEBKGND
message is to fill the area with the current window background color.
So the sequence of events is first to fill the area with solid color
and then to draw the text on top. The net result of doing this
frequently is that the window state alternates between its erased
state and its drawn stateā€”it flickers.
And
To prevent the control from flickering when we update it frequently,
we need to make two changes to how the control handles messages.
First, we need to prevent Windows from providing the default handling
of WM_ERASEBKGND messages. Secondly, we need to handle WM_PAINT
messages so that the background is painted with the window background
color and so that the changes to the control's client area happen at
once.
A status bar flicker free solution in .NET: Searching Visual Studio .NET style status bar. Or Simple Mode Status Bars could be enough.

How to disable the vertical header tracking line in Win32 ListView Control

I am customizing Win32 ListView control and I want to remove the vertical line that is automatically drawn when I resize the headers. I am talking about the line drawn in the row area not in the header. The vertical tracking line can be restricted by handling the HDN_TRACK notification and changing the cxy value in notification data but there seems to be no way to restrict or remove the vertical tracking line in the row area. Anyone has any ideas on how to remove/hide/restrict that line?
The above screenshot was taken while I am tracking the header
Removing the line just makes it harder for the user to use the control!
The easy method is probably to enable visual styles/comctl32 v6, it seems to use live resizing instead but that might depend on the chosen theme/style.
I was able to come up with a ugly hack for the classic control:
HWND hLV = CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTVIEW, NULL, WS_CHILD|WS_VISIBLE|WS_HSCROLL|WS_VSCROLL|LVS_REPORT, ...);
SendMessage(hLV, CCM_SETVERSION, 5, 0); // <--- Important
...
case WM_NOTIFY:
{
HWND hLV = ...;
NMHDR&nmh = *(NMHDR*) lparam;
switch(nmh.code)
{
case HDN_BEGINTRACKA:case HDN_BEGINTRACKW:
LockWindowUpdate(hLV); // Block all drawing in the listview
return false;
case HDN_ENDTRACKA:case HDN_ENDTRACKW:
LockWindowUpdate(NULL);
return false;
}
This might depend on the HDS_FULLDRAG header style and you probably don't want to do this when visual styles are enabled.

Processing NM_CUSTOMDRAW on a pushbutton - but Windows still draws the text

I'm experimenting with using NM_CUSTOMDRAW instead of WM_DRAWITEM for bitmap buttons in my win32 app. The WM_DRAWITEM stuff works fine - except that it doesn't work under WINE with a desktop theme enabled (for some reason, with a theme enabled, WINE only sends WM_DRAWITEM when you click a pushbutton).
Anyway, I tried removing the BS_OWNERDRAW from the OK button below - leaving the others alone. To test processing the WM_NOTIFY, I just copy the fields I need from the NMCUSTOMDRAW struct to a DRAWITEMSTRUCT and pass that to my existing WM_DRAWITEM handler. The button draws fine, but then Windows draws the OK text over mine (my text is shifted to make room for the checkmark). I've pasted the code below. I thought that if I returned CDRF_SKIPDEFAULT in response to all NM_CUSTOMDRAW notifications, Windows wouldn't try to draw anything. There's obviously something else I need to do...
case WM_NOTIFY:
// Only intrested in NM_CUSTOMDRAW messages here.
nmh = (LPNMHDR) lParam;
if (nmh->code != NM_CUSTOMDRAW)
break;
// Only interested in CDDS_PREPAINT.
lpNMC = (LPNMCUSTOMDRAW) lParam;
if (lpNMC->dwDrawStage != CDDS_PREPAINT)
return(CDRF_SKIPDEFAULT);
// Copy fields we need from NMCUSTOMDRAW to a DRAWITEMSTRUCT.
memset(&dis, 0, sizeof(dis));
dis.hwndItem = nmh->hwndFrom;
dis.hDC = lpNMC->hdc;
dis.rcItem = lpNMC->rc;
if (lpNMC->uItemState & CDIS_FOCUS)
dis.itemState |= ODS_FOCUS;
if (lpNMC->uItemState & CDIS_SELECTED)
dis.itemState |= ODS_SELECTED;
if (lpNMC->uItemState & CDIS_DEFAULT)
dis.itemState |= ODS_DEFAULT;
if (lpNMC->uItemState & CDIS_DISABLED)
dis.itemState |= ODS_DISABLED;
DrawBitmapButtonOnWindowsDialog(wParam, (LPARAM) &dis, -1);
return(CDRF_SKIPDEFAULT);
case WM_DRAWITEM:
DrawBitmapButtonOnWindowsDialog(wParam, lParam, -1);
break;

WinAPI: set fill color of a readonly textbox

I have a program winapi (C++) nearly complete. The problem now is I want to set fill color of text box and that textbox is readonly. When I set that textbox readonly, I can't fill it white. And when I don't, it can be filled with white.
This is how I create a textbox:
CreateWindow(L"EDIT", text, WS_CHILD|WS_VISIBLE|WS_BORDER|ES_READONLY|ES_RIGHT, left, top, width, height, hWnd, (HMENU)ID, hInst, NULL)
And this code is in WinProc:
case WM_CTLCOLOREDIT:
SetTextColor((HDC)wParam,RGB(0,0,255));
SetBkColor((HDC)wParam,RGB(255,255,255));
SetBkMode((HDC)wParam, TRANSPARENT);
return (LRESULT)GetStockObject(WHITE_BRUSH);
You'll want to use WM_CTLCOLORSTATIC for read-only text boxes; see the docs for WM_CTLCOLOREDIT.
As per HerrJoebob's solution, but you need to differentiate between static's and edit's: (untested code, but the idea is there)
case WM_CTLCOLORSTATIC:
{
TCHAR senderClass[256] ;
GetClassName((HWND)lParam, senderClass, 256);
if (_tscmp(senderClass, WC_EDIT)
{
//Code to change the colour of edit controls
}
}
break;

Win32 scrolling examples

Could anyone point me to (or provide?) some nice, clear examples of how to implement scrolling in Win32? Google brings up a lot of stuff, obviously, but most examples seem either too simple or too complicated for me to be sure that they demonstrate the right way of doing things. I use LispWorks CAPI (cross-platform Common Lisp GUI lib) in my current project, and on Windows I have a hard-to-figure-out bug relating to scrolling; basically I want to do some tests directly via the Win32 API to see if I can shed some light on the situation.
Many thanks,
Christopher
I think you are talking for an example how to handle WM_VSCROLL/WM_HSCROLL event. If so first step is to handle that event. You shouldn't use the HIWORD(wParam) value of that call but use GetScrollInfo, GetScrollPos, and GetScrollRange functions instead.
Following is an example code snipped by MSDN - Using Scroll Bars. xCurrentScroll is determined before by calling GetScrollPos() for example.
int xDelta; // xDelta = new_pos - current_pos
int xNewPos; // new position
int yDelta = 0;
switch (LOWORD(wParam)) {
// User clicked the scroll bar shaft left of the scroll box.
case SB_PAGEUP:
xNewPos = xCurrentScroll - 50;
break;
// User clicked the scroll bar shaft right of the scroll box.
case SB_PAGEDOWN:
xNewPos = xCurrentScroll + 50;
break;
// User clicked the left arrow.
case SB_LINEUP:
xNewPos = xCurrentScroll - 5;
break;
// User clicked the right arrow.
case SB_LINEDOWN:
xNewPos = xCurrentScroll + 5;
break;
// User dragged the scroll box.
case SB_THUMBPOSITION:
xNewPos = HIWORD(wParam);
break;
default:
xNewPos = xCurrentScroll;
}
[...]
// New position must be between 0 and the screen width.
xNewPos = max(0, xNewPos);
xNewPos = min(xMaxScroll, xNewPos);
[...]
// Reset the scroll bar.
si.cbSize = sizeof(si);
si.fMask = SIF_POS;
si.nPos = xCurrentScroll;
SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);
Here's one, ScrollCall, (copy from page):.
ScrollCall is a demo program that takes a sample of Windows standard
controls, along with a standard GDI image, and arranges them on a
Device Context (or DC), in a window. Depending on the dimensions of
the image, and the size of the containing window, horizontal and/or
system scrollbars become visible, to enable scrolling for the image
and controls. Thus ScrollCall is as at least as much focused on sizing
as it is scrolling, and both offer unique challenges for the
programmer.
ScrollCall features:
System scroll bars
Optional groupbox
Button to open images on the Device Context (DC)
Radio options for choice of window scroll function
Checkbox to stretch rather than scroll the image
Label Paint Mult with UpDown and Buddy to increase the wait times of WM_SIZE during sizing, thus reduced WM_PAINT processing
Right click for system snapshot of view in default or monitor attached to desktop
Double-click to print the visible part of the (mostly empty) client window to the DC, and back to the client window (experimental)
ScrollCall temporarily turns on SPI_SETDRAGFULLWINDOWS for the testing of the visual effects of dragging, if ever it was toggled off
Compatibility with AeroSnap sizing

Resources