How to localize win32 dialogs? - winapi

I am working on Win32 dialogs with various controls like Static Text , Checkbox etc and all the strings need to be localized for different languages.
I have designed the dialogs for US intl . But when I put localized strings those, not fitting properly and I have to change layout for each intl.
Is there a better way to do this?
Can I create one dialogs with one layout that should work with all Intsl???

I remember reading somewhere that, during initial layout of GUI resources at MS, they create the dialogs initially in German, and then double check the layouts at least in English and Japanese.
Once a dialog layout accommodates those three languages, it typically did not require further layout changes.
You could consider using ShowHTMLDialog. If you can work out the black magic of getting data into and out of the dialog HTML does have the advantage of controls that automatically scale to accommodate their text bounds.

In the past I implemented the following derived class from CDialog called CLanguageDialog. Then I called loadLanguage() in the OnInitdialog(). Then all my dialogs in my application would derive from CLanguageDialog instead of CDialog.
void CLanguageDialog::loadLanguage()
{
CWnd *pChild = this->FindWindowEx(this->m_hWnd, NULL, NULL, NULL);
while(pChild)
{
theApp.languageLoader.loadStringForWnd(pChild);
pChild = pChild->GetNextWindow();
}
}

Related

How to get correct background and control colors in property pages?

I'm trying to handle background color properly in a dynamically generated property sheet in dynamically generated property pages in win32 api using MFC (though I expect my question is general, and not restricted to MFC, but since my code and examples use it, it's germane to my question anyway).
So we have a:
CPropertySheet
containing multiple
CPropertyPage
I generate the contents of any given page dynamically - from file resources using a custom dialog definition language - all irrelevant other than to say - a list of controls and their coordinates is created within a given page, and the page is resized to accommodate them. This logic is working beautifully.
However, what doesn't work is that the controls and background of each page draws using the dialog default color/brush.
I've tried a number of ways to attempt to force it to draw using the white color/brush that a hard-coded property sheet / page would.
There are two important pieces to this:
Page Background
Control (on the page) background
For #1, I've tried:
acquire the background brush from parent window class (it's dialog bkgrd) (same is true if I do this and ask the tab control)
change the property page to use WS_EX_TRANSPARENT (PreCreateWindow is not called by the framework when generating a page viz PropertySheet::AddPage)
For #2, I've tried:
overriding OnWndMsg / WM_CTLCOLORSTATIC to forward that request to (A) the parent (sheet), and (B) to the tab control (which is what wants the white in the first place).
However, anytime I use any of the above "ask for the background / forward the request" up the chain to either the sheet or the tab control - I get the dialog background color, never the white I'd expect.
Using Spy64, I can see that for a fully hardcoded property sheet / page - that the only discernable differences I can see is that the dialog window created in AddPage (or its moral equivalent) has WS_CHILD instead of mine which has WS_POPUP (the rest of the styles appear to be the same, such as WS_VISIBLE|DS_3DLOOK|DS_FIXEDSYS|DS_SETFONT|DS_CONTROL and WS_EX_CONTROLPARENT.
So, other than the WS_CHILD, I see no significant differences from what I'm creating and from another property sheet that works properly from a standard resource (i.e. hard coded).
I'm also flummoxed as to how this works normally anyway - since forwarding things like the ctrlcolor message doesn't respond correctly - and asking for the windows background colors similar doesn't - then how is it in a standard case the background colors of controls and pages comes out as white, and not dialog background?
Any ideas or help would be appreciated - I'm kind of running out of ideas...
When Visual Styles were added in Windows XP they really wanted to show off this new feature so they made the tab background a gradient (really a stretched image) instead of a single color and this caused problems in old applications that did custom drawing with the dialog brush as the background.
Because of this, only applications with a comctl32 v6 manifest got the new look but there was a problem; old propertysheet shell extensions would load in new applications (including Explorer) and things would look wrong.
To work around this they also require you (or your UI framework) to call EnableThemeDialogTexture(.., ETDT_ENABLETAB) to get the correct tab page look.
As if things are not tricky enough, there is a undocumented requirement that you also need a button or a static control on the page!
If you have custom controls they have to call DrawThemeParentBackground when you draw if they are partially transparent.
Turns out my old code had defined an ON_WM_ERASEBKGND handler - and removing that (and all of my above attempts) makes it work.
So simply doing NOTHING is the correct answer. D'oh!!!
I'm leaving my shame here in case someone else trips on this! [Whoops!]
(Still interested if anyone has deeper insight into how this mechanism works under the hood)

VB 6 and Right to Left layout windows application

I have an old windows application with it's Ocxs. I want to localize it's OCX to arabic. no problem on changing labels and strings.
but I can't change layout to Right to left.
I find some resources about using Mirroring in windows. but the provided samples don't help me. Link1 & Link2
I'm not a VB fan and don't have enough experience.
Is there any clear and tested approach for VB to mirroring UI?
From Platform SDK 2001
Complex Scripts in Edit Controls
A complex script is a language whose printed form is not laid out in a simple way. For example, a complex script may allow bi-directional rendering, contextual shaping of glyphs, or combining characters. The standard edit controls have been extended to support multilingual text and complex scripts. This includes not only input and display, but also correct cursor movement over character clusters (in Thai and Devanagari script, for example).
A well-written application will receive this support automatically, without modification. Again, you should consider adding support for right-to-left reading order and right alignment. In this case, toggle the extended style flags of the edit control window to control these attributes, as shown in the following example:
// ID_EDITCONTROL is the control ID in the resource file.
HANDLE hWndEdit = GetDlgItem(hDlg, ID_EDITCONTROL);
LONG lAlign = GetWindowLong(hWndEdit, GWL_EXSTYLE) ;
// To toggle alignment
lAlign ^= WS_EX_RIGHT ;
// To toggle reading order
lAlign ^= WS_EX_RTLREADING ;
After setting the lAlign value, enable the new display by setting the extended style of the edit control window as follows:
// This assumes your edit control is in a dialog box. If not,
// get the edit control handle from another source.
SetWindowLong(hWndEdit, GWL_EXSTYLE, lAlign);
InvalidateRect(hWndEdit, NULL, FALSE);
Windows 2000/XP: The standard edit control supports a context menu that allows the user to toggle the reading order and insert/display Unicode bi-directional control characters.

UI layout nightmare with WinAPI

I would like to know what should I do with GUI layout under WinAPI/MFC.
In the ideal world I should just create the form/dialog via resource editor, and everything should just work. In the real world the dialog editor is ancient behemoth from the ice-age and doesn't support most of the comctl32 controls.
This is where the problem creeps up. Dialog editor uses DLU units, and when I create new controls at runtime, I have to express them in pixel offsets.
I stumbled upon one article about calculating DLUs based on font http://support.microsoft.com/kb/145994/en-us, but also saw a warning somewhere that dialogs can have non system fonts in some circumstances, so this approach is not very safe. Plus the article seems to look only at English characters, without regard to all other characters in unicode space which might be wider?.
Has anyone done a research in this direction and found a better way?
P.S.: No Winforms/WPF/Delphi, requirements.
the dialog editor is ancient behemoth from the ice-age and doesn't support most of the comctl32 controls
It doesn't need to support the controls directly, you can still use it just for positioning by inserting it as a custom control and filling in the window class in the property page. For example, that's how I insert link controls in VS2005: as a custom control with class "SysLink".
MapDialogRect (mentioned in the article) is the function that Windows uses to translate the dialog units in the dialog resource to pixel units. MapDialogRect works (where GetDlgBaseUnits fails) because its given an actual handle to the dialog box, and can send it a WM_GETFONT message to retrieve the actual font the dialog will be rendered with.

Big problems with MFC/WinAPI

I need to create a SDI form with a formview that has two tabs, which encapsulate multiple dialogs as the tab content. But the form has to have a colored background.
And things like these makes me hate programming.
First, I tried CTabControl, via resource editor, tried different things, but the undocumented behavior and the quirks with no answers led me into a roadblock.
After many hours of searching, I found that there is a control called property sheet, which is actually what I need.
Some more searching later, I found that property sheet can even be actually embedded onto CFormView like so: http://www.codeguru.com/Cpp/controls/propertysheet/article.php/c591
And that the dialog classes derived from CPropertyPage can be directly added as pages via AddPage method of CPropertySheet.
Great! Not quite so... Some of the controls didn't worked, and were not created, ran into weird asserts. Turns out the DS_CONTROL style was missing from the dialogs. Found it completely accidentaly on Link, no word about that on MSDN!!!! Property page must have: DS_3DLOOK | DS_CONTROL | WS_CHILD | WS_TABSTOP, and can have: DS_SHELLFONT | DS_LOCALEDIT | WS_CLIPCHILDREN styles! Not any other, which are created by default with resource editor. Sweet, super hidden information for software developers!
The quote in comments on that page: "OMG. That's where that behavior came from...
It turns out that the PlaySound API relied on that behavior when playing sounds on 64bit machines." by Larry Osterman, who as I understand works for Microsoft for 20 years, got me laughing out loud.
Anyway, fixed that, the dialog-controls(CPropertyPages) are created as expected now, and that part looks something remotely promising, but the next part with color is dead end again!
Normally you override WM_CTLCOLOR, check for control ID or hwnd and supply the necessary brush to set the color you need. Not quite so with CPropertySheet, the whole top row stays gray! For CTabCtrl it somehow works, for CPropertySheet it doesn't.
Why? Seems that the CPropertySheet is kinda embedded inside CTabControl or something, because if I override WM_ERASEBKGND, only the internal part changes the color.
Now it seems that there is a GetTabControl() method in the CPropertySheet, that returns the actual CTabCtrl* of the CPropertySheet. But since it's constructed internally, I can't find how to override it's WM_CTLCOLOR message processing.
There seems to be a way to subclass the windowproc, but after multiple tries I can't find any good source on how to do it. SubclassWindow doc on MSDN says: "The window must not already be attached to an MFC object when this function is called."?! What's that?
I tried creating a custom CCustomTabCtrl class based on CTabCtrl via MFC wizard, created an instance of it, called SubclassWindow from one of the CCustomPropertySheet handlers to override the internal CTabCtrl, but nothing works, mystical crashes deep inside MFC.
Tried setting WindowLong with GCL_HBRBACKGROUND for the internal CTabCtrl, nothing changed.
And worst of all, I can't find any sort of useful documentation or tutorials on the topic.
Most I can find is how to ownerdraw the tab control, but this is seriously wrong on so many ways, I want a standard control behavior minus background color, I don't want to support different color schemes, windows versions, IAccesible interfaces and all this stuff, and none of the ownerdraw samples I've seen can get even 10% of all the standard control behavior right. I have no illusion that I will create something better, I wont with the resources at hand.
I stumbled upon this thread, and I can't agree with the author more: http://arstechnica.com/civis/viewtopic.php?f=20&t=169886&sid=aad002424e80121e514548d428cf09c6 owner draw controls are undocumented PITA, that are impossible to do right, and there is NULL information on MSDN to help.
So is there anything I have missed or haven't tried yet? How to change the top strip background color of the CPropertySheet? Anyone?
Your only option is to ownerdraw the tab control. It's not that hard. Well, it is frustrating because MFC doesn't tell you how to make the necessary Win32 calls.
In your CPropertySheet-derived class, overwrite OnInitDialog() and add:
GetTabControl()->ModifyStyle(0,TCS_OWNERDRAWFIXED);
This puts your CPropertySheet-derived class in charge of drawing the tab control. Add a handler for WM_DRAWITEM (OnDrawItem) and change backgroundColor and textColor to match whatever colors you wanted. Code for OnDrawItem follows:
void CPropSht::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)
{
if (ODT_TAB != lpDrawItemStruct->CtlType)
{
CPropertySheet::OnDrawItem(nIDCtl, lpDrawItemStruct);
return;
}
// prepare to draw the tab control
COLORREF backgroundColor = RGB(0,255,0);
COLORREF textColor = RGB(0,0,255);
CTabCtrl *c_Tab = GetTabControl();
// Get the current tab item text.
TCHAR buffer[256] = {0};
TC_ITEM tcItem;
tcItem.pszText = buffer;
tcItem.cchTextMax = 256;
tcItem.mask = TCIF_TEXT;
if (!c_Tab->GetItem(c_Tab->GetCurSel(), &tcItem )) return;
// draw it
CDC aDC;
aDC.Attach(lpDrawItemStruct->hDC);
int nSavedDC = aDC.SaveDC();
CBrush newBrush;
newBrush.CreateSolidBrush(backgroundColor);
aDC.SelectObject(&newBrush);
aDC.FillRect(&lpDrawItemStruct->rcItem, &newBrush);
aDC.SetBkMode(TRANSPARENT);
aDC.SetTextColor(textColor);
aDC.DrawText(tcItem.pszText, &lpDrawItemStruct->rcItem, DT_CENTER|DT_VCENTER|DT_SINGLELINE);
aDC.RestoreDC(nSavedDC);
aDC.Detach();
}
Thank you for this solution but...
The above solution works well with one tab, but when you have multiple tabs it seems rename the wrong tabs. I needed to change the if statement for GetItem to:
if (!c_Tab->GetItem(lpDrawItemStruct->itemID, &tcItem )) return;
Needed lpDrawItemStruct->itemID to get the tabs named correctly

How to provide Input to Dialogs designed by Qt Designer

I am a Qt beginner and working with Qt Designer to develop some small UI elements. I read http://doc.trolltech.com/4.5/designer-using-a-ui-file.html to use these GUI elements in my code and using multiple inheritance approach.
I am introducing bookmark feature which somewhat look like http://img293.imageshack.us/img293/3041/screenshotyb.png. Now the problem I am facing is How can I show all existing bookmark folders in the drop down(say folders are in a QVector). So my main problem is how can I pass some inputs to the UI element.
I think I'm clear, please let me know if further explanation is required. Sorry for adding links directly, rich formatting in my browser is not working.
EDIT :
As some suggested, I have to go via code, but in that case is it possible that create all other components like textEdit, labels, buttons and add combobox using code. Because I have already developed code for bookmarks and adding folder feature in already existing thing.
Thanks For suggestions.
Finally I came up with the solution. I was using multiple inheritance implementation of UI file generated by QT Designer. So solution look like :
Dialog.ui will be UI file generated by QtDesigner
//bookmarDialog.h
#include "ui_Dialog.h"
class BookmarkDialog : public QWidget, private Ui::Dialog
{
Q_OBJECT
public:
BookmarkDialog (QWidget *parent = 0);
}
//bookmarkDialog.cpp
#include "bookmarkDialog.h"
BookmarkDialog::BookmarkDialog()
: QWidget(parent)
{
setupUi(this);
QList folders = getAllFolders();
comboBox->insertItems(0,folders);//comboBox is defined in UI file
}
With Qt Designer, you can add items to a combo box (double-click on the combobox to show up the editor). But if your folder list will vary, you'll have to do it by code.
Have a look to QCombobox documentation (Qt doc is really good).
How are your storing your folders in the vector ? As strings ?
Il your QVector is containing strings, you can easily convert it into a QStringList and use it to populate your combobox :
QVector<QString> FolderList;
myComboBox->addItems(FolderList.toList());
Then, you can connect the signal currentIndexChanged(const QString&) of your QComboBox to a slot to do something when the folder has changed.
I think you have to do it in code. You can fill the combo box in the designer as soon as you are using static values. It is something you are doing dynamically like obtaining the bookmarks folders then you have to do it in your business logic code.
Maybe QtDesigner has been improved since the last time I used and now is possible to do complex things like that, but even in that case, from my experience, I would recommend you not to depend so much of QtDesigner. If you want to do complicated things is faster to do it in code and you will commit less mistakes and will have more control over what you are doing.
You can set the values to the combo box like this:
Suppose the vector contains the folder names as strings and is called folders.
for (int i = 0; i < folders.count(); i++)
{
comboBox.addItem(folders.at(i));
}
If this is not what you are looking for give me a comment and I will try to help.

Resources