winforms 在带有图像的按钮上设置高度时,自动省略号不工作

t5zmwmid  于 2023-03-19  发布在  其他
关注(0)|答案(1)|浏览(143)

我有一个按钮

_BtnDump = new Button();
            _BtnDump.Name = "dum" + i;
            _BtnDump.Text = data.DumpName;
            _BtnDump.Width = 98;
            _BtnDump.Height = 52;
            //add icon dump puja
            _BtnDump.Image = Image.FromFile(@"Images\dump.ico");
            _BtnDump.TextAlign = ContentAlignment.MiddleCenter;
            _BtnDump.TextImageRelation = TextImageRelation.TextAboveImage;
            // Below code is not work yet. the layout get screwed
            //_BtnDump.Font = new Font("Microsoft Sans Serif", 11); //new methode
            _BtnDump.Visible = true;
            _BtnDump.AutoSize = false;
            _BtnDump.AutoEllipsis = true;
            _BtnDump.TextAlign = ContentAlignment.MiddleCenter;

将高度默认值设置为23到52时,文本将更改为多行且不显示“...”
如何保持文本单行时,高度设置与自动省略号?
我设置高度是因为我在文本下面有图像。所以,当文本多行时,图像被裁剪。

编辑

这是使用@ dr. null中的代码时的结果图像。图像现在未被裁剪,但文本之间的图像区域较小,因此按下图像,并且使用TextImageRelation.ImageAboveText

时图像始终在底部
这是我想要的钮扣

t8e9dugd

t8e9dugd1#

Button控件在设计上没有提供很多指示文本应如何格式化和呈现的信息。无论是在使用Gdi还是Gdi+方法呈现字符串时。如果启用了UseCompatibleTextRendering属性,则使用Gdi+。两种文本格式都有断字标志。
虽然默认的文本呈现在我看来近乎完美,但如果愿意,您仍然可以更改此行为,使文本在一行中进行修剪。重写OnPaint方法以保持按钮的视觉样式,并在正确的位置和大小绘制每个部分。(文本、图像、面部、高亮显示......等),主要根据TextTextAlignImageImageAlignTextImageRelationFont等的值。
这里我将使用Reflection从基类、适配器和相关的helper类获取所有绘图需求,而不是执行所有这些操作。

  • 来自LayoutOptions.LayoutData示例的文本和图像边界。
  • 分别来自LayoutOptions.TextFormatFlagsLayoutOptions.StringFormat属性的TextFormatFlagsStringFormat
  • 来自DetermineState方法的PushButtonState
[DesignerCategory("Code")]
public class WordWrapButton : Button
{
    private bool _wordWrop = true;
    // false to enable the single line text...
    [DefaultValue(true)]
    public bool WordWrap
    {
        get => _wordWrop;
        set
        {
            if (_wordWrop != value)
            {
                _wordWrop = value;
                Invalidate();
            }
        }
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);

        if (WordWrap || FlatStyle != FlatStyle.Standard) return;

        LayoutData data = new LayoutData(this, e);

        ButtonRenderer.DrawButton(e.Graphics, ClientRectangle,
            string.Empty, Font, false, data.State);

        if (UseCompatibleTextRendering)
        {
            using (var br = new SolidBrush(Enabled
                ? ForeColor : SystemColors.GrayText))
                e.Graphics.DrawString(Text, Font, br,
                    data.TextBounds, data.StringFormat);
        }
        else
        {
            TextRenderer.DrawText(e.Graphics, Text, Font, data.TextBounds,
                Enabled ? ForeColor : SystemColors.GrayText, data.TextFormat);
        }

        if (Image != null)
        {
            if (Enabled)
                e.Graphics.DrawImage(Image, data.ImageBounds);
            else
            {
                ControlPaint.DrawImageDisabled(e.Graphics, Image,
                    data.ImageBounds.X, data.ImageBounds.Y, Color.Transparent);
            }
        }            
    }

    class LayoutData
    {
        public LayoutData(ButtonBase button, PaintEventArgs e)
        {
            var pubFlags = BindingFlags.Instance | BindingFlags.Public;
            var nonPubFlags = BindingFlags.Instance | BindingFlags.NonPublic;
            var adapter = button.GetType()
                .GetProperty("Adapter", nonPubFlags)
                .GetValue(button);
            var layoutOptions = adapter.GetType()
                .GetMethod("Layout", nonPubFlags)
                .Invoke(adapter, new object[] { e });
            var layoutData = layoutOptions.GetType()
                .GetMethod("Layout", nonPubFlags)
                .Invoke(layoutOptions, null);

            Client = (Rectangle)layoutData.GetType()
                .GetField("client", nonPubFlags)
                .GetValue(layoutData);

            ImageBounds = (Rectangle)layoutData.GetType()
                .GetField("imageBounds", nonPubFlags)
                .GetValue(layoutData);

            TextBounds = (Rectangle)layoutData.GetType()
                .GetField("textBounds", nonPubFlags)
                .GetValue(layoutData);

            TextFormat = (TextFormatFlags)layoutOptions.GetType()
                .GetProperty("TextFormatFlags", pubFlags)
                .GetValue(layoutOptions);

            TextFormat &= ~TextFormatFlags.WordBreak;

            if (button.AutoEllipsis)
                TextFormat |= TextFormatFlags.WordEllipsis;

            StringFormat = (StringFormat)layoutOptions.GetType()
                .GetProperty("StringFormat", pubFlags)
                .GetValue(layoutOptions);

            StringFormat.FormatFlags |= StringFormatFlags.NoWrap;

            if (button.AutoEllipsis)
                StringFormat.Trimming = StringTrimming.EllipsisWord;                

            State = (System.Windows.Forms.VisualStyles.PushButtonState)
                adapter.GetType()
                .GetMethod("DetermineState", nonPubFlags)
                .Invoke(adapter, new object[] { true });

            if (button.ClientRectangle.
                Contains(button.PointToClient(MousePosition)) &&
                MouseButtons == MouseButtons.Left)
                State = System.Windows.Forms.VisualStyles.PushButtonState.Pressed;
        }

        public Rectangle Client { get; }
        public Rectangle TextBounds  { get; }
        public Rectangle ImageBounds { get; }
        public TextFormatFlags TextFormat { get; }
        public StringFormat StringFormat { get; }
        public System.Windows.Forms.VisualStyles.PushButtonState State { get; }
    }
}

下面是针对您的特定要求的另一个示例,其中:

  • 你有一个Image要显示在文本下面(从TextImageRelation = TextImageRelation.TextAboveImage开始),如果它的大小大于可用空间,它不应该被剪切。为此,你需要调用一个Graphics.DrawImage方法重载,它同时接受目标矩形和源矩形。
  • 如果需要,文本应呈现为一行,并进行修剪。
  • 填充按钮面的颜色,并保持悬停,按下,聚焦效果。
// +
using VisualStyles = System.Windows.Forms.VisualStyles;

[DesignerCategory("Code")]
public class WordWrapButton : Button
{
    protected override void OnPaint(PaintEventArgs e)
    {
        var g = e.Graphics;
        var flags = TextFormatFlags.VerticalCenter
            | TextFormatFlags.HorizontalCenter;

        if (AutoEllipsis) flags |= TextFormatFlags.WordEllipsis;

        var recFocus = new Rectangle(4, 4, Width - 8, Height - 8);
        var recText = new Rectangle(recFocus.X, recFocus.Y, recFocus.Width,
            TextRenderer.MeasureText(g, Text, Font, recFocus.Size, flags).Height * 2);
        var recImage = new Rectangle(recFocus.X, recText.Bottom, recFocus.Width,
            recFocus.Bottom - recText.Bottom);
        var state = VisualStyles.PushButtonState.Normal;

        if (Enabled)
        {
            if (ClientRectangle.Contains(PointToClient(MousePosition)))
            {
                if (MouseButtons == MouseButtons.Left)
                    state = VisualStyles.PushButtonState.Pressed;
                else
                    state = VisualStyles.PushButtonState.Hot;
            }
            else if (Focused)
            {
                state = VisualStyles.PushButtonState.Default;
            }
            else
            {
                recFocus.Inflate(1, 1);
            }
        }
        else
        {
            state = VisualStyles.PushButtonState.Disabled;
            recFocus.Inflate(1, 1);
        }

        base.OnPaint(e);

        ButtonRenderer.DrawButton(g, ClientRectangle, state);

        using (var br = new SolidBrush(BackColor))
            g.FillRectangle(br, recFocus);

        TextRenderer.DrawText(g, Text, Font, recText, Enabled
            ? ForeColor : SystemColors.GrayText, flags);

        if (Image != null)
        {
            g.InterpolationMode = InterpolationMode.HighQualityBicubic;

            if (Enabled)
            {
                g.DrawImage(Image, recImage,
                    0, 0, Image.Width, Image.Height, GraphicsUnit.Pixel);
            }
            else
            {
                var cm = new ColorMatrix(new float[][]
                {
                        new [] { 0.299f, 0.299f, 0.299f, 0f, 0f},
                        new [] { 0.587f, 0.587f, 0.587f, 0f, 0f},
                        new [] { 0.114f, 0.114f, 0.114f, 0f, 0f},
                        new [] { 0f, 0f, 0f, 1f, 0f},
                        new [] { 0f, 0f, 0f, 0f, 1f}
                });
                using (var att = new ImageAttributes())
                {
                    att.SetColorMatrix(cm, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);

                    g.DrawImage(Image, recImage, 0, 0, Image.Width, Image.Height,
                        GraphicsUnit.Pixel, att);
                }
            }
        }
    }
}

注意,忘记在我的第一篇文章中提到,如果文本被裁剪并且AutoEllipsis属性被启用,则调用base.OnPaint(e);也是显示工具提示所必需的。

相关问题