From: Joseph M. Newcomer on 11 May 2010 22:28 See below... On Tue, 11 May 2010 17:43:15 -0700, "David Ching" <dc(a)remove-this.dcsoft.com> wrote: >"Joseph M. Newcomer" <newcomer(a)flounder.com> wrote in message >news:5mrju51mtsp5d5nvukncshptsgc9lshlum(a)4ax.com... >> Note that retaining the combo box settings after the dialog is dismissed, >> or thinking the >> variable makes sense to do the correct initial selection, indicates >> someone who is living >> in a serious fantasy. The whole scheme is about as totally useless as the >> preloaded combo >> box feature of the dialog editor. >> >> When you go for localization, combo boxes are organized typically >> alphabetically, making >> any assumption about order totally useless. Therefore, the only reliable >> data you can >> have are static controls, edit controls, and check boxes. Nothing else >> can be trusted. >> >> Therefore, I rarely use this capapbility. >> > >Not if you use DDX_CBString which associates a CString to the combobox >value. **** And generally this is useless also. Getting back a string that might say "Black" or "schwartz" or "negro" or "noir" does not convey that I want RGB(0,0,0). **** > > >> If you read what I have written in the past, I have stated that the ONLY >> valid UpdateData >> calls are tnose that happen in the MFC framework, to preload static, edit, >> and checkbox >> controls, or to deliver their values. Anything else must be handled >> explicitly by the >> programmer, because nothing can be trusted to have meaningful values. >> >> And I handle that by putting code in the OnOK method that captures what I >> need to capture >> in the way I need to capture it, and not in some whimsical fashion that is >> sensitive to >> program evolution and localization. >> >> Adding a line to get what I need is not a burden, and it makes the code >> more robust. > >UpdateData() is not whimsical, the results are very defined depending on the >DDX map. Why you would want to manually add data members and initialize >them in the OnOK() is beyond me, when there is a fully automatic alternative >built-in. I don't know what you mean that this is not robust, if you have a >test case that the DDX members are not accurately populated with the >control's values after the DoModal() returns, do tell. **** It generally exposes to the caller the implementation of the controls, which is irrelevant to the caller. The data members I add are designed to be interface-independent, and do not depend on how the implementation works. Since I want this to work on day one and be maintainable for the life of the program, I do not want to use techniques that a change in the UI will make obsolete. I don't WANT a "fully automatic" alternative if it is tied to the implementation I selected today and may want to change tomorrow. It also makes some unfortunate couplings that I may not want; for example, I may want to supply an initial bit vector and get a bit vector back (e.g., a DWORD) and I should not have to care if this requires, say, 32 check boxes or a 32-deep CCheckListBox or a 32-line CListCtrl with check boxes. Currently, DDX does not support this level of independence, and rather than invent entirely new mechanisms I simply write code that maps my representation to controls and controls to my representation, rather than forcing me to use a DDX-specified representation. Robust means "robust under maintenance", that is, the caller does not see or know about my implementation details outside the dialog or CFormView; it is completely neutral. DDX does not come with this "out of the box". **** > >BTW, the same argument holds true when the caller initializes the dialog's >initial state prior to calling DoModal(). By initializing the DDX member >variables, the results are put into the dialog controls on construction, >automatically. **** Yes, I said that; I even use it if all I have is a dialog with a simple edit control. I so rarely have the trivial case that I rarely use the primitive tools I get with MFC. joe **** > >-- David > Joseph M. Newcomer [MVP] email: newcomer(a)flounder.com Web: http://www.flounder.com MVP Tips: http://www.flounder.com/mvp_tips.htm
From: David Ching on 11 May 2010 23:14 "Joseph M. Newcomer" <newcomer(a)flounder.com> wrote in message news:l44ku5pkipf6uadm83inqm08j0b9vchust(a)4ax.com... > And generally this is useless also. Getting back a string that might say > "Black" or > "schwartz" or "negro" or "noir" does not convey that I want RGB(0,0,0). That's true (but see below). > It generally exposes to the caller the implementation of the controls, > which is irrelevant > to the caller. The data members I add are designed to be > interface-independent, and do > not depend on how the implementation works. Since I want this to work on > day one and be > maintainable for the life of the program, I do not want to use techniques > that a change in > the UI will make obsolete. I don't WANT a "fully automatic" alternative > if it is tied to > the implementation I selected today and may want to change tomorrow. It > also makes some > unfortunate couplings that I may not want; for example, I may want to > supply an initial > bit vector and get a bit vector back (e.g., a DWORD) and I should not have > to care if this > requires, say, 32 check boxes or a 32-deep CCheckListBox or a 32-line > CListCtrl with check > boxes. Currently, DDX does not support this level of independence, and > rather than invent > entirely new mechanisms I simply write code that maps my representation to > controls and > controls to my representation, rather than forcing me to use a > DDX-specified > representation. > You keep coming back to "Well, DDX doesn't work in my non-trivial dialogs, so I don't ever use it. Omitting the fact that it works most of the time for most people. What you are proposing is the same as never using a remote control because it doesn't have all the buttons as on the front panel. IOW, if there are corner cases where it doesn't work, you don't use it at all. Man, you should take a gander at WCF RIA Services and see what it's like to have to trust a system you don't understand. It's unreal. But that is the way things are because it lets us solve problems quickly (at least once the concepts are understood which is not trivial) without having to worry about what's under the hood. Your "roll my own" attitude simply doesn't scale, and no amount of useless metrics about lines of code per hour changes that fact. > Robust means "robust under maintenance", that is, the caller does not see > or know about my > implementation details outside the dialog or CFormView; it is completely > neutral. DDX > does not come with this "out of the box". See my previous comment about making DDX variables protected or private. -- David
From: David Ching on 12 May 2010 19:38 "Joseph M. Newcomer" <newcomer(a)flounder.com> wrote in message news:8ntku5h0mp4lppeobsd534slinasr2uort(a)4ax.com... > Key here: explain how there is going to be exactly ONE place where I > specify the mapping > between strings and values, and still use DDX. In my case, I might write > > class CMyParametersDialog :public CDialog { > protected: > CIDCombo c_Colors; > public: > COLORREF m_DesiredColor; > // Set to obtain preselected color on input > // Selected color available after completion > ... other stuff > }; > > In the implementation, I would write: > > static const IDData colors[] = { > {IDS_COLOR_BLACK, RGB(0,0,0)}, > {IDS_CO:OR_RED, RGB(255, 0, 0)}, > {IDS_COLOR_GREEN, RGB(0, 255, 0)}, > {IDS_COLOR_BLUE, RGB(0, 0, 255)}, > {0, 0} // end of table marker > > In OnInitDialog I do > c_Colors.LoadStrings(colors); > if(c_Colors.Select(m_DesiredColor) < 0) > c_Colors.SetCurSel(0); > > in OnOK I do > m_DesiredColor = (COLORREF)c_Colors.GetItemData(c_Colors.GetCurSel())' > > Note that I am always guaranteed GetCurSel will be defined. What doesn't > "scale" about > something this trivial? Or is it just tne notion that I had to write code > to accomplish > what I need the issue? How would you handle this using DDX? > > Now, to add new colors, I simply add new STRINGTABLE names, and the RGB > values, and it > works. And if I fail to add the IDS_ entry to the STRINGTABLE, I get a > compilation error, > not code that subtly fails six months after it is deployed. I don't care > what "name" > IDS_BLACK has in the localized STRINGTABLE, I will always get the correct > mapping between > the selected color and the RGB triple that represents it. This is a > trivial example > because I can encode the value directly in the ItemData component; mostly, > I use much more > complex structures which are referenced by ItemData pointers. > > Note also that if the selected color fails, instead of selecting some > default (such as > whatever the first color is), then I might convert the parameter to an RGB > string and add > it to the combo box, and select that item. LoadStrings and Select are > methods of my > CIDCombo class. I wrote this once, over twelve years ago, and have not > needed to change > it (except to handle 64-bit ItemData) since. And it works, robustly and > reliably. It > makes my code completely insensitive to the actual colors available, and > it means the > caller of the dialog has a *natural* interface (the COLORREF), not some > artifice of an > index of a combo box. > > Yes, you can make the DDX variables private, but then you still have to > write code in > OnInitDialog and OnOK, so what good did DDX do? Instead of having to > recast the problem > into a different domain, I eliminate the need to have lookup tables in > parallel with the > data and just use one table that creates the combobox with the data > preloaded, and > everyone else knows the data, whatever it might be, is preloaded, and not > one line of code > changes if I add more colors; instead, I just add an entry to the preload > table and a > corresponding entry inthe STRINGTABLE (and failure to update both places > means a > compilation error!) and I can "scale up" from 1 color to 256 colors or > 24=bit color if I > want. (Don't tell me about the CColorDialog; I am using colors here to > illustrate a > point. Also, CColorDialog has to be a separate dialog, which is one of > the Really Stupid > Ideas of the "common dialogs", which is that they are necessarily dialogs, > which > introduces an unfortunate modality that does not need to exist, but that's > a separate > discussion) This is a robust implementation and is justified due to the special meanings of the combobox items. Mostly they are ordinary strings with no semantic meaning like a specific color, and all this is unnecessary. Anyway, we seem to be going in circles, so I will stop. I will note that your approach of using the combo box's item data to store a pointer to a struct that takes additional info about the item is not in keeping with modern MVC (model-view-controller), TDD (test driven development) or unit testing, for what that's worth (not much, IMO, but if you want to debate the merits of your advanced scheme, you'll need to talk about that). TDD requires no UI elements be constructed to test the logic, meaning the combobox can't be the thing that stores the list. BTW, the hidden tragedy of sticking with a legacy framework like MFC is that you aren't exposed to modern advanced in application development like the above. -- David
From: Joseph M. Newcomer on 13 May 2010 02:13 See below... On Wed, 12 May 2010 16:38:54 -0700, "David Ching" <dc(a)remove-this.dcsoft.com> wrote: >"Joseph M. Newcomer" <newcomer(a)flounder.com> wrote in message >news:8ntku5h0mp4lppeobsd534slinasr2uort(a)4ax.com... >> Key here: explain how there is going to be exactly ONE place where I >> specify the mapping >> between strings and values, and still use DDX. In my case, I might write >> >> class CMyParametersDialog :public CDialog { >> protected: >> CIDCombo c_Colors; >> public: >> COLORREF m_DesiredColor; >> // Set to obtain preselected color on input >> // Selected color available after completion >> ... other stuff >> }; >> >> In the implementation, I would write: >> >> static const IDData colors[] = { >> {IDS_COLOR_BLACK, RGB(0,0,0)}, >> {IDS_CO:OR_RED, RGB(255, 0, 0)}, >> {IDS_COLOR_GREEN, RGB(0, 255, 0)}, >> {IDS_COLOR_BLUE, RGB(0, 0, 255)}, >> {0, 0} // end of table marker >> >> In OnInitDialog I do >> c_Colors.LoadStrings(colors); >> if(c_Colors.Select(m_DesiredColor) < 0) >> c_Colors.SetCurSel(0); >> >> in OnOK I do >> m_DesiredColor = (COLORREF)c_Colors.GetItemData(c_Colors.GetCurSel())' >> >> Note that I am always guaranteed GetCurSel will be defined. What doesn't >> "scale" about >> something this trivial? Or is it just tne notion that I had to write code >> to accomplish >> what I need the issue? How would you handle this using DDX? >> >> Now, to add new colors, I simply add new STRINGTABLE names, and the RGB >> values, and it >> works. And if I fail to add the IDS_ entry to the STRINGTABLE, I get a >> compilation error, >> not code that subtly fails six months after it is deployed. I don't care >> what "name" >> IDS_BLACK has in the localized STRINGTABLE, I will always get the correct >> mapping between >> the selected color and the RGB triple that represents it. This is a >> trivial example >> because I can encode the value directly in the ItemData component; mostly, >> I use much more >> complex structures which are referenced by ItemData pointers. >> >> Note also that if the selected color fails, instead of selecting some >> default (such as >> whatever the first color is), then I might convert the parameter to an RGB >> string and add >> it to the combo box, and select that item. LoadStrings and Select are >> methods of my >> CIDCombo class. I wrote this once, over twelve years ago, and have not >> needed to change >> it (except to handle 64-bit ItemData) since. And it works, robustly and >> reliably. It >> makes my code completely insensitive to the actual colors available, and >> it means the >> caller of the dialog has a *natural* interface (the COLORREF), not some >> artifice of an >> index of a combo box. >> >> Yes, you can make the DDX variables private, but then you still have to >> write code in >> OnInitDialog and OnOK, so what good did DDX do? Instead of having to >> recast the problem >> into a different domain, I eliminate the need to have lookup tables in >> parallel with the >> data and just use one table that creates the combobox with the data >> preloaded, and >> everyone else knows the data, whatever it might be, is preloaded, and not >> one line of code >> changes if I add more colors; instead, I just add an entry to the preload >> table and a >> corresponding entry inthe STRINGTABLE (and failure to update both places >> means a >> compilation error!) and I can "scale up" from 1 color to 256 colors or >> 24=bit color if I >> want. (Don't tell me about the CColorDialog; I am using colors here to >> illustrate a >> point. Also, CColorDialog has to be a separate dialog, which is one of >> the Really Stupid >> Ideas of the "common dialogs", which is that they are necessarily dialogs, >> which >> introduces an unfortunate modality that does not need to exist, but that's >> a separate >> discussion) > >This is a robust implementation and is justified due to the special meanings >of the combobox items. Mostly they are ordinary strings with no semantic >meaning like a specific color, and all this is unnecessary. *** I cannot remember a time when I have used a combobox represented strings that had no meaning other than being strings. For example, a combo box that represents enumeration constants for an embedded controller, or a combo box that represents enumeration constants for certain options that the user can select (e.g., "No parity, even parity, odd parity, mark parity, space parity" for a serial port). I almost always have to convert between external encodings and combo box indices. **** >Anyway, we seem >to be going in circles, so I will stop. I will note that your approach of >using the combo box's item data to store a pointer to a struct that takes >additional info about the item is not in keeping with modern MVC >(model-view-controller), TDD (test driven development) or unit testing, for >what that's worth (not much, IMO, but if you want to debate the merits of >your advanced scheme, you'll need to talk about that). TDD requires no UI >elements be constructed to test the logic, meaning the combobox can't be the >thing that stores the list. **** Actually, I work in the model that the UI holds the ONLY valid copies of data, and anything else is an illusion. This way, I don't have to deal with deleting my copy of an object if it is deleted from the control, or otherwise have to maintain "background" copies of things that have to be kept in sync with the UI. The UI, and the UI alone, is the arbiter of the values. So there is no need for "unit testing" to work without the UI because in my world, the "unit" to test is the entire dialog. If the problem is so large that it must be tested without a UI, that's a different class of problem than I work on. (My problem domain is the 100K SLOC-250K SLOC, which is a size which is intellectually manageable by one person...I don't work in the megalines-of-code world, where some of these testing disciplines are essential) **** > >BTW, the hidden tragedy of sticking with a legacy framework like MFC is that >you aren't exposed to modern advanced in application development like the >above. **** MFC is a really poor imitation of MVC, which I was using back in the mid-1970s. So I'm not use MVC is a "modern advanced" concept. Unit testing is a concept that dates back to the 1960s. I have found most "modern" ideas to be rewarmed ideas from decades ago, rediscovered and expressed in UML (today's Universal Solution That Makes All Programming Easy) to make them legitimate. In most cases, for programs in the sizes I work in, they are overkill; they address megaline-class issues, important if you have teams of 30 people. I've worked in those environments, but I do not live in those environments today. I work in a one-person environment, and scale my needs accordingly. I know there are beginners out there who think that 20K SLOC is a "massive" program but I rarely work in programs this small, except for little toys I put on on my MVP Tips site. But I do not work any longer in the megalines-of-code world or the multimember team world. So I don't need a lot of the tools these larger projects need. And I don't really care too much about what they do need, because I have no interactions there. So all my answers are relative to the single-programmer model. You don't use my techniques to build missile-control software, gamma-knife software, or nuclear power-plant software. But I do not see many of the participants in this NG as people who work in those environments, either; they are individual programmers working on relatively small projects compared to the scale of the ones I just mentioned. I think we have only one MVP who works in megaline scale. joe **** > >-- David Joseph M. Newcomer [MVP] email: newcomer(a)flounder.com Web: http://www.flounder.com MVP Tips: http://www.flounder.com/mvp_tips.htm
From: David Ching on 13 May 2010 11:01
"Joseph M. Newcomer" <newcomer(a)flounder.com> wrote in message news:255nu5hsbc9m28gqo11hofghu7c7ve31lj(a)4ax.com... > (My problem domain is the 100K SLOC-250K SLOC, which is a size which is > intellectually > manageable by one person...I don't work in the megalines-of-code world, > where some of > these testing disciplines are essential) Heh, these young upstarts are pushing Agile and TDD into the smallest projects these days because it is supposed to be cool. They don't ask what is the size of the project, Agile fits all sizes, don't you know? You can't checkin unless all your unit tests pass. What's that? Oh, it failed because the unit test was out of date, and you had to waste time updating it? Oh well, it's all for the TEAM! (It's funny when management keeps referring to THE TEAM when it turns out there is only one developer on it.) Anyway, like it or not, this is what the software industry is turning into. -- David |