MFC: how come change in caret postion in document calls OnUpdateCmdUI? - visual-studio-2010

I was reading about toolbars, and I came across this
Let's say you've derived a toolbar class named CStyleBar from CToolBar that includes a combo box with a list of all the fonts installed in the system. As the user moves the caret through a document, you want to update the combo box so that the item selected in it is the name of the typeface at the current caret position. Rather than respond to each change in the caret position by updating the combo box selection directly, you can override OnUpdateCmdUI as shown here:
void CStyleBar::OnUpdateCmdUI (CFrameWnd* pTarget,
BOOL bDisableIfNoHndler)
{
CToolBar::OnUpdateCmdUI (pTarget, bDisableIfNoHndler);
CString string = GetTypefaceAtCaret ();
if (m_wndComboBox.SelectString (-1, string) == CB_ERR)
m_wndComboBox.SetCurSel (-1);
}
So, the only thing confusing me is, how come moving caret throught the document call OnUpdateCmdUI? and if it doesn't calls OnUpdateCmdUI what else does moving caret thru the document calls?
Any help is appreciated.
Regards.

Moving the caret does not call OnUpdateCmdUI.
According to "The MFC Answer Book", when CWinThread::Run() finds there are no more messages to process, calls CWinThread::OnIdle() which sends WM_IDLEUPDATECMDUI messages to the frame window and all of its children. After a couple more functions, CToolBar::OnUpdateCmdUI() is called.
So, moving the caret does not call the function. It's the main loop, when idle, who asks the mainframe and its children to update themshelves.

Related

wxWidgets pprogrammaticaly move to next input control

I originally had code that set the focus to the first widget in a dialog, in the onInit method. But there were problems with it: if I pressed TAB, indeed focus moved to next control (wxTextCtrl), which got the blue 'focus' color, but the 'focus' color/highlight was not removed from previous focus widget. So now it looked like both first and second control had focus at the same time...
When cycling manually (by pressing TAB) full circle (till last control and then wrap around to the first), suddenly all worked well. That is, when moving focus from first control to next one, the first visually lost focus (blue color was removed) as it should. From now on, only one item had the focus color/highlight.
So instead of setting focus on the first control, I tried a different approach: I set the focus to the last control in the dialog, which is always the OK button. Next, I want to emulate programmatically that a TAB is pressed and received by the dialog. So I wrote this (inside Dialog::onInit):
m_buttonOK->SetFocus();
wxKeyEvent key;
key.SetEventObject(this);
key.SetEventType(wxEVT_CHAR);
key.m_keyCode=WXK_TAB;
ProcessWindowEvent(key);
Now the focus indeed moves away from the OK button, but it does not wrap around to the first control.
Only when I manually press TAB after the dialog opened, the first item gets focus.
Question: why does this wrapping around to set focus on first widget not work with the code shown above?
First of all, your initial problem is almost certainly related to not calling event.Skip() in one of your event handlers, see the note in wxFocusEvent documentation.
Second, you can't send wx events to the native windows, they don't know anything about it. In this particular case you can use wxWindow::Navigate() to do what you want, but generally speaking what you're doing simple can't, and won't, work reliably.

CEdit not set focus automatically

I'v create an Edit control dynamic by calling the constructor function and the Create function of CEdit:
m_pMyEdit = new CEdit;
m_pMyEdit->Create(style,zindex,100,100,100,100,pParentWindow,ID);
As you know, we can pass the this to the parent window parameter or set this parameter to another window. In my code, I passed the parent window parameter the value of:
CWnd::FromHandle(GetDesktopWindow())
This piece of code can get a pointer of CWnd (CWnd*) from the specific handle. Now run program and the Edit window shows at the position as we expect, and the caret shows in the Edit control and the focus is activited. But when I moved this edit to somewhere else, for example, move it to:
RECT rect = {200,200,100,100};
the caret disappear and the focus has been killed, further more, when I move the cursor on it, click mouse, the caret not appear and the focus not set any more. I have read the MSDN again and again, but I don't know why this happens.
By the way, the m_pMyEdit is the var of CEdit, I haven't derived the CEdit class yet.

How to get text/range at a point in an Outlook Inspector?

I want to know the text at a point in for example an Outlook email.
In Excel and Word I am able to get the ActiveWindow. Both object models offer the RangeFromPoint method which I have working.
In Outlook the Applicaion object does have a ActiveWindow but it returns either an Explorer or Inspector object.
Further I tried the following code, however it seems the disabled Word Application object in Outlook does not offer the RangeFromPoint.
Dim ins As Outlook.Inspector = olMail.GetInspector
Dim wDoc As Word.Document = ins.WordEditor
Dim w As Word.Window = wDoc.ActiveWindow
Dim rng As Word.Range = w.RangeFromPoint(mousePosition.X, mousePosition.Y)
I am assuming that Outlook's object model will not help me.
Are there any other methods in the Word Document object model that helps me out?
If the Word Object model does not help must I rely on WinAPI?
If I must use the WinAPI what steps do I need to take?
For example;
Convert Screen point to a window point of the window holding the text (body of the email)
get the text at this point.
What is the best WinAPI to get the text at a point in a Window. Is it to SendMessage with EM_GETSEL?
I tried a few things here.
Why I want to know the text at a point.
I am building custom tooltips into office. When the mouse hovers over a point (through the use of the winapi function TrackMouseEvent) I receive from Windows the point where the mouse is. I then need to know in Outlook (Explorer / Inspector) what the mouse is over.
First Thought - Outlook and Word Object Model alone.
As you can see in the question my first thought was to use the same Window object you can use in Word and implement the RangeFromPoint method. But MS decided to not support this in Outlook. So this is a dead end.
The second option here was to use either or both of these
Selection.Information(Word.WdInformation.wdHorizontalPositionRelativeToPage)
Selection.Information(Word.WdInformation.wdVerticalPositionRelativeToPage)
and / or
Selection.Information(Word.WdInformation.wdHorizontalPositionRelativeToTextBoundary)
Selection.Information(Word.WdInformation.wdVerticalPositionRelativeToTextBoundary)
Vertical relative to page always returned -1 even when the text was clearly in view.
The Relative to Text Boundary returned numbers and they changed with positions but I did not work out where the Boundary was when in the Outlook Inspector. Margins did not help me. This could be a way to do this but i did not work it out.
IUIAutomation or Automation
I have no experience with these however my attempts to get the TextPattern failed on Outlook 2007 and Outlook 2010. I name these versions because I found questions here reporting that they were successful with 2013. I think MS at the time intentionally tried to hide the body of the email to stop ummm slow down email viruses.
WinApi
The text body of the email is in a window of Class _WwG and the contents of the window is not visible. You get "message" as the text. Seems here too MS did this intentionally. Thus trying to get the text at a position is not going to work.
Combination of WinApi and Word Object Model
The solution that I found which works with the Explorer reading panes and with all inspectors is to use a combination of the WinApi and Word.
Receive a mouse hover event with point in a window (_WwG Class for Outlook)
Use SendMessage and send a messsage to this window with the WM_LBUTTONDOWN flag.
Get the Word Document from the Inspector.WordEditor method.
The current Range selected will be where the mouse is located in the text.
Expand the range to the word or whatever you need and now you have what is under your mouse.
For read only windows in Outlook there is no caret visible to the user but it still exists and can be found and used.
I have not implemented this on Outlook items that are being drafted (Cursor is in use and visible), but I suppose I will have to move the selection to the mouse position and then move it back to be able to implement it. I could imagine this is not the best for some users.
Edit
There is one issue with this that I could not solve. By sending a click to the window, you click on what is at that point. If there is a hyperlink there, which is the case with email addresses in a mailItem then it follows the hyperlink. I could not work around this issue properly. The only thing I did find in the WinProc was that when the mouse is over a hyperlink then Outlook shows a tooltip and there is a WM_USER + 2 message. Listen for this message and do not click if this message is received.

Win32: How to custom draw an Edit control?

i need to implement the functionality of EM_SETCUEBANNER, where a text hint appears inside an Edit control:
The catch is that i cannot use version 6 of the Common Controls, which is what is required to get the Microsoft supplied implementation of a cue banner.
i've looked into simply changing the text of the edit control, and the font format to
Dark Gray Italic Text
but it will throw Change events (component wrapper provided by higher component library) that i can't find a way to avoid.
So i was instead going to custom draw the text, drawing the Cue Banner text when the control is unfocused and empty, and rely on default painting otherwise.
The Edit control doesn't nicely expose a custom drawing mechanism, like ListView, TreeView and others provide.
Other people have looked into it, but it seems to be an nearly impossible task:
From the way things are looking, I'll
have to handle the following
messages:
WM_ERASEBKGND, WM_PAINT (for obvious reasons)
WM_SETFOCUS, WM_KILLFOCUS (to prevent
the white bar from displaying --
described above)
WM_CHAR (to process and update the
text in the control)
And I also need to find a way to
display the caret in the control,
since I haven't found a way to allow
Windows to do that for me without also
painting the white bar I mentioned.
This is going to be fun. :rolleyes:
Given that the Windows Edit control was never meant to be custom drawn: does anyone know how to custom draw a Windows Edit control?
Note: i will also accept answers that solve my problem, rather than answering my question. But anyone else wanting to custom draw an Edit control, coming across this question, would probably like an answer.
Custom drawing an Edit control is essentially impossible. There are a few specialized cases were you are doing so little that can get away with it, but you risk breaking badly in the next revision of windows (or when someone runs your app on an older version, or via terminal services, etc).
Just taking over WM_PAINT and WM_ERASEBKGROUND aren't good enough, because the control will sometimes paint on other messages as well.
You are better off just writing your own edit control. I know that's a huge amount of work, but in the long run it will be less work than trying to hack your way into taking over all of the Edit controls' drawing code.
I remember back in the good old days when everyone use to subclass the button control to add color and graphics, etc. The thing is, one day I sat down and just wrote my own button window class. and it was LESS CODE than what we had in our source tree to subclass and custom draw the Windows button.
Create a window class of your own that looks like and empty edit control, that draws the cue text and shows a caret and has focus. Create the edit control also, but position it behind your window. (or leave it hidden)
Then when you get the first WM_CHAR message (or WM_KEYDOWN?). You put your window behind the edit conrol, give focus to the edit, and pass the WM_CHAR message on. From then on the edit control will take over.
You can listen to EN_CHANGE notifications from the edit control if you need to go back to showing your cue text when the edit gets empty. But I'd think that it would be fine to go back to the cue text only when the edit looses focus AND is empty.
Subclassing the EDIT control worked well for me - needed to display some formatting information to the user when editing object attributes (and some attributes could be multiple lines). The important thing, like Adrian said in his answer too, is to call the EDIT control's procedure before your own drawing. Calling it afterward or issuing your own BeginPaint/EndPaint (with return 0 or DefWindowProc) caused issues for me from the text not displaying at all, to it displaying only when resizing but not after editing, to leaving screen litter of the leftover caret. With that, I haven't had any issues regardless of the EDIT control's other repaint times.
Some setup:
SetWindowSubclass(attributeValuesEdit, &AttributeValueEditProcedure, 0, reinterpret_cast<DWORD_PTR>(this));
// Not only do multiline edit controls fail to display the cue banner text,
// but they also ignore the Edit_SetCueBannerText call, meaning we can't
// just call GetCueBannerText in the subclassed function. So store it as
// a window property instead.
SetProp(attributeValuesEdit, L"CueBannerText", L"<attribute value>");
The callback:
LRESULT CALLBACK AttributeValueEditProcedure(
HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam,
UINT_PTR subclassId,
DWORD_PTR data
)
{
...
case WM_PRINTCLIENT:
case WM_PAINT:
{
auto textLength = GetWindowTextLength(hwnd);
if (textLength == 0 && GetFocus() != hwnd)
{
// Get the needed DC with DCX_INTERSECTUPDATE before the EDIT
// control's WM_PAINT handler calls BeginPaint/EndPaint, which
// validates the update rect and would otherwise lead to drawing
// nothing later because the region is empty. Also, grab it from
// the cache so we don't mess with the EDIT's DC.
HDC hdc = (message == WM_PRINTCLIENT)
? reinterpret_cast<HDC>(wParam)
: GetDCEx(hwnd, nullptr, DCX_INTERSECTUPDATE|DCX_CACHE|DCX_CLIPCHILDREN | DCX_CLIPSIBLINGS);
// Call the EDIT control so that the caret is properly handled,
// no caret litter left on the screen after tabbing away.
auto result = DefSubclassProc(hwnd, message, wParam, lParam);
// Get the font and margin so the cue banner text has a
// consistent appearance and placement with existing text.
HFONT font = GetWindowFont(hwnd);
RECT editRect;
Edit_GetRect(hwnd, OUT &editRect);
// Ideally we would call Edit_GetCueBannerText, but since that message
// returns nothing when ES_MULTILINE, use a window property instead.
auto* cueBannerText = reinterpret_cast<wchar_t*>(GetProp(hwnd, L"CueBannerText"));
HFONT previousFont = SelectFont(hdc, font);
SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));
SetBkMode(hdc, TRANSPARENT);
DrawText(hdc, cueBannerText, int(wcslen(cueBannerText)), &editRect, DT_TOP|DT_LEFT|DT_NOPREFIX|DT_NOCLIP);
SelectFont(hdc, previousFont);
ReleaseDC(hwnd, hdc);
// Return the EDIT's result (could probably safely just return zero here,
// but seems safer to relay whatever value came from the edit).
return result;
}
}
break;
Writing your own EDIT control (which I've actually done more than once, to partial degrees of completeness compared to the built-in one) is not much work if you do the bare minimum (maybe English only with basic caret support), but it's a LOT of work to get correct if you want caret navigation over complex scripts with variable sized clusters, selection over ranges, IME support, context menus with copy and paste, high contrast modes, and accessibility features such as text to speech. So unlike so many other answers, I recommend not implementing your own EDIT control merely for cue banner text.
Subclass the edit control. Handle WM_PAINT by first calling the original window procedure and then, if it's empty and not in focus, draw the cue text. Pass every other message to the original window procedure.
I've done this--it works. The problem the CodeGuru person had doesn't seem to apply to your situation. I believe he's trying to do more to the appearance. For performance, it looks like the edit control is doing some updates outside of WM_PAINT processing (probably for performance). That's going to make it nearly impossible to take complete control of the appearance. But you CAN draw the cue prompt.
And I also need to find a way to display the caret in the control,
since I haven't found a way to allow Windows to do that for me without
also painting the white bar I mentioned.
If you want to handle WM_PAINT by yourself without forwarding the message to the original windowproc of your superclass, you should not forget to call DefWindowProc. So that the caret will be drawn.
To avoid the white bar you should remove class brush with SetClassLongPtr.
And somehow keep your DC's clipping region to clip Edit controt's ExtTextOut outputs.
The white bar may be the result of OPAQUE option passed to ExtTextOut by Edit control.
Conclusion: Write your own control. No pain, no gain.

Symbian S60 - Scrolling text in a CEikLabel

I have a single line CEikLabel in my application that needs to scroll text.
The simple solution that comes to mind (but possibly naive) would be something like..
[begin pseduo code]
on timer.fire {
set slightly shifted text in label
redraw label
}
start timer
[end pseudo code]
Using a CPeriodic class as the timer and label.DrawDeferred() on each update.
Do you think this is the best way, it may be rather inefficient redrawing the label two or three times a second.. but is there any other way?
Thanks :)
I've seen the timer based solution used for scrolling item names in listboxes.
A couple of things to watch out for are that it could flicker a bit while scrolling and that you need to make sure the text you put on the label is not too long, otherwise it will automatically clip the string and add an elipsis (...)
Use TextUtils::ClipToFit to get a string that fits on the label and remove the elipsis it adds before putting the text on the label (search for KTextUtilClipEndChar in your clipped string). You will need to work out how many characters to skip at the beginning of the string before passing it to the clip function.
I don't know whether there is another way to do it and can't say whether the approach you have in your mind will be inefficient. However, you may want to take a look at this thread which discusses pretty much the same question as yours and also briefly mentions somewhat the same solution as the one you have conceived of.
I have done it like this
TTimeIntervalMicroSeconds32 scrolltime(70000);
iPeriodicScroll = CPeriodic::NewL(CActive::EPriorityIdle);
iPeriodicScroll->Start(scrolltime, scrolltime, TCallBack(CVisTagContainerView::ScrollTextL, this));
and then in the repeated function
CEikLabel *label = iContainer->Label();
const TDesC16 *temp = label->Text();
if (temp->Length() <= 0) {
if (iTextState != ETextIdle) { return; }
DownloadMoreTextL();
return;
}
TPtrC16 right = temp->Right(temp->Length()-1);
label->SetTextL(right);
label->DrawDeferred();
So text moves right to left, and when all gone, the label is repopulated by DownloadMoreTextL

Resources