首页 > 开发 > 综合 > 正文

OwnerDraw in C#

2024-07-21 02:18:50
字体:
来源:转载
供稿:网友

对于像combobox等控件,我们可以通过设置它们的drawmode特性(attribute)来对其进行绘制.

为了方便起见,我们先定义一个类stringcolorobject(这与ownerdraw本身没有关系,只是针对这里要使用到的combobox而特意书写的一个类.类的命名得益于quickstart).这个类本身很简单:



using system.drawing;



namespace ownerdrawsample

{

public class stringcolorobject

{

//field to hold the string representing the color

private string colorrepresent;

//field to hold the actually color,the value of the string colorrepresent

private color color;



//the constructor

//takes 2 parameters, the color representation and the color itself

public stringcolorobject(string colorrepresent,color color)

{

this.colorrepresent = colorrepresent;

this.color = color;

}



//some attributes

public string colorrepresentation

{

get

{

return this.colorrepresent;

}

//only getter,no setter

}



public color color

{

get

{

return this.color;

}

//only getter,no setter

}



//override the tostring method in system.object

public override string tostring()

{

return this.colorrepresent;

}



//override the gethashcode method

public override int gethashcode()

{

//return the key field’s hash code

return this.color.gethashcode();

}



//override the equals method

public override bool equals(object obj)

{

if(!(obj is stringcolorobject))

return false;

return this.color.equals(((stringcolorobject)obj).color);

}

}

}



建立一个windows application,并从工具箱中拖拽一个combobox到form中去,并命名为cmbcolors然后在form的构造函数中添加:



//

// todo: 在initializecomponent调用后添加任何构造函数代码

//

this.fillcomboxcolor(this.cmbcolors);

this.cmbcolors.selectedindex = 0;



其中,fillcomboxcolor(combobox )为自定义函数,它用来填充参数指定的combobox对象.它的实现为:

private void fillcomboxcolor(combobox cmb){

cmb.items.addrange(new object[]{

new stringcolorobject("黑色(black)",color.black),

new stringcolorobject("蓝色(blue)",color.blue),

new stringcolorobject("深红(dark red)",color.darkred),

new stringcolorobject("绿色(green)",color.green),

//……

});

}

上面只是一些准备工作,ownerdraw的实际工作现在才刚刚开始.将combobox对象cmbcolors的drawmode设置为ownerdrawfixed(或是ownerdrawvariable,这里设置为ownerdrawfixed模式).附带说明一下:drawmode可以取normal,ownerdrawfixed和ownerdrawvariable三者之一.其中,normal模式表示控件由操作系统绘制,并且元素的大小都相等;ownerdrawfixed模式表示控件由手工绘制,并且元素的大小都相等;ownerdrawvariable则是表示控件由手工绘制,并且元素的大小可以不相等。



下面开始ownerdraw的核心部分:

1) 撰写控件的measureitem事件

当要显示combobox的某一项(item)的时候[即是单击combobox的下拉按钮时],这个事件会被首先唤起。它用来测量item的长度,宽度信息。例如:

//注册事件

this.cmbcolor.measureitem += new measureitemeventhandler(this.cmbcolor_measureitem);

//实现cmbcolor_measureitem---测量combobox的每一个item

private void cmbcolor_measureitem(object sender, system.windows.forms.measureitemeventargs e)

{

//一般来说,这里需要设置的是measureitemeventargs对象e的itemheight属性和itemwidth属性

combobox cmb = (combobox)sender;

e.itemheight = cmb.itemheight;//当然,你可以写e.itemheight = 20;

//不过对于ownerdrawfixed模式,这个函数好像都是多余.(对于combobox而言如此)

//why?????????????more work is essential.

}



2) 撰写控件的drawitem事件

combobox中的项的绘制任务将在drawitem事件中完成.类似地,先注册该事件,然后再添加适当的代码完成对事件的响应:

//注册事件

this.cmbcolor.drawitem += new

drawitemeventhandler(this.cmbcolor_drawitem);

//绘制item

private void cmbcolor_drawitem(object sender, system.windows.forms.drawitemeventargs e)

{

combobox cmb = (combobox)sender;

if(cmb == null) return;

int index = e.index; //获取要绘制的item的index(索引)

if(index == -1) return;

//如果item被选择,绘制正确的背景色

e.drawbackground();

e.drawfocusrectangle();//因为item被选择,绘制焦点矩形



graphics g = e.graphics;

//根据item的index获取对应的颜色

color c = ((stringcolorobject)cmbcolor.items[index]).color;

rectangle rectcolor = e.bounds;//获取包围item的边框,并存储在rectcolor中

//将rectcolor做适当变换,这不会影响到e.bounds本身

rectcolor.offset(2,2);//右移2,下移2

rectcolor.width = 20;//宽度设置为20

rectcolor.height -= 4;//高度减4

g.drawrectangle(new pen(c),rectcolor);//绘制rectcolor代表的矩形,即是在图中看到的item左边的矩形部分



//再次将rectcolor做变换,并填充之

rectcolor.offset(2,2);

rectcolor.width = 17;//要注意,在c#中绘制和填充

rectcolor.height -= 3;// 对最后一个象素点的不同处理方式

g.fillrectangle(new solidbrush(c),rectcolor);//填充rectcolor矩形,这个矩形就是在图中看到的item左边的那个被填充的矩形



g.drawstring(((stringcolorobject)cmbcolor.items[index]).tostring(),

this.font,new solidbrush(c),e.bounds.left + 25,e.bounds.top);

//绘制字符串

}



这段程序会运行得很好.为了能够读懂程序,你得知道如下的一些概念:

1). e.index measureitemeventargs对象的index属性表达的意思是欲绘制的item的索引值之义.对于上面的例子,黑色(black),蓝色(blue)…分别对应着index的0,1…(这种说法不是很严密,但易于接受.比较严密的说法是,stringcolorobject对象对应着index…).

2). e.graphics 这是要在item上绘制的graphics对象.有了它,就能在item上实现图形的绘制了.

3). e.bounds 这是要绘制的item的边界矩形.


知道了这些概念,就不难理解上面drawitem完成的操作以及为什么会那样去完成。



对于menuitem的手工绘制,你要做的事和上面差不多.不同的是,你需要将其ownerdraw由默认的false设置为true.然后再measureitem,drawitem.如果你亲身实践,你会发现如果你不注册measureitem并辅以相应代码,你不会看到那个menuitem.



---the end



发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表