2016-04-04 5 views
0

В настоящее время мне нужно обработать арабскую строку (اسمي مصير الطفل. من أي بلد أنت) в моем проекте. Если строка отображается в одной строке, она отображается правильно.Печать арабской строки правильно в нескольких строках

enter image description here

Однако, когда размер шрифта намного больше, дисплей (я использую ярлык) неправильно.

enter image description here

строка печатается, начиная со второй строки. Я обнаружил, что на каркасе .Net мы могли бы использовать drawstring с StringFormatFlags.DirectionRightToLeft. Однако это не доступно в компактных рамках. Итак, как я могу напечатать арабскую строку в нескольких строках? Любые советы приветствуются, спасибо.

ответ

1

Я извиняюсь, неправильно: С WinCE 5 и CompactFramework v 2.0 управление, такими как Textbox поддерживает RicghtToLeft свойства (см также http://www.danielmoth.com/Blog/rtl-problem.aspx). Поэтому вы должны убедиться, что используете CF> = 2.0 и базовый SDK WinCE 5 (то есть Windows Mobile 6.x).

Ознакомившись с помощью класса Textbox, RightToLeft отмечен как НЕ ДОСТУПНЫЙ для Compact Framework.

enter image description here

Таким образом, вы должны написать свой собственный класс DrawText, который разделяет слова и позиционирует их справа налево.

Уроженец DrawText API поддерживает DT_RTLREADING флаг uFormat (в соответствии с интерактивной справке для Windows CE 5 Platform Builder):

DT_RTLREADING Компоновка в справа налево порядок чтения для двунаправленного текста когда шрифт выбранный в hdc - это иврит или арабский шрифт. Порядок чтения по умолчанию для всего текста слева направо.

Существует также опция DT_WORDBREAK, которую я бы выбрал для многострочного текста и достаточно большого прямоугольника рисования.

НО, что дает следующий результат, используя два прямоугольника и два размеров шрифта, чтобы заставить wordbreak:

enter image description here

Как я не могу читать, что я не уверен, но я предполагаю, что флаг wordbreak делает не работает правильно. Я предполагаю, что вторая строка в верхней части тоже должна начинаться справа.

Native Код для выше:

... 
#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

Я использую compactframework 3.5 с Wince 6.0. Тем не менее, я не могу найти никакого права собственности. – Ytan

+0

@josef Возможно, ваш выход просто нуждается в 'DT_RIGHT', верно? Также я думаю, что символы отображаются раздельно, потому что ваш WinCE не построен с полной поддержкой арабского скрипта. +1, хотя это, насколько мне известно, единственный способ отобразить арабский текст на WinCE. –

+0

DT_RIGHT может быть ошибкой, так как он выравнивается по правому краю, но нам нужно чтение справа налево (RTL). Нет поддержки «с полным арабским», есть только Unicode, и это по умолчанию с WinCE. Одна из проблем - иметь ttf с полной арабской поддержкой. С другой стороны: я не знаю, какие параметры компоновщика плат необходимы, за исключением RTL и Unicode, чтобы получить «полный арабский дизайн» образа ОС Windows CE. BTW: редактирование ARABIC_TEXT в VS было проблемой, поскольку VS признал язык RTL и ведет себя странно с BACKSPACE, END и POS1. Хороший опыт. – josef

1

Следующая форма представляет собой пример вызова DrawText (см ответ Йозефа) из C#:

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 
    } 
} 

(Как вы можете видеть, что я проигнорировал возвращаемые значения каждого нативного метода)

+0

Извините, мне потребовалось столько времени, чтобы взглянуть на это, было занято в эти дни. Метод, который вы предложили, тоже не сработал, если предложение напечатано более чем на одной строке, оно все равно будет начинаться со второй строки и заканчивается в первой строке. – Ytan

0

Похоже, что нет твердого решения этой проблемы, поэтому я создал временное обходное решение.Я предполагаю, что размер моей метки исправлен, и если размер моей строки больше ширины моей метки, я разделил ее на две части. Метод, который я использую для разделения строки, заключается в том, чтобы найти точку разделения (в настоящее время я делаю это в 0,2 от общей длины строки).

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]; 
} 

Хотя арабская строка напечатана справа налево, индекс по-прежнему подсчитывается слева направо. Вышеприведенный фрагмент довольно жесткий и применяется только в том случае, если вы хотите разбить строку на две части. Я уверен, что есть много способов улучшить вышеуказанный код, любые комментарии/предложения приветствуются.

 Смежные вопросы

  • Нет связанных вопросов^_^