WPF绘图

本文详细介绍了WPF中的基本图形绘制,包括直线、矩形、椭圆、多边形、折线和路径的使用,以及如何通过Path进行界面元素的剪裁。内容涵盖了图形的属性设置,如Stroke、Fill、GradientBrush等,并展示了各种图形的实际效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

WPF的基本图形包括以下几个:

Line:直线段,可以设置触笔(Stroke)
Rectangle:矩形,既有触笔,又有填充(Fill)
Ellicps:椭圆,长宽相等即为正圆,既有触笔又有填充
Polygon:多边形,由多条直线段围成的闭合区域,既有触笔又有填充。
Polyline:折线(不闭合),由多边收尾相接的直线段组成。
Path:路径(闭合区域),由若干直线、圆弧、贝塞尔曲线组成。

1. 直线:

使用X1、Y1设置起点,X2、Y2设置终点。Stroke属性类型是Brush(画刷),凡是Brush的派生类均可用于给这个属性赋值。 通过StrokeDashArray画出虚线,StrokeEndLineCap控制线段终点形状,LinearGradientBrush画出渐变色。

<Grid>
    <Line X1="10" Y1="20" X2="260" Y2="20" Stroke="Red" StrokeThickness="10"/>
    <Line X1="10" Y1="40" X2="260" Y2="40" Stroke="Orange" StrokeThickness="6"/>
    <Line X1="10" Y1="60" X2="260" Y2="60" Stroke="Green" StrokeThickness="3"/>
    <Line X1="10" Y1="80" X2="260" Y2="80" Stroke="Purple" StrokeThickness="2"/>
    <Line X1="10" Y1="100" X2="260" Y2="100" Stroke="Black" StrokeThickness="1"/>
    <Line X1="10" Y1="120" X2="260" Y2="120" StrokeDashArray="3" Stroke="Black"
            StrokeThickness="1"/>
    <Line X1="10" Y1="140" X2="260" Y2="140" StrokeDashArray="5" Stroke="Black"
            StrokeThickness="1"/>
    <Line X1="10" Y1="160" X2="260" Y2="160" Stroke="Black" StrokeEndLineCap="Flat"
            StrokeThickness="6"/>
    <Line X1="10" Y1="180" X2="260" Y2="180" Stroke="Black" StrokeEndLineCap="Triangle"
            StrokeThickness="8"/>
    <Line X1="10" Y1="200" X2="260" Y2="200" StrokeEndLineCap="Round" StrokeThickness="8">
        <Line.Stroke>
            <LinearGradientBrush EndPoint="0,0.5" StartPoint="1,0.5">
                <GradientStop Color="Blue"/>
                <GradientStop Offset="1"/>
            </LinearGradientBrush>
        </Line.Stroke>
    </Line>
</Grid>

效果图如下:
这里写图片描述

2. 矩形:

矩形由笔触(Stroke,即边线)和填充(Fill)构成。Stroke属性设置和Line一样。Fill属性的数据类型是Brush。Brush是抽象类,只能用其派生类的事例为其赋值,常见的Brush类型有:
SolidColorBrush:实心画刷。可以直接用字符串(如Red、Blue等)直接赋值。
LinearGradientBrush:径向渐变画刷。
ImageBrush:使用图片作为填充内容。
DrawingBrush:使用矢量图(Vector)和位图(Bitmap)作为填充内容。
VisualBrush:WPF中每个控件都是由FrameworkElement类派生来的,而FrameworkElement又是由Visual类派生来。Visual意为“可视”之意,每个控件的可视化形象就可以通过Visual类的方法获得。获得这个可视化形象后,就可以用这个可视化形象进行填充。

<Grid Margin="10">
    <Grid.RowDefinitions>
        <RowDefinition Height="160"/>
        <RowDefinition Height="10"/>
        <RowDefinition Height="160"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="180"/>
        <ColumnDefinition Width="10"/>
        <ColumnDefinition Width="180"/>
        <ColumnDefinition Width="10"/>
        <ColumnDefinition Width="180"/>
    </Grid.ColumnDefinitions>
    <!--实心填充-->
    <Rectangle Grid.Column="0" Grid.Row="0" Stroke="Black" Fill="LightBlue"/>
    <!--线性渐变-->
    <Rectangle Grid.Column="2" Grid.Row="0">
        <Rectangle.Fill>
            <LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
                <GradientStop Color="#ffb6f8f1" Offset="0"/>
                <GradientStop Color="#ff0082bd" Offset="0.25"/>
                <GradientStop Color="#ff95deff" Offset="0.6"/>
                <GradientStop Color="#ff005f72" Offset="1"/>
            </LinearGradientBrush>
        </Rectangle.Fill>
    </Rectangle>
    <!--径向渐变-->
    <Rectangle Grid.Column="4" Grid.Row="0">
        <Rectangle.Fill>
            <RadialGradientBrush>
                <GradientStop Color="#ffb6f8f1" Offset="0"/>
                <GradientStop Color="#ff0082bd" Offset="0.25"/>
                <GradientStop Color="#ff95deff" Offset="0.6"/>
                <GradientStop Color="#ff005f72" Offset="1"/>
            </RadialGradientBrush>
        </Rectangle.Fill>
    </Rectangle>
    <!--图片填充-->
    <Rectangle Grid.Column="0" Grid.Row="2">
        <Rectangle.Fill>
            <ImageBrush ImageSource=".\logo.jpg" Viewport="0,0,0.3,0.15" TileMode="Tile"/>
        </Rectangle.Fill>
    </Rectangle>
    <!--矢量图填充-->
    <Rectangle Grid.Column="2" Grid.Row="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"/>
                        </GeometryDrawing.Geometry>
                    </GeometryDrawing>
                </DrawingBrush.Drawing>
            </DrawingBrush>
        </Rectangle.Fill>
    </Rectangle>
    <!--无填充,用线性渐变填充边缘-->
    <Rectangle Grid.Column="4" Grid.Row="2" StrokeThickness="10">
        <Rectangle.Stroke>
            <LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
                <GradientStop Color="White" Offset="0.3"/>
                <GradientStop Color="Blue" Offset="1"/>
            </LinearGradientBrush>
        </Rectangle.Stroke>
    </Rectangle>
</Grid>

效果图如下:这里写图片描述

看一个VisualBrush的例子,利用一个Button控件。

<Grid Margin="10">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="160"/>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="160"/>
    </Grid.ColumnDefinitions>
    <StackPanel x:Name="stackPanelLeft" Background="White">
        <Button x:Name="realButton" Content="OK" Height="40"/>
    </StackPanel>
    <Button Content=">>>" Grid.Column="1" Margin="5,0" Click="CloneVisual"/>
    <StackPanel x:Name="stackPanelRight" Background="White" Grid.Column="2"/>
</Grid>

效果图如下:
这里写图片描述

3. 椭圆:

它的方法与矩形没有什么区别。Width与Height相等的椭圆即是正圆。

<Grid>
    <Ellipse Stroke="Gray" Width="140" Height="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"/>
                    </TransformGroup>
                </RadialGradientBrush.RelativeTransform>
                <GradientStop Color="#ffffffff" Offset="0"/>
                <GradientStop Color="#ff444444" Offset="0.66"/>
                <GradientStop Color="#ff999999" Offset="1"/>
            </RadialGradientBrush>
        </Ellipse.Fill>
    </Ellipse>
</Grid>

这里写图片描述

4. 路径:

可以将直线、圆弧、贝塞尔曲线等基本元素结合进来,形成复杂的图形。路径最重要的一个属性是Data,Data的数据类型是Geometry(几何图形),使用这个属性将一些基本的线段拼接起来。
为Data属性赋值的语法有两种:一种是标签式的标准语法,另一种是专门用于绘制几何图形的“路径标记语法”。
Path的Data属性是Geometry类,Geometry是抽象类,只能使用Geometry的子类。子类包括:
这里写图片描述
Line、Rectangle等类与LineGeometry、RectangleGeometry类的区别:Line、Rectangle类是可独立存在的对象,而*Geometry类只能用于结合成其他几何图形、不能独立存在–当我们在Blend里选中一组独立的几何图形执行组合路径命令时,本质上是把原本独立的Line、Rectangle对象转换为*Geometry对象并结合成新的复合几何图形。

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="160"/>
        <ColumnDefinition Width="160"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="160"/>
        <RowDefinition Height="160"/>
    </Grid.RowDefinitions>
    <!--直线-->
    <Path Stroke="Blue" StrokeThickness="2" Grid.Column="0" Grid.Row="0">
        <Path.Data>
            <LineGeometry StartPoint="20,20" EndPoint="140,140"/>
        </Path.Data>
    </Path>
    <!--矩形路径-->
    <Path Stroke="Orange" Fill="Yellow" Grid.Column="1" Grid.Row="0">
        <Path.Data>
            <RectangleGeometry Rect="20,20,120,120" RadiusX="10" RadiusY="10"/>
        </Path.Data>
    </Path>
    <!--椭圆路径-->
    <Path Stroke="Green" Fill="LawnGreen" Grid.Column="0" Grid.Row="1">
        <Path.Data>
            <EllipseGeometry Center="80,80" RadiusX="60" RadiusY="40" />
        </Path.Data>
    </Path>
    <Path Stroke="Yellow" Fill="Orange" Grid.Column="1" Grid.Row="1">
        <Path.Data>
            <PathGeometry>
                <PathGeometry.Figures>
                    <PathFigure StartPoint="25,140" IsClosed="True">
                        <PathFigure.Segments>
                            <LineSegment Point="20,40"/>
                            <LineSegment Point="40,110"/>
                            <LineSegment Point="50,20"/>
                            <LineSegment Point="80,110"/>
                            <LineSegment Point="110,20"/>
                            <LineSegment Point="120,110"/>
                            <LineSegment Point="140,40"/>
                            <LineSegment Point="135,140"/>
                        </PathFigure.Segments>
                    </PathFigure>
                </PathGeometry.Figures>
            </PathGeometry>
        </Path.Data>
    </Path>
</Grid>

效果图如下:
这里写图片描述
PathGeometry:Path的Figures属性可以容纳PathFigure对象,而PathFigure的Segment属性又可以容纳各种线段用于结合成复杂图形。

这里写图片描述
在绘制线的时候所有线都是没有起点(StartPoint)的,因为起点就是前一个线段的终点,而第一个线段的起点则是PathFigure的StartPoint。如上面代码中PathGeometry部分。

ArcSegment:
用来绘制圆弧,Point属性用来指名圆弧连接的终点;
圆弧截取自椭圆,Size属性即完整椭圆的横纵半径;
SweepDirection属性指名圆弧顺时针方向还是逆时针方向;
椭圆上两点不对称,圆弧会有大弧和小弧,IsLargeArc属性用于指名是否使用大弧连接;
RotationAngle属性用来指明圆弧母椭圆的旋转角度。

BezierSegment(三次贝塞尔曲线)由四个点决定:
(1) 起点:即前一个线段终点 或 PathFigure的StartPoint。
(2)终点:Point3属性,即曲线的终点位置。
(3)两个控制点:Point1和Point2属性。
粗略说,三次贝塞尔曲线就是由起点出发走向Point1方向,在走向Point2方向,最后到达终点的平滑曲线。
这里写图片描述

QuadraticBezierSegment(二次方贝塞尔曲线)与BezierSegment类似,由三个点决定:
(1)起点:同BezierSegment
(2)终点:Point2属性,曲线终点。
(3)一个控制点:Point1。
这里写图片描述

想绘制出复杂的图形,我们要做的仅仅是在PathFigure把Segment一段一段加上去。

5. 路径标记语法:

路径标记语法实际上就是各种线段的简记法,比如<LineSegment Point="150,5"/>可以简写为”L 150,5”,比如H用来画水平直线,”H 180”指从当前点画一条水平直线,终点的横坐标是180(不需要考虑坐标,与当前纵坐标一致),类似还有V命令,用来画竖直直线。
这里写图片描述
这里写图片描述

例:

<Path Stroke="Red" Data="M 0,0 C 30,0 70,100 100,100 S 170,0 200,0"/>
<Path Stroke="Red" Data="M 0,200 Q 100,0 200,200 T 400,200"/>

路径标记语法是不区分大小写的,使用两个double数值表示一个点(x,y),用逗号分隔,又可以使用空格。由于路径标记语法中使用空格作为连个点之间的间隔,为了避免混淆,建议使用逗号作为点横纵坐标的分隔符。

6. 使用Path剪裁界面元素

不规则窗体或控件,WPF中仅需要使窗体或控件的Clip属性即可。
Clip属性被定义在UIElement类中,因此WPF窗体和所有控件、图形都具有这个属性。
Clip属性的数据类型是Geometry,与Path的Data属性一致,因此我们只要按需求制作好特殊图形的Path并把Path的Data属性赋值给目标窗体、控件或其他图形,对目标的裁剪就完成了。

想让一个窗体能被剪切,那么气AllowsTransparency必须设为True,这个属性设为True后,WindowStyle属性必须设为None。

<Grid VerticalAlignment="Center" HorizontalAlignment="Center">
    <Path Visibility="Hidden" x:Name="clipPath"
            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"/>
    <Button VerticalAlignment="Center" HorizontalAlignment="Center" Width="80" Height="25" x:Name="btnClip" Click="btnClip_Click">Clip</Button>
</Grid>

private void btnClip_Click(object sender, RoutedEventArgs e)
{
    this.Clip = this.clipPath.Data;
}

效果:
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值