MFC CEdit input limits text to 10 characters on 4k resolution - winapi

I use a CEdit text field to input a search term in an MFC application. When using it on FullHD resolution it works fine, I can input as long as big of a string as i need, but when using on 4k resolution the text is limited to 10 characters. The return of GetLimitText is 3000, and if I SetLimitText to a value smaller than 10 it works, limiting to more (such as 20) doesn't do anything, only 10 characters can be input still. Has anyone had this problem before or it might be from my implementation?

I "fixed" it in a way. I was calling CWnd::ModifyStyleEx(0, WS_EX_CLIENTEDGE). I replaced with CWnd::ModifyStyle(0, WS_BORDER). This is not a true fix as it changes the way it looks a bit, but I guess this is a bug.

I ran into a similar problem when creating the equivalent of resources for a CDialogBar on-the-fly (instead of using the resource editor). One of the controls was a CEdit control, and as user3808318 pointed out, MFC or Windows mysteriously ignores any value you assign using SetLimitText, and seems to ignore any characters you type that would extend beyond the edit control on the screen.
This is the original way that I created the edit control that resulted in this problem.
Create (WS_CHILD | WS_VISIBLE | WS_BORDER, rectDummy, this, IDC_FIND_TEXT)
Here is the correct way, now including the ES_AUTOHSCROLL option.
Create(WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL, rectDummy, this, IDC_FIND_TEXT)

Related

Displaying a tooltip with an icon

I want to display a tooltip with text and an icon when the mouse pointer hovers over a specific button. Below are two variants of this that I've seen, but I couldn't find information about the implementation.
(source: microsoft.com)
Take a look at TTM_SETTITLE message -- custom Icons can be used in Windows XP SP2 and later.
#Edward Clements already told you an useful way, so you maybe know how to use it.
Anyway, I just add detailed code for refernce.
case WM_CREATE:
hTip=CreateWindowEx(WS_EX_TOPMOST,TOOLTIPS_CLASS,NULL,0,
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
hWnd,NULL,g_hInst,NULL);
hBtn=CreateWindow("button","Test",WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
50,50,200,100,hWnd,(HMENU)0,g_hInst,NULL);
ti.cbSize=sizeof(TOOLINFO);
ti.uFlags=TTF_SUBCLASS | TTF_IDISHWND;
ti.hwnd=hWnd;
ti.uId=(WPARAM)hBtn;
ti.lpszText="This is a button";
SendMessage(hTip,TTM_ADDTOOL,0,(LPARAM)(LPTOOLINFO)&ti);
SendMessage(hTip, TTM_SETTITLE, (WPARAM)TTI_WARNING, (LPARAM)"Information");
return 0;

Transparent text box

I would like to use a transparent read-only text box as a replacement for a label; to allow users to select+copy the text. Exactly what Windows Explorer uses on the file properties window:
I've found similar question: Making a TextBox Transparent
Comments there suggest that proposed solutions do not work with ClearType. But my testing of suggested "AlphaBlendTextBox - A transparent/translucent textbox for .NET" component shows otherwise.
Anyway, the code looks quite complex for such a "simple task". They do save parent control image to a bitmap, drawing that bitmap over and over again with the text on top of it. I would expect there there has to be a solution delegating drawing of the background to parent control.
Possibly their solution is that complex because it allows alpha-blending too. I do not need that. I just want to see a parent background behind the text. Is there a simpler/smarter way?
Note that I'm happy with any winapi solution (pure winapi, MFC, WinForms, Delphi, whatever).
According to Spy++, it's a typical Edit control with WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR | WS_EX_NOPARENTNOTIFY as extended style and WS_CHILDWINDOW | WS_VISIBLE | ES_LEFT | ES_AUTOHSCROLL | ES_READONLY as original window style.
I've tested it in Win32 and I can confirm that it does what you want it to do.
Also, next time you want to mimic the appearances of other controls, simply fire up Spy++ to get the detailed information about them.

Removing window frame / border properly

I've been working on a custom GUI framework since I just can't deal with managed crap or native code which requires development of UIs through markup (XAML). I am trying to create a prototype of an application which uses that GUI framework, but I am having a platform-specific issue with the nature of windows within WinAPI.
The DWM doesn't really allow customization of the non-client area which breaks immersion, the only thing it allows is extension into the client area in order to give an illusion of customization.
So, the best course of action is to reconstruct the "non-client area" within the client area (relative to WINAPI) and that required me to strip the caption, maximize, minimize buttons etc. So, I basically enumerated all the things I want out and OR-ed them together and flipped all the bits in order to deactivate them.
~(WS_CAPTION | WS_SYSMENU | WS_HSCROLL | WS_VSCROLL | WS_MINIMIZE | WS_MAXIMIZE | WS_THICKFRAME)
Once these style go away, I cannot use normal shutdown procedures (Alt+F4, or right clicking in the taskbar and going "Close") because they don't work. I had to intercept VK_ESCAPE and PostQuitMessage(0) manually just so I could exit without being forced to kill the process.
Why is this so? And how can I fix this?
The short answer
Replace:
~(WS_CAPTION | WS_SYSMENU | WS_HSCROLL | WS_VSCROLL | WS_MINIMIZE | WS_MAXIMIZE | WS_THICKFRAME)
With:
WS_POPUP
And no more funky behavior. The application responds correctly. Enjoy the cake.
The long answer
Ah, as with everything on MSDN lately, the cake is a lie. Window styles are not really just visual. They also specify what inherent window functionalities are available to the application's window(s). Now, there is a fair amount of trickery here to be observed.
First of all, the MSDN isn't really forthcoming and useful with its window style definition table. The default behavior for windows is the classic caption, close, border package which is identified as the WS_OVERLAPPEDWINDOW which occupies the simplest expression, 0 (a 32-bit value, all bits down, 0x00000000), so someone wishing to rush through things could just set 0 for styles in the CreateWindow* function and it would yield a classic window.
What you want is a bare-bone, dirty and empty window. And Microsoft's got exactly the thing you're looking for - WS_POPUP which sets the highest bit to 1 and everything else is 0. This will drop all the fancy resizing automata, window captioning and the cute minimize, maximize and close buttons.
Which means you're going to have to reimplement everything. But that's what you're going for, right?
Just flipping all the bits isn't enough, you will drop the wanted options, but also activate the rest of the options resulting in the application acting funny, what you're experiencing right now. Therefore, you either AND it with something else or use something readily defined by Microsoft - WS_POPUP.
And again. Enjoy the cake and happy coding.

Big problems with MFC/WinAPI

I need to create a SDI form with a formview that has two tabs, which encapsulate multiple dialogs as the tab content. But the form has to have a colored background.
And things like these makes me hate programming.
First, I tried CTabControl, via resource editor, tried different things, but the undocumented behavior and the quirks with no answers led me into a roadblock.
After many hours of searching, I found that there is a control called property sheet, which is actually what I need.
Some more searching later, I found that property sheet can even be actually embedded onto CFormView like so: http://www.codeguru.com/Cpp/controls/propertysheet/article.php/c591
And that the dialog classes derived from CPropertyPage can be directly added as pages via AddPage method of CPropertySheet.
Great! Not quite so... Some of the controls didn't worked, and were not created, ran into weird asserts. Turns out the DS_CONTROL style was missing from the dialogs. Found it completely accidentaly on Link, no word about that on MSDN!!!! Property page must have: DS_3DLOOK | DS_CONTROL | WS_CHILD | WS_TABSTOP, and can have: DS_SHELLFONT | DS_LOCALEDIT | WS_CLIPCHILDREN styles! Not any other, which are created by default with resource editor. Sweet, super hidden information for software developers!
The quote in comments on that page: "OMG. That's where that behavior came from...
It turns out that the PlaySound API relied on that behavior when playing sounds on 64bit machines." by Larry Osterman, who as I understand works for Microsoft for 20 years, got me laughing out loud.
Anyway, fixed that, the dialog-controls(CPropertyPages) are created as expected now, and that part looks something remotely promising, but the next part with color is dead end again!
Normally you override WM_CTLCOLOR, check for control ID or hwnd and supply the necessary brush to set the color you need. Not quite so with CPropertySheet, the whole top row stays gray! For CTabCtrl it somehow works, for CPropertySheet it doesn't.
Why? Seems that the CPropertySheet is kinda embedded inside CTabControl or something, because if I override WM_ERASEBKGND, only the internal part changes the color.
Now it seems that there is a GetTabControl() method in the CPropertySheet, that returns the actual CTabCtrl* of the CPropertySheet. But since it's constructed internally, I can't find how to override it's WM_CTLCOLOR message processing.
There seems to be a way to subclass the windowproc, but after multiple tries I can't find any good source on how to do it. SubclassWindow doc on MSDN says: "The window must not already be attached to an MFC object when this function is called."?! What's that?
I tried creating a custom CCustomTabCtrl class based on CTabCtrl via MFC wizard, created an instance of it, called SubclassWindow from one of the CCustomPropertySheet handlers to override the internal CTabCtrl, but nothing works, mystical crashes deep inside MFC.
Tried setting WindowLong with GCL_HBRBACKGROUND for the internal CTabCtrl, nothing changed.
And worst of all, I can't find any sort of useful documentation or tutorials on the topic.
Most I can find is how to ownerdraw the tab control, but this is seriously wrong on so many ways, I want a standard control behavior minus background color, I don't want to support different color schemes, windows versions, IAccesible interfaces and all this stuff, and none of the ownerdraw samples I've seen can get even 10% of all the standard control behavior right. I have no illusion that I will create something better, I wont with the resources at hand.
I stumbled upon this thread, and I can't agree with the author more: http://arstechnica.com/civis/viewtopic.php?f=20&t=169886&sid=aad002424e80121e514548d428cf09c6 owner draw controls are undocumented PITA, that are impossible to do right, and there is NULL information on MSDN to help.
So is there anything I have missed or haven't tried yet? How to change the top strip background color of the CPropertySheet? Anyone?
Your only option is to ownerdraw the tab control. It's not that hard. Well, it is frustrating because MFC doesn't tell you how to make the necessary Win32 calls.
In your CPropertySheet-derived class, overwrite OnInitDialog() and add:
GetTabControl()->ModifyStyle(0,TCS_OWNERDRAWFIXED);
This puts your CPropertySheet-derived class in charge of drawing the tab control. Add a handler for WM_DRAWITEM (OnDrawItem) and change backgroundColor and textColor to match whatever colors you wanted. Code for OnDrawItem follows:
void CPropSht::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)
{
if (ODT_TAB != lpDrawItemStruct->CtlType)
{
CPropertySheet::OnDrawItem(nIDCtl, lpDrawItemStruct);
return;
}
// prepare to draw the tab control
COLORREF backgroundColor = RGB(0,255,0);
COLORREF textColor = RGB(0,0,255);
CTabCtrl *c_Tab = GetTabControl();
// Get the current tab item text.
TCHAR buffer[256] = {0};
TC_ITEM tcItem;
tcItem.pszText = buffer;
tcItem.cchTextMax = 256;
tcItem.mask = TCIF_TEXT;
if (!c_Tab->GetItem(c_Tab->GetCurSel(), &tcItem )) return;
// draw it
CDC aDC;
aDC.Attach(lpDrawItemStruct->hDC);
int nSavedDC = aDC.SaveDC();
CBrush newBrush;
newBrush.CreateSolidBrush(backgroundColor);
aDC.SelectObject(&newBrush);
aDC.FillRect(&lpDrawItemStruct->rcItem, &newBrush);
aDC.SetBkMode(TRANSPARENT);
aDC.SetTextColor(textColor);
aDC.DrawText(tcItem.pszText, &lpDrawItemStruct->rcItem, DT_CENTER|DT_VCENTER|DT_SINGLELINE);
aDC.RestoreDC(nSavedDC);
aDC.Detach();
}
Thank you for this solution but...
The above solution works well with one tab, but when you have multiple tabs it seems rename the wrong tabs. I needed to change the if statement for GetItem to:
if (!c_Tab->GetItem(lpDrawItemStruct->itemID, &tcItem )) return;
Needed lpDrawItemStruct->itemID to get the tabs named correctly

TabCtrl_SetItemSize and user drawn tab controls

I have this Win32 user-drawn tab control that is created as:
CONTROL "Tab1",IDC_TAB_CONT,"SysTabControl32",TCS_BOTTOM |
TCS_OWNERDRAWFIXED | NOT WS_VISIBLE,0,14,185,88
I'd like for this control to have its tabs resize as never to have to see the "sliding arrows":
Now, pretty much everything about this control works as expected, except for that fact that it won't respond to TabCtrl_SetItemSize. Try as I may, the size I get for the tabs when I get to draw them (in the DRAWITEMSTRUCT passed to WM_DRAWITEM) is always the size that fits the longest caption in them and never the size I've set with TabCtrl_SetItemSize.
However, in the TabCtrl_SetItemSize documentation, it says that:
[TabCtrl_SetItemSize] sets the width and height of tabs in a
fixed-width or owner-drawn tab
control.
The only way I've managed to have a decent resizing is by setting a dummy string of the desired length in it by sending the control a TCM_SETITEM message, and writing the desired text in it at draw time. This is rather inconvenient and not a particularly nice hack.
Is there anybody who would know
Why TabCtrl_SetItemSize isn't working as expected? and/or
How to set the tab size properly?
Many thanks,
joce.
Setting TCS_OWNERDRAWFIXED style is not enough, you have also to add TCS_FIXEDWIDTH style.
The minimum size of a tab is at least icon width + 3 if icon is present.
If you have icons (imageList attached to tabControl), you might get those "sliding arrows" even with fixed width (if there is less space available than: number of tabs*(icon width+3)

Resources