v18では,プロジェクトメソッドをプリエンプティブモードで実行できるようにするため,スレッドセーフではないコマンドのチェックを部分的にスキップすることができるようになりました。チェックを無効化するためには,下記のようにアンセーフなコマンドの前後にコンパイラー指示を記述します。
//%T
SET MENU BAR(1) //not thread safe
//%T+
このテクニックは,論理的な条件分岐により,スレッドセーフではないコマンドがプリエンプティブモードで実行されることはないとわかっているような場合に有用です。
チェックの対象から外されるのは,4Dコマンドだけであることに留意してください。プリエンプティブモードで実行できないプロジェクトメソッドをチェックから除外することはできません。
この点はドキュメントに明記されています。
新規プロセスで作成したウィンドウの初期座標をメインモニター以外に設定した場合,ウィンドウがすぐには表示されないことがあります。これはMac版の仕様(修正できない問題)であると考えられています。
Open form window
とDIALOG
の間にWINDOW LIST
を呼び出した場合On Load
イベントでWINDOW LIST
を呼び出した場合問題を回避するためには,メインモニターにOpen form window
でウインドウを表示した後,SET WINDOW RECT
で移動することができます。
クライアント/サーバー版のORDAでデータストアクラスの戻り値($0
)にエンティティやエンティティセレクションをそのまま返すことはできますが,オブジェクト型のプロパティにンティティやエンティティセレクションを設定して返すことはできません。ORDAオブジェクトだけでなく,JFile
Folder
など,JSONにシリアライズできないナイティブ(C++)オブジェクトは,いずれもRESTサーバーから返すことができません。メンバーメソッドからダイレクトに返せるという点で,エンティティやエンティティセレクションは例外的な存在です。ダイレクトであればORDAで返せるオブジェクトには,ピクチャ・Write Proドキュメント・View Proドキュメントが含まれます。
スタンドアロン版であれば問題がなく,クライアント/サーバー版で替さえれるエラーメッセージ(不正なJSON)が直接的ではないという点で意表を突かれたように感じるかもしれませんが,これは仕様です。なお,ORDAオブジェクト(データストア・データクラス・エンティティ・エンティティセレクション)に加え,ポインター型もオブジェクト型のプロパティとしてRESTサーバーから返すことができません。
Random
は0
から32767
までの乱数を返す関数です。v18では,
プラットフォームAPIのarc4random
(macOS)およびCryptGenRandom
(Windows)が内部的にコールされています。
SDIモードでウィンドウタイプのToolbar form window
はサポートされていません。これは仕様です。
ツールバータイプのウィンドウは,常に画面の幅いっぱい最上部に表示されるウィンドウです。Windowsのタスクバーをデスクトップの「上」「右」「左」に表示した場合,4Dで表示したツールバーの一部がWindowsタスクバーの下に隠れてしまうかもしれません。
ドキュメントの記述は近日中に修正されます。
ウィンドウの水平方向のサイズはデスクトップ(macOSおよびSDIモードのWindows)または4Dのメインウィンドウ内部(MDIモードのWindows)の利用可能な全ての水平方向のスペースを埋める形で自動的に調整されます。
デザインモードの「編集」メニューの最下段にある「すべてを置換」アクションは,直前に実行された「編集>検索>置換…」の条件をメソッド内で適用するというものですが,「単語全体」条件は適用されず。単純な文字列の置換となることに留意してください。これは仕様です。
たとえば,検索条件を「単語全体」を有効にし,プロジェクトメソッド「Method1」を「Method2」に変換した場合,変数「<>Method1」および「$Method1」は影響を受けません。「単語全体」が指定されているためです。しかし,「すべてを置換」は,単純な置換となるため,変数も置換の対象となります。
タブコントールに「選択リスト」が設定されている場合,データソースは階層リストになります。とはいえ,「式の型(旧称:式のタイプ)」は「整数」と「テキスト配列」のどちらも選択することができます。選択リストが設定されていながら,式の型がテキスト配列に設定されているタブコントールは,データソース変数が明示的に宣言されていない場合,配列型なのかリスト型なのか,はっきりしないことになります。
v17以前,選択リストが設定されていれば,そのタブコントールはリスト型であるとみなされ,データソースは階層リストになりました。つまり,式の型がテキスト配列であることは無視されました。
18以降,式の型がテキスト配列であれば,そのタブコントールは配列型であるとみなされるようになりました。選択リストが設定されている場合,そのリストから配列にデータがコピーされました。
配列型のタブコントールはSelected list items
のようなリストコマンドでコントールすることができません。リスト型のタブコントールとして使用するのであれば,式の型を整数に設定するか,データソース変数を明示的に宣言する必要があります。これは仕様です。
Windowsには,GDIベースのアプリケーションが高解像度ディスプレイでも鮮明に表示されるようにするための表示スケールという仕組みがあります。GDIは,Windowsネイティブアプリで2Dグラフィックを描画するための標準的なAPIのひとつで,高解像度ディスプレイ以前から存在し,テキスト・アイコン・図形・画像といった2Dグラフィックを常に96 DPIで描画するように設計されています。GDIで描画した画面が高解像度ディスプレイで縮小されないようにするためには,実際のDPIに合わせて画像を拡大する必要があります。画面がぼやけて表示されるのはそのためです。
Creators Update(Windows 10 1703)では,この現象を改善するため,GDIスケーリングという仕組みが導入されました。アプリの表示スケールの修正で表示がぼやける可能性があるといわれている一部のデスクトップアプリは,GDIで画面を描画しているアプリのことを指しています。4Dは,GDIとDirect2D(高解像度ディスプレイに対応したAPI)を併用しているので,これに該当します。
高解像度ディスプレイ(4Kなど)を搭載したノートパソコンに標準的な外部モニター(1080pなど)を接続し,デスクトップを拡大しているユーザーは少なくありません。その場合,ノートパソコンは解像度を200%(192 DPI)に設定し,外部モニターは100%(96 DPI)のまま使用する,といったことができます。従来のスケーリングでは,物理的なサイズを再現するため,画面の解像度に合わせて画像を引き伸ばしていました。そのように拡大された画像は,96 DPIのデータしか持ち合わせていないため,おおきなピクセルで表示されたり,ぼやけて表示されたりします。
ディスプレイ毎のDPIを考慮し,場面に合わせて動的に画像データを差し替えるようにアプリが設計されていれば良いのですが,高解像度ディスプレイ以前から存在するGDIアプリは,そのような仕組みを持っていません。GDIスケーリングは,アプリの代わりにシステムがスケーリングするので,DPIを意識したプログラミングをしなくても良い,というメリットがあります。特にテキストの表示が改善されます。
GDIに限らず,Windowsアプリには,下記のDPIモードが用意されています。
DPIを気にしない。100%(96 DPI)を前提に描画します。その他の解像度は想定されていません。
システムDPIに合わせる。ユーザーがログインした時点におけるメイン画面のDPIを前提に描画します。メイン画面は鮮明に描画されますが,その他のモニターは表示がぼやける可能性があります。
モニター毎のDPIに合わせる。モニターのDPIに合わせて描画します。正しく開発されていれば,モニター間でウィンドウを移動しても,鮮明に画面が表示されます。
ウィンドウ別にDPIを管理する。上述したモードを組み合わせてアプリを開発することができます。
High DPI Desktop Application Development on Windows
GDIスケーリングは,実際のDPIと同等以上(x2, x3, x4など)の解像度でテキストやベクトル図形をレンダリングした後,Desktop Window Manager (DWM) が合成したビットマップを画面に表示するというものです。画面の解像度96の倍数であれば,DWMは使用されません。いずれにしても,単純な拡大よりも鮮明な表示が期待できます。96 DPIのデータしか持ち合わせていないビットマップ画像は,引き延ばされてレンダリングされるため,ぼやけて表示されます。また,実際のDPIが96の倍数でなかった場合,単純な拡大ほどではありませんが,テキストやベクトル図形であっても,ぼやけて表示されるという限界があります。
GDIスケーリングは,おもにテキストの表示を鮮明にすることを意図した仕組みですが,一部の文字は端のピクセルが欠落されて表示されないことがあります。たとえば,10ptのフォントを200%の画面に表示する場合,20ptのフォントが2倍の領域にレンダリングされますが,フォントや文字の種別により,テキストの線が「太く」なれば,表示領域の幅が200%を超えることがあるためです。
前述したモードとGDIスケーリングの関係は,下記のとおりです。
DPIを気にしない: GDIスケーリングは適用されません。
システムDPIに合わせる: システムDPIよりも高解像度の外部モニターであっても,GDIスケーリングが適用されることにより,図形とテキストの表示が改善されます。システムDPIは,ユーザーがログインした時点におけるメイン画面のDPIなので,途中でメイン画面を別のディスプレイに切り替えたり,メイン画面の解像度を変更した場合,従来のスケーリングは再ログインするまで表示がぼやけたままになりました。GDIスケーリングが有効であれば,システムがDPIの変更を検出するので,自動的に表示が調整されます。
モニター毎のDPIに合わせる: すでに高解像度ディスプレイを意識したアプリであれば,GDIスケーリングを使用する必要はないはずです。テキストや図形はもちろんのこと,ビットマップ画像もDPIに合わせたものを使用しているので,GDIスケーリングよりも鮮明に画面が描画されます。これには,チェックボックスやポップアップメニューのキャレット(実際にはビットマップ画像)も含まれます。カーニング(隣接する文字の距離の計算)も係数を掛けるのではなく,実際のフォントサイズに基づいて計算されるため,GDIスケーリングよりも自然になります。このようなアプリでは,GDIスケーリングを無効にしたいと思うでしょう。判断の材料として,それぞれのモードでアプリを実行して詳細な点を比較することができます。
アプリには,開発者が設定したデフォルトの表示モードがありますが,「プロパティ>互換性>高 DPI 設定の変更」で上書きすることもできます。「システム(拡張)」がGDIスケーリングです。4D v18は,このモードに設定されています。「アプリケーション」に設定した場合,スケーリングが無効となります。「システム」は,Creators Update(Windows 10 1703)以前のスケーリングです。
ユーザーは,プロパティで自由にスケーリングの設定を変更することができます。,IT管理者は,System Center Configuration Manager (SCCM) やMicrosoft IntuneでGDIスケーリングのポリシーを設定することにより,これを制御したいと考えるかもしれません。
参考資料
Improving the high-DPI experience in GDI based Desktop Apps
前述したように,4DはGDIとDirect2Dを併用しています。GDIスケーリングを無効にした場合,Direct2Dで描画されている部分は鮮明に表示され,そうでない部分は96 DPIの位置とサイズにレンダリングされます。「システムスタイルシート」は自動的に調整されますが,その他のフォントサイズは絶対値で計算されるので,文字が小さくなります。スケーリングが適用されないため,画面のレイアウトは変わりますが,すべて鮮明に表示されるというメリットがあります。
MDIウィンドウの「閉じるボタン」上でマウスポインターを移動すると,ボタンが高速で点滅するという現象が報告されています。これはGDIスケーリングの不具合であることがわかっています。「高 DPI 設定」を「アプリケーション」に変更した場合,あるいは96 DPIの画面であれば,問題は発生しません。
具体的には,GDIスケーリングで描画されているウィンドウのウィンドウプロセスマネージャーで,WM_NCMOUSEMOVE
メッセージ処理中にWindowFromPoint
を呼び出した場合,ボタンのハイライト表示がリセットされることがわかっています。
Mac/Windowsの違いを吸収し,過去のバージョンでデザインされたフォーム等を高解像度ディスプレイで同じように表示するためには,WindowsのGDIスケーリングを利用するのが,現状,最良のソリューションであるように思われます。4D側でこの現象を解消することは困難かもしれません。