2015年12月19日土曜日

WPF用縦書きテキストブロック Tategaki ver.2.1.1

(2024/05/11追記)
Google等からこのページに直接来られる方が多いようですが、最新版はver.3.2.2になっていますので、こちらからどうぞ。

先日Nugetデビューしたので、ついでにTategakiもNugetにアップロードしました。
バージョンを少し進めていますが、これはまあコードの一部をnameofにしてC#6.0化したり、XAML名前空間をURLで指定できるようにしたためです。

Glyphs特有の癖と言いますか、どうしても横書きのTextBlock等と同じように使えないところをどうにかしたいなとは思ってはいるのですが、なかなか上手くいかないですね…。例えば、フォント名→フォントファイルの変換なんかは独自に私が実装していますので、どうしてもTextBlockの抽象化ほどきれいにいっていなかったりします。早くWPF側で縦書きに対応してほしいのですが、なんていうか、もうMicrosoft内ではWPFを時代遅れとみている風潮すらありそうな気がして、あまり期待はしていません…。


Tategakiの使い方

そういえば、Tategakiをいかにして作るかみたいな話はしましたが、使い方はサンプルコードに頼りっぱなしで全然解説していなかったなーって思いましたので、ここで少し解説しておきます。

Nugetからダウンロード

まずは適当なWPFプロジェクトを作りNugetからTategakiを落としてきます。



これで必要な参照は追加されます。

XAMLでの配置

まずはXAMLでTategakiに使う名前空間を設定します。
xmlns:tg="http://schemas.eh500-kintarou.com/Tategaki"
そしたら、コントロールを適当に配置します。
<Grid>
    <tg:TategakiText Text="羅生門" VerticalAlignment="Center" FontSize="36" FontWeight="Bold" FontFamily="MS ゴシック" />
</Grid>
これで完成です。どうです?簡単でしょう。
ちなみに、自動的に改行される複数行に渡ったテキストはTategakiMultilineを使います。
<tg:TategakiMultiline Text="{Binding ElementName=textBox1, Path=Text, UpdateSourceTrigger=PropertyChanged}" />
どうです?簡単でしょう。

ちなみに、縦書きでテキストを作る場合、右から左へスタックしていくかと思いますが、WPFのStackPanelではそういうことはできません(たぶん)。なので、私は左右反転させたテキストStackPanelで左から右へスタックし、 そのStackPanel全体をもう一度左右反転させる、なんてことをやってそれっぽいコードを書いています。初めから内容がわかってるんだったら後ろの行から順に左からスタックしていくのとかもぜんぜんありでしょうが…。

てな感じで、適当にコントロールを配置するとこんな感じのアプリケーションが出来上がります。



ちゃんとフォントファイルから縦書き用の文字のインデックスを取ってきているので、カッコや句読点など横書きと縦書きで位置が変わるようなものでも正確に表示できていることがわかるかと思います。

ダウンロード


5 件のコメント:

  1. Hello
    In a French user interface, an Exception occurs (more details below).

    . I referenced the NuGet package.
    . To reproduce the problem, I suggest you to add this to your MainWindow:
    CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("fr");
    CultureInfo.CurrentUICulture = CultureInfo.CurrentCulture;
    . When I set English ("en-us") as the IU language, there is no exception, it works fine.
    But Italian fails just as French does.

    Do you have any idea ?

    System.InvalidOperationException
    HResult=0x80131509
    Message=Sequence contains no elements
    Source=System.Core
    Arborescence des appels de procédure :
    à System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
    à Tategaki.TategakiText.RedrawText()
    à Tategaki.TategakiText.OnApplyTemplate()
    à System.Windows.FrameworkElement.ApplyTemplate()
    à System.Windows.FrameworkElement.MeasureCore(Size availableSize)
    à System.Windows.UIElement.Measure(Size availableSize)
    à System.Windows.Controls.StackPanel.StackMeasureHelper(IStackMeasure measureElement, IStackMeasureScrollData scrollData, Size constraint)
    à System.Windows.Controls.StackPanel.MeasureOverride(Size constraint)
    à System.Windows.FrameworkElement.MeasureCore(Size availableSize)
    à System.Windows.UIElement.Measure(Size availableSize)
    à MS.Internal.Helper.MeasureElementWithSingleChild(UIElement element, Size constraint)
    à System.Windows.Controls.ContentPresenter.MeasureOverride(Size constraint)
    à System.Windows.FrameworkElement.MeasureCore(Size availableSize)
    à System.Windows.UIElement.Measure(Size availableSize)
    à System.Windows.Documents.AdornerDecorator.MeasureOverride(Size constraint)
    à System.Windows.FrameworkElement.MeasureCore(Size availableSize)
    à System.Windows.UIElement.Measure(Size availableSize)
    à System.Windows.Controls.Border.MeasureOverride(Size constraint)
    à System.Windows.FrameworkElement.MeasureCore(Size availableSize)
    à System.Windows.UIElement.Measure(Size availableSize)
    à System.Windows.Window.MeasureOverrideHelper(Size constraint)
    à System.Windows.Window.MeasureOverride(Size availableSize)
    à System.Windows.FrameworkElement.MeasureCore(Size availableSize)
    à System.Windows.UIElement.Measure(Size availableSize)
    à System.Windows.Interop.HwndSource.SetLayoutSize()
    à System.Windows.Interop.HwndSource.set_RootVisualInternal(Visual value)
    à System.Windows.Interop.HwndSource.set_RootVisual(Visual value)
    à System.Windows.Window.SetRootVisual()
    à System.Windows.Window.SetRootVisualAndUpdateSTC()
    à System.Windows.Window.SetupInitialState(Double requestedTop, Double requestedLeft, Double requestedWidth, Double requestedHeight)
    à System.Windows.Window.CreateSourceWindow(Boolean duringShow)
    à System.Windows.Window.CreateSourceWindowDuringShow()
    à System.Windows.Window.SafeCreateWindowDuringShow()
    à System.Windows.Window.ShowHelper(Object booleanBox)
    à System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
    à System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
    à System.Windows.Threading.DispatcherOperation.InvokeImpl()
    à System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state)
    à MS.Internal.CulturePreservingExecutionContext.CallbackWrapper(Object obj)
    à System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
    à System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
    à System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
    à MS.Internal.CulturePreservingExecutionContext.Run(CulturePreservingExecutionContext executionContext, ContextCallback callback, Object state)
    à System.Windows.Threading.DispatcherOperation.Invoke()

    返信削除
  2. Hello
    In order to make the library and the example application on a French Windows, I had to modify the source code.

    FIXES:
    . utils.cs line 50:
    /* if(cultures.Where(p => gtf.FamilyNames.ContainsKey(p)).Count() > 0)*/ {
    . MainWindows.xaml line 89:


    PROBLEMS REMAIN with latin characters and texts:
    . TategakiMultiline displays latin texts from right to left, and that can not be changed in the properties. Changing FlowDirection only applies a kind of horizontal mirror, characters are wrongly reversed horizontally.
    . TategakiMultiline displays latin characters in a fixed height. That makes reading difficult.
    . TategakiText does not display latin texts correctly. The space between characters is huge and wrong.
    . StackPanel is forced to display from right to left. Changing FlowDirection only applies a kind of horizontal mirror, characters are wrongly reversed horizontally.

    Unfortunately, too many problems remain that make the library unusable internationally.

    I suggest to publish the library on source code website like GitHub and invite developpers to collaborate to make it usable in any language.

    返信削除
    返信
    1. XAML:
      SelectedValue="MS ゴシック"

      削除
  3. 下記アドレスに対処したソースコードを置きます。
    詳しい説明は、ソースコードに添付した説明ファイルを
    確認してください。
    ある程度時間が経過したら公開は停止します。
    改変、公開は、ご自由にお願いします。

    https://3ft5tyy.web.fc2.com/WpfTategakiTest.zip

    簡単に説明しますと、DocumentViewerコントロールに
    TategakiTextコントロールを配置して、プレビュー表示をすると、
    TategakiTextにフォーカスが当たった瞬間落ちてしまうという
    現象です。

    返信削除
    返信
    1. 連絡ありがとうございました。
      提案いただいた形とは異なるのですが、DocumentViewerでも例外が発生しないような対処をしたバージョンを公開しました。
      https://days-of-programming.blogspot.com/2024/04/wpf-tategaki-ver300.html
      よろしくお願いします。

      削除