• 11.WPF绘图


    11.绘图

    WPF基本的图形包括:

    • Line,直线段
    • Rectangle,矩形
    • Ellipse,椭圆
    • Polygon,多边形,由多条直线段围成的闭合区域
    • Polylin,折线,不闭合
    • Path,路径,闭合区域,基本图形中功能最强大的一个,可由直线、圆弧、贝塞尔曲线组成

    绘图不一定要在Canvas中完成,可以再任何一种布局中完成。

    基本图形

    Line

    X1,Y1作为起点,X2,Y2作为终点。Stroke(边线)属性的数据类型是Brush,用来填充。

    <Window x:Class="WpfApplication1.Window45"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="Window45" Height="293" Width="437">
        <Grid>
            <Line X1="10" Y1="20" X2="260" Y2="20" Stroke="Red" StrokeThickness="10">Line>
            <Line X1="10" Y1="40" X2="260" Y2="40" Stroke="Orange" StrokeThickness="6">Line>
            <Line X1="10" Y1="60" X2="260" Y2="60" Stroke="Green" StrokeThickness="3">Line>
            <Line X1="10" Y1="80" X2="260" Y2="80" Stroke="Purple" StrokeThickness="2">Line>
            <Line X1="10" Y1="100" X2="260" Y2="100" Stroke="Black" StrokeThickness="1">Line>
            <Line X1="10" Y1="120" X2="260" Y2="120" StrokeDashArray="3" Stroke="Black" StrokeThickness="1">Line>
            <Line X1="10" Y1="140" X2="260" Y2="140" StrokeDashArray="5" Stroke="Black" StrokeThickness="1">Line>
            <Line X1="10" X2="260" Y1="160" Y2="160" Stroke="Black" StrokeThickness="6" StrokeEndLineCap="Flat">Line>
            <Line X1="10" X2="260" Y1="180" Y2="180" Stroke="Black" StrokeThickness="8" StrokeEndLineCap="Triangle">Line>
            <Line X1="10" X2="260" Y1="200" Y2="200" StrokeEndLineCap="Round" StrokeThickness="10">
                <Line.Stroke>
                    <LinearGradientBrush EndPoint="0,0.5" StartPoint="1,0.5">
                        <GradientStop Color="Blue">GradientStop>
                        <GradientStop Offset="1" Color="Red">GradientStop>
                    LinearGradientBrush>
                Line.Stroke>
            Line>
        Grid>
    Window>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dv5lBODs-1668244504880)(C:\Users\cni23287938\AppData\Roaming\Typora\typora-user-images\image-20221111151636222.png)]

    Rectangle

    矩形由Stroke(边线)和Fill(填充)构成。数据类型均为Brush,常见的Brush子类有:

    • SolidColorBrush:实心画刷,常用Red、Blue等字符串赋值
    • LinearGradientBrush:线性渐变画刷
    • RadialGradentBrush:径向渐变画刷
    • ImageBrush:图片作为内容
    • DrawingBrush:矢量图或者位图填充
    • VisualBrush:每个控件的可视化形象可以通过Visual类的方法获得,并用该形象进行填充,这就是VisualBrush。如:控件被拖拽过程中显示一个幻影,这个幻影就可以使用VisualBrush来填充。
    <Window x:Class="WpfApplication1.Window46"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="Window46" Height="390" Width="600">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="180" />
                <ColumnDefinition Width="10" />
                <ColumnDefinition Width="180" />
                <ColumnDefinition Width="10" />
                <ColumnDefinition Width="180*" />
            Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="160" />
                <RowDefinition Height="10" />
                <RowDefinition Height="160" />
            Grid.RowDefinitions>
            
            <Rectangle Grid.Row="0" Grid.Column="0" Stroke="Black" Fill="LightBlue">Rectangle>
            
            <Rectangle Grid.Row="0" Grid.Column="2">
                <Rectangle.Fill>
                    <LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
                        <GradientStop Color="#FFB6F8F1" Offset="0">GradientStop>
                        <GradientStop Color="#FF0082BD" Offset="0.25">GradientStop>
                        <GradientStop Color="#FF95DEFF" Offset="0.6">GradientStop>
                        <GradientStop Color="#FF004F72" Offset="1">GradientStop>
                    LinearGradientBrush>
                Rectangle.Fill>
            Rectangle>
            
            <Rectangle Grid.Row="0" Grid.Column="4">
                <Rectangle.Fill>
                    <RadialGradientBrush>
                        <GradientStop Color="#FFB6F8F1" Offset="0">GradientStop>
                        <GradientStop Color="#FF0082BD" Offset="0.25">GradientStop>
                        <GradientStop Color="#FF95DEFF" Offset="0.75">GradientStop>
                        <GradientStop Color="#FF004F72" Offset="1.5">GradientStop>
                    RadialGradientBrush>
                Rectangle.Fill>
            Rectangle>
            
            <Rectangle Grid.Row="2" Grid.Column="0">
                <Rectangle.Fill>
                    <ImageBrush ImageSource="./01077_1.png" Viewport="0,0,0.3,0.3" TileMode="Tile">
                        
                    ImageBrush>
                Rectangle.Fill>
            Rectangle>
            
            <Rectangle Grid.Row="2" Grid.Column="2">
                <Rectangle.Fill>
                    <DrawingBrush Viewport="0,0,0.2,0.2" TileMode="Tile">
                        <DrawingBrush.Drawing>
                            <GeometryDrawing Brush="LightBlue">
                                <GeometryDrawing.Geometry>
                                    <EllipseGeometry RadiusX="10" RadiusY="10">EllipseGeometry>
                                GeometryDrawing.Geometry>
                            GeometryDrawing>
                        DrawingBrush.Drawing>
                    DrawingBrush>
                Rectangle.Fill>
            Rectangle>
            
            <Rectangle Grid.Row="2" Grid.Column="5" StrokeThickness="10">
                <Rectangle.Stroke>
                    <LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
                        <GradientStop Color="White" Offset="0.3">GradientStop>
                        <GradientStop Color="Blue" Offset="1">GradientStop>
                    LinearGradientBrush>
                Rectangle.Stroke>
            Rectangle>
        Grid>
    Window>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-acj40m9h-1668244504881)(11.绘图.assets/image-20221111153230825.png)]

    使用visualBrush的案例

    <Grid Margin="10">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="160" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="160" />
        Grid.ColumnDefinitions>
        <StackPanel Background="White" x:Name="spleft">
            <Button Height="40" Content="OK" x:Name="btnReal" Click="btnReal_Click">Button>
        StackPanel>
        <Button Grid.Column="1" Content=">>" Margin="5,0">Button>
        <StackPanel Grid.Column="2" Background="White" x:Name="spRight">
        StackPanel>
    Grid>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    double o = 1;//不透明度指数
    private void btnReal_Click(object sender, RoutedEventArgs e)
    {
        VisualBrush vb = new VisualBrush(this.btnReal);
        Rectangle rtg = new Rectangle();
        rtg.Width = btnReal.Width;
        rtg.Height = btnReal.Height;
        rtg.Fill = vb;
        rtg.Opacity = o;
        o -= 0.2;
        this.spRight.Children.Add(rtg);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fuS3Exaf-1668244504881)(11.绘图.assets/image-20221111154534841.png)]

    Ellipse

    <Grid>
        <Ellipse Height="140"  Name="ellipse1" Stroke="Gray" Width="140" Cursor="Hand" ToolTip="A Ball">
            <Ellipse.Fill>
                <RadialGradientBrush GradientOrigin="0.2,0.8" RadiusX="0.75" RadiusY="0.75">
                    <RadialGradientBrush.RelativeTransform>
                        <TransformGroup>
                            <RotateTransform Angle="90" CenterX="0.5" CenterY="0.5">RotateTransform>
                        TransformGroup>
                    RadialGradientBrush.RelativeTransform>
                    <GradientStop Color="#FFFFFFFF" Offset="0" />
                    <GradientStop Color="#FF444444" Offset="0.66" />
                    <GradientStop Color="#FF999999" Offset="1" />
                RadialGradientBrush>
            Ellipse.Fill>
        Ellipse>
    Grid>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-peioLCuy-1668244504882)(11.绘图.assets/image-20221111154656159.png)]

    Path

    路径可以替代其他几种图形,并且可以将直线、圆弧等基本元素结合形成复杂的图形。Path最重要的属性是Data,其数据类型为Geometry抽象类。Geometry子类包括:

    • LineGeometry:直线几何
    • RectangleGeometry:矩形几何
    • EllipseGeometry:椭圆几何
    • PathGeometry:路径几何
    • StreamGeometry:PathGeometry的轻量替代类,不支持Binding、动画等
    • CombinedGeometry:多个基本图形的组合,形成一个几何图形
    • GeometryGroup:多个基本图形的组合,形成一个几何图形组

    与Line、Rectangle等的区别:Line等可以独立存在,而Geometry只能结合其他几何,不能独立存在。

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="160" />
            <RowDefinition Height="160" />
        Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="160" />
            <ColumnDefinition Width="160" />
        Grid.ColumnDefinitions>
        
        <Path Stroke="Blue" StrokeThickness="2" Grid.Row="0" Grid.Column="0">
            <Path.Data>
                <LineGeometry StartPoint="0,0" EndPoint="160,160">LineGeometry>
            Path.Data>
        Path>
        
        <Path Stroke="Orange" Fill="Yellow" Grid.Row="0" Grid.Column="1">
            <Path.Data>
                <RectangleGeometry Rect="20,20,120,120" RadiusX="10" RadiusY="10">RectangleGeometry>
            Path.Data>
        Path>
        
        <Path Stroke="Green" Fill="LawnGreen" Grid.Column="0" Grid.Row="1">
            <Path.Data>
                <EllipseGeometry Center="80,80" RadiusX="60" RadiusY="40">EllipseGeometry>
            Path.Data>
        Path>
        
        <Path Stroke="Yellow" Fill="Orange" Grid.Row="1" Grid.Column="1">
            <Path.Data>
                <PathGeometry>
     
                    <PathGeometry.Figures>
                        <PathFigure StartPoint="25,140" IsClosed="True">
                            <PathFigure.Segments>
                                <LineSegment Point="20,40">LineSegment>
                                <LineSegment Point="40,110">LineSegment>
                                <LineSegment Point="50,20">LineSegment>
                                <LineSegment Point="80,110">LineSegment>
                                <LineSegment Point="110,20">LineSegment>
                                <LineSegment Point="120,110">LineSegment>
                                <LineSegment Point="140,40">LineSegment>
                                <LineSegment Point="135,140">LineSegment>
                            PathFigure.Segments>
                        PathFigure>
                    PathGeometry.Figures>
                PathGeometry>
            Path.Data>
        Path>
    Grid>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    PathFigure的Segments属性所包含的线段:

    • LineSegment:直线
    • ArcSegment:圆弧
    • BezierSement:三次方贝塞尔曲线
    • QuadraticBezierSement:二次方贝塞尔曲线
    • PolyLineSegment:多直线段
    • PolyBezierSegment:多三次方贝塞尔曲线
    • PolyQuadraticBezierSement:多二次方贝塞尔曲线

    注意:绘制上面的线段是没有起点的,起点就是上一个线段的终点,第一个线段的起点是PathFigure的StartPoint。

    路径标记法

    Path非常强大,但是上面的标签式的语法过于繁琐。WPF提供路径标记法来替代标签式语法。、

    路径标记法就是各种线段的简记法,如可以改为L, 15,15。除此之外,路径标记法还增加了一些实用的命令,如H 80,代表从当前点画一条水平直线,横坐标终点是80。

    使用路径标记法的步骤分为三步移动至起点->绘图->闭合图形,常用命令如下:

    命令用途语法示例标签式语法分类
    M移动到起点M 起始点M 10,10移动命令
    L绘制直线L 终点L 150,30绘图命令
    H绘制水平直线H 终点横坐标H 180绘图命令
    V绘制数值线V 终点纵坐标V 180绘图命令
    A绘制圆弧A 母椭圆尺寸 旋转角度是否大弧 顺/逆 终点A 180,80 45 1 1 150,150绘图命令
    C三次方贝塞尔曲线C 控制点1 控制点2 终点C 250,0 50,200 300,200绘图命令
    Q二次方贝塞尔Q 控制点1 终点Q 150,100 300,200绘图命令
    S平滑三次贝塞尔S 控制点2 终点S 100,200 200,300绘图命令
    T平滑二次方贝塞尔T 终点T 400,200绘图命令
    Z闭合图形ZM 0,0 L 40,80 L80,40 Z关闭命令

    裁剪界面

    不规则窗体和控件仅需使用Clip属性就可以做到。

    <Grid VerticalAlignment="Center" HorizontalAlignment="Center">
        <Path Stroke="Orange" Fill="Yellow" x:Name="clipPath0" Visibility="Hidden" Data="M 55,100 A 50,50 0 1 1 100,60 A 110,95 0 0 1 200,60 A 50,50 0 1 1 250,100 A 110,95 0 1 1 55,100 Z">
        Path>
        <Button Content="Clip" Width="80" Height="25" Click="Button_Click" HorizontalAlignment="Center" VerticalAlignment="Center">Button>
    Grid>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    private void Button_Click(object sender, RoutedEventArgs e)
    {
        this.Clip = clipPath0.Data;
    }
    
    • 1
    • 2
    • 3
    • 4

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uIIf142q-1668244504882)(11.绘图.assets/image-20221111165718454.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rFXmg5cL-1668244504883)(11.绘图.assets/image-20221111165800466.png)]

    图形的效果与滤镜

    简单易用的BitmapEffect

    WPF早期的效果属性,是使用CPU来进行运算,会导致程序卡顿,不建议使用

    BitmapEffect派生类

    • BevelBitmapEffect:斜角效果
    • BitmapEffectGroup:符合效果
    • BlurBitmapEffect:模糊效果
    • DropShadowBitmapEffect:投影效果
    • EmbossBitmapEffect:浮雕效果
    • OuterGlowBitmapEffect:外发光效果
    <Button Content="Click Me" Grid.Column="0" Grid.Row="0" Margin="20">
        <Button.BitmapEffect>
            <BlurBitmapEffect Radius="3"/>
        Button.BitmapEffect>
    Button>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IAm7FxjF-1668244504883)(11.绘图.assets/image-20221112164221060.png)]

    Effect

    采用GPU对UI进行渲染,功能强大。

    Effect具有如下派生类

    • BlurEffect:模糊效果
    • DropShadowEffect:投影效果
    • ShaderEffect:着色器(抽象类)

    图形的变形

    WPF中的变形与UI元素是分开的,可以单独设置一个旋转45度的变形,然后把该变形赋值给不同的UI元素。

    控制变形的属性有两个:

    • RenderTransform:呈现变形
    • LayoutTransform:布局变形

    这两个属性的值类型为Transform抽象类型,常见的派生类有:

    • MatrixTransform:矩阵变形
    • RotateTransform:旋转变形
    • ScaleTransform:缩放变形
    • SkewTransform:拉伸变形
    • TranslateTransform:偏移变形
    • TransformGroup:变形组

    呈现变形(Render Transform)

    让UI元素呈现出来的属性与本来的属性不一样,如按钮本来在左上角,但是让他呈现在右下角,且旋转45度。

    <Window x:Class="WpfApplication1.Window59"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="Window59" Height="334" Width="485">
        <Grid Margin="10" Background="AliceBlue">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto">
                ColumnDefinition>
                <ColumnDefinition Width="*">
                ColumnDefinition>
            Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto">
                RowDefinition>
                <RowDefinition Height="*">RowDefinition>
            Grid.RowDefinitions>
            <Button Width="80" Height="80" Content="OK" Background="Red" Foreground="White">
                <Button.RenderTransform>
                    
                    <TransformGroup>
                        
                        <RotateTransform CenterX="40" CenterY="40" Angle="45">RotateTransform>
                        
                        <TranslateTransform X="300" Y="150">TranslateTransform>
                    TransformGroup>
                Button.RenderTransform>
            Button>
        Grid>
    Window>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ynrVYjuf-1668244504884)(11.绘图.assets/image-20221112170224537.png)]

    在Grid中划分了2行2列,第一行第一列根据Button自动调整,然后利用变形天正button的位置和角度,但是Button本身的位置属性却没有改变,这样仅仅改变button的显示效果会极大提高效率。所以在做动画的时候一定要用Render Transform。

    布局变形

    与呈现变形不同,布局变形会影响整个窗体的布局导致重新测算,所以会影响程序的性能。布局变形一般用在静态变形上。

    实现文字纵向排列

    • 使用呈现变形
    <Grid x:Name="titleBar" Background="LightBlue">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto">ColumnDefinition>
            <ColumnDefinition Width="*">ColumnDefinition>
        Grid.ColumnDefinitions>
        <TextBlock FontSize="24" Text="Hello Transformer" VerticalAlignment="Bottom" HorizontalAlignment="Center">
            <TextBlock.LayoutTransform>
                <RotateTransform Angle="-90">RotateTransform>
            TextBlock.LayoutTransform>
        TextBlock>
    Grid>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p3CXShVD-1668244504884)(11.绘图.assets/image-20221112170931574.png)]

    看上去实现了纵向排列,但事实上TextBox本身属性没有变,所以Grid的第一列宽度任然没有变。

    • 使用布局变形

    将上面的

    <TextBlock.LayoutTransform>
        <RotateTransform Angle="-90">RotateTransform>
    TextBlock.LayoutTransform>
    
    • 1
    • 2
    • 3

    改为

    <TextBlock.LayoutTransform>
        <RotateTransform Angle="-90">RotateTransform>
    TextBlock.LayoutTransform>
    
    • 1
    • 2
    • 3

    此时,Grid的第一列宽度改变。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jd0b6Tf3-1668244504884)(11.绘图.assets/image-20221112171325173.png)]

  • 相关阅读:
    技术先驱视角:长城汽车工程师揭秘Hi4技术的无限潜力
    Hadoop运行模式
    数据隐私保护的方法有哪些?
    Qt mysql客户端,测试
    Golang——从入门到放弃
    不同的操作加不同的锁详解
    SSO 系统设计_token 生成
    Django框架基础
    Spring Boot + EasyExcel导入导出,简直太好用了!
    Code Inspector:点击页面元素自动定位到代码
  • 原文地址:https://blog.csdn.net/weixin_44064908/article/details/127822779