——评星级控件)
tkinter绘制组件28——评星级控件引言布局函数结构绘制星级绑定事件共同的背景完整代码函数效果测试代码最终效果2020-8-9新改进2023-1-16新改进2023-1-25新样式2024-2-14新样式2026-7-18样式更新github项目pip下载结语引言可能大多数tkinter“玩家”对于评星级控件不了解实际上这种组件很常见其实我也不知道常不常见它会出现在谷歌、苹果、微软的应用商场以及各类反馈界面中。实际上评星级控件是一个重要的交互式控件它允许使用者对于某件事做出价值评价。在tkinter中没有此控件但是在winUI3中存在即RatingControl。TinUI的评星级控件是ratingbar。布局函数结构defadd_ratingbar(self,pos:tuple,fg#585858,bg#f3f3f3,onfg#3041d8,onbg#3041d8,r10,num:int5,linew:int10,commandNone):#绘制评星级控件 pos::位置 fg::边框颜色 bg::星级颜色 onfg::响应鼠标时边框颜色 onbg::响应鼠标时星级颜色 r::星级半径 num::星级个数 linew::一行星级个数 command::响应函数必须接受一个参数当次选择时所选择的星级数 绘制星级这是这个控件的重点。如何绘制五角星需要满足以下条件完整的五角星连接十个顶点☆而不是连接五个顶点可区分边框和本体显而易见我们需要绘制多边形准确来讲是十边形。以下是纯计算内容不想看可以跳过。很简单的看看无妨。五个外围顶点设为A, B, C, D, E 五边形中心(pos[0]r,pos[1]r) (x,y) A(x,y-r) B(xr*sin(2*pi/5),y-(r*cos(2*pi/5)) C(xr*sin(pi/5),yr*cos(pi/5)) D(x-(r*sin(pi/5)),yr*cos(pi/5)) E(x-(r*sin(2*pi/5)),y-(r*cos(2*pi/5))) 内围五个顶点的半径rmr*sin(pi/10)/sin(7*pi/10) 坐标求解思路同上略。以上是绘制一个星级的方法那么我们需要绘制多个星级也就是需要循环。nowon0sinmath.sin cosmath.cos pimath.pi rmr*sin(pi/10)/sin(7*pi/10)bars[]item_num1#总数量line_num1#行数量center_xpos[0]r center_ypos[1]r uidratingbarstr(id(bars))foriinrange(0,num):points(#左上顶点center_x-(r*sin(2*pi/5)),center_y-(r*cos(2*pi/5)),center_x(rm*cos(7*pi/10)),center_y-(rm*sin(7*pi/10)),#上顶点center_x,center_y-r,center_x(rm*cos(3*pi/10)),center_y-(rm*sin(3*pi/10)),#右上顶点center_x(r*sin(2*pi/5)),center_y-(r*cos(2*pi/5)),center_x(rm*cos(19*pi/10)),center_y-(rm*sin(19*pi/10)),#右下顶点center_x(r*sin(pi/5)),center_y(r*cos(pi/5)),center_x(rm*cos(3*pi/2)),center_y-(rm*sin(3*pi/2)),#左下顶点center_x-(r*sin(pi/5)),center_y(r*cos(pi/5)),center_x(rm*cos(11*pi/10)),center_y-(rm*sin(11*pi/10)),)barself.create_polygon(points,fillbg,outlinefg,joinstylemiter,tagsuid)bars.append(bar)ifitem_numnum:breakifline_numlinew:center_xpos[0]r center_y3*r line_num1continueitem_num1line_num1center_x3*r其中nowon记录当前响应个数这个稍后会讲到bars提供了一个整合所有星级了列表方便后续操作line_num记录本行个数是否达到限制个数item_num记录总数量。此外在每次循环后需要根据下一次绘制条件重新更改坐标中心。绑定事件样式变化。都已经是第29篇TinUI构建文章了样式变化就直接给代码了。def__onnum(num):foriinbars[:num1]:self.itemconfig(i,fillonbg,outlineonfg)ifnum!len(bars):foriinbars[num1:]:self.itemconfig(i,fillbg,outlinefg)defclick(barid):nonlocalnowon nowonbars.index(barid)ifcommand!None:command(nowon1)defonin(barid):indexbars.index(barid)__onnum(index)defonleave(barid):pass会好奇为什么onleave“无作为”吗共同的背景实际上因为绘制的是多边形因此鼠标的进入和离开发生在多边形顶点所包围的范围内也就是说这里的响应范围是☆。所以不能每次离开一个星级就要重绘一次这样不符合逻辑也耗能。因此创建一个统一的背景进行控件背景范围的管理。defleaveback(event):ifnowon0:foriinbars:self.itemconfig(i,fillbg,outlinefg)return__onnum(nowon)#...startself.bbox(uid)backself.create_rectangle(start,fill,outlinefg,width1,tagsuid)self.tag_bind(back,Leave,leaveback)完整代码函数defadd_ratingbar(self,pos:tuple,fg#585858,bg#f3f3f3,onfg#3041d8,onbg#3041d8,r10,num:int5,linew:int10,commandNone):#绘制评星级控件def__onnum(num):foriinbars[:num1]:self.itemconfig(i,fillonbg,outlineonfg)ifnum!len(bars):foriinbars[num1:]:self.itemconfig(i,fillbg,outlinefg)defclick(barid):nonlocalnowon nowonbars.index(barid)ifcommand!None:command(nowon1)defonin(barid):indexbars.index(barid)__onnum(index)defonleave(barid):passdefleaveback(event):ifnowon0:foriinbars:self.itemconfig(i,fillbg,outlinefg)return__onnum(nowon)nowon0sinmath.sin cosmath.cos pimath.pi rmr*sin(pi/10)/sin(7*pi/10)bars[]item_num1#总数量line_num1#行数量center_xpos[0]r center_ypos[1]r uidratingbarstr(id(bars))foriinrange(0,num):points(#左上顶点center_x-(r*sin(2*pi/5)),center_y-(r*cos(2*pi/5)),center_x(rm*cos(7*pi/10)),center_y-(rm*sin(7*pi/10)),#上顶点center_x,center_y-r,center_x(rm*cos(3*pi/10)),center_y-(rm*sin(3*pi/10)),#右上顶点center_x(r*sin(2*pi/5)),center_y-(r*cos(2*pi/5)),center_x(rm*cos(19*pi/10)),center_y-(rm*sin(19*pi/10)),#右下顶点center_x(r*sin(pi/5)),center_y(r*cos(pi/5)),center_x(rm*cos(3*pi/2)),center_y-(rm*sin(3*pi/2)),#左下顶点center_x-(r*sin(pi/5)),center_y(r*cos(pi/5)),center_x(rm*cos(11*pi/10)),center_y-(rm*sin(11*pi/10)),)barself.create_polygon(points,fillbg,outlinefg,joinstylemiter,tagsuid)bars.append(bar)self.tag_bind(bar,Enter,lambdaevent,barbar:onin(bar))self.tag_bind(bar,Leave,lambdaevent,barbar:onleave(bar))self.tag_bind(bar,Button-1,lambdaevent,barbar:click(bar))ifitem_numnum:breakifline_numlinew:center_xpos[0]r center_y3*r line_num1continueitem_num1line_num1center_x3*r startself.bbox(uid)backself.create_rectangle(start,fill,outlinefg,width1,tagsuid)self.tag_bind(back,Leave,leaveback)returnbars,uid效果测试代码#...b.add_ratingbar((0,1150),num28,commandprint)#...最终效果2020-8-9新改进背景颜色为bg目前还不想添加相应参数不点击到星星图标上仍然可以响应2023-1-16新改进当再次点击第一个星级时取消选择command返回值为0。2023-1-25新样式小修外观。2024-2-14新样式巅峰外观。2026-7-18样式更新可适配高DPI边框改为圆角添加“边框”多边形元素github项目TinUI的github项目地址pip下载pipinstalltinui结语TinUI的改进需要更多智慧欢迎前往GitHub-TinUI开源代码库献计献策。tkinter创新