如何正确获得一个WinForms Button控件绘制自定义文本 [英] How to correctly get a WinForms Button control to draw custom text

查看:195
本文介绍了如何正确获得一个WinForms Button控件绘制自定义文本的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建一个自定义的WinForms按钮控制,将允许按钮文字的旋转通过旋转属性。我大部分时间得到它的工作,但它是非常缺憾,我想知道正确的方式来做到这一点。



特别是现在的文本重绘的行为异常。如果控制移出屏幕,然后慢慢移动回来的文字要么变得非常搞砸了(如只有一半绘制),或者完全消失,直到将鼠标悬停。很显然,我做错了什么,但无法弄清楚什么。



我是从控制按钮继承并重写其OnPaint方法。



下面是代码:

 公共类RotateButton:按钮
{
私人字符串文本;
私人布尔绘画= FALSE;

公共枚举RotationType {无,右,翻转,左}

[默认值(RotationType.None),类别(外观),说明(旋转按钮文本 )
公共RotationType旋转{搞定;组; }

公众覆盖字符串文本
{
得到
{
如果
返回文本(画!);
,否则
返回;
}

{
文本=价值;
}
}

保护覆盖无效的OnPaint(PaintEventArgs的E)
{
绘画= TRUE;

base.OnPaint(E);

格式的StringFormat =新的StringFormat();
的Int32 LNUM =(Int32)已将Math.log((双人间)this.TextAlign,2);
format.LineAlignment =(StringAlignment)(LNUM / 4);
format.Alignment =(StringAlignment)(LNUM%4);

INT填充= 2;

的SizeF TXT = e.Graphics.MeasureString(文字,this.Font);
的SizeF SZ = e.Graphics.VisibleClipBounds.Size;

如果(旋转== RotationType.Right)
{
// 90度
e.Graphics.TranslateTransform(sz.Width,0);
e.Graphics.RotateTransform(90);
e.Graphics.DrawString(文字,this.Font,Brushes.Black,新的RectangleF(填充,填充sz.Height - 填充,sz.Width - 填充),格式);
e.Graphics.ResetTransform();
}
,否则如果(旋转== RotationType.Flip)
{
// 180度
e.Graphics.TranslateTransform(sz.Width,sz.Height) ;
e.Graphics.RotateTransform(180);
e.Graphics.DrawString(文字,this.Font,Brushes.Black,新的RectangleF(填充,填充sz.Width - 填充,sz.Height - 填充),格式);
e.Graphics.ResetTransform();
}
,否则如果(旋转== RotationType.Left)
{
// 270度
e.Graphics.TranslateTransform(0,sz.Height);
e.Graphics.RotateTransform(270);
e.Graphics.DrawString(文字,this.Font,Brushes.Black,新的RectangleF(填充,填充sz.Height - 填充,sz.Width - 填充),格式);
e.Graphics.ResetTransform();
}
,否则
{
// 0 = 360度
e.Graphics.TranslateTransform(0,0);
e.Graphics.RotateTransform(0);
e.Graphics.DrawString(文字,this.Font,Brushes.Black,新的RectangleF(填充,填充sz.Width - 填充,sz.Height - 填充),格式);
e.Graphics.ResetTransform();
}

绘画= FALSE;
}
}



所以我的主要问题是我怎么可能会解决文本?重绘问题



另外,我有几个其他问题/上述代码的注释:




  1. 起初文本是显示了两次,一次在它的默认位置,并且曾经在旋转的位置。我想这是因为该文本被抽中当 base.OnPaint 方法被调用。如果是这样的话,我怎么保持文本从图纸开始?



    我的解决办法是重写的文本字符串,并调用 base.OnPaint 使用一个布尔值,这不是一个解决方案,我感到特别高兴。


  2. 我应该处理的在与 e.dispose 到底PaintEventArgs的?我想我不知道PaintEventArgs的对象是如何被处理的。




在此先感谢!



诗。这是我的第一篇文章/问题,所以我提前道歉,如果我在不经意间忽略了一些礼仪和规则。


解决方案

  1. VisibleClipBounds返回如果需要一半的按钮,需要重新绘制重新绘制,例如区域(上形成覆盖半个键关闭时)VisibleClipBounds只返回该地区。所以你不能利用它来进行绘画居中文本。
    的SizeF SZ =新的SizeF(宽度,高度);
    应该照顾重绘问题。


  2. 按钮不支持业主绘图,用自己的方式看起来很好。


  3. 作为一个规则,你不应该处理您尚未创建对象,一次性事件参数创建它们(并称为上的逻辑布置......摆在首位),所以不用担心PaintEventArgs的处置




欢迎堆栈溢出。)


I'm trying to create a custom winforms button control that will allow rotation of the button text through a rotation property. I've mostly got it working, but it's very kludgy and I would like to know the proper way to do this.

Particularly right now the text redrawing is behaving strangely. If the control is moved off screen, and then moved slowly back on the text either becomes very messed up (such as only half drawn), or disappears entirely, until moused over. Obviously I'm doing something wrong, but can't figure out what.

I'm inheriting from the button control and overriding its OnPaint method.

Here is the code:

public class RotateButton : Button
{
    private string text;
    private bool painting = false;

    public enum RotationType { None, Right, Flip, Left}

    [DefaultValue(RotationType.None), Category("Appearance"), Description("Rotates Button Text")]
    public RotationType Rotation { get; set; }

    public override string Text
    {
        get
        {
            if (!painting)
                return text;
            else
                return "";
        }
        set
        {
            text = value;
        }
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        painting = true;

        base.OnPaint(e);

        StringFormat format = new StringFormat();
        Int32 lNum = (Int32)Math.Log((Double)this.TextAlign, 2);
        format.LineAlignment = (StringAlignment)(lNum / 4);
        format.Alignment = (StringAlignment)(lNum % 4);

        int padding = 2;

        SizeF txt = e.Graphics.MeasureString(Text, this.Font);
        SizeF sz = e.Graphics.VisibleClipBounds.Size;

        if (Rotation == RotationType.Right)
        {
            //90 degrees
            e.Graphics.TranslateTransform(sz.Width, 0);
            e.Graphics.RotateTransform(90);
            e.Graphics.DrawString(text, this.Font, Brushes.Black, new RectangleF(padding, padding, sz.Height - padding, sz.Width - padding), format);
            e.Graphics.ResetTransform();
        }
        else if (Rotation == RotationType.Flip)
        {
            //180 degrees
            e.Graphics.TranslateTransform(sz.Width, sz.Height);
            e.Graphics.RotateTransform(180);
            e.Graphics.DrawString(text, this.Font, Brushes.Black, new RectangleF(padding, padding, sz.Width - padding, sz.Height - padding), format);
            e.Graphics.ResetTransform();
        }
        else if (Rotation == RotationType.Left)
        {
            //270 degrees
            e.Graphics.TranslateTransform(0, sz.Height);
            e.Graphics.RotateTransform(270);
            e.Graphics.DrawString(text, this.Font, Brushes.Black, new RectangleF(padding, padding, sz.Height - padding, sz.Width - padding), format);
            e.Graphics.ResetTransform();
        }
        else
        {
            //0 = 360 degrees
            e.Graphics.TranslateTransform(0, 0);
            e.Graphics.RotateTransform(0);
            e.Graphics.DrawString(text, this.Font, Brushes.Black, new RectangleF(padding, padding, sz.Width - padding, sz.Height - padding), format);
            e.Graphics.ResetTransform();
        }

        painting = false;
    }
}

So my main question is how might I fix the text redrawing problem?

In addition I have a few other questions/comments on the above code:

  1. At first the text was showing up twice, once in it's default location, and once in the rotated location. I assume this is because the text is being drawn first when the base.OnPaint method is called. If this is the case, how do I keep the text from drawing initially?

    My solution is to to override the Text string and clear it before calling base.OnPaint using a boolean, which is not a solution I'm particularly happy with.

  2. Should I be disposing of the PaintEventArgs at the end with e.dispose? I guess I'm not sure how the PaintEventArgs object is being dealt with.

Thanks in advance!

Ps. This is my first post/question, so I apologize in advance if I inadvertently ignored some etiquette or rules.

解决方案

  1. VisibleClipBounds returns the area that needs to be repainted, for example if half the button needs to be repainted (a top form covering half the button is closed) VisibleClipBounds returns only that area. So you can't use that for painting centered text. SizeF sz = new SizeF(Width, Height); Should take care of the repainting problem.

  2. Button doesn't support owner drawing, your way seems fine.

  3. As a rule you shouldn't dispose objects you haven't created, and disposable event arguments are disposed by the logic that created them (and called the On... in the first place) so don't worry about disposing PaintEventArgs.

Welcome to Stack Overflow :)

这篇关于如何正确获得一个WinForms Button控件绘制自定义文本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆