MFC、VS2012
ボタンクリックでウィンドウ全体にWS_EX_LAYOUTRTLを適用させたいのですが、
部分的にしか適用されず困っています。
VS2012のリソースエディタで画面プロパティ[Layout RTL]を
有効にすると画面のタイトルバー・テキスト・ボタンなど全てのコントロールが
WS_EX_LAYOUTRTLが反映されたのですが、
void CChangeDlg::OnBtnClick()
{
this->ModifyStyleEx(0, WS_EX_LAYOUTRTL);
}
としてボタンクリックで動的に変更させようとすると
タイトルバーしか反映されません。
コントロール全体に対して、動的にWS_EX_LAYOUTRTLの適用は可能でしょうか?
よろしくご教授お願いいたします。
>タイトルバーしか反映されません。
this(つまりこのウインドウ)だけしかやってないようなので、
当然な気がします。
全ての子ウインドウ、または、適用したい子ウインドウに対して
スタイルの変更をやらないといけないと思ういます。
リソースエディタではウィンドウのみ設定する事で
全体に反映されるのですが、動的に変更したい場合は個々に
設定しないといけないのでしょうか?
試しにスタティックテキストに WS_EX_LAYOUTRTLを
適用させてみたのですが、リソースエディタで設定した場合と
挙動が異なります。
リソースエディタで設定時は文字が右寄り+スタティックテキストも右寄り
になるのですが、
m_text->ModifyStyleEx(0, WS_EX_LAYOUTRTL);
とすると中身の文字は右寄りになるのですが
スタティックテキスト本体は右寄りになりません。
コントロールに対しては他に設定が必要でしょうか?
1.リソースエディタ設定の結果は*.rcの中身をみれば
便宜的にやってくれているのだな、ということがわかります。
2.起動中のコントロールにどのようなスタイルが適用されているのかは、
Spy++を使えば見ることができます。
3.また、拡張も含めて、ウインドウスタイルの一部は
すべてのウインドウに適用できるわけではありません。
4.拡張スタイルの一部は、CreateWindow時に適用できないものがあります。
以上のような点に注意して調べてみてはどうでしょう。
うーーん、
スタティックテキストは特殊なのでウインドウスタイルを動的に変更
するのは難しかったと思います。
(できなかったケースが多い)
エディットボックスは、リッチエディットに変えたほうが動的に変更するのは
楽です。
リソースエディタで設定した場合と動的に変更した場合で
スタイルの違いは無く、どちらもWS_EX_LAYOUTRTLが適用されていました。
ただ、見た目の挙動だけが異なっています。
スタイルの動的変更は技術的に無理なのでしょうか?
皆さんならこの場合どうするのか、何か案を頂けると助かります・・・
ITOさんも仰ってますが、ウィンドウスタイルは生成時にしか反映されないものがあるの
で、変更できないスタイルを切り替える場合は、コントロールの破棄+生成で切り替えて
ます。
あと、スタティックコントロールだったら、描画を全部自前でやっちゃうこともありますね。
流し込む画像ファイルを切り替えて・・・という感じで見た目を変える場合が多いです。
ピクチャボックスを使う手もありますね。
CDC +pDCも取得できるので自由に描けます。
SDKで
ダイアログにIDC_STATIC_TEXT, IDC_BUTTON_LAYOUTをつくり、
case WM_COMMAND:
if(LOWORD(wParam) == IDC_BUTTON_LAYOUT)
{
HWND hwnd = GetDlgItem(hDlg, IDC_STATIC_TEXT);
LONG ex = GetWindowLong(hwnd, GWL_EXSTYLE);
SetWindowLong(hwnd, GWL_EXSTYLE, ex ^ WS_EX_LAYOUTRTL);
InvalidateRect(hwnd, 0, TRUE);
}
これで、IDC_STATIC_TEXTの文字列は、IDC_BUTTON_LAYOUTを押す毎に左右に動きました
(win7)。
質問を誤解していました。私の上記書き込みを削除します。
> リソースエディタで設定時は文字が右寄り+スタティックテキストも右寄り
> になるのですが、
> m_text->ModifyStyleEx(0, WS_EX_LAYOUTRTL);
> とすると中身の文字は右寄りになるのですが
> スタティックテキスト本体は右寄りになりません。
やっと意味がわかりました。
対策は、各コントロールを移動するしかないと思います。
WS_EX_LAYOUTRTLがある場合、
ダイアログ作成時に各コントロールはダイアログの右上を原点として位置決めされます。
各コントロールの位置は、作成後には変わりませんです。
返信遅くなって申し訳ありません。
回答ありがとうございます。
頂いた回答を見る限り、スタイルの動的変更は難しいのですね・・・
ARさんの仰った、ウィンドウ破棄+生成で対応しようかと思います。
Win32ならばCreateWindowExにパラメータを指定すれば良いみたいですが、
MFCでは生成時にスタイルを指定するのはどこが良いのでしょうか?
DoModalで表示するウィンドウではPreCreateWindowのようなものは
無いようですし・・・・
WM_CREATEをオーバーライドしたOnCreateで指定できそうなんですが、
以下の方法では反映してくれませんでした。
ここのタイミングではウィンドウが既に生成されていて遅いんでしょうか?
int OnCreate(LPCREATESTRUCT lpCS)
{
lpCS->dwExStyle += WS_EX_LAYOUTRTL;
if(CDialog::OnCreate(lpCS) == -1)
return -1;
return 0;
}
>頂いた回答を見る限り、スタイルの動的変更は難しいのですね・・・
厳密には、スタティックテキストのように大量に使われるコンポーネントは、軽量なコ
ンポーネントにする必要がある→大胆に機能を削る必要があったという事だと思います。
またITOさんのおっしゃってる通りなんですが、凝ったことがしたければ高機能なコン
ポーネントを使え、その代わり大量に使うと重くなる、と言うことだと思います。
>Win32ならばCreateWindowExにパラメータを指定すれば良いみたいですが、
>MFCでは生成時にスタイルを指定するのはどこが良いのでしょうか?
MFCならCStatic::Create()で、拡張属性も指定できるCreateEx()はMSDNに存在してません。
ただMFCでもWin32APIでもやることは大差ないので、CreateWindowEx()を使用するのが
一番簡単だと思います。
一応、CWnd::CreateEx()のヘルプをみると、スタティックテキストの生成サンプルも
載ってるので参考にしてください。
https://msdn.microsoft.com/ja-jp/library/atzdh4ys.aspx
あと、OnCreate()はCreateWindowEx()などを使った結果として、WM_CREATEのイベント
が発生し、そのイベントを受け取った時に呼ばれるメソッドですので混同しないようにし
てください。
例えば、OnCreate()は生成した後に呼ばれるものですし、
>lpCS->dwExStyle += WS_EX_LAYOUTRTL;
足し算じゃなくて論理和使ってくださいとか、
PreCreateWindow()はイベントメソッドじゃなくてオーバーライドメソッドでしょうとか、
そもそも、ダイアログに対してWS_EX_LAYOUTRTL属性を付与してどーするんです
か?・・・この辺りが突っ込みどころでしょう。
え~と、いまさらで申し訳ないのですが、
Right to Left を使うってことは、各国語対応したいってことでよいですよね。
最近のMFCでは複数言語に対応する場合、
言語毎のサテライトDLL(リソースのみのDLL)を作れって事らしいです。
んで、各言語毎のサテライトDLLにはDLGのテンプレートリソースごと入るわけで、この場
合、
1.そもそも、動的にスタイル変更する必要が「無い」
ってことになります。
スタティックコントロールの位置なども、この場合、
例えば、「アラビア語専用リソースDLL」等に実装されるわけで、
アラビア語用にガチにレイアウトしてOKというわけです。
う~む、どうもすみません(vv;)。
>ARさん
ダイアログに対してWS_EX_LAYOUTRTL属性を付与する意味は、
タイトルバーも右寄りにしたいのです。
リソースエディタならばダイアログのみに属性付与で反映できるのに、
コードを書く場合は全てのコントロールに対して書かねばならないというのは
ソースの見栄えも悪くなるし、何より面倒だったので・・・
リソースエディタの一括付与が出来るのだから、
コード上でも一括付与が簡単に出来るんじゃないのか?と思った次第です。
>足し算じゃなくて論理和使ってください
忘れてました。指摘ありがとうございます。
>仲澤@失業者さん
はい。仰る通り、各国語対応が主目的となります。
(質問は大分省略させてもらいました)
普通に起動時の言語のみで動くアプリならば問題ないのですが、
今回の要件は、ボタンで言語を切り替える機能を求められておりまして・・・
MFCの意向には背いているかもしれませんが、動的に変更する必要があるのです。
連投すみません。
ARさんの仰っていたCreateEx()で何とかしようと思っていたのですが、
以下の方法で生成時の属性適用が出来ました。
int CChangeDlg::OnCreate(LPCREATESTRUCT lpCS)
{
if(CDialog::OnCreate(lpCS) == -1)
return -1;
this->ModifyStyleEx(0, WS_EX_LAYOUTRTL);
return 0;
}
OnInitDialog()にModifyStyleEx()で属性適用させようとしても駄目でしたが
OnCreate()で適用可能なのがイマイチ良くわかりません。
ARさんは
>OnCreate()は生成した後に呼ばれるもの
と仰っていますが、少しタイミングが違うのでしょうか?
OnCreate() → ダイアログ生成、属性適用可能? → OnInitDialog()
内部ではこのような順に呼ばれているのでしょうか?