编写Roma小部件集(c# X11)——一个零依赖GUI应用程序框架——编程技术

介绍 本文描述了一些有关Roma小部件集(Xrw)的编程技术—eiter,它用于扩展小部件集或将其应用于应用程序编程。它之所以被创建是因为整个主题超过了50个印刷页,我决定把它分成三部分和四部分。我将完整的API描述转移到单独的HTML文档中(这是Xrw项目的一部分),并重新构造了这四篇文章,使阅读更加有趣和激动人心: 最初的一个:编写Roma小部件集(c# X11)——一个零依赖的GUI应用程序框架——介绍。它包含一个小部件集特性的简短说明。(之前是:~基础。它包含了一般的描述。)这个起点应该永远是首选的。第一个分裂:编程罗马小部件集(c# X11) -零依赖GUI应用程序框架部件集。由于不断增长的“无聊”API文档,,的API文档被移动,一个单独的HTML文件(即Xrw项目的一部分),本文专注于所有部件的简要介绍。(之前是:~ Intrinsic widgets。它只包含内部部件的API引用描述。)第二个分支:编写Roma小部件集(c# X11)——一个零依赖GUI应用程序框架——编程技术。由于“无聊”的API文档不断增加,API文档已经被转移到一个单独的HTML文档中(这是Xrw项目的一部分),本文主要关注编程技术。(之前是:简单的小部件。它只包含简单部件的API引用描述。)第三个分支:编写Roma小部件集(c# X11)——一个零依赖GUI应用框架——MVVM/XAML支持。由于“无聊”的API文档不断增加,API文档已经被转移到一个单独的HTML文档中(这是Xrw项目的一部分),本文重点介绍了Xrw对MVVM/XAML的支持。(之前是:~ Composite widgets。它只包含组合小部件的API引用描述。) 后面描述的所有特征可以标记为: 从版本0.1中可用,从版本0.2中可用,从版本0.3中可用,从版本0.4中可用,从版本0.5中可用,从版本0.6中可用,从版本0.7中可用,从版本0.8中可用,从版本0.9和版本0中可用 在0.2版本中禁用,在0.3版本中禁用,在0.4版本中禁用,在0.5版本中禁用,在0.6版本中禁用,在0.7版本中禁用,在0.8版本中禁用,在0.9版本中禁用。 主题支持 框架有一个通用的主题支持和这些预定义的主题: & lt; img src = " / / 758151 / V0.1on KB /对话框。png”/比;XrwTheme.GeneralStyle。wincl叠统(in and named XrwTheme.GeneralStyle.Win95;看起来像Windows 95/98/Me/2K,有点像Motif -经典灰色3D), <img src="/KB/dialog/758151/V0.3on。png”/比;XrwTheme.GeneralStyle。WinLuna(类似于Windows XP / MS Office 2007), <code> img src="/KB/dialog/758151/V0.3on。png”/比;XrwTheme.GeneralStyle。WinRoyale(类似于windowsvista /7 / MS Office 2010), <code><img src="/KB/dialog/758151/V0.3on。png”/比;XrwTheme.GeneralStyle。和img src="/KB/dialog/758151/V0.1on。png”/比;XrwTheme.GeneralStyle。Gtk2Clearlooks(看起来像Gnome 2.30.0 Clearlooks -典型的GTK 2)。 主题支持涵盖了颜色、几何图形和图像。 要为特定应用程序设计不常见的GUI,受主题影响的几乎所有小部件属性也可以被单个值否决。或者一个新的XrwTheme。可以创建和应用GeneralStyle。 看,XrwTheme.GeneralStyle的感觉。WinClassic展示了“文件选择”对话框。 看,XrwTheme.GeneralStyle的感觉。Gtk2Clearlooks演示了“文件选择”对话框。 详细信息请参阅XrwTheme类的HTML代码,支持的股票项目请参阅X11Graphic类。 字体支持 大多数Xfree86安装的默认字体是“-misc-fixed-medium-r半densed- 13-*-*-*-*-*-* -*-*-*-*-*-* -*"。因此,XrwTheme类预定义了这些默认字体规范: 隐藏,复制Code

DefaultFontName        = "-misc-fixed-medium-r-semicondensed--13-*-*-*-*-*-*";
DefaultItalicFontName  = "-misc-fixed-medium-o-semicondensed--13-*-*-*-*-*-*";
DefaultBoldFontName    = "-misc-fixed-bold-r-semicondensed--13-*-*-*-*-*-*"; 

这些字体几乎保证在每个X服务器上都可用,但它们是单空间位图字体,看起来不是很聪明。 该图像显示了一个示例-misc-fixed- font输出。 这个版本引入了方便的方法,可以用用户定义的字体更改预定义的字体规范使用DefaultFontName字体规范确定并确保所有小部件的GC(图形上下文)初始化。 TrySetDefaultFont将DefaultFontName设置为用户定义的字体规范,成功时返回true(字体可用),否则将保持DefaultFontName不变,返回false。trysetdefaultitalicfontname将DefaultItalicFontName设置为用户定义的字体规范,成功时返回true(字体可用),否则将保留DefaultItalicFontName不变,返回false。将DefaultBoldFontName设置为用户定义的字体规范,成功时返回true(字体可用),否则将保留DefaultBoldFontName不变,返回false。 建议在创建应用程序外壳之后,在构建小部件层次结构之前,设置用户定义的字体规范。 隐藏,复制Code

public static void Main ()
{
    XrwTheme.Style = XrwTheme.GeneralStyle.Gtk2Clearlooks;
    
    Point assignedPosition = new Point (0, 0);
    Size  assignedSize     = new Size  (353, 480);
    X11Window appWindow    = new X11Window(ref assignedPosition, ref assignedSize);
    
    // Set the preferred font before the widget hierarchy is build up,
    // but after application shell creation.
    XrwTheme.TrySetDefaultBoldFont (appWindow.Display, appWindow.GC,
        "-*-helvetica-bold-r-normal--12-*-*-*-*-*-*");
    XrwTheme.TrySetDefaultItalicFont (appWindow.Display, appWindow.GC,
        "-*-helvetica-medium-o-normal--12-*-*-*-*-*-*");
    XrwTheme.TrySetDefaultFont (appWindow.Display, appWindow.GC,
        "-*-helvetica-medium-r-normal--12-*-*-*-*-*-*");
    
    appWindow.Run ();
}

这个版本为XrwTheme类预定义引入了-*-helvetica-字体,因为它们看起来比-misc-fixed-字体更聪明。 该图像显示了一个示例-*-helvetica-字体输出。 支持16位颜色模型 支持16位颜色模型的一般方法是为应用程序使用单独的视觉和颜色映射。在这个特定的示例中,它基于(实际上)24位颜色模型(硬件和X11服务器具有24位颜色功能),而X服务器在16位颜色模式下运行。没有使用(物理上)16位颜色模型的经验(硬件和X11服务器没有24位颜色能力)。 必要的代码,特别是XrwCore.InitializeApplicationShellWindow()、XrwCore.InitializeTransientShellWindow()和XrwCore.InitializeOverrideShellWindow()已经由img src="/KB/dialog/758151/ v8.1 on准备好了。png”/祝辞。为了最终支持这个特定的16位颜色模型案例,实现了以下更改: 减少股票图标的颜色深度到15位(不一定需要,但推荐)。减少应用程序的图标颜色深度到15位(必需的)。修改XrwApplicationFramework.SetWmShellIcon()(见“Fixed with”No. 3).修改<code> x11graphics . createindependentgraphicpixmap()(见“Fixed with”No. 4)。 我打开的SUSE 11.3 Linux 32位EN上的/etc/ x11 / xorg.con.d /50 screen.conf被修改为这样,以测试16位颜色模型支持: 隐藏,复制Code

Section "Screen"
  Identifier "Default Screen"
  Device "Default Device"

  ## Doesn't help for radeon/radeonhd drivers; use magic in
  ## 50-device.conf instead
  Monitor "Default Monitor"

  # DefaultDepth 32 Chrashing!
  # DefaultDepth 24 # Running!
  DefaultDepth 16 # Running!
  # DefaultDepth 15 Chrashing!
  # DefaultDepth 8 # Running, but ugly!

  #############################################################################
  # Use one of these GRUB start options to repair a crashing X11 session:
  # - vga=ask: This option allows you to select the mode for the video adaptor.
  # - init=/bin/sh: Run the program /bin/sh (the shell) instead of init.
  #############################################################################
EndSection 

("X -configure"生成)/etc/X11/xorg.conf在我的OPEN SUSE 12.3 Linux 64位DE上已被修改为这样,以测试16位颜色模型支持: 隐藏,复制Code

Section "Screen"
  ...

  # DefaultDepth 32 Chrashing!
  # DefaultDepth 24 # Running!
  DefaultDepth 16 # Running!
  # DefaultDepth 15 Running with Xfce only!
  # DefaultDepth 8 # Running, but ugly!
EndSection 

国际化 支持国际化文本输出 有一个关于I18N的很好的文件。第13.1章TWM——使用XFontSet代替XFontStruct是X11应用程序的国际化文本输出实现的综合guid。 第一个罗马部件集的内部架构的主要变化是引入X11FontData结构,支持XFontSet或者XFontStruct并提供X11Surface.TextBoundings()作为所有文本的单点测量以及X11Surface.DrawString()作为所有文本输出的单点。 内部体系结构的第二个主要变化是在字体分配期间交替地向XFontStruct提供XFontSet。根据X服务器和C运行时的I18N功能,XrwApplicationShell的UseFontSet属性被设置为true(或false),使用XFontSet而不是XFontStruct(或不是)。字体分配是通过XrwCore的PrepareFont()方法实现的。 接下来将快速叙述后续方法的故事:在检查先决条件之后,将测试FontData是否要设置为应用程序的默认fontset/字体,或者当前FontData已经是最新的。另外,加载并分配所请求的字体(如果XrwApplicationShell的UseFontSet属性为真)或字体。为了提供快速的几何计算,FontData还提供了字体/字体的最大高度、上升和下降。 XrwApplicationShell字体初始化: 隐藏,复制Code

/// <summary>Set a new default font (associate the indicated font with the graphics
/// context).</summary>
/// <param name="fontSpecification">The font specification to set as new default
/// font.<see cref="System.String"/></param>
/// <returns>True on success, or false otherwise.<see cref="System.Boolean"/></returns>
public virtual bool SetFont (string fontSpecification)
{    X11.X11FontData fontData = null;
     PrepareFont (fontSpecification, ref fontData);

    if (fontData == null)
        return false;
    _fontData = fontData;
    return true;
}

XrwCore字体的准备: 隐藏,收缩,复制Code

/// <summary>Prepare a new font for usage.</summary>
/// <param name="fontSpecification">The font specification to set as new font.<see cref="System.String"/></param>
/// <param name="fontData">The font data to set with the new font.<see cref="X11.X11FontData"/></param>
/// <returns>True on success, or false otherwise.<see cref="System.Boolean"/></returns>
protected bool PrepareFont (string fontSpecification, ref X11.X11FontData fontData)
{
    // Check prerequisits.
    if (_surface.Display == IntPtr.Zero)
    {
        SimpleLog.LogLine (TraceEventType.Error, CLASS_NAME +
            "::PrepareFont () Can not set a fontset/font to undefined display.");
        return false;
    }
    if (string.IsNullOrEmpty (fontSpecification))
    {
        SimpleLog.LogLine (TraceEventType.Error, CLASS_NAME +
            "::PrepareFont () Can not set a fontset/font with empty specification.");
        return false;
    }
    XrwApplicationShell appShell = ApplicationShell;
    if (appShell == null)
    {
        SimpleLog.LogLine (TraceEventType.Error, CLASS_NAME +
            "::PrepareFont () Can not set a fontset/font for a widget/gadget " +
            "that is not associated with an application shell.");
        return false;
    }
    
    // If fontset/font is equal to the current fontset/font, skip.
    if (fontData != null && fontData.FontSpecification == fontSpecification)
    {
        SimpleLog.LogLine (TraceEventType.Warning, CLASS_NAME +
            "::PrepareFont () Skip to reset fontset/font from '" + fontData.FontSpecification +
            "' to '" + fontSpecification + "'.");
        return true;
    }
    
    // If fontset/font is equal to the application's default fontset/font, assign a reference copy.
    if ((appShell.FontData != null ?
         appShell.FontData.FontSpecification == fontSpecification : false) == true)
    {
        fontData = appShell.FontData;
        return true;
    }
    
    // If fontset/font is not equal to the application's default fontset/font and
    // not equal to the current fontset/font, load and assign fontset/font.
    // Use fontset, if supported.
    return X11FontService.PrepareFont (fontSpecification, _surface.Display,
                                       appShell.UseFontset, ref fontData);
}

X11FontService字体的准备: 隐藏,收缩,复制Code

/// <summary>Prepare a font or fonteset for utilization with Xrw.</summary>
/// <paramname="fontSpecification">The font specification, that identifies a font/fontset.<seecref="System.String"/></param>
/// <paramname="x11display">The display pointer, that specifies the connection to the X server.<seecref="IntPtr"/></param>
/// <paramname="useFontset">The flag defining whether to use a fontset or a single font.<seecref="System.Boolean"/></param>
/// <paramname="fontData">The resulting font data on success, or null otherwise.<seecref="X11.X11FontData"/></param>
/// <returns>True on success, or false otherwise.<seecref="System.Boolean"/></returns>
public static bool PrepareFont (string fontSpecification, IntPtr x11display, bool useFontset, ref X11.X11FontData fontData)
{
    fontData = null;
    
    // Check font cache.
    foreach (KeyValuePair<FontDataKey, X11FontData> loadedFont in _loadedFonts)
    {
        if (loadedFont.Key.FontSpecification == fontSpecification &&
            loadedFont.Key.X11Display == x11display && loadedFont.Key.UseFontset)
        {
            fontData = loadedFont.Value;
            return true;
        }
    }
    
    FontDataKey key = new FontDataKey (fontSpecification, x11display, useFontset)
    ...

开始加载请求的字体集。如果所请求的fontSpecification与现有的fontSpecification不完全对应,请一步一步地使fontSpecification更加模糊,直到现有的fontset对应为止。这从伸展开始,接着是重量和倾斜。如果没有成功,则加载字体服务器的备用字体集。 隐藏,收缩,复制Code

...
// Load fontset, if fontset isn't supported.
if (useFontset)
{
    IntPtr  missingCharsetList;
    TInt    missingCharsetCount;
    X11.XID fontsetResourceId = X11lib.XCreateFontSet (x11display, fontSpecification, out missingCharsetList,
                                                       out missingCharsetCount, IntPtr.Zero);
    // Check whether directly matching fontset has been loaded,
    // and - if not - load the most similar fontset (fuzzy).
    int fuzzyFactor = 0;
    string fuzzyFontSpecification = (fontsetResourceId == (X11.XID)0 ? fontSpecification : null);
    while (fontsetResourceId == (X11.XID)0 && fuzzyFactor < 3)
    {
        string lastFuzzyFontSpecification = fuzzyFontSpecification;
        if (fuzzyFactor == 0)
            fuzzyFontSpecification = X11FontData.ModifyFontSpecificationStretch (fuzzyFontSpecification, "*");
        if (fuzzyFactor == 1)
            fuzzyFontSpecification = X11FontData.ModifyFontSpecificationWieght  (fuzzyFontSpecification, "*");
        if (fuzzyFactor == 2)
            fuzzyFontSpecification = X11FontData.ModifyFontSpecificationSlant   (fuzzyFontSpecification, "*");

        fuzzyFactor++;
        // Safe time if no change has been made.
        if (lastFuzzyFontSpecification == fuzzyFontSpecification)
            continue;

        if (!string.IsNullOrEmpty(lastFuzzyFontSpecification) && lastFuzzyFontSpecification.Trim() != "")
        {
            fontsetResourceId = X11lib.XCreateFontSet (x11display, fuzzyFontSpecification,
                                                       out missingCharsetList,
                                                       out missingCharsetCount, IntPtr.Zero);
            if (fontsetResourceId != (X11.XID)0)
            {
                SimpleLog.LogLine (TraceEventType.Information, CLASS_NAME +
                                   "::PrepareFont () Fuzzy load fontset with specification '" +
                                   fuzzyFontSpecification + "' " +
                                   "instead of '" + fontSpecification + "' succeeded.");
            }
        }
    }

    // Check whether directly matching or most similar fontset has been loaded,
    // and - if not - load a fallback fontset.
    string extFontSpecification = null;
    if (fontsetResourceId == (X11.XID)0)
    {
        // Let the font server guess a fallback fontset.
        if (!string.IsNullOrEmpty(fontSpecification) && fontSpecification.Trim() != "" &&
            !fontSpecification.Trim().EndsWith (",*"))
        {
            extFontSpecification = fontSpecification + ",*";

            SimpleLog.LogLine (TraceEventType.Warning, CLASS_NAME +
                               "::PrepareFont () Can not load a fontset with specification '" +
                               fontSpecification + "'.");
            SimpleLog.LogLine (TraceEventType.Information, CLASS_NAME +
                               "::PrepareFont () Retry to load a fontset with specification '" +
                               extFontSpecification + "'.");

            fontsetResourceId = X11lib.XCreateFontSet (x11display, extFontSpecification,
                                                       out missingCharsetList,
                                                       out missingCharsetCount, IntPtr.Zero);
        }
        // The font specification already includs a joker to guess a fallback fontset.
        else
        {
            SimpleLog.LogLine (TraceEventType.Error, CLASS_NAME +
                               "::PrepareFont () Can not load a fontset with specification '" +
                               fontSpecification + "'.");

            // No success at all - even with a guess of a fallback fontset!
            return false;
        }
    }

    // Check whether matching fontset has been loaded.
    if (fontsetResourceId == (X11.XID)0)
    {
        SimpleLog.LogLine (TraceEventType.Error, CLASS_NAME +
                           "::PrepareFont () Can not load a fontset with specification '" +
                           extFontSpecification + "'.");

        // No success at all - even with a guess of a fallback fontset!
        return false;
    }
    ...

报告最后加载的字体集和缺失的字符集。计算一些fontset属性并创建fontData。 隐藏,收缩,复制Code

    ...
    if (!string.IsNullOrEmpty (extFontSpecification))
        SimpleLog.LogLine (TraceEventType.Information, CLASS_NAME +
                           "::PrepareFont () Successfully loaded best matching fontset for specification '" +
                           fontSpecification + "' " +
                           "using specification '" + extFontSpecification + "'.");
    else if (!string.IsNullOrEmpty (fuzzyFontSpecification))
        SimpleLog.LogLine (TraceEventType.Information, CLASS_NAME +
                           "::PrepareFont () Successfully loaded best matching fontset for specification '" +
                           fontSpecification + "' " +
                           "using specification '" + fuzzyFontSpecification + "'.");
    else
        SimpleLog.LogLine (TraceEventType.Information, CLASS_NAME +
                           "::PrepareFont () Successfully loaded best matching fontset for specification '" +
                           fontSpecification + "'.");

    for (int countCharSet = 0; countCharSet < (int)missingCharsetCount; countCharSet++)
    {
        IntPtr p = Marshal.ReadIntPtr (missingCharsetList, countCharSet * Marshal.SizeOf(typeof(IntPtr)));
        string s = Marshal.PtrToStringAuto (p);
        if (!string.IsNullOrEmpty (extFontSpecification))
            SimpleLog.LogLine (TraceEventType.Warning, CLASS_NAME +
                               "::PrepareFont () Fontset for specification '" +
                               extFontSpecification + "' is missing font for charset  '" + s + "'.");
        else if (!string.IsNullOrEmpty (fuzzyFontSpecification))
            SimpleLog.LogLine (TraceEventType.Warning, CLASS_NAME +
                               "::PrepareFont () Fontset for specification '" +
                                fuzzyFontSpecification + "' is missing font for charset  '" + s + "'.");
        else
            SimpleLog.LogLine (TraceEventType.Warning, CLASS_NAME +
                               "::PrepareFont () Fontset for specification '" +
                               fontSpecification + "' is missing font for charset  '" + s + "'.");
    }

    // Calculate maximum font height, ascent and descent.
    int                        ascent  = 0;
    int                        descent = 0;
    X11lib.XFontSetExtents     extents = X11lib.XExtentsOfFontSet (fontsetResourceId);

    X11lib.XFontStruct[]       fontStructArray;
    string[]                   fontNameArray;
    int                        maxFonts;

    maxFonts = X11lib.XFontsOfFontSet (fontsetResourceId, out fontStructArray, out fontNameArray);
    for (int countFonts = 0; countFonts < maxFonts; countFonts++)
    {
        if (ascent  < (int)fontStructArray[countFonts].ascent)
            ascent  = (int)fontStructArray[countFonts].ascent;
        if (descent < (int)fontStructArray[countFonts].descent)
            descent = (int)fontStructArray[countFonts].descent;
    }

    string finalFontSpecification = null;
    if (!string.IsNullOrEmpty (extFontSpecification))
        finalFontSpecification = extFontSpecification;
    else if (!string.IsNullOrEmpty (fuzzyFontSpecification))
        finalFontSpecification = fuzzyFontSpecification;
    else
        finalFontSpecification = fontSpecification;

    // Maximum font height, ascent and descent might be frequently used for calculation.
    fontData = X11FontData.NewFontSetData (finalFontSpecification, x11display, fontsetResourceId,
                                           (int)extents.max_logical_extent.height, ascent, descent);

    IntPtr gc = X11lib.XCreateGC (x11display, X11lib.XDefaultRootWindow (x11display), 0, IntPtr.Zero);
    if (gc != IntPtr.Zero)
    {
        fontData.SetTypicalCharWidth (AverageCharacterWidth(x11display, gc, fontData));
        X11lib.XFreeGC (x11display, gc);
    }
    _loadedFonts.Add (key, fontData);
    return true;
}
...

如果不支持fontset,就开始加载所请求的字体。如果请求的fontSpecification不对应于现有的font com一定程度上,使字体说明更加模糊,直到现有字体对应。这从伸展开始,接着是重量和倾斜。如果没有成功,则加载字体服务器的回退字体。 隐藏,收缩,复制Code

...
// Use font, if fontset isn't supported.
else // of (useFontset)
{
    // Load font and query font structure (to get maximum font height, ascent and descent).
    IntPtr fontStructure = X11lib.XLoadQueryFont (x11display, fontSpecification);

    // Check whether directly matching font has been loaded,
    // and - if not - load the most similar font (fuzzy).
    int fuzzyFactor = 0;
    string fuzzyFontSpecification = (fontStructure == IntPtr.Zero ? fontSpecification : null);
    while (fontStructure == IntPtr.Zero && fuzzyFactor < 3)
    {
        string lastFuzzyFontSpecification = fuzzyFontSpecification;
        if (fuzzyFactor == 0)
            fuzzyFontSpecification = X11FontData.ModifyFontSpecificationStretch (fuzzyFontSpecification, "*");
        if (fuzzyFactor == 1)
            fuzzyFontSpecification = X11FontData.ModifyFontSpecificationWieght  (fuzzyFontSpecification, "*");
        if (fuzzyFactor == 2)
            fuzzyFontSpecification = X11FontData.ModifyFontSpecificationSlant   (fuzzyFontSpecification, "*");

        fuzzyFactor++;
        // Safe time if no change has been made.
        if (lastFuzzyFontSpecification == fuzzyFontSpecification)
            continue;

        if (!string.IsNullOrEmpty(lastFuzzyFontSpecification) && lastFuzzyFontSpecification.Trim() != "")
        {
            fontStructure = X11lib.XLoadQueryFont (x11display, lastFuzzyFontSpecification);
            if (fontStructure != IntPtr.Zero)
            {
                SimpleLog.LogLine (TraceEventType.Information, CLASS_NAME +
                                   "::PrepareFont () Fuzzy load font with specification '" +
                                   fuzzyFontSpecification + "' " +
                                   "instead of '" + fontSpecification + "' succeeded.");
            }
        }
    }

    // Check whether directly matching or most similar font has been loaded,
    // and - if not - load a fallback font.
    string extFontSpecification = null;
    if (fontStructure != IntPtr.Zero)
    {
        // Let the font server guess a fallback fontset.
        if (!string.IsNullOrEmpty(fontSpecification) && fontSpecification.Trim() != "" &&
            !fontSpecification.Trim().EndsWith (",*"))
        {
            extFontSpecification = fontSpecification + ",*";

            SimpleLog.LogLine (TraceEventType.Warning, CLASS_NAME +
                               "::PrepareFont () Can not load a fontset with specification '" +
                               fontSpecification + "'.");
            SimpleLog.LogLine (TraceEventType.Information, CLASS_NAME +
                               "::PrepareFont () Retry to load a fontset with specification '" +
                               extFontSpecification + "'.");

            fontStructure = X11lib.XLoadQueryFont (x11display, extFontSpecification);
        }
        // The font specification already includs a joker to guess a fallback fontset.
        else
        {
            SimpleLog.LogLine (TraceEventType.Error, CLASS_NAME +
                               "::PrepareFont () Can not load a font with specification '" +
                               fontSpecification + "'.");

            // No success at all - even with a guess of a fallback font!
            return false;
        }
    }

    // Check whether matching font has been loaded.
    if (fontStructure == IntPtr.Zero)
    {
        SimpleLog.LogLine (TraceEventType.Error, CLASS_NAME +
                           "::PrepareFont () Can not load a font with specification '" +
                           fontSpecification + "'.");
        // No success at all - even with a guess of a fallback font!
        return false;
    }
    ...

报告最后加载的字体。创建fontData。 隐藏,收缩,复制Code

        ...
        if (!string.IsNullOrEmpty (extFontSpecification))
            SimpleLog.LogLine (TraceEventType.Information, CLASS_NAME +
                               "::PrepareFont () Successfully loaded best matching font for specification '" +
                               fontSpecification + "' " +
                               "using specification '" + extFontSpecification + "'.");
        else if (!string.IsNullOrEmpty (fuzzyFontSpecification))
            SimpleLog.LogLine (TraceEventType.Information, CLASS_NAME +
                               "::PrepareFont () Successfully loaded best matching font for specification '" +
                               fontSpecification + "' " +
                               "using specification '" + fuzzyFontSpecification + "'.");
        else
            SimpleLog.LogLine (TraceEventType.Information, CLASS_NAME +
                               "::PrepareFont () Successfully loaded best matching font for specification '" +
                               fontSpecification + "'.");
        
        X11lib.XFontStruct    fs  = (X11lib.XFontStruct)Marshal.PtrToStructure (fontStructure,
                                                                                typeof(X11lib.XFontStruct));

        string finalFontSpecification = null;
        if (!string.IsNullOrEmpty (extFontSpecification))
            finalFontSpecification = extFontSpecification;
        else if (!string.IsNullOrEmpty (fuzzyFontSpecification))
            finalFontSpecification = fuzzyFontSpecification;
        else
            finalFontSpecification = fontSpecification;
        
        // Maximum font height, ascent and descent might be frequently used for calculation.
        fontData = X11FontData.NewSingleFontData (finalFontSpecification, x11display, fs.fid,
                                                  (int)fs.ascent + (int)fs.descent,
                                                  (int)fs.ascent, (int)fs.descent);
        
        IntPtr gc = X11lib.XCreateGC (x11display, X11lib.XDefaultRootWindow (x11display), 0, IntPtr.Zero);
        if (gc != IntPtr.Zero)
        {
            fontData.SetTypicalCharWidth (AverageCharacterWidth(x11display, gc, fontData));
            X11lib.XFreeGC (x11display, gc);
        }
        _loadedFonts.Add (key, fontData);
        return true;
    }
}

剖析应用程序或对话框窗口 应用程序窗口基于XrwApplicationShell,对话框窗口基于XrwDialogShell。两者都派生自抽象的XrwWmShell,而XrwWmShell则派生自XrwComposite——容器的基类,它管理任意数量的子部件。XrwWmShell提供与windows管理器的交互(移动,调整大小,关闭,…一个窗口)。由于XrwComposite没有集成的布局管理,建议为每个XrwApplicationShell或XrwDialogShell实例分配一个XrwBox、XrwGridForm、XrwUniformGrid或XrwDockPanel子实例,以管理shell子实例的布局。 因为XrwWmShell派生将XSetWindowAttributes属性bit_gravity设置为NorthWestGravity,将窗口的背景颜色设置为XrwTheme。GeneralBackgroundColor,闪烁的影响在重绘过程(如concequence ConfigureNotify事件——观察窗口大小调整操作)壳牌的布局管理器部件/配件已经最小化:大部分的闪烁的影响来自于黑(拉开)壳牌背景和外壳之间的时间延迟背景清洁和经理部件/设备重新划定。 闪烁效果还有其他一些原因——参见事件处理的特定方面。 示例代码展示了如何使用XrwBox作为对话框外壳的管理器小部件。 隐藏,收缩,复制Code

public class XrwBitmapAndVectorFontSelectionDialog : XrwDialogShell
{
    // Define constants and member attributes.
    ...
 
    // Implement the constructor.
    public XrwBitmapAndVectorFontSelectionDialog (XrwApplicationShell parent,
                                                  ref Point assignedPosition,
                                                  ref Size assignedSize, string title)
        : base (parent, ref assignedPosition, ref assignedSize)
    {
        // Initialize member attributes.
        ...
 
        // Create shell's primary layout manager.
        XrwBox vboxMain = XrwBox.NewVBoxGadget (this);
        vboxMain.BorderWidth = XrwTheme.DlgShellPrimaryChildBorderWidth;
        vboxMain.BorderColor = _backgroundColorPixel;
        vboxMain.VertSpacing = XrwTheme.DlgShellPrimaryChildSpacing;
        AddChild (vboxMain);
 
        // Create shell's grandchildren.
        ...
    }
 
    // Implement the destructor, properties and methods.
    ...   
} 

对话框窗口通常包含一个带有操作按钮的操作区域,例如Cancel和OK。 下一个示例代码展示了如何从对话框构造函数中提取一个操作区域。 隐藏,收缩,复制Code

{

    ...

    // ---- Begin "Action" area.

    // Create a HBox to group the action buttons.
    XrwBox hboxActionArea = XrwBox.NewHBoxGadget (vboxMain);
    hboxActionArea.BorderWidth = 2;
    hboxActionArea.ChildAlign = 1.0F;
    hboxActionArea.HorzSpacing = XrwTheme.DlgShellPrimaryChildSpacing;
    hboxActionArea.BorderColor = hboxActionArea.BackgroundColorDark;
    vboxMain.AddChild (hboxActionArea);

    // Create and register Cancel button.
    X11Graphic cancelGraphic = XrwTheme.GetGraphic (_surface.Display, _surface.ScreenNumber,
                                                    X11Graphic.StockIcon.Cancel16);
    XrwCommand cbCancel = XrwCommand.NewCommandWidget (hboxActionArea, "Cancel", cancelGraphic,
                                                       true, null, false);
    cbCancel.ExpandToMaxSiblingWidth = true;
    cbCancel.HorzTextAlign = 0.5F;
    cbCancel.Clicked += HandleCancelButtonClicked;
    hboxActionArea.AddChild (cbCancel);

    // Register "Cancel" button ation as input receiver.
    ICommand cmd0 = new RelayCommand (ProcessCancelButtonAction);
    Xrw.Utils.KeyGestureBinding kgb0 = new Xrw.Utils.KeyGestureBinding (cmd0,
        X11lib.XKeySym.XK_Escap,    System.Windows.Input.ModifierKeys.None);
    base._inputReceiver.Add (kgb0);
            
    // Create and register OK button.
    X11Graphic okGraphic = XrwTheme.GetGraphic (_surface.Display, _surface.ScreenNumber,
                                                X11Graphic.StockIcon.Ok16);
    XrwCommand cbOk = XrwCommand.NewCommandWidget (hboxActionArea, "OK", okGraphic,
                                                   true, null, false);
    cbOk.ExpandToMaxSiblingWidth = true;
    cbOk.HorzTextAlign = 0.5F;
    cbOk.Clicked += HandleOkButtonClicked;
    hboxActionArea.AddChild (cbOk);
                
    // Register "OK" button action as input receiver.
    ICommand cmd1 = new RelayCommand (ProcessOkButtonAction);
    Xrw.Utils.KeyGestureBinding kgb1 = new Xrw.Utils.KeyGestureBinding (cmd1,
        X11lib.XKeySym.XK_Return,   System.Windows.Input.ModifierKeys.None);
    Xrw.Utils.KeyGestureBinding kgb2 = new Xrw.Utils.KeyGestureBinding (cmd1,
        X11lib.XKeySym.XK_Num_Enter, System.Windows.Input.ModifierKeys.None);
    base._inputReceiver.Add (kgb1);
    base._inputReceiver.Add (kgb2);
            
    // ---- End "Action" area.

    ...

}

这是它的样子: 按钮回调连接到所单击的事件。 隐藏,收缩,复制Code

/// <summary> Handle the ButtonPress event. </summary>
/// <paramname="source"> The widget, the ButtonPress event is assigned
/// to. <seecref="XrwRectObj"/> </param>
void HandleOkButtonClicked (XrwRectObj source)
{
    if ((source is XrwCommand) && !(source as XrwCommand).Focused)
        return;
    
    ProcessOkButtonAction (null);
}

/// <summary>The default 'action' implementation for XrwCommand to execute if triggered.</summary>
/// <paramname="o">A parameter to use for any purpose.</param>
private void ProcessOkButtonAction (object o)
{
    _result = System.Windows.MessageBoxResult.OK;
    this.DefaultClose ();
    this.OnEnd (_result);
}

/// <summary> Handle the ButtonPress event. </summary>
/// <paramname="source"> The widget, the ButtonPress event is assigned
/// to. <seecref="XrwRectObj"/> </param>
void HandleCancelButtonClicked (XrwRectObj source)
{
    if ((source is XrwCommand) && !(source as XrwCommand).Focused)
        return;
    
    ProcessCancelButtonAction (null);
}

/// <summary>The default 'action' implementation for XrwCommand to execute if triggered.</summary>
/// <paramname="o">A parameter to use for any purpose.</param>
private void ProcessCancelButtonAction (object o)
{
    _result = System.Windows.MessageBoxResult.Cancel;
    this.DefaultClose ();
    this.OnEnd (_result);
}

由于这个版本引入了关键手势绑定,最终的点击事件处理不是事件处理程序的一部分,而是切换到相应的动作方法。这就提供了再次使用动作方法的可行性。即作为键盘输入接收器使用Xrw.Utils.KeyGestureBinding。因此,对话框可以用[Escape]键(相当于对话框的取消按钮)、[Enter]或[Return]键(相当于对话框的OK按钮)关闭。 对话框基于临时shell,经常从应用程序shell接管(无限)消息循环处理。要通过关闭应用程序窗口来完全清除这些活动对话框,它们必须覆盖临时shell。DefaultClose()方法停止它的(无限)消息循环处理。下面再仔细看看:XrwTransientShell实现了这两个消息处理程序。 只有在通过窗口装饰的关闭按钮调用shell关闭时才调用OnWmClose()。它的唯一目的是提供事件转发到已注册的委托。即使它是虚拟的,附加的功能也应该通过委托而不是覆盖来实现。此外,这还促进了代码重用。 无论关闭是通过窗口装饰的关闭按钮、对话框中的小部件/小工具(如[OK]或[Cancel]按钮)还是键盘快捷键(如[Return]或[Escape])调用,都应该始终调用DefaultClose()。派生类可以使用此重写准备返回值并终止其(无限)消息循环处理。 隐藏,收缩,复制Code

#region Event handler

/// <summary>Handle the ClientMessage event.</summary>
/// <paramname="e">The event data.<seecref="XrwClientMessageEvent"/></param>
/// <remarks>Set XawClientMessageEvent.Result to nonzero to stop further event processing.</remarks>
internal virtual void OnWmClose (XrwClientMessageEvent e)
{
    WmShellCloseDelegate wmShellClose = WmShellClose;
    if (wmShellClose != null)
        wmShellClose (this, e);
}

/// <summary>Default processing for the Close event.</summary>
/// <returns>True to continue closing, false otherwise.</returns>
/// <remarks>This method should be overwritten, if transient shell calls the message loop
/// within Run(). Otherwise the message loop continues to run and the garbage collector
/// can't clean the application.</remarks>
public virtual bool DefaultClose ()
{
    if (_disposed == true)
        return true;
    
    // Attention: Avoid double dispose by calling Dispose() a second time within derived classes!

    this.ApplicationShell.RemoveTransientShell (this);
    Unrealize ();
    Dispose ();
    
    // Don't disconnect from X server - application shell is still running.
    
    return true;
}

#endregion

XrwTransientShell派生类,例如XrwFileSelectionDialog,应该重写DefaultClose()以准备返回值并终止它的(无限)消息循环处理。它应该注册并实现HandleDialogClose()来提供一致的关闭行为,无论关闭是通过窗口装饰的关闭按钮、对话框的[取消]按钮还是[转义]快捷键来调用。 隐藏,复制Code

WmShellClose += HandleDialogClose;

隐藏,收缩,复制Code

#region Overwritten methods (XrwTransientShell)

/// <summary>Default processing for the Close event.</summary>
/// <paramname="source">The widget, the Close event is assigned to.<seecref="XrwTransientShell"/></param>
/// <returns>True to continue closing, false otherwise.</returns>
/// <remarks>This method should be overwritten, if transient shell calls the message loop.</remarks>
public override bool DefaultClose ()
{
    // FIRST: Ensure the message loop will be released.
    _result = System.Windows.MessageBoxResult.Cancel;
    
    // SECOND: Standard transient shell behaviour is appropriate.
    return base.DefaultClose ();
}

#endregion Overwritten methods (XrwTransientShell)

#region Event handler

/// <summary> Application specific processing of the ApplicationClose event. </summary>
/// <paramname="source"> The widget, the WmShellClose event is assigned to. <seecref="XrwRectObj"/> </param>
/// <paramname="e"> The event data. <seecref="XawClientMessageEvent"/> </param>
/// <remarks> Set XawClientMessageEvent.Result to nonzero to stop further event processing. </remarks>
void HandleDialogClose (XrwRectObj source, XrwClientMessageEvent e)
{
    this.DefaultClose ();

    // Stop event processing here!
    e.Result = 1;
    
    this.OnEnd (_result);
}

...

使用弹出式菜单 弹出式菜单可以非常容易地创建。步骤如下: 创建一个弹出菜单shell XrwSimpleMenuShell。将XrwSme类的菜单项添加到菜单shell中,并注册对菜单项的回调。强制壳的几何管理。创建一个菜单按钮XrmMenuButton,并将其添加到父组合中。将菜单外壳程序注册到菜单按钮。 不需要额外的代码来处理弹出、布局、下拉或选择。 图片显示了一个简单的XrwMenuButton和左和右(透明的多色)位图-包括它的弹出菜单,基于一个XrwDialogShell包含两个XrwSme的左和右(transpar)ent多色)位图。 示例代码展示了如何创建简单的弹出菜单,如上图所示。 隐藏,收缩,复制Code

XrwSimpleMenu _fileMenuShell = null;

...

// ---- Create popup menu.
Point origin   = new Point (20, 20);
Size  initSize = new Size  (-1, -1);
_fileMenuShell = new XrwSimpleMenu (this, ref origin, ref initSize);

// ---- Add menu entries.
X11Graphic menuEntryGraphicA = XrwTheme.GetGraphic ( _display,_screenNumber,
    X11Graphic.StockIcon.Information16);
X11Graphic menuEntryGraphicB = XrwTheme.GetGraphic ( _display,_screenNumber,
    X11Graphic.StockIcon.Question16);
XrwSme menuEntry1 = XrwSme.NewSmeGadget (_fileMenuShell, "File menu entry 1",
    menuEntryGraphicA, true, menuEntryGraphicB, true);
menuEntry1.ButtonRelease += HandleMenuEntry1ButtonRelease;
_fileMenuShell.AddChild (menuEntry1);
XrwSme menuEntry2 = XrwSme.NewSmeGadget (_fileMenuShell, "File menu entry 2",
    menuEntryGraphicA, true, menuEntryGraphicB, true);
menuEntry2.ButtonRelease += HandleMenuEntry2ButtonRelease;
_fileMenuShell.AddChild (menuEntry2);

// ---- Beautify popup menu.
_fileMenuShell.CalculateChildLayout ();
_fileMenuShell.SetFixedWidth  (_fileMenuShell.AssignedSize.Width);
_fileMenuShell.SetFixedHeight (_fileMenuShell.AssignedSize.Height);

// ---- Create menu button.
X11Graphic cbw0GraphicA = XrwTheme.GetGraphic ( _display,_screenNumber,
    X11Graphic.StockIcon.FileGeneric16);
X11Graphic cbw0GraphicB = XrwTheme.GetGraphic ( _display,_screenNumber,
    X11Graphic.StockIcon.FolderClose16);
XrwMenuButton commandFileMenu = XrwMenuButton.NewMenuButtonWidget
    (hboxFileRibbon, "File", cbw0GraphicA, true, cbw0GraphicB, true);
commandFileMenu.FrameType = XrwTheme.StaticFrameType;
commandFileMenu.FrameWidth = XrwTheme.StaticFrameWidth;
commandFileMenu.ExpandToAvailableHeight = true;

// ---- Register menu to menu button and insert menu button into parent widget.
commandFileMenu.Menu = _fileMenuShell;
hboxFileRibbon.AddChild (commandFileMenu); 

关闭应用程序窗口 为了给应用开发者提供一个方便的API,有些东西必须在内部准备框架: 1. 要清除XrwApplicationShell,注册一个主shell的close委托: 隐藏,复制Code

// Register close event.
this.WmShellClose += HandleApplicationShellCloseDefault;

...

/// <summary> Application specific processing of the WmShellClose event. </summary>
/// <paramname="source"> The widget, the ApplicationClose event is
/// assigned to. <seecref="XrwRectObj"/> </param>
/// <paramname="e"> The event data. <seecref="XawClientMessageEvent"/> </param>
/// <remarks> Set XawClientMessageEvent.
/// Set result to nonzero to stop further event processing. </remarks>
void HandleApplicationShellCloseDefault (XrwRectObj source, XrwClientMessageEvent e)
{
     ...

     Dispose ();

     // Disconnect from X server.
     X11lib.XCloseDisplay (_surface.Display);
     _surface.SetDisplay (IntPtr.Zero);

     e.Result = 0;
}

2. 由于OnClose委托的实现是以相反的顺序调用注册处理程序的,所以清理过程总是从派生类处理到基类处理程序——而且基类处理程序必须是最后一个处理程序,因为它从X11服务器断开了连接。 隐藏,复制Code

/// <summary> Handle the ClientMessage 'Close' event. </summary>
/// <paramname="e"> The event data. <seecref="XawClientMessageEvent"/> </param>
/// <remarks> Set XawClientMessageEvent result to nonzero to stop further event processing. </remarks>
public void OnClose (XrwClientMessageEvent e)
{
    // Call the close delegates in reverse order!
    object[]    param = new object[] {this, e};
    Delegate[]    delegates = WmShellClose.GetInvocationList();
    for (int i=delegates.Length-1;i>=0;i--)
        delegates[i].DynamicInvoke (param);
        
    //WmShellCloseDelegate wmShellClose = WmShellClose;
    //if (wmShellClose != null)
    //    wmShellClose (this, e);
}

这将支持资源释放而不会出现内存泄漏。 使用标准对话框 目前这些标准对话框是可用的: 用于只通知对话框的XrwMessageBox(除了OK和Cancel之间的选择外,没有输入)。用于单个文件选择的XrwFileSelectionDialog。使用所有X11字体信息选择字体。 这是带有纯文本和标记文本的XrwMessageBox的图像。 ,, 这是XrwFileSelectionDialog的一个映像。 这是XrwBitmapAndVectorFontSelectionDialog的一个图像。 (此对话框适合使用XLoadFont和XDrawString或XDrawString16输出非国际化文本,但不适合使用字体集输出I18N文本。) 现在这些额外的标准对话框是可用的: 这些是XrwColorSelectionDialog的图像,在8列和2行中使用16种预定义的颜色,或者在2列和8行中使用颜色名称。 现在这个附加的标准对话框是可用的: 这些是XrwColorChooseDialog的图像,使用一个用于标准颜色的笔记本页面和一个用于自定义颜色的笔记本页面。 现在这个附加的标准对话框是可用的: 这是XrwFontSelectionDialog的一个图像。 (此对话框适合使用字体集、XCreateFontSet和XwcDrawString进行国际化文本输出。) 创建XrwFileSelectionDialog、XrwBitmapAndVectorFontSelectionDialog、XrwColorSelectionDialog、XrwColorChoseDialog 和XrwFontSelectionDialog是很直接的。 示例代码展示了如何使用XrwFileSelectionDialog。 隐藏,收缩,复制Code

/// <summary> Handle the Clicked event. </summary>
/// <paramname="source"> The widget, the Clicked event is assigned to. <seecref="XrwRectObj"/> </param>
void HandleFileSelectionDialogButtonClicked (XrwRectObj source)
{
    XrwFileSelectionDialog fileDialog = XrwFileSelectionDialog.
        NewFileSelectionDialog (this, "Mono Develop - File selection", Environment.CurrentDirectory);
    fileDialog.SetMinimumSize (fileDialog.AssignedSize);

    // This call has been required before version 0.6.
    // Starting with version 0.6 the dialog's constructor sets the shell icon.
    // ApplicationFramework.SetWmShellIcon (fileDialog, AppIconFilePath);
 
    // This call has been required before version 0.6.
    // Starting with version 0.6 the dialog's Run() method registers the transient shell to the
    // application by this.AddTransientShell (fileDialog);
    XrwDialogShell.DialogResult result = fileDialog.Run ();

    if (result == XrwDialogShell.Result.OK)
    {
        if (XrwApplicationSettings.VERBOSE_OUTPUT_TO_CONSOLE)
            Console.WriteLine ("VERBOSE: " + CLASS_NAME +
                               "::HandleFileSelectionDialogButtonClicked() " +
                               "File dialog closed with: OK, File selected is: " + fileDialog.SelectedFile);
        ApplicationFramework.WriteStatus ("File selection dialog closed with: OK");
    }
    else
    {
        if (XrwApplicationSettings.VERBOSE_OUTPUT_TO_CONSOLE)
            Console.WriteLine ("VERBOSE: " + CLASS_NAME +
                               "::HandleFileSelectionDialogButtonClicked() " +
                               "File dialog closed with: Cancel");
        ApplicationFramework.WriteStatus ("File selection dialog closed with: Cancel");
    }
}

下一个示例代码展示了如何使用XrwBitmapAndVectorFontSelectionDialog。 隐藏,收缩,复制Code

/// <summary> Handle the Clicked event. </summary>
/// <paramname="source"> The widget, the Clicked event is assigned to. <seecref="XrwRectObj"/> </param>
void HandleFontDialogButtonClicked (XrwRectObj source)
{
    XrwBitmapAndVectorFontSelectionDialog fontDialog = XrwBitmapAndVectorFontSelectionDialog.
        NewBitmapAndVectorFontSelectionDialog (this, "Mono Develop - Font selection");
    fontDialog.SetMinimumSize (fontDialog.AssignedSize);
 
    // This call has been required before version 0.6.
    // Starting with version 0.6 the dialog's constructor sets the shell icon.
    // ApplicationFramework.SetWmShellIcon (fontDialog, APPICON_FILEPATH);
 
    // This call has been required before version 0.6.
    // Starting with version 0.6 the dialog's Run() method registers the transient shell to the
    // application by this.AddTransientShell (fontDialog);
 
    XrwDialogShell.DialogResult result = fontDialog.Run ();
 
    if (result == XrwDialogShell.Result.OK)
    {
        if (XrwApplicationSettings.VERBOSE_OUTPUT_TO_CONSOLE)
            Console.WriteLine ("VERBOSE: " + CLASS_NAME + "::HandleFontDialogButtonClicked() " +
                               "Font dialog closed with: OK");
        ApplicationFramework.WriteStatus ("Font selection dialog closed with: OK");
    }
    else
    {
        if (XrwApplicationSettings.VERBOSE_OUTPUT_TO_CONSOLE)
            Console.WriteLine ("VERBOSE: " + CLASS_NAME + "::HandleFontDialogButtonClicked() " +
                               "Font dialog closed with: Cancel");
        ApplicationFramework.WriteStatus ("Font selection dialog closed with: Cancel");
    }
}

下一个示例代码展示了如何使用XrwColorSelectionDialog。 隐藏,收缩,复制Code

/// <summary> Handle the Clicked event. </summary>
/// <paramname="source"> The widget, the Clicked event is assigned to. <seecref="XrwRectObj"/> </param>
void HandleColorSelectionDialogButtonClicked (XrwRectObj source)
{
    XrwColorSelectionDialog colorDialog = XrwColorSelectionDialog.NewColorSelectionDialog8x2 (this,
                                              "Mono Develop - Color selection", 0x00ffffff);
    colorDialog.SetMinimumSize (colorDialog.AssignedSize); 
    // This call has been required before version 0.6.
    // Starting with version 0.6 the dialog's constructor sets the shell icon.
    // ApplicationFramework.SetWmShellIcon (colorDialog, APPICON_FILEPATH);    
 
    // This call has been required before version 0.6.
    // Starting with version 0.6 the dialog's Run() method registers the transient shell to the
    // application by this.AddTransientShell (colorDialog); 
 
    XrwDialogShell.DialogResult result = colorDialog.Run ();    
    if (result == XrwDialogShell.Result.OK)
    {
        SimpleLog.LogLine (TraceEventType.Verbose, CLASS_NAME +
            "::HandleColorSelectionDialogButtonClicked () Color dialog closed with: OK, " +
            "Color selected is: #{0:X000000}", colorDialog.SelectedColor);
        ApplicationFramework.WriteStatus ("Color selection dialog closed with: OK");
    }
    else
    {
        SimpleLog.LogLine (TraceEventType.Verbose, CLASS_NAME +
            "::HandleColorSelectionDialogButtonClicked () Color dialog closed with: Cancel");
        ApplicationFramework.WriteStatus ("Color selection dialog closed with: Cancel");
    }
}

下一个示例代码展示了如何使用XrwColorChooseDialog。 隐藏,收缩,复制Code

/// Handle the ButtonRelease event.
/// <paramname="source"/>The widget, the ButtonRelease event is assigned to. <seecref="XrwRectObj"/>
/// <paramname="e"/>The event data. <seecref="XawButtonEvent"/>
/// <remarks>Set XawButtonEvent.result to nonzero to stop further event processing. </remarks>
void HandleColorChooseDialogButtonRelease (XrwRectObj source, XrwButtonEvent e)
{
    XrwColorChooseDialog colorDialog = XrwColorChooseDialog.NewColorCooseDialog (this,
        "Mono Develop - Color choose", 0x00ffffff);
    colorDialog.SetMinimumSize (colorDialog.AssignedSize); 
    // This call has been required before version 0.6.
    // Starting with version 0.6 the dialog's constructor sets the shell icon.
    // ApplicationFramework.SetWmShellIcon (colorDialog, APPICON_FILEPATH);    
 
    // This call has been required before version 0.6.
    // Starting with version 0.6 the dialog's Run() method registers the transient shell to the
    // application by this.AddTransientShell (colorDialog); 
 
    XrwDialogShell.DialogResult result = colorDialog.Run ();    
    if (result == XrwDialogShell.Result.OK)
    {
        SimpleLog.LogLine (TraceEventType.Verbose, CLASS_NAME +
            "::HandleColorChooseDialogButtonRelease () Color dialog closed with: OK, " +
            "Color selected is: #{0:X000000}", colorDialog.SelectedColor);
        ApplicationFramework.WriteStatus ("Color selection dialog closed with: OK");
    }
    else
    {
        SimpleLog.LogLine (TraceEventType.Verbose, CLASS_NAME +
            "::HandleColorChooseDialogButtonRelease () Color dialog closed with: Cancel");
        ApplicationFramework.WriteStatus ("Color selection dialog closed with: Cancel");
    }
}

下一个示例代码展示了如何使用XrwFontSelectionDialog。 隐藏,收缩,复制Code

/// <summary> Handle the ButtonRelease event. </summary>
/// <paramname="source"> The widget, the ButtonRelease event is assigned to.<seecref="XrwRectObj"/> </param>
/// <paramname="e"> The event data. <seecref="XawButtonEvent"/> </param>
/// <remarks> Set XawButtonEvent. Set result to nonzero to stop further event processing. </remarks>
void HandleVectorFontDialogButtonRelease (XrwRectObj source, XrwButtonEvent e)
{
    XrwFontSelectionDialog fontDialog =
        XrwFontSelectionDialog.NewFontSelectionDialog (this, "Mono Develop - GTK/Windows " +
                                                             "compatible font selection");
    fontDialog.Font = new Xrw.FontInfo ("Adobe Helvetica", 14, System.Drawing.FontStyleEx.Italic);
        
    System.Windows.MessageBoxResult result = fontDialog.Run ();
    
    if (result == System.Windows.MessageBoxResult.OK)
    {
        SimpleLog.LogLine (TraceEventType.Verbose, CLASS_NAME +
                        "::HandleVectorFontDialogButtonRelease () Font dialog closed with: OK");
        ApplicationFramework.WriteStatus ("Font selection dialog closed with: OK");
        
        // Get the font specification, that alows to load a specific font from X11 font server.
        // string fs = fontDialog.FontSpecification;
        // Get the font info to determine Strikeout and Underline.
        Xrw.FontInfo font = fontDialog.Font;
        if (font == null)
            return;
        
    }
    else
    {
        SimpleLog.LogLine (TraceEventType.Verbose, CLASS_NAME +
                           "::HandleVectorFontDialogButtonRelease () " +
                           "Font dialog closed with: Cancel");
        ApplicationFramework.WriteStatus ("Font selection dialog closed with: Cancel");
    }

    e.Result = 1;
}

在对话实例化之后,建议调用此调用: dialog.SetMinimumSize(dialog.AssignedSize)防止大小溢出。 所有的对话框计算它们的初始大小的方式是它是所有控件正确显示的最小大小。将初始大小设置为最小大小可以防止对话框调整为不合适的显示。 以前版本的Xrw也建议在对话框实例化后调用这些方法: ApplicationFramework。SetWmShellIcon(对话框,APPICON_FILEPATH)设置shell图标。addtransientshell(对话框)将对话框注册到应用程序的临时shell列表中。 但是这些调用已经不再必要了,因为它们现在在内部被称为框架。 XrwFileSelectionDialog, XrwBitmapAndVectorFontSelectionDialog, XrwColorSelectionDialog和XrwFontSelectionDialog被实现为应用模态对话框。因此调用XrwDialogShell。DialogResult result = dialog. run()等待对话框结束,然后可以对结果进行计算。 现在所有的标准对话框都支持键手势绑定。因此,对话框可以用[Escape]键(如果对话框包含取消按钮),[Enter]或[Return]键(相当于对话框的OK按钮)关闭。 事件处理的特定方面 重绘性能问题和/或闪烁 在窗口调整过程中,windows管理器会发出大量配置通知事件。应用程序为每个ConfigureNotify事件重新计算子部件的布局。新的大小会导致相应的Expose事件。由于X11的异步绘制模型-特别是对于复杂的布局由于布局重新计算时间-重绘制性能问题和/或闪烁的结果。 为了避免这种情况,雅典娜和Motif用他们的wigets (compress_motion, compress_exposure, compress_enterleave)提供了事件压缩标志。但是,这不是一个令人满意的解决方案,因为要压缩的事件必须已经排队并立即按顺序进行。我用这种方法进行的测试没有显示出显著的改进。 示例代码显示了XrwApplicat的一个片段ionShell DoEvent()方法,说明了这个事件压缩方法。 隐藏,收缩,复制Code

if (xevent.type == XEventName.ConfigureNotify)
{
    // ***************************************************************************************
    // Why does the GUI flicker and is there a way out?
    // http://fixunix.com/xwindows/556305-resizing-motif-xaw-xlib-apps-vs-resizing-gtk-qt-
    // apps-how-tospeed-up-xlib-app.html
    // ***************************************************************************************

    // This compression approach requires, that compressible events are ALREADY in the queue.
    // This assumption is NOT very realistic!!!
    X11EventHelper.Matches = 0;
    X11lib.XCheckIfEvent (_display, ref X11EventHelper.Event,
                          X11EventHelper.CountConfigureMatchesProcPtr,
                          xevent.ConfigureEvent.window);
    if (X11EventHelper.Matches > 0)
    {
        Console.WriteLine ("INFORMATION: " + CLASS_NAME + "::DoEvent () // CONFIGURE " +
                           "found subsequent configure events for window " +
                           xevent.ConfigureEvent.window.ToString("x") + " and skip this event.");
        return true;
    }

    ...
}
else if (xevent.type == XEventName.Expose)
{
    if (xevent.ExposeEvent.count > 0)
        return true;
    
    // ***************************************************************************************
    // Why does the GUI flicker and is there a way out?
    // http://fixunix.com/xwindows/556305-resizing-motif-xaw-xlib-apps-vs-resizing-gtk-qt-
    // apps-how-tospeed-up-xlib-app.html
    // ***************************************************************************************

    // This compression approach requires, that compressible events are ALREADY in the queue.
    // This is assumption NOT very realistic!!!
    X11EventHelper.Matches = 0;
    X11lib.XCheckIfEvent (_display, ref X11EventHelper.Event,
                          X11EventHelper.CountExposeMatchesProcPtr, xevent.ExposeEvent.window);
    if (X11EventHelper.Matches > 0)
    {
        Console.WriteLine ("INFORMATION: " + CLASS_NAME + "::DoEvent () // EXPOSE " +
                           "found subsequent expose events for window " +
                           xevent.ExposeEvent.window.ToString("x") + " and skip this event.");
        return true;
    }

    ...
}

我发现最好的方式,以避免重新绘制性能问题和/或闪烁的是每个ConfigureNotify暂停事件对于一些毫秒和压缩所有ConfigureNotify均等的emmitted期间暂停。这将导致重新划定延迟等于暂停时间间隔,但整个印象在调整过程更为顺畅。 示例代码显示了一个代码片段的XrwApplicationShell DoEvent()方法,说明了事件悬挂方式。 隐藏,收缩,复制Code

/// <summary>Define the suspension interval in milli-seconds.</summary>
private ulong           _compressConfigureBySuspend = 350;
    
/// <summary>Remember the point in time the last configuration took place.</summary>
private ulong           _lastConfigureShell = 0;
    
/// <summary>Keep the latest configuration event to process it after suspension.</summary>
private XConfigureEvent _lastConfigureEvent = new XConfigureEvent();

...


/// <summary> Process the topmost event and remove it from the event queue. </summary>
/// <returns> True if event processing must contionue, false otherwise. </returns>
public bool DoEvent()
{
    // Prevent event processing *** after dispose *** but *** before destruction ***.
    if (_display == IntPtr.Zero)
        return false;
    
    XEvent xevent = new XEvent ();
    
    // Ensure all events are queued.
    X11lib.XFlush (_display);
    
    // Check for suspended ConfigureEvent and process it after the suspension interval.
    if (X11lib.XQLength (_display) == 0 && _compressConfigureBySuspend > 0)
    {
        DateTime dt        = DateTime.Now;
        ulong timeStamp    = (ulong)(dt.Millisecond + dt.Second * 1000 + dt.Minute * 60000 +
                             dt.Hour * 3600000) + (ulong)dt.Day * (ulong)86400000;
        
        if (timeStamp - _lastConfigureShell > _compressConfigureBySuspend &&
            _lastConfigureEvent.window != IntPtr.Zero)
        {
            XrwConfigureEvent e = new XrwConfigureEvent (ref _lastConfigureEvent);
            OnConfigure (e);
            _lastConfigureEvent.window = IntPtr.Zero;
            _lastConfigureShell = timeStamp;
        }
        return true;
    }


    ...
}

_compressConfigureBySuspend间隔可以调整到一个特定的用例之间找到最优延迟和闪烁。值0完全抑制活动暂停。 我发现唯一的缺点是,XrwPaned不受益于这种方法。 无疑是最好的方法,以避免重新绘制性能问题和/或闪烁的是使用双缓冲技术。这种方法保存供以后使用,因为它打破了Xrw零依赖的承诺。 关键动作绑定 这个版本关键动作绑定支持。它可以用来注册全球任何XrwShell键盘快捷键(通常是应用程序shell或对话框shell)针对任何GUI元素。如可以使用这种技术来提高应用程序的可访问性(或对话框)。通常一个关键姿态的首选目标绑定菜单和丝带。示例代码显示了如何绑定关键姿态XrwRibbon并选择特定XrwRibbonTab。 隐藏,收缩,复制Code

...

    // -- Start connection of application global key gesture bindings.

    System.Windows.Input.ICommand      activateRibbonTab0_Action  = new RelayCommand
        (ActivateRibbonTab0_Action);
    Xrw.Utils.KeyGestureBinding        activateRibbonTab0_Gesture = new Xrw.Utils.KeyGestureBinding
        (activateRibbonTab0_Action, null, null, X11lib.XKeySym.XK_D,
         System.Windows.Input.ModifierKeys.Alt);
    ApplicationShell.InputReceiver.Add (activateRibbonTab0_Gesture);

    System.Windows.Input.ICommand      activateRibbonTab1_Action  = new RelayCommand
        (ActivateRibbonTab1_Action);
    Xrw.Utils.KeyGestureBinding        activateRibbonTab1_Gesture = new Xrw.Utils.KeyGestureBinding
        (activateRibbonTab1_Action, null, null, X11lib.XKeySym.XK_R,
         System.Windows.Input.ModifierKeys.Alt);
    ApplicationShell.InputReceiver.Add (activateRibbonTab1_Gesture);

    System.Windows.Input.ICommand      activateRibbonTab2_Action  = new RelayCommand
        (ActivateRibbonTab2_Action);
    Xrw.Utils.KeyGestureBinding        activateRibbonTab2_Gesture = new Xrw.Utils.KeyGestureBinding
        (activateRibbonTab2_Action, null, null, X11lib.XKeySym.XK_S,
     System.Windows.Input.ModifierKeys.Alt);
    ApplicationShell.InputReceiver.Add (activateRibbonTab2_Gesture);

    // -- End connection of application global key gesture bindings.

...

/// <summary>Activate ribbon tab 0 action to execute on kex gesture binding.</summary>
/// <paramname="parameter">Data used by the command. If the command does not require data
/// to be passed, this object can be set to null.<seecref="System.Object"/></param>
public void ActivateRibbonTab0_Action (object parameter)
{
    ribbon.SetSelectedTab (0);
}
/// <summary>Activate ribbon tab 1 action to execute on kex gesture binding.</summary>
/// <paramname="parameter">Data used by the command. If the command does not require data
/// to be passed, this object can be set to null.<seecref="System.Object"/></param>
public void ActivateRibbonTab1_Action (object parameter)
{
    ribbon.SetSelectedTab (1);
}
/// <summary>Activate ribbon tab 2 action to execute on kex gesture binding.</summary>
/// <paramname="parameter">Data used by the command. If the command does not require data
/// to be passed, this object can be set to null.<seecref="System.Object"/></param>
public void ActivateRibbonTab2_Action (object parameter)
{
    ribbon.SetSelectedTab (2);
}

...

来表示一个GUI元素的键盘快捷键,应该使用标记语法。 隐藏,复制Code

...

    XrwRibbonTab dialogtestTab = XrwRibbonTab.NewRibbonTabGadget
        (ribbon, "<markup><u>D</u>ialog test</markup>");

...

    XrwRibbonTab radiotoggletestTab  = XrwRibbonTab.NewRibbonTabGadget
        (ribbon, "<markup><u>R</u>adio & toggle test</markup>");

...

    XrwRibbonTab splitTab  = XrwRibbonTab.NewRibbonTabGadget
        (ribbon, "<markup><u>S</u>plit test</markup>");

...

这就是结果的样子。带选项卡可以通过组合键secected [Alt] + [d], [Alt] + [r]或[Alt] + [s]。 事件管理政策比较 这个表需要更仔细的观察到指针调用的事件和动作。一致的用户接受行为是一个非常重要的事实。不同的行为是用红色突出显示。 行动windows 8.1 gtk 2明显看起来xrw评论xrw打开一个菜单 下拉按钮1新闻 在任何按钮按下菜单按钮 在任何按钮按下菜单按钮 在菜单按钮,关闭一个菜单 延迟下拉按钮1 按适当 菜单按钮推迟任何按钮 在适当的释放 菜单按钮推迟任何按钮 按适当 菜单按钮按下 常见的接近一个菜单 下拉按钮按下任何 外的菜单 下拉按钮释放任何 外的菜单 下拉按钮按下任何 外的菜单 下拉按更 共同选择一个菜单项按钮1释放 在菜单项任何按钮释放 在菜单项任何按钮释放 在菜单项目前没有 打开一个组合框按钮1按上下文帮助 在组合框按钮1出版社 在组合框按钮按下 在组合框,关闭一个组合框延迟按钮1 按组合 框下拉延迟按钮1 在组合 框下拉推迟任何按钮 按组合 框下拉按更 常见的接近一个组合框按钮按下 外的组合 框下拉按钮释放 外的组合 框下拉按钮按下 外的组合 框下拉按更 共同选择一个组合框 item按钮1版本 在组合框按钮1项 在组合框按钮1项 在组合框项目目前没有 上下文帮助打开丝带 应用程序菜单按钮1出版社 菜单按钮,按钮按下 在菜单按钮,关闭丝带的 应用程序菜单延迟按钮1 按适当 菜单按钮——推迟任何按钮 按适当 菜单按钮,关闭丝带的 应用程序菜单按钮按下 外的菜单 拉-任何按钮按下 外的菜单 下拉,选择一个丝带的 应用程序菜单 item按钮1版本 在菜单项——任何按钮释放 在菜单项目前没有 上下文帮助打开丝带 分割按钮菜单按钮1出版社 在分裂——任何按钮按下的按钮 分割按钮上,关闭丝带的 分割按钮菜单延迟按钮1 按适当 分割按钮——推迟任何按钮 按适当 分割按钮,关闭丝带的 分割按钮菜单按钮按下 外的分裂 按钮下拉-任何按钮按下 外的分裂 按钮下拉,选择一个丝带的 分割按钮菜单 item按钮1版本 菜单项,按目前没有任何按钮 上下文帮助选项卡选择按钮1按钮按任何按钮按下,丝带选择按钮1新闻-任何按钮按下,合适的文本 编辑器调用延迟按钮1 按项目后 通过上下文菜单选择 delayed 选物品的;任何按钮 按项目后 选择延迟按钮 媒体更 常见的就地文本 编辑留下任何按钮按下 外, 编辑任何按钮按下 外, 编辑任何按钮按下 外, 地方编辑器, 使用剪贴板 目前仅支持剪贴板数据类型是字符串(原子_XA_STRING)。看到XrwApplicationShell地区更多的原子属性定义,如果其他剪贴板数据类型的支持。 复制或粘贴文本数据(应用程序)之间通过剪贴板任何部件(但不是一个小工具)可以通过XrwApplicationShell.ProvideClipboardText提供数据()或请求数据通过XrwApplicationShell.RequestClipboardText()。XrwText部件的剪贴板支持看起来像这样: 隐藏,收缩,复制Code

{
    ...
    // XrwText widget: Provide text data (_selectionStart and _selectionEnd are character positions).
    XrwApplicationShell app = this.ApplicationShell;
    if (_selectionStart != _selectionEnd && app != null)
    {
        SetCopyBuffer ();
        app.ProvideClipboardText (_surface, e.Event.time);
    }
    ...
}

...

{
    ...
    // XrwText widget: Request test data.
    XrwApplicationShell app = this.ApplicationShell;
    if (app != null)
    {
        app.RequestClipboardText (_surface, e.Event.time);
    }
    ...
}

...

{
    ...
    // XrwApplicationShell: What happens inside the application's event loop to inject result?
    s = Marshal.PtrToStringAuto (data);
    if (target as XrwText != null)
    {
        (target as XrwText).Paste (s);
    }
    ...
}

旁边XrwApplicationShell.ProvideClipboardText遗留X11兼容的方法()和XrwApplicationShell.RequestClipboardText(),现在Windows兼容的名字但不同参数列表的方法支持或者方便MS Windows相似的行为。为实现这一目标,“遗产X11兼容”funftionality System.Windows坐立的。剪贴板的方法SetText()和GetText()。 注意:即使namespace  System.Windows。的剪贴板方便MS Windows相似的行为意味着一个应用独立剪贴板,X11并不提供一个应用独立剪贴板——它必须实现由窗口管理器来执行,而不是应用程序或应用程序编程框架。因此一个成功的复制/粘贴操作总是要求供应商小部件和接收小部件是人工生命。 最后因为剪贴板数据分布式存储的(任何小部件可以是一个剪贴板数据提供者)和异步处理的剪贴板数据(应用程序之间的消息处理)在X11系统(Windows剪贴板系统相比集中式/单片)委托给请求者必须提供注入结果GetText()。 隐藏,收缩,复制Code

{
    ...
    // XAML TextBox control: Provide text data.
    XrwApplicationShell app = this.ApplicationShell;
    if (_selectionStart != _selectionEnd && app != null)
    {
        Clipboard.SetText (Entry.Text);
    }

...

    // XAML TextBox control: Request test data.
    XrwApplicationShell app = this.ApplicationShell;
    if (app != null)
    {
        // Besause of the asynchronous processing of clipboard data(inter-application
        // message processing) a delegate to inject the result must be provided.
        Clipboard.GetText (this.ProcessClipboardPasteToEntry);
    }
    ...
}

...

/// <summary>Handle the ClipboardGetResult event.</summary>
/// <paramname="result">The clipboard get text result.<seecref="System.Object"/></param>
private void ProcessClipboardPasteToEntry (object result)
{
    if (result != null)
    {
        Entry.Text = result.ToString ();
    }
}

...

{
    ...
    // XrwApplicationShell: What happens inside the application's event loop to inject result?
    s = Marshal.PtrToStringAuto (data);
    if (target as XrwApplicationShell != null)
    {
        System.Windows.ClipboardGetResultDelegate clipboardGetResult =
            System.Windows.Clipboard.ClipboardGetResult;
        if (clipboardGetResult != null)
            clipboardGetResult (s);
    }
    ...
}

历史 本文从文章编程罗马分裂部件集(c# X11)——零依赖GUI应用程序框架——第1部分,基本与公众第四版的罗马小部件集,来自13个版本。2014年5月。 第五公共版本的罗马version 小部件集;从15。2014年8月。 第六届公共版本的罗马小部件集从05版。2014年10月。 第七个公共版本的罗马version 小部件集;从14。2014年12月。 第八届公共版本的罗马version 小部件集;从8。2015年3月。 第八届公共版本的罗马version 小部件集;从21。2015年10月。 本文转载于:http://www.diyabc.com/frontweb/news4885.html

posted @ 2020-08-09 10:51  Dincat  阅读(370)  评论(0编辑  收藏  举报