2016-04-04 12 views
0

Zur Zeit muss ich arabische Zeichenkette (اسمي مصير الططل. من بي بلد أنت) in meinem Projekt verarbeiten. Wenn die Zeichenfolge in einer einzelnen Zeile angezeigt wird, wird sie korrekt angezeigt.Arabische Zeichenkette korrekt in mehreren Zeilen drucken

enter image description here

Wenn jedoch die Schriftgröße viel größer ist, wird die Anzeige (I Etikett verwendet) ist falsch.

enter image description here

Die Zeichenkette gedruckt wird, aus der zweiten Zeile beginnt. Ich fand, dass auf dem. NET-Framework können wir Kordelzug mit StringFormatFlags.DirectionRightToLeft verwenden. Dies ist jedoch nicht in einem kompakten Rahmen verfügbar. Also, wie könnte ich arabische Zeichenfolge in mehreren Zeilen drucken? Jeder Rat wird geschätzt, danke.

Antwort

1

Es tut mir leid, das geht nicht: Da WinCE 5 und Compact v 2.0-Steuerelemente wie die Textbox ein RicghtToLeft Eigenschaft unterstützen (siehe auch http://www.danielmoth.com/Blog/rtl-problem.aspx). Sie sollten also sicherstellen, dass Sie CF> = 2.0 und WinCE 5 base sdk (dh Windows Mobile 6.x) verwenden.

Betrachtet man die Hilfe für die Textbox-Klasse, ist RightToLeft für Compact Framework als NICHT VERFÜGBAR gekennzeichnet.

enter image description here

So müssen Sie Ihre eigene DrawText Klasse schreiben, die die Worte und positioniert sie von rechts nach links aufteilt.

Die native DrawText API unterstützt die uFormat Flagge DT_RTLREADING (nach der Online-Hilfe für Windows CE 5 Platform Builder):

DT_RTLREADING Layout-in von rechts nach links Lesereihenfolge für den bidirektionalen Text, wenn die Schriftart ausgewählt in der hdc ist eine hebräische oder arabische Schriftart. Die Standardleseanweisung für den gesamten Text ist von links nach rechts.

Es gibt auch eine Option DT_WORDBREAK, die ich für mehrzeiligen Text und ein ausreichend großes Zeichenrechteck auswählen würde.

ABER, dass das folgende Ergebnis mit zwei Rechtecken und zwei Schriftgrößen gibt einen wordbreak zu zwingen:

enter image description here

Da ich nicht lesen kann, dass ich bin nicht sicher, aber ich nehme an, die wordbreak Flagge tut funktioniert nicht richtig. Ich nehme an, die zweite Zeile im oberen Teil muss auch von rechts beginnen.

Ureinwohner-Code für die oben:

... 
#define ARABIC_TEXT L"اسمي مصير الطفل. من أي بلد أنت" 
#define MulDiv(a,b,c)  (((a)*(b))/(c)) 
... 
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 
{ 
int wmId, wmEvent; 
PAINTSTRUCT ps; 
HDC hdc; 
RECT rect; 
LOGFONT lf; 
HFONT hFontNew, hFontOld; 
... 
    case WM_PAINT: 
     hdc = BeginPaint(hWnd, &ps); 

     // TODO: Add any drawing code here... 
     // Clear out the lf structure to use when creating the font. 
     memset(&lf, 0, sizeof(LOGFONT)); 
     wsprintf(lf.lfFaceName,L"Arial Unicode MS"); 

     GetClientRect(hWnd, &rect); 

     hFontNew = CreateFontIndirect(&lf); 
     hFontOld = (HFONT) SelectObject(hdc, hFontNew); 
     rect.bottom=rect.bottom/2; 
     lf.lfHeight=-MulDiv(16, GetDeviceCaps(hdc, LOGPIXELSY), 72); 
     if(DrawText(hdc, ARABIC_TEXT, -1, &rect, DT_RTLREADING | DT_WORDBREAK)==0){ 
      DEBUGMSG(1, (L"DrawText failed with %i\n", GetLastError())); 
     } 

     GetClientRect(hWnd, &rect); 
     lf.lfHeight=-MulDiv(10, GetDeviceCaps(hdc, LOGPIXELSY), 72); 
     hFontNew = CreateFontIndirect(&lf); 
     hFontOld = (HFONT) SelectObject(hdc, hFontNew); 
     rect.top=rect.bottom/2; 
     if(DrawText(hdc, ARABIC_TEXT, -1, &rect, DT_RTLREADING | DT_WORDBREAK)==0){ 
      DEBUGMSG(1, (L"DrawText failed with %i\n", GetLastError())); 
     } 

     EndPaint(hWnd, &ps); 

     SelectObject(hdc, hFontOld); 
     DeleteObject(hFontNew); 

     break; 
+0

Ich benutze compactframework 3.5 mit Wince 6.0. Ich finde jedoch keine rechte Eigentumsrechte. – Ytan

+0

@josef Vielleicht braucht Ihre Ausgabe nur ein 'DT_RIGHT', oder? Ich denke auch, dass die Zeichen getrennt erscheinen, weil Ihr WinCE nicht mit voller arabischer Skriptunterstützung gebaut wird. +1, das ist, soweit ich weiß, die einzige Möglichkeit, arabischen Text auf WinCE anzuzeigen. –

+0

DT_RIGHT könnte ein Fehler sein, da er nach rechts ausgerichtet ist, aber wir wollen von rechts nach links (RTL) lesen. Es gibt keine Unterstützung für 'voll arabisch', es gibt nur Unicode, und das ist standardmäßig bei WinCE. Ein Problem ist ein ttf mit voller arabischer Unterstützung. Auf der anderen Seite: Ich weiß nicht, welche Platform-Builder-Optionen außer RTL und Unicode benötigt werden, um ein vollständiges arabisches Build eines Windows CE-BS-Images zu erhalten. BTW: Bearbeiten von ARABIC_TEXT in VS war eine Herausforderung, da VS die RTL-Sprache erkannt hat und sich mit BACKSPACE und END und POS1 merkwürdig verhält. Schöne Erfahrung. – josef

1

Das folgende Formular ist ein Beispiel DrawText der Aufruf von C# (josef Antwort sehen):

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 
    } 

    protected override void OnPaint(PaintEventArgs e) 
    { 
     base.OnPaint(e); 
     Menu = null; 
     DrawText(e.Graphics, "اسمي مصير الطفل. من أي بلد أنت", Font, ClientRectangle); 
    } 

    private void DrawText(Graphics g, string text, Font font, Rectangle rectangle) 
    { 
     IntPtr dc = g.GetHdc(); 
     RECT rect = (RECT)rectangle; 
     IntPtr hFont = IntPtr.Zero; 
     IntPtr previousFont = IntPtr.Zero; 

     try 
     { 
      hFont = font.ToHfont(); 
      previousFont = SelectObject(dc, hFont); 
      DrawText(dc, text, text.Length, ref rect, DrawTextFlags.RightToLeft | DrawTextFlags.Right | DrawTextFlags.WordBreak); 
     } 
     finally 
     { 
      if (previousFont != IntPtr.Zero) 
      { 
       SelectObject(dc, previousFont); 
      } 
      if (hFont != IntPtr.Zero) 
      { 
       DeleteObject(hFont); 
      } 

      g.ReleaseHdc(dc); 
     } 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    internal struct RECT 
    { 
     internal int Left; 
     internal int Top; 
     internal int Right; 
     internal int Bottom; 

     public static explicit operator RECT(Rectangle rect) 
     { 
      return new RECT() 
      { 
       Left = rect.Left, 
       Top = rect.Top, 
       Right = rect.Right, 
       Bottom = rect.Bottom 
      }; 
     } 
    } 
    [DllImport("coredll.dll", CharSet = CharSet.Unicode)] 
    internal static extern int DrawText(IntPtr hdc, string lpStr, int nCount, ref RECT lpRect, DrawTextFlags flags); 
    [DllImport("coredll.dll", EntryPoint = "DeleteObject")] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    internal static extern bool DeleteObject([In] IntPtr hObject); 
    [DllImport("coredll.dll")] 
    internal static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj); 
    [Flags] 
    public enum DrawTextFlags : uint 
    { 
     /// <summary> 
     /// Use default values. 
     /// </summary> 
     None = 0x00000000, 

     /// <summary> 
     /// Justifies the text to the top of the rectangle. 
     /// </summary> 
     Top = 0x00000000, 

     /// <summary> 
     /// Aligns text to the left. 
     /// </summary> 
     Left = 0x00000000, 

     /// <summary> 
     /// Centers text horizontally in the rectangle. 
     /// </summary> 
     Center = 0x00000001, 

     /// <summary> 
     /// Aligns text to the right. 
     /// </summary> 
     Right = 0x00000002, 

     /// <summary> 
     /// Centers text vertically. This value is used only with the SingleLine value. 
     /// </summary> 
     VerticalCenter = 0x00000004, 

     /// <summary> 
     /// Justifies the text to the bottom of the rectangle. This value is used only with the 
     /// SingleLine value. 
     /// </summary> 
     Bottom = 0x00000008, 

     /// <summary> 
     /// Breaks words. Lines are automatically broken between words if a word would extend past the 
     /// edge of the rectangle specified by the lpRect parameter. A carriage return-line feed sequence 
     /// also breaks the line. If this is not specified, output is on one line. 
     /// </summary> 
     WordBreak = 0x00000010, 

     /// <summary> 
     /// Displays text on a single line only. Carriage returns and line feeds do not break the line. 
     /// </summary> 
     SingleLine = 0x00000020, 

     /// <summary> 
     /// Expands tab characters. The default number of characters per tab is eight. 
     /// </summary> 
     ExpandTabs = 0x00000040, 

     /// <summary> 
     /// Sets tab stops. Bits 15-8 (high-order byte of the low-order word) of the uFormat parameter 
     /// specify the number of characters for each tab. The default number of characters per tab is 
     /// eight. 
     /// </summary> 
     Tabstop = 0x00000080, 

     /// <summary> 
     /// Draws without clipping. 
     /// </summary> 
     NoClip = 0x00000100, 

     /// <summary> 
     /// Includes the font external leading in line height. Normally, external leading is not included 
     /// in the height of a line of text. 
     /// </summary> 
     ExternalLeading = 0x00000200, 

     /// <summary> 
     /// Determines the width and height of the rectangle. If there are multiple lines of text, DrawText 
     /// uses the width of the rectangle pointed to by the lpRect parameter and extends the base of the 
     /// rectangle to bound the last line of text. If the largest word is wider than the rectangle, the 
     /// width is expanded. If the text is less than the width of the rectangle, the width is reduced. 
     /// If there is only one line of text, DrawText modifies the right side of the rectangle so that it 
     /// bounds the last character in the line. In either case, DrawText returns the height of the 
     /// formatted text but does not draw the text. 
     /// </summary> 
     CalcRect = 0x00000400, 

     /// <summary> 
     /// Turns off processing of prefix characters. Normally, DrawText interprets the mnemonic-prefix 
     /// character & as a directive to underscore the character that follows, and the mnemonic-prefix 
     /// characters && as a directive to print a single &. By specifying DT_NOPREFIX, this processing 
     /// is turned off. 
     /// </summary> 
     NoPrefix = 0x00000800, 

     /// <summary> 
     /// Uses the system font to calculate text metrics. 
     /// </summary> 
     Internal = 0x00001000, 

     /// <summary> 
     /// Duplicates the text-displaying characteristics of a multiline edit control. Specifically, 
     /// the average character width is calculated in the same manner as for an edit control, and 
     /// the function does not display a partially visible last line. 
     /// </summary> 
     EditControl = 0x00002000, 

     /// <summary> 
     /// For displayed text, if the end of a string does not fit in the rectangle, it is truncated 
     /// and ellipses are added. If a word that is not at the end of the string goes beyond the 
     /// limits of the rectangle, it is truncated without ellipses. 
     /// </summary> 
     EndEllipsis = 0x00008000, 

     /// <summary> 
     /// Layout in right-to-left reading order for bidirectional text when the font selected into the 
     /// hdc is a Hebrew or Arabic font. The default reading order for all text is left-to-right. 
     /// </summary> 
     RightToLeft = 0x00020000, 

     /// <summary> 
     /// Truncates any word that does not fit in the rectangle and adds ellipses. 
     /// </summary> 
     WordEllipsis = 0x00040000 
    } 
} 

(Wie man sehen kann ich ignoriert habe die Rückgabewerte jeder systemeigenen Methode)

+0

Entschuldigung, es hat so lange gedauert, einen Blick darauf zu werfen, war in diesen Tagen beschäftigt. Die von Ihnen vorgeschlagene Methode funktionierte nicht so gut. Wenn der Satz auf mehr als einer Zeile gedruckt wird, beginnt er immer noch in der zweiten Zeile und endet in der ersten Zeile. – Ytan

0

Es scheint, dass es keine solide Lösung für dieses Problem gibt, also habe ich eine temporäre Problemumgehung erstellt.Ich nehme an, dass meine Label-Größe festgelegt ist, und wenn meine String-Größe größer als die Breite meines Labels ist, werde ich es in zwei Teile teilen. Die Methode, die ich benutze, um die Zeichenfolge zu teilen, ist es, einen Teilungspunkt zu finden (momentan mache ich das bei 0,2 der gesamten Stringlänge).

private void processArabic(string arabicString) 
{ 
    string[] stringArray = new string[2]; 

    double index = 0.8 * arabicString.Length; 
    index = Math.Ceiling(index); 
    int Index = (int)index; 

    for (int i = Index; i != 0; i--) 
    { 
     if (Char.IsWhiteSpace(arabicString, i)) 
     { 
      stringArray[1] = arabicString.Substring(0, Index + 1); 
      stringArray[0] = arabicString.Substring(Index + 1, arabicString.Length - (Index + 1)); 
      break; 
     } 
    } 

     label1.Text = stringArray[0]; 
     label1.Text += "\n"; 
     label1.Text += stringArray[1]; 
} 

Obwohl die arabische Zeichenfolge von rechts nach links gedruckt wird, wird der Index immer noch von links nach rechts gezählt. Das obige Snippet ist ziemlich starr und gilt nur, wenn Sie die Zeichenfolge in zwei teilen möchten. Ich bin mir sicher, dass es viele Möglichkeiten gibt, den obigen Code zu verbessern, jeder Kommentar/Vorschlag ist willkommen.