Board index » Visual Studio » How do you interactively write to a CEditView Window
|
Deeno
|
|
Deeno
|
How do you interactively write to a CEditView Window
Visual Studio352
(Newbie): I am trying to output status and diagnostic information to a CEditView Window and allow users input annotations to the same window. The User input is handled by Windows. How do I output to the window? How do I ensure that program output is appended to existing text? DrawText erases the screen and outputs to (0,0). What is the magic? (Please) skidmarks - |
| Doug
Registered User |
Thu Apr 17 12:55:55 CDT 2008
Re:How do you interactively write to a CEditView Window
On Thu, 17 Apr 2008 10:34:00 -0700, skidmarks
<skidmarks@discussions.microsoft.com>wrote: Quote(Newbie): I am trying to output status and diagnostic information to a control using CEdit functions (see GetEditCtrl), and the underlying EDIT control draws itself. -- Doug Harrison Visual C++ MVP - |
| Jonathan
Registered User |
Thu Apr 17 13:03:12 CDT 2008
Re:How do you interactively write to a CEditView Window
skidmarks,
Quote(Newbie): I am trying to output status and diagnostic information to a the most experienced MFC developer. When you use CEditView, you are saying that you will let an EDIT control handle painting within your view window in order to save you the trouble. If you decide to try and draw to that same window, then you and the EDIT control will be overwriting each other and things will not work. There are a couple of approaches to handling this: 1. Eliminate the EDIT control (don't use CEditView) and draw all the text and handle all the editing yourself. As you might guess, this is a major undertaking. The advantage is that you can then display text however and where you like. This is the approach a program like Microsoft Word would take. 2. Combine an EDIT control and your own window within the view. If you don't give your windows a border, you can even make it appear as though everything is part of the same window. Note that I would not use CEditView when trying something like this. 3. Finally, if all you want to do is programatically add text to the EDIT control, if you check the CEditView docs, you can use GetEditCtrl() method to get a reference to the edit control. You can then modify the contents of the EDIT control view the CEdit reference that is returned. You then allow the EDIT control to handle painting those changes to your view window. To insert text at a particular location in the EDIT control, you can use the SetSel() and ReplaceSel() methods. Unfortunately, all but the last item are fairly advanced techniques. -- Jonathan Wood SoftCircuits Programming www.softcircuits.com">www.softcircuits.com - |
| Joseph
Registered User |
Sun Apr 20 15:21:20 CDT 2008
Re:How do you interactively write to a CEditView Window
When I was a newbie I thought edit windows would be good for this purpose. I quickly
learned that they are largely unsuitable for this purpose, and over the years, designed my Logging ListBox control, which is a lot easier to use, much more effective, and does not have the endless set of problems that an edit control has. You can download it from my MVP Tips site. joe On Thu, 17 Apr 2008 10:34:00 -0700, skidmarks <skidmarks@discussions.microsoft.com>wrote: Quote(Newbie): I am trying to output status and diagnostic information to a Web: www.flounder.com">www.flounder.com MVP Tips: www.flounder.com/mvp_tips.htm">www.flounder.com/mvp_tips.htm - |
| Joseph
Registered User |
Sun Apr 20 15:26:15 CDT 2008
Re:How do you interactively write to a CEditView Window
CListBox works EXCEEDINGLY WELL for this purpose, requires no specialized knowledge other
than turning off the "sort" flag in the listbox. But my Logging ListBox allows for copy, cut, well-behaved scrolling, writing to a log file (immediately or on demand) and several other features, and is VERY easy to use once it is set up. I might do something like log->PostMessage(UWM_LOG, new TraceFormatComment(TraceEvent::None, _T("The answer is now %d"), answer))); although for localization I'm more likely to write log->PostMessage(UWM_LOG, new TraceFormatComment(TraceEvent::None, IDS_ANSWER, answer), answer)); It supports using STRINGTABLE ids for messages, and as shown by the use of PostMessage allows messages to be logged from separate threads quite readily. All you have to do is put an appropriate user-defined message handler in the window and identify the window to which the logging is done. Or call the AddString method directly. joe On Thu, 17 Apr 2008 12:03:12 -0600, "Jonathan Wood" <jwood@softcircuits.com>wrote: Quoteskidmarks, Web: www.flounder.com">www.flounder.com MVP Tips: www.flounder.com/mvp_tips.htm">www.flounder.com/mvp_tips.htm - |
| skidmarks
Registered User |
Mon Apr 21 15:40:22 CDT 2008
Re:How do you interactively write to a CEditView WindowQuote3. Finally, if all you want to do is programatically add text to the EDIT I just looked at VC Help. 1. The SetSel function allows specification of the start byte and end byte in the first parameter DWORD. This gives a 1 6-bits *(65,526) reference in the Edit Window. Isn't this restrictive? 2, Thanks. You've got my little grey cells going. To decrease simultaneous writes can I use the buffer lock/unlock functions? skidmarks - |
| Jonathan
Registered User |
Mon Apr 21 16:57:05 CDT 2008
Re:How do you interactively write to a CEditView Window
skidmarks,
Quote1. The SetSel function allows specification of the start byte not a combined DWORD. Internally, the start position goes in wParam and the end position goes in lParam. So, no, that limitation does not exist. At least not with 32-bit Windows. -- Jonathan Wood SoftCircuits Programming www.softcircuits.com">www.softcircuits.com - |
| skidmarks
Registered User |
Mon Apr 21 17:26:10 CDT 2008
Re:How do you interactively write to a CEditView Window
Joseph;
Thank you for helping the hapless. I do have a comment based on a previous comment on using SetSel and ReplaceSel (which maybe you can comment on). In using SetSel followed by ReplaceSel it seems to work, except that I can't seem to append a leading carriage return ("\n") to force the output to the next line. What I have tried to do is to prevent an issue with an attempt to write by the user and the program from causing problems by using LockBuffer and UnlockBuffer. The question I have is why this ReplceSel and SetSel won't work, or maybe, work correctly? What am I missing? I am looking at your MVP code for logging and will probably gratefully adopt it for perhaps this, but most certainly for other things. The residual question is can I change the project to use CListBox for the project view and incorporate your code? This seems like a lot of work. And as always, you have left jewels. Thanks skidmarks - |
| Joseph
Registered User |
Mon Apr 21 22:03:40 CDT 2008
Re:How do you interactively write to a CEditView Window
To put a newline sequence in, you have to use "\r\n". One of the problems of using the
SetSel/ReplaceSel is that if you scroll the edit control back to see something, it rips the focus away from where you are and leaves you at the end of the control again. This is very disruptive to the user (my Logging ListBox, for example, decides if it should auto-scroll or not scroll based on the position you are looking at; if you scroll back it won't rip your attention back to the end just to do the append) As to how much work it is, that's hard to judge. Typically, I will do something like c_Log.AddString(new TraceComment(...))); if I'm not using threads, so if you had c_Log.SetSel(...at end...); c_Log.ReplaceSet(_T("\r\nThis is a message")); I would write c_Log.AddString(new TraceComment(_T("This is a message"))); so it isn't all that much effort to convert. I've done it a couple times when clients sent code that was using a CEdit to log data. Depends on how many instances you have, and whether or not you are doing partial-line output. Most forms have a TraceSomething and a TraceFormatSomething, where the TraceSomething usually has a form with a UINT and with an LPCTSTR, so you can easily use the STRINGTABLE, and the TraceFormatSomething usually has a form with a UINT and an LPCSTR as a formatting string and then use the usual varargs to supply arguments. joe On Mon, 21 Apr 2008 15:26:10 -0700, skidmarks <skidmarks@discussions.microsoft.com>wrote: QuoteJoseph; Web: www.flounder.com">www.flounder.com MVP Tips: www.flounder.com/mvp_tips.htm">www.flounder.com/mvp_tips.htm - |
| skidmarks
Registered User |
Tue Apr 22 07:18:01 CDT 2008
Re:How do you interactively write to a CEditView Window
Thanks Joe.
skidmarks - |
| Joseph
Registered User |
Tue Apr 22 10:35:54 CDT 2008
Re:How do you interactively write to a CEditView Window
Oops, that should be
new TraceComment(TraceEvent::None, _T("whatever")); because I allow an integer to be displayed in the left column; TraceEvent::None says "don't display an integer, leave the column blank" joe On Tue, 22 Apr 2008 05:18:01 -0700, skidmarks <skidmarks@discussions.microsoft.com>wrote: QuoteThanks Joe. Web: www.flounder.com">www.flounder.com MVP Tips: www.flounder.com/mvp_tips.htm">www.flounder.com/mvp_tips.htm - |
| skidmarks
Registered User |
Tue Apr 22 16:01:00 CDT 2008
Re:How do you interactively write to a CEditView Window
Joe;
I've got a little issue with one of your statements on why not to use <CEditCtrl>.SetSel and <CEditCtrl>.ReplaceSel. Remember I'm a newbie not so much trying to make a name for myself as trying how best to do a task. Your prior post indicated an issue with scrolling. When you scroll the CEditView window this puts the cursor out of sorts and using the <CEditCtr> methods leads to putting text in the incorrect position on screen. I tried that. Works fine - code below. My guess is that the caveat should be to use <CEdit>.GetBufferLength to determine the placement location. In any case. are there other issues? ================================================== // Selecting Menu Item "Test" causes execution void <CAppView>::OnTestText() { static const char Message[] = _T("\r\n\nThe Last Message Is:\r\n"); static const int MsgSz = sizeof(Message); CEdit& y = GetEditCtrl(); int Lo = GetBufferLength() + 1; int Hi = GetBufferLength() + MsgSz - 1; DWORD Wrd = Hi << 16 | Lo; LockBuffer(); y.SetSel(Wrd); y.ReplaceSel(Message); UnlockBuffer(); - |
| Joseph
Registered User |
Tue Apr 22 21:34:55 CDT 2008
Re:How do you interactively write to a CEditView Window
See bekiw,,,
On Tue, 22 Apr 2008 14:01:00 -0700, skidmarks <skidmarks@discussions.microsoft.com>wrote: QuoteJoe; have scrolled the window back to see some earlier output, as soon as a new line is added, the window is repositioned to the end, so you have to scroll back again, at which point, while you are reading, the next line added scrolls you back to the end of the text, and so on. Miserable to use, and trying to control the flashing and deal with the user resetting the cursor adds further complexity. Performance also degrades as the contents get longer and longer, because doing things like finding the end takes longer and longer, and the ReplaceSel causes a reallocation of the buffer so the whole buffer has to be copied. Using a list box means never having to say "reallocate the buffer", so the performance remains essentially constant no matter how many items you have. My control also allows you to set a maximum limit on the number of items, and will remove them from the front of the control after the limit is hit. A simple CListBox is a better choice, but then it won't automatically scroll, although you can see how I handle this in my control, and use just that much of the control. It isn't a question of making a name for anything or anyone; it's a question of coming up with a solution that works well. CEdit just doesn't work well. **** Quote
the initializer is Unicode-aware and will generate a Unicode string in a Unicode build, so this would fail to compile. You could write static const TCHAR Message[] = _T("..."); but then sizeof is wrong; the correct way to write it would be static const int MsgSize = (sizeof(Message) - 1)/sizeof(TCHAR); note that sizeof() a string will include the NUL character, while what you really want is the length of the string, not the length of the array. In fact, you should forget the existence of sizeof(). There is a _countof() defined in VS2005, but you can easily define it yourself: #define _countof(x) (sizeof(x) / sizeof( (x)[0]) ) (This is the oversimplified version; there is a much fancier version that is C++ compatible, but the above will do for now) **** Quote
The code you wrote would be incorrect if GetBufferLength() returned a value>65535. **** Quote
that you are using the wrong form of SetSel; you should be calling y.SetSel(Lo, Hi); y.ReplaceSel(Message); which will do the same thing but which will work correctly if the edit control contains more than 64K characters. What do LockBuffer/UnlockBuffer do? joe **** QuoteUnlockBuffer(); Web: www.flounder.com">www.flounder.com MVP Tips: www.flounder.com/mvp_tips.htm">www.flounder.com/mvp_tips.htm - |
| Joseph
Registered User |
Tue Apr 22 21:37:59 CDT 2008
Re:How do you interactively write to a CEditView Window
What do you mean by "simultanous updates"? There should be no such concept; there is one,
and ONLY one, thread that is permitted to access this control, which is the main GUI thread, and it cannot perform more than one update at a time, and therefore "simultaneous" updates are impossible. If you are using threads, you must NOT, repeat NOT, touch any control owned by the main GUI thread from any secondary thread for any reason. See my essay on worker threads; a thread would PostMessage the information to be displayed to the main GUI thread, which would do the update. Any attempt to manipulate a control directly by any thread other than its owner will lead to situations in which you can get deadlock. joe On Mon, 21 Apr 2008 13:40:22 -0700, skidmarks <skidmarks@discussions.microsoft.com>wrote: Quote
Web: www.flounder.com">www.flounder.com MVP Tips: www.flounder.com/mvp_tips.htm">www.flounder.com/mvp_tips.htm - |
| skidmarks
Registered User |
Wed Apr 23 08:33:00 CDT 2008
Re:How do you interactively write to a CEditView WindowHey Joe. "Joseph M. Newcomer" wrote: Quote
Quotebut the initializer is Unicode-aware and will generate a Unicode string in a was created 'Unicode' was not selected and therefor no issue. Quote**** --- New about the 64k limit, didn't know how to solve it. Quote
does not include SetSel(Lo, Hi) as an option. I will try it and hope it works. Quote
program into the CEditView buffer. At the end I think the case for NOT using a CEditView and using a CListBox is conclusive, final, solid reasoning, and drat!!! As soon as I can I'm going to change the code and use yours, with accreditation. Thank you for your time. You have convincingly and conclusively nailed the idea of using a CEditView into a coffin. Sigh. A programmer's life is never easy (but it is very rewarding). skidmarks Quotejoe |
| Joseph
Registered User |
Wed Apr 23 10:38:57 CDT 2008
Re:How do you interactively write to a CEditView Window
See below...
On Wed, 23 Apr 2008 06:33:00 -0700, skidmarks <skidmarks@discussions.microsoft.com>wrote: Quote
with reality. Therefore, had you written static const char Message[] = "\r\nThe Last Message is:\r\n"; it would have merely been poor style using what is now thought of as an obsolete data type. But what you have above, using char on one side and _T() on the other, is out-and-out wrong. **** Quote
char x[] = L"abc"; can work because it is not a legal assignment. You can't assign a wchar_t* to a char* or a wchar_t[] to a char[]. VC2003 produces the following message: char data[] = L"ABC"; // <= line 6 i:\tests\wct\wct\wct.cpp(6) : error C2440: 'initializing' : cannot convert from 'const unsigned short [4]' to 'char []' There is no context in which this conversion is possible **** Quote
solves it. **** Quote> CEditView::LockBuffer Call this member founction to obtain a pointer to the buffer. The buffer should not be modified. And what do you do? You modify the buffer! Drop the code. **** Quote
Web: www.flounder.com">www.flounder.com MVP Tips: www.flounder.com/mvp_tips.htm">www.flounder.com/mvp_tips.htm - |
