How do I use 'placeholder text' in a win32 edit control? - winapi

Take a look at the top-right of the Stack Overflow site. The search box has some text in it saying "search". When you click within it, the text disappears.
I want to do something similar to this - if a win32 edit control is empty (i.e. has no text), I want to paint some text inside it, in a more subdued color than the normal text. If the control has the focus, or if there's text inside it, I don't want to paint that.
Is there any way I can do it without setting the actual text into the control and changing the text color? Maybe by intercepting the control paint or something?
Thanks.

It is possible as of XP. Check the EM_SETCUEBANNER message. However, there are certain issues that make it not work entirely as it should on XP, so it's best if you're dealing with Vista.
If you need it for Win2k or older versions, you'll need to do it yourself, at least on those platforms.

Thanks for this question, I will be able to use this in the future.
FWIW (not much, probably), here is an implementation in Delphi:
procedure TForm1.FormShow(Sender: TObject);
const
ECM_FIRST = $1500;
EM_SETCUEBANNER = ECM_FIRST + 1;
begin
SendMessage(edt.Handle,EM_SETCUEBANNER,0,LParam(PWideChar(WideString('Enter search here'))));
end;

One possibility: Make it owner-draw, and manually paint the text onto it if the .Text property is empty.

Take a look at EM_SETCUEBANNER

Maybe, but why not just set the default text and color as needed, and clear it with an 'onClick' event?

You don't need owner-drawn, it's native with User apis (Banner)
See Winapi grp for samples (in C)

Related

How would you render soft returns in a Richedit control?

In an application that displays a richedit control I would like to be able to visually distinguish soft returns (produced with SHIFT ENTER) from hard returns (produced with ENTER).
I already use the JVCL richedit and don't want to switch at that point.
How would you proceed to do that?
Microsoft Word may be an inspiration source, they display a ↵ sign for soft returns and a ¶ sign for hard returns at the end of each line.
I am just looking for hints, good ideas how you would tackle this project. I am not asking anybody to do my work, of course. :-)
I already use the JVCL richedit and don't want to switch at that point.
The JVCL rich edit control wraps the Windows rich edit control. The Windows rich edit control won't show whitespace the way you desire. It has no functionality to do so. If you want the control to display such symbols you'd need to paint them yourself and I doubt that can be done in a very effective and slick way.
It sounds like you are displaying code because you mention syntax highlighting. In which case a rich edit control is the wrong choice. You should use a control designed for displaying and/or editing code.
Although not a direct answer to your question, there is a possible solution to the problem you mentioned of needing to use both Richedit and Syntax highlighting in one control and that is the use of SynEdit.
SynEdit include some non-visual components that allow exporting syntax formatted text, one of those components is TSynExporterRTF.
Suppose you have a section of code which is in plain text inside your richedit and you want to syntax highlight that portion, you could select and copy that text to a TSynEdit and then export it to a TSynExporterRTF which will now contain syntax formatted text (assuming a highlighter has been defined correctly). Then you can simply write the data to a TMemoryStream and replace the selected richedit text with the now syntax formatted code.
To do this you can try something like this:
procedure SyntaxFormatRichEditText(RichEdit: TRichEdit; SynHighlighter: TSynCustomHighlighter);
var
SynEdit: TSynEdit;
SynExporterRTF: TSynExporterRTF;
MS: TMemoryStream;
begin
SynEdit := TSynEdit.Create(nil);
try
SynEdit.Highlighter := SynHighlighter;
SynEdit.Lines.Text := RichEdit.SelText;
SynExporterRTF := TSynExporterRTF.Create(nil);
try
SynExporterRTF.Highlighter := SynHighlighter;
MS := TMemoryStream.Create;
try
SynExporterRTF.ExportAll(SynEdit.Lines);
SynExporterRTF.SaveToStream(MS);
MS.Seek(0, soBeginning);
RichEdit.SetSelTextBuf(MS.Memory);
RichEdit.SetFocus;
finally
MS.Free;
end;
finally
SynExporterRTF.Free;
end;
finally
SynEdit.Free;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
SyntaxFormatRichEditText(RichEdit1, SynPasSyn1);
end;
If anything though, as others have suggested the requirements you need are likely out of scope as to what the Richedit controls can offer.

Win32 custom message box

I want to make a custom message box. What I want to customize is the button's text.
MessageBoxW(
NULL,
L"Target folder already exists. Do you want to overwrite the folder?",
L"No title",
MB_YESNOCANCEL | MB_ICONQUESTION
);
I'd like to just change the buttons text to Overwrite, Skip, Cancel.
What's the most simple way?
I have to make this as having same look and feel with Windows default messagebox.
As said by others, a typical way is to create a dialog resource and have a completely independent dialog, which GUI you need to design in the way that it looks like standard dialog (to meet your request for feel and look). If you want to accept text messages, you might probably need to add code which resizes the window appropriately.
Still, there is another option for those who feel like diving into advanced things. While MessageBox API does not offer much for fint tuning, you still have SetWindowsHookEx in your hands. Having registgered the hook, you can intercept standard MessageBox window procedure and subclass it in the way you like.
Typical things include:
changing button text
adding more controls
adding timed automatic close
Hooking standard window can do all of those.
UPD. Hey, I realized I have some code with SetWindowsHookEx to share: http://alax.info/blog/127
You could create an own dialog. Or you could use a window hook as described in this article.
An archived version of the article can be found on web.archive.com.
Make a dialog resource (with a GUI editor, or by hand) and call DialogBox on it. There's no way to alter MessageBox behaviour, other than what's supported by its arguments.
That said, your message box can very well use stock Yes/No options.
The task dialog functionality introduced in Vista does exactly what you want and follows the prevailing system theme. However, if you have to support XP, then this will be of little comfort to you.
I know this question is old, but I just stumbled upon it now.
I would like to expand the other answers in regards to using a TaskDialog instead of a MessageBox. Here's a concise example of using a TaskDialog to do precisely what was asked; change the button's texts:
const TASKDIALOG_BUTTON buttons[] = { {IDYES, L"Overwrite"}, {IDNO, L"Skip"}, {IDCANCEL, L"Cancel"} };
TASKDIALOGCONFIG taskDialogConfig = {
.cbSize = sizeof(TASKDIALOGCONFIG),
.pszMainIcon = TD_WARNING_ICON, // TaskDialog does not support a question icon; see below
.pButtons = buttons,
.cButtons = ARRAYSIZE(buttons),
.pszWindowTitle = L"No title",
.pszContent = L"Target folder already exists. Do you want to overwrite the folder?"
};
TaskDialogIndirect(&taskDialogConfig, NULL, NULL, NULL);
Some noteworthy things:
You need to use TaskDialogIndirect, not the basic TaskDialog function
when not specifying a parent window, the icon specified in pszMainIcon is displayed in the title bar as well
There is no equivalent to the MessageBox's MB_ICONQUESTION, quoting a quote from this forumpost: Don't use the question mark icon to ask questions. Again, use the question mark icon only for Help entry points. There is no need to ask questions using the question mark icon anyway—it's sufficient to present a main instruction as a question.
checking which button was selected would have to be done by passing a pointer to an int as the second argument of TaskDialogIndirect and checking its value on return (the documentation should be pretty clear)
Here is a small open source library that allows you to customize Message Boxes. Developed by Hans Ditrich.
I have successfully used it in another POC that allows embedding a custom icon in such MessageBox that can be called even from a Console application.
I should also point to the Task Dialog. Here is an example of using it:
int nButtonPressed = 0;
TaskDialog(NULL, hInst,
MAKEINTRESOURCE(IDS_APPLICATION_TITLE),
MAKEINTRESOURCE(IDS_DOSOMETHING),
MAKEINTRESOURCE(IDS_SOMECONTENT),
TDCBF_OK_BUTTON | TDCBF_CANCEL_BUTTON,
TD_WARNING_ICON,
&nButtonPressed);
if (IDOK == nButtonPressed)
{
// OK button pressed
}
else if (IDCANCEL == nButtonPressed)
{
// Cancel pressed
}

Rich Edit Control: Prevent Rich Formatting?

How do you prevent the user from changing anything other than the text in a Win32 Rich Edit control?
(i.e. They shouldn't be able to change the formatting of any text, add graphics, etc.; if they copy-paste new text, only the text should be kept, and associated formatting should be discarded.)
I've never found a particularly elegant way to handle this: what I've done in the past is:
1) Catch WM_KEYDOWN messages for the control and discard all formatting keys (Ctrl+E,J,R,L,1,2,5,+, and Ctrl+Shift+A,7)
2) Catch all paste operations by catching WM_COMMAND messages with an id of ID_EDIT_PASTE, and replace the paste message with a message EM_PASTESPECIAL,CF_UNICODETEXT to the control. (This is with MFC: Depending on what framework or language you're using, this may require catching Ctrl+V and similar rather than ID_EDIT_PASTE.)
Not pretty, I conceed, but it seems to work.
This answer is probably a bit late but for anybody else looking for an answer to this questions, the best way that I've found have total control of paste operations in a Rich edit control is to provide an implementation of IRichEditOleCallback::QueryAcceptData and then return S_FALSE to stop them all together or to filter out certain clip board formats by changing the lpcfFormat parameter.
The CRichEditView::QueryAcceptData function in MFC provides an excellent example of how this can be done. This will work for all kinds of paste operations including drag and drop so is the best way to get full control of what happens.
Even later :)
SendMessage(wndEdit, EM_SETEDITSTYLE, SES_EMULATESYSEDIT, SES_EMULATESYSEDIT)
seems to do the trick: paste pastes plain text, and the formatting hot keys are disabled.
SES_EMULATESYSEDIT: When this bit is on, rich edit attempts to emulate the system edit control (default: 0).
You still retain some of the "bonus" features of the richedit, such as scrollbars on demand.
Note: While this will prevent the pasting of richly formatted text into the RichEdit control, it will also prevent you from programatically formatting the text; all rich formatting is disabled.

How do you create a textbox in visual Studio with c#?

I feel kind of silly asking this question as it seems really simple, but how do I create a text box that I can type in instructions and stuff like that. I don't need the user to be able to change it, it is just to give instructions. I tried the label, but it only allows one line. I need something that can allow about a paragraph or so. Similar to the box in an installer that describes what the program does. What did I miss?
You can use a label but set its AutoSize property to false. This allows you to size the label as you wish and it will automatically wrap the text to fit.
You can also anchor the label to the parent form to have it automatically resize and reflow the text if the user resizes the parent form.
You want a text box, but set its Read Only property to TRUE, and maybe Enabled to FALSE

Changing Win32 menu colors

Is there a way to change the colors used by plain Win32 menus (background, text, and highlight) for a single process, without using SetSysColors?
(SetSysColors does a global change, which is bad, and if you crash or forget to set the colors back with SetSysColors again before exiting, they will not be restored until you logout.)
The SetMenuInfo() API is your friend. It lets you apply any brush to paint your menu's background.
Something along these lines should solve your problem:
MENUINFO mi = { 0 };
mi.cbSize = sizeof(mi);
mi.fMask = MIM_BACKGROUND|MIM_APPLYTOSUBMENUS;
mi.hbrBack = hBrush;
HMENU hMenu = ::GetMenu(hWnd);
SetMenuInfo(hMenu, &mi);
If I believe your comment to Rob, it is for a skinned application, with special look and feel. So the way to go is probably indeed, as ferek points out (in an unfriendly way...) to use owner-drawn menus: you will be able to define precisely their look.
I have to ask, why? Adopting the regular Windows look-and-feel is good; it means users can be confident that there are consistent elements in your user interface, onto which they can map their experience using other software for the platform.
[I'm probably preaching to the converted, of course, but I thought I'd make the point so anyone who reads an answer for this doesn't start making all their menus sky-blue-pink 'cause it looks pretty.]

Resources