Prev: How to show underlined menu shortcut letters by default for a contextmenu ?
Next: panel method (from Java) in MFC
From: Joseph M. Newcomer on 22 Jun 2010 12:52 See below... On Tue, 22 Jun 2010 08:05:07 -0700 (PDT), mfc <mfcprog(a)googlemail.com> wrote: > >first of all, thank you very much for your support. It is also my >first programm in MFC and with C++. > >> >is it much better to create all the buttons from a view in the >> >OnInitialUpdate() method instead of placing the buttons with the >> >resource editor.... >> >> **** >> No. In fact, the simplest categorization is that is always and forever a MISTAKE to try to >> do this. �The truth is more complex than that, but this simple guideline will serve you >> well. >> ***** > >Ok, I hope I got you right: You should install all button items and so >on in the resource-editor (dialog-box) and add all specific code (like >images for the buttons) in the OnInitialUpdate() and OnUpdate() >method. That means if I use more than one language I will use the >function LoadString() in the OnUpdate() method in each view to load >the correct text string to each specific item in the current dialog >box. > >But how will I get the specific ID (of each item from the dialogbox) >in the view-class to add additional things like images, textstrings? >>>>m_btnMenu1Ok.SetButtonImg(IDB_BTN_IMG_OK, IDB_BTN_IMG_OK_PRESSED); >>>>m_btnMenu1Ok.SubclassDlgItem(IDC_MENU1_BTN_BACK_OK, this); **** Yhy do you need to call SubclassDlgItem? You have not explained the reason you want to do this. You will either have CButton variables which you will create in the dialog editor (right click on the control; Add Variable) or you have your own custom class, e.g., CMyButton, that you will use for these variables. No need to call SubclassDlgItem./ **** > >With this line, the Cbutton object m_btnMenu1Ok will be connected to >the cbutton, drawn in the dialog with this id >(IDC_MENU1_BTN_BACK_OK).... **** But that's what the ClassWizard does for you. Right click, Add Variable **** > > >Ok I think I found the correct function for that: if it is also >working in a sdi app. > >void CApplicationDlg::DoDataExchange(CDataExchange* pDX) >{ > CDialog::DoDataExchange(pDX); > DDX_Control(pDX, lblExample, m_lblExample); **** The Add Variable menu item creates the variables and adds these lines to DoDataExchange for you. **** >} > >After that: add a string from the string-table: >m_lblExample.SetWindowText(m_pLanguage- >>GetString(IDS_EXAMPLE).c_str()); **** What is c_str()? Oh, you are using std::string? This would be wrong in an MFC program. std::string Does Not Play Well with MFC functions. Use CString. By the way, if the purpose of this is to get the string contents c_str() is the wrong thing to do. You have not specified what GetString does, so I have no idea why it needs to exist. A sensible function might be CString GetString(UINT id) { CString s; s.LoadString(id); return s; } or, if the m_pLanguage method has the DLL in it, you might do CString GetString(UINT id) { CString s; s.LoadString(DLLhandle, id); return s; } But those are the only two implementations that make sense to me; it sounds like the definition is void GetString(UINT id, LPTSTR s) and that would be a very, very, VERY bad design. As an alternative, which doesn't seem to have much value, you might consider void GetString(UINT id, CString & s) but I don't like that approach. Forget LPTSTR exists. Forget std::string exists. If you need to use them in a library, you have probably made a mistake. **** > > > >> **** >> Why do you think white makes sense here? �Why did you not use >> � � � � ::GetSysColor(COLOR_WINDOW) >> for the color? �Either follow the user's color scheme, or don't do ANYTHING! >> ****>m_btnMenu1Ok.SetColor(CImageTextButton::BTNST_COLOR_FG_OUT, RGB(150, >> >150, 150)); >> >> **** >> What could 150, 150, 150 POSSIBLY mean? �Did you not mean >> � � � � ::GetSysColor(COLOR_BTNFACE) >> ? >> >> FOLLOW THE USER'S COLOR SCHEME! >> ****>m_btnMenu1Ok.SubclassDlgItem(IDC_MENU1_BTN_BACK_OK, this); >> >> **** >> You are in such deep trouble here. �Why in the world would you SubclassDlgItem? �If you >> are calling this, you are not using MFC correctly! �Even if you create buttons >> dynamically, you would not need to do this! >> ***** >> >> >I`ve read in the www that SubclassDlgItem() is not a safe method - is >> >this statement true? Maybe someone of you could give me some more >> >information about this statement to improve me knowledge... >> >> ***** >> It is an indication that you have no idea how to use MFC correctly. �So if you need to do >> it, re-examine what you are doing! �When I was clueless about MFC, I once wrote it (some >> time in my first or second MFC program) and was given similar advice. >> >> There is no need to use it. �So don't. >> ***** > >As you pointed it out - I`m very new to c++ and to mfc: But I`ll learn >this language - and therefore it would be great if you could point it >out why this function (SubclassDlgItem()) is useless? Is it a unsafe >method? Or is it a global function? **** Because you only need to create the variables using Add Variable. Then the SubclassDlgItem is automatically done for you deep in the innards of MFC. It is not unsafe. It is not global, it is a method of the CWnd class, but it makes no sense to use it when there is a much better mechanism and a much more standard approach to the problem. Also remember: if you ever do GetDlgItem, you are using MFC incorrectly (there are VERY rare and exotic exceptions to this guideline, and I end up writing about one GetDlgItem per year when I hit those exotic circumstances) The only places I know it is still reasonable to actually code a control ID in application code is (a) the aforementioned extremely exotic circumstances (b) CheckRadioButton (c) ON_COMMAND_RANGE message map entries and their handlers (d) if you are adding a DoDataExhcnage call by hand, normally a rare occurrence/ There may be a couple I forgot, but mostly you want to avoid ever using a control ID in source code outside those cases. **** > > > >> >Version2: create the whole button in the OnInitialUpdate() method >> >> >m_btnMenu1Ok.Create("OK", WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, >> >CRect(10, 10, 30, 30), this, 1); >> >> **** >> First the CRect is a colossal blunder. �Where in the world did you get the idea that >> 10,10,30,30 could possibly make sense? �Sure, on YOUR machine, with YOUR display, YOUR >> graphics card, YOUR current version of the display driver, YOUR current resolution, and >> YOUR default font size, but unless the program is now and forever going to run on YOUR >> machine and you will never, ever change any one of these settings or components, it cannot >> possibly run correctly anywhere else. �So don't do it. > >Thanks for the hint - I didn`t recoginze it.... And 10,10,30,30 was >only a example.... **** For demo purposes, I usually write things of the form CRect r; .....fill in values in r... whatever.Create(..., r, ...); to make it obvious that I am doing some work to figure out what the correct values of r ought to be. So I never just "plug in" values in a code example. The reason I pointed this out was that so many beginners work really hard to figure these numbers out, not realizing that their code will never work correctly anywhere else but on their machine. joe **** > >> >> In situations where I have to create buttons dynamically (because the number of buttons is >> based on some only-known-at-run-time set of parameters) I will always create an >> *invisible* button on the dialog, and use it to get the necessary parameters, e.g., >> >> � � � � CRect r; >> � � � � c_ButtonPrototype.GetWindowRect(&r); >> � � � � ScreenToClient(&r); >> >> This will give me the width and height I need; for positioning, I usually place some >> control on the dialog I can use as a reference point (sometimes an invisible CStatic) and >> use it to determine the top and left of an array of buttons. �I usually separate them by >> some platform-independent computation, like 3 * ::GetSystemMetrics(SM_CXEDGE) or 3 * >> ::GetSystemMetrics(SM_CYEDGE) or some similar computation that will work on every screen, >> every resolution, etc.. >> >> Assume that ANY hardwired integer you use for computing position, unless it is a simple >> multiplier or divisor of a runtime-determined value, is erroneous. >> >> For example, to center a button, I will use >> � � � � CRect r; >> � � � � GetClientRect(&r); >> � � � � CRect b; >> � � � � c_OK.GetWindowRect(&b); >> � � � � ScreenToClient(&b); >> � � � � c_OK.SetWindowPos(NULL, �r.Width() / 2 - b.Width() / 2, >> � � � � � � � � � � � � � � � � � � r.Height() / 2 - b.Height() / 2, >> � � � � � � � � � � � � � � � � � � 0, 0, >> � � � � � � � � � � � � � � � � � � SWP_NOZORDER | SWP_NOSIZE); >> >> and this will put the button dead center in the dialog. �But if you EVER choose an >> absolute coordinate or size, you are DEAD WRONG. �This includes font sizes. >> >> What is "1" for a control ID? �Did you not mean IDOK? �And what is English-language text, >> and 8-bit text at that, doing in a source program? >> >> OK, a new record. �There are FOUR things wrong with the above line, not the least of which >> is its very existence! >> *****>m_btnMenu1Ok.SetButtonImg(IDB_BTN_IMG_OK, IDB_BTN_IMG_OK_PRESSED); >> >m_btnMenu1Ok.SetFont("Arial",16); >> >> **** >> You should not be deciding either the font or its size! �Why do you think Arial 16 could >> possibly make sense? �Because it sort-of-looks-like what you are seeing? �In exactly which >> version of Windows? �(Did you know that Microsoft has changed the default dialog font >> appearance in every recent version of Windows? �You should not presume your dialog is >> going to run on the same version of the operating system, including service pack, that you >> are using!) >> >> When you create a dialog control explicitly, the best way to set the font is >> � � � � CFont * f = GetFont(); >> � � � � ctl.SetFont(f); >> which uses the same font as the dialog, and this font will track OS versions and user >> preferences. �It will look like all the other dialogs the user has, and its size will >> track properly. >> *****>m_btnMenu1Ok.SetColor(CImageTextButton::BTNST_COLOR_FG_IN, RGB(255, >> >255, 255)); >> >m_btnMenu1Ok.SetColor(CImageTextButton::BTNST_COLOR_FG_OUT, RGB(150, >> >150, 150)); >> > > >best regards >Hans Joseph M. Newcomer [MVP] email: newcomer(a)flounder.com Web: http://www.flounder.com MVP Tips: http://www.flounder.com/mvp_tips.htm
From: Mihai N. on 23 Jun 2010 03:23
> That means if I use more than one language I will use the > function LoadString() in the OnUpdate() method in each view to load > the correct text string to each specific item in the current dialog > box. No, you don't do that. You have a DLL with resources only and that is localized. So you get a full dialogs, for instance, with all the text, fonts, size info, get menus, strings, etc. All you have to do is load the resource dll with LoadLibrary and call AfxSetResourceHandle http://msdn.microsoft.com/en-us/library/d8ws31ff%28VS.80%29.aspx From that point on everything you load as resource comes from that localized dll. Take a look at this example, http://msdn.microsoft.com/en-us/goglobal/bb688102.aspx And read some of the stuff here: http://msdn.microsoft.com/en-us/library/dd317706%28VS.85%29.aspx (at least the "Development of MUI Applications" section) And the MUI APIs here: http://msdn.microsoft.com/en-us/library/dd319074%28v=VS.85%29.aspx -- Mihai Nita [Microsoft MVP, Visual C++] http://www.mihai-nita.net ------------------------------------------ Replace _year_ with _ to get the real email |