第1章 基本画刷 标准窗口的内部,被称为客户区。正是在窗口的这一区域,显示文字、图形、控件,并接收用户的输入。 WPF 的颜色被封闭成 Color 结构体,定义在 System.Window.Media 命名空间中。和一般的图形环境一样, Color 结构体使用 RGB 三原色来表达颜
第1章 基本画刷
标准窗口的内部,被称为客户区。正是在窗口的这一区域,显示文字、图形、控件,并接收用户的输入。
WPF的颜色被封闭成Color结构体,定义在System.Window.Media命名空间中。和一般的图形环境一样,Color结构体使用RGB三原色来表达颜色。
Color结构包含名为R、G、B的三个可读写属性,它们的类型都是byte。三个属性都是0时为黑色,都是255时为白色。
Color结构还包含一个“alpha通道”,其属性名为A。它是用来控制颜色的“不透明”度的,0表示完全透明,255表示完全不透明。
和所有结构体一样,Color具有一个无参数的构造函数,它产生一个A、R、G、B都是0的颜色,也就是一个透明的黑色。你可以手动设定这四个属性,如下:
Color clr=new Color();
clr.A=255;
clr.R=255;
clr.G=0;
clr.B=255;
这样我们就得到了一个洋红色。
此Color结构提供了几个静态方法,让你可以方便的创建Color对象:
Color color=Color.FromRgb(r,g,b);
这里会得到你所指定的颜色,其Alpha值是255。你还可以这样:
Color color=Color.FromArgb(a,r,g,b);
由你来指定Alpha值。
前面我们所使用的RGB颜色空间,也被称为sRGB颜色空间,“s”就是标准的意思。而Color结构也支持另一种被称为scRGB的颜色空间,这种颜色空间通常又被称为sRGB64,因为它不是使用一个字节而是8个字节来存储颜色值。在Color结构中,scRGB被储存为了float类型。分别叫ScA、ScR,ScG,WcB。这些属性和A、R、G、B会相互影响,改变G会造成ScG的改变,反之亦然。
另外,System.Window.Media也包含一个叫Colors的类,它有141个静态颜色值属性,它们的名称都是好记的颜色名称,从AliceBlue和AntiqueWhite到Yellow和YellowGreen。我们可以这样使用:
Color color=Colors.PapayaWhip;
这些颜色的名称和Web浏览器常用的颜色名称是一样的。另外需要注意的一个问题是,140个颜色属性的Alpha值都是255,有一个颜色属性的Alpha值是0,它就是Transparent属性。
程序可以设定Background属性,但这个属性的类型却不是Color,它是一个Brush对象。
Brush是一个抽象类,只有它的子类实例才能用来设定Window对象的Background属性,而所有这些子类都在System.Window.Media命名空间里。本章稍后将讨论SolidColorBrush(单色画刷)类和两个继承自GradientBrush(渐变画刷)的类
SolidColorBrush是最简单的画刷,只使用单一的颜色。你可以在第1章后面的程序中加入以下代码来改变窗口的背景色。
Color backColor = Color.FromRgb(0,255,255);
SolidColorBrush brush = new SolidColorBrush(backColor);
this.Background = brush;
下面的程序在执行时,会依据“鼠标指针靠近窗口中心的程度”,来改变客户区的背景颜色。此程序利用using将System.Window.Media命名空间加进来,本书后面大部分的程序也都会用到这个命名空间。
//*********************************************************
//VaryTheBackground.cs 2010 18th July by mouyong
//*********************************************************
using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
namespace part1.ch01
{
class VaryTheBackground:Window
{
SolidColorBrush brush = new SolidColorBrush(Colors.Black);
[STAThread]
public static void Main()
{
Application app = new Application();
app.Run(new VaryTheBackground());
}
public VaryTheBackground()
{
Title = "改变背景色";
Width = 384;
Height = 384;
Background = brush;
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
//得到客户区的实际宽和高
double height = ActualHeight - 2 * SystemParameters.ResizeFrameHorizontalBorderHeight - SystemParameters.CaptionHeight;
double width = ActualWidth - 2 * SystemParameters.ResizeFrameVerticalBorderWidth;
//得到鼠标的坐标
Point ptMouse = e.GetPosition(this);
//计算客户区的实际中心点
Point ptCenter = new Point(width/2,height/2);
//计算中心点与鼠标位置的距离
Vector vectMouse = ptMouse - ptCenter;
//计算中心点与鼠标位置之间连线与水平线形成的夹角
double angle = Math.Atan2(vectMouse.Y,vectMouse.X);
//计算在鼠标与中心点连线上,客户区内切椭圆边框到中心点的距离
Vector vectEllipse = new Vector(width/2*Math.Cos(angle),height/2*Math.Sin(angle));
//根据前面两个距离的比值,来设定灰度的多少
Byte byLevel=(Byte)(255*(1-Math.Min(1,vectMouse.Length/vectEllipse.Length)));
//重新设置背景颜色
Color color = brush.Color;
color.R = color.G = color.B = byLevel;
//这句代码一定要有,否则背景不会重绘
brush.Color = color;
}
}
}
当你向客户区中心点移动鼠标时,背景变成较亮的白色,而鼠标超过内切椭圆边线时,背景会变成黑色(默然说话:的确是一个椭圆,你可以把鼠标移向窗体的四个角,你会发现,在还没有把鼠标移出窗体外的时候,窗口已经变成黑色,没有更多的变化了。)。
这个变化在鼠标每次移动时都会发生,那是因为只要brush一有改变,客户区就会被重绘,但这一切都是幕后进行的。这所以会有动态的反应,是因为Brush继承自Freezable类,而Freezable类实现了一个名为Changed的事件(event),Brush对象只要一有改变,这个事件就会被触发。所以只要一改变brush,背景就会被重绘。
WPF底层大量使用Changed事件和类似机制,以实现动画和其他特性。
画刷也有一个与Colors相似的类Brushes类。它也提供了141个静态只读的属性,对应于Colors的141个颜色属性,名称也是一样的。不过Brushes返回的是SolidColorBrush对象。你可以用下面的方式设定Background:
Background=Brushes.PaleGoldenrod;
但是Brushes下面所有的SolidColorBrush对象都是处于冻结状态,也就是说,不能再被改变。它是通过把Freeable对象的CanFreeze属性设为true来实现的。你可以通过调用Freeze方法来实现对象的冻结和不可变动。IsFrozen属性如果变成true,就表示已经被冻结。冻结的对象可以提高效率,还可以在多个线程间共享,没有被冻结的则不行。虽然无法将冻结的对象解冻,但是你可以做出一个没冻结的复制版本。下面的代码可以定义VaryTheBackground中的brush字段:
SolidColorBrush brush=Brushes.Black.Clone();
如果你想看到这141个画刷出现在同一个窗口的客户区,FlipThroughTheBrushes程序可以达成你的愿望,你可以用上下箭头来改变画刷。
//*********************************************************
//FlipThroughTheBrushes.cs 2010 18th July by mouyong
//*********************************************************
using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Reflection;
namespace part1.ch01
{
namespace part1.ch01
{
class FlipThroughTheBrushes : Window
{
int index = 0;
PropertyInfo[] props;
[STAThread]
public static void Main()
{
Application app = new Application();
app.Run(new FlipThroughTheBrushes());
}
public FlipThroughTheBrushes()
{
props = typeof(Brushes).GetProperties(BindingFlags.Public | BindingFlags.Static);
SetTitleAndBackground();
}
private void SetTitleAndBackground()
{
Title = "变化笔刷到 - " + props[index].Name;//获得属性的名称
Background = (Brush)props[index].GetValue(null, null);//获得实际的SolidColorBrush对象
}
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
if (e.Key == Key.Down || e.Key == Key.Up)
{
index += e.Key == Key.Up ? 1 : props.Length - 1;
index %= props.Length;
SetTitleAndBackground();
}
}
}
}
}
此程序使用反射(reflection)来取得Brushes类的成员。构造函数第一行使用typeof(Brushes)来得到一个Type类的对象。Type类有一个方法,叫GetProperties,返回PropertyInfo对象的数组,数组内的每个元素都对应到Brushes类里的一个属性。调用GetProperties时,可以通过BinddingFlags来限制获得的属性状态,这里就限制只获得公开和静态的属性。
在构造函数和重写的OnKeyDown方法中,程序都调用了SetTitleAndBackground,以便将Title属性和Background属性设定为Brushes类的某个成员。Name会返回属性的名称,这里一开始就是“AliceBlue”。GetValue方法返回实际的SolidColorBrush对象。它需要两个参数,第一个参数需要属性所在的对象,因为我们现在取到的都是静态属性,所以传入null;第二个参数只有属性是一个数组时才有必要传入,所以我们也传入null。
System.Windows命名空间具有SystemColors类,其作用类似于Colors和Brushes,只具有静态的只读属性,返回Color值和SolidColorBrush对象。这些设定存储在Windows注册表中。利用此类,可以得知目前用户的颜色喜欢。比方说,SystemColors.WindowColor用来表示用户对于客户区的颜色喜好,而SystemColors.WindowTextColor是用户对于客户区文字的颜色喜好,而SystemColors.WindowBrusht 和SystemColors.WindowTextBrush则是返回对应颜色的SolidColorBrush对象。对于大多数的真实应用程序来说,应该使用这些颜色,可以达到统一、协调的视觉效果。
只继承自Freezeable类的对象,才可以被冻结。而Color是一个结构体,所以不存在冻结不冻结的问题。
如果不用单色画刷,可以改用渐变画刷,将两种(或多种)颜色混合,逐渐改变。对于WPF来说,创建一个渐变画刷是非常容易的,且渐变画刷在现代的色彩设计中也很受欢迎。
渐变画刷最简单的形式是LinearGradientBrush,只需要两个Color(我们不妨称这两种颜色为clr1和clr2)对象,和两个Point(pt1和pt2)对象。pt1的位置的颜色是clr1,而pt2的位置的颜色是clr2.在pt1和pt2之间的连线上,则是混合了crl1和crl2的颜色,连线中心点是clr1和clr2的平均值。垂直于连线的位置,和连线上的点使用相同的颜色。至于超过pt1和pt2的两边会是什么颜色,稍后再讨论。
WPF渐变画刷有一个特性,让你不用基于窗口尺寸而调整画刷的点。默认情况下,你指定的点是“相对于窗口面积”的,这里的窗口面积被视为一个单位宽,一个单位高。(默然说话:即无论你的窗口的实际宽高是多少,我们统统认为它们都是一个单位宽,一个单位高,这就叫“相对”)那么,左上角的坐标就是(0,0),而右下角的坐标就是(1,1)。
例如,如果你想要让客户区的左上角为红色,右下角为蓝色,是间是渐变色,则使用下面的构造函数,这里需要指定两种颜色和两个点。
LinearGradientBrush brush = new LinearGradientBrush(Colors.Red,Colors.Blue,new Point(0,0),new Point(1,1));
下面是完整的程序:
//*********************************************************
//GradiateTheBrush.cs 2010 17th July by mouyong
//*********************************************************
using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
namespace part1.ch01
{
class GradiateTheBrush:Window
{
[STAThread]
public static void Main()
{
Application app = new Application();
app.Run(new GradiateTheBrush());
}
public GradiateTheBrush()
{
Title = "渐变画刷";
LinearGradientBrush brush = new LinearGradientBrush(Colors.Red,Colors.Blue,new Point(0,0),new Point(1,1));
Background = brush;
}
}
}
当你改变客户区的尺寸时,渐变画刷会随之改变。这要归功于Freezable所实现的Changed事件。
使用相对坐标系统来设定点很方便,但这不是唯一的做法。GradientBrush类有一个MappingMode属性,类型为BrushMappingMode枚举。此枚举只有两种值,分别为RelativeToBoundingBox(使用相对坐标,默认值)和Absolute(使用“设备无关单位”)。
如果你需要建立水平或垂直的渐变,还可以使用LinearGradientBrush的构造函数:
new LinearGradientBrush(clr1,clr2,angle);
指定角度。0度是水平渐变,clr1在左边,等同于:
new LinearGradientBrush(clr1,clr2,new Point(0,0),new Point(1,0));
90度是垂直渐变,clr1在上面,等同于:
new LinearGradientBrush(clr1,clr2,new Point(0,0),new Point(0,1));
其他的角度用起来可能需要一点技巧,就一般的例子来说,第一个点一定是原点,第二个点计算如下:
new Point(cos(angle),sin(angle));
以45度为例,第二个点逼近(0.707,0.707)。别忘了这是“相对于”客户区的点,所以,如果客户区不是正方形(通常都不是),这两个点之间的连线就不会是45度。另外,窗口右下角也会有一大块超出这个点,这部分会如何处理呢?默认情况下,通常会着上第二种颜色。你可以设置LinearGradientBrush的SpreadMethod属性,它是GradientSpreadMethod枚举类型,默认是Pad,表示超出部分延续之前的颜色,不渐变,你还可以设置为Reflect或Repeat。试着把GradiateTheBrush程序修改为下面这样:
LinearGradientBrush brush = new LinearGradientBrush(Colors.Red,Colors.Blue,new Point(0,0),new Point(0.25,0.25));
brush.SpreadMethod = GradientSpreadMethod.Reflect;
Background = brush;
在(0,0)到(0.25,0.25)之间,画刷从红到蓝渐变,然后(0.25,0.25)到(0.5,0.5)之间,从蓝到红渐变,接着在(0.5,0.5)和(0.75,0.75)之间,从红到蓝渐变,最后在(0.75,0.75)和(1,1)之间,从蓝到红渐变。
如图2-1所示,我们的pt1和pt2位于窗口的左上和右下角,而虚线代表的是等色线(意思就是在这条线上的颜色都是相等的)。在窗口的宽和高发生改变的时候,等色线的角度也就会随之更改(因为等色线总是垂直于pt1和pt2的连线的),但我们可能并不希望这样的一个效果,我们希望无论如何改变窗口的宽和高,等色线总是保持某个角度不变的(如图2-2,洋红的等色线始终保持在对角的连线上),这样,我们就要去调整pt1和pt2的位置,以使得等色线始终处于对角线的连线上。
图2-1
图2-2
这样一来,就带来了一个问题,如何随着窗口的调整,动态的求出pt1和pt2的位置,好让连接pt1和pt2和连线始终垂直于左下到右上的对角线呢?换句话说,我们应该设计一个公式,让pt1和pt2的位置与窗口的宽和高关联起来。我们再来看图2-3:我们需要再添加一点标识和一条辅助线,以便得到我们想要的公式。
图2-3
|
如图2-3,这个窗口的宽我们用W来表示,高用H来表示,则左下到右上的对角线长度就应该是(默然说话:著名的勾股定理还记得吧?斜边的平方等于两个直角边的平方和,所以斜边长就是两个直角边的平方和开根),计算对角线的长度干嘛?其实这不是我们的目的,我们的目的是为了得到对角线到pt2的距离。这里我们作了一条辅助线L,它平行于pt1到pt2的连线,也垂直于对角线。根据定律, L的长度与对角线到pt2的长度是相等的,也就是说,求出了L的长度,也就得到了pt2到对角线的长度。接下来请看演算:(默然说话:下面将要使用三角函数,我就不多罗嗦了,记不得的同学请参考别的书籍)
一方面,如果我们把H当作α所在的直角三角形的对边,那就有成立。
另一方面,如果我们把L当作α所在直角三角形的对边,那就有成立。
(默然说话:好吧,我就再多罗嗦几句。正弦就是对边比斜边,如果把H作为对边,那么,斜边就是对角线,而对角线长度的计算,前面已经写过了。如果以L为对边,那斜边就是W。所以就有了上面的两个等式)
根据等量代换原则,就有 成立。
整理后得到。
这样我们就计算出了L的长度,也就是pt2到对角线的距离。在这里重要的是,我们找到了pt2的位置与长和宽的关系,同理可证pt1的位置与长和宽的关系也是相似的。
(默然说话:不用多想α是多少,因为它只是我们的一个引入的中间变量,对于我们研究的问题,毫无关系。我只是想找出pt1或pt2的位置和长宽的关系而引入了它而已。)
下面的程序在构造函数中建立一个“可以被修改的”LinearGradientBrush对象,其MappingMode是Absolute。构造函数中还委托了SizeChanged事件的处理器,只要窗口尺寸改变,就会跟着发生SizeChanged事件。
//*********************************************************
//AdjustTheGradient.cs 2010 17th July by mouyong
//*********************************************************
using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
namespace part1.ch01
{
class AdjustTheGradient:Window
{
LinearGradientBrush brush;
[STAThread]
public static void Main()
{
Application app = new Application();
app.Run(new AdjustTheGradient());
}
public AdjustTheGradient()
{
Title = "调整渐变";
SizeChanged += WindowOnSizeChanged;
brush = new LinearGradientBrush(Colors.Red,Colors.Blue,0);
brush.MappingMode = BrushMappingMode.Absolute;
Background = brush;
}
private void WindowOnSizeChanged(object sender, SizeChangedEventArgs e)
{
double width = ActualWidth - 2 * SystemParameters.ResizeFrameVerticalBorderWidth;
double height = ActualHeight - 2 * SystemParameters.ResizeFrameHorizontalBorderHeight - SystemParameters.CaptionHeight;
Point ptCenter = new Point(width/2,height/2);//中心点
Vector vectDiag = new Vector(width,-height);
Vector vectPerp = new Vector(vectDiag.Y,-vectDiag.X);
vectPerp.Normalize();
vectPerp *= width * height / vectDiag.Length;
brush.StartPoint = ptCenter + vectPerp;
brush.EndPoint = ptCenter - vectPerp;
}
}
}
(默然说话:你可以看到,无论你如何调整窗口的大小,两个颜色的中间过渡色总是处于左下至右上角的对角线上,太神奇了!而这一切都发生在WindowOnSizeChanged事件方法里)
事件处理器一开始是计算客户区的宽度和高度,如同本章稍早的VaryTheBackground程序做法一样。用Vector对象vectDiag来表示对角线的向量(从左下到右上)。也可以利用右上角坐标减左下角坐标,来计算得到:
vectDiag=new Point(width,0)-new Point(0,height);
vectPerp向量垂直于对角线。建立相互垂直的向量很容易,只要把X和Y属性的值对调,并把其中一个数的正负号反向就可以了。调用Normalize方法是为了正规化这个向量,之后,又把vectPerp乘以L(默然说话:就是前面我们计算过的那个公式),这样就得到了一个pt1到pt2的一个向量。
(默然说话:是不是还是觉得晕?看不明白?嘿嘿,说实话,我也看不明白这一段呀,实在是超出了我的所学范围,仍然盼望高手解惑。)
最后的步骤是设定StartPoint和EndPoint属性。这些属性一般是通过画刷的构造函数来设定的,而且除去继承的属性,它们是LinearGradientBrush仅有的两个属性。

小红书笔记怎么删除?在小红书APP中是可以编辑笔记的,多数的用户不知道小红书笔记如何的删除,接下来就是小编为用户带来的小红书笔记删除方法图文教程,感兴趣的用户快来一起看看吧!小红书使用教程小红书笔记怎么删除1、首先打开小红书APP进入到主页面,选择右下角【我】进入到专区;2、之后在我的专区,点击下图所示的笔记页面,选择要删除的笔记;3、进入到笔记页面,右上角【三个点】;4、最后下方会展开功能栏,点击【删除】即可完成。

小红书删除的笔记不能恢复。小红书作为一款知识分享和购物平台,为用户提供了记录笔记和收藏有用信息的功能。根据小红书的官方说明,已经删除的笔记是无法恢复的。小红书平台并没有提供专门的笔记恢复功能。这意味着,一旦在小红书中删除了笔记,无论是不小心误删还是其他原因,一般情况下是无法从平台上找回被删除的内容的。如果遇到特殊情况,可以尝试联系小红书的客服团队,看是否能够协助解决问题。

作为一名小红书的用户,我们都曾遇到过发布过的笔记突然不见了的情况,这无疑让人感到困惑和担忧。在这种情况下,我们该怎么办呢?本文将围绕“小红书发布过的笔记不见了怎么办”这一主题,为你详细解答。一、小红书发布过的笔记不见了怎么办?首先,不要惊慌。如果你发现笔记不见了,保持冷静是关键,不要慌张。这可能是由于平台系统故障或操作失误引起的。检查发布记录很简单。只需打开小红书App,点击“我”→“发布”→“所有发布”,就可以查看自己的发布记录。在这里,你可以轻松找到之前发布的笔记。3.重新发布。如果找到了之

使用添加链接功能在iPhone上链接AppleNotes。笔记:如果您已安装iOS17,则只能在iPhone上的AppleNotes之间创建链接。在iPhone上打开“备忘录”应用。现在,打开要在其中添加链接的注释。您还可以选择创建新备忘录。点击屏幕上的任意位置。这将向您显示一个菜单。点击右侧的箭头以查看“添加链接”选项。点击它。现在,您可以键入注释的名称或网页URL。然后,点击右上角的完成,添加的链接将出现在笔记中。如果要添加指向某个单词的链接,只需双击该单词即可将其选中,选择“添加链接”并按

小红书怎么在笔记中添加商品链接?在小红书这款app中用户不仅可以浏览各种内容还可以进行购物,所以这款app中关于购物推荐、好物分享的内容是非常多的,如果小伙伴在这款app也是一个达人的话,也可以分享一些购物经验,找到商家进行合作,在笔记中添加连接之类的,很多人都愿意使用这款app购物,因为不仅方便,而且有很多达人会进行一些推荐,可以一边浏览有趣内容,一边看看有没有适合自己的衣服商品。一起看看如何在笔记中添加商品链接吧!小红书笔记添加商品链接方法 在手机桌面上打开app。 在app首页点击

WPF是微软开发的一种基于.NET Framework的桌面应用程序开发框架。它提供了丰富的用户界面元素、数据绑定和动画等功能,使得开发者可以轻松地创建高质量的桌面应用程序。

小红书作为一个生活方式分享平台,涵盖了美食、旅行、美妆等各个领域的笔记。许多用户希望在小红书上分享自己的笔记,但却不清楚如何操作。在这篇文章中,我们将详细介绍小红书发布笔记的流程,并探讨如何在平台上屏蔽特定用户。一、小红书发布笔记教程怎么弄?1.注册登录:首先,需要在手机上下载小红书APP,并完成注册登录。在个人中心完善个人资料是很重要的。通过上传头像、填写昵称和个人简介,可以让其他用户更容易了解你的信息,也能帮助他们更好地关注你的笔记。3.选择发布频道:在首页下方,点击“发笔记”按钮,选择你想

随着PHP在Web开发中的重要性不断提高,PHP函数库设计也成为了开发中的关键问题之一。好的函数库不仅可以提高开发效率,还能保证代码的质量和可维护性。因此,设计函数库需要遵循一些基本原则和标准。一、可重用性好的函数库应该是可重用的,可以在不同的项目中使用。因此,函数应该是抽象的、通用的,不能和特定的项目或场景捆绑在一起。二、易用性函数库应该易于使用,传递参数


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

Atom编辑器mac版下载
最流行的的开源编辑器

Dreamweaver Mac版
视觉化网页开发工具

VSCode Windows 64位 下载
微软推出的免费、功能强大的一款IDE编辑器

适用于 Eclipse 的 SAP NetWeaver 服务器适配器
将Eclipse与SAP NetWeaver应用服务器集成。

EditPlus 中文破解版
体积小,语法高亮,不支持代码提示功能