范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

Qt实现表格树控件自绘树节点虚线

  一、开心一刻
  一程序员第一次上女朋友家她妈板着脸问 :你想娶我女儿,有多少存款?
  程序员低了下头:五百!
  她妈更鄙视了:才五百块,买个厕所都不够!
  程序员忙说:不是人民币!
  她妈:就算是美元,还是不够买厕所!
  程序员:其实是比特币!
  她妈:哇,贤婿,我给你买只大龙虾去 二、自绘树节点?
  自绘树节点?听起来都挺复杂的,可是为什么还要自绘树节点呢?这充分说明产品的脑子是什么东西都能想出来的。
  有一天产品说我们的软件里缺少一个美丽的树控件,然后就要求开发去实现这个功能。
  对于有一定开发经验的同学可能直接会去百度,或者上Qt帮助文档上查找资料,然后发现直接设置qss就能达到我们需要的效果,于是一顿操作后,发现效果还是不错滴。 setStyleSheet("" 	"QTreeView {outline:none;show-decoration-selected: 1;}" 	"QTreeView {outline:none;border:0px;}" 	"QTreeView::branch{		background-color: transparent;	}" 	"QTreeView::item:hover, QTreeView::branch:hover { background-color: transparent;border-color: rgb(255, 0, 0);}" 	"QTreeView::item:selected, QTreeView::branch:selected { background-color: #C5E0F7;}" 	"QTreeView::branch:open:has-children{image: url(:/branch-expand.png);}" 	"QTreeView::branch:closed:has-children{image: url(:/branch-collapse.png);}" 	"QTreeView::branch:has-siblings:!adjoins-item{border-image:url(:/branch-line.png) 0;}" 	"QTreeView::branch:has-siblings:adjoins-item{border-image:url(:/branch-more.png) 0;}" 	"QTreeView::branch:!has-children:!has-siblings:adjoins-item{border-image:url(:/branch-end.png) 0;	}" 	"QTreeView::branch:has-children:!has-siblings:closed,QTreeView::branch:closed:has-children:has-siblings{border-image:none;image: url(:/branch-collapse.png);	}" 	"QTreeView::branch:open:has-children:!has-siblings,QTreeView::branch:open:has-children:has-siblings{border-image:none;image: url(:/branch-expand.png);	}" 	);
  遂找来产品验证,当产品看到这个效果后,脸直接都绿了。
  产品:我不是说要一个树形控件吗?行高需要能动态调整那种!
  开发:…
  开发:行高调整了,那branch上贴的图拉伸后不是模糊了么…
  产品:…
  产品:我不管,这个行高可拖拽功能很重要,怎么实现我不管,但是功能必须要有。
  开发:卧槽,看来只有出终极大法了,直接自绘吧 三、效果展示
  如下图所示,是一个简单的树branch自绘效果。
  此处主要是展示一个demo效果,如果需要美化需要专业设计师出图来做。
  四、实现思路
  既然要自己绘制树形节点,那必然要去研究Qt的源码。 1、可扩展接口
  首先我们打开QTreeView类的帮助文档,查找这个类都有哪些可供重写的接口,然后就发现了这么几个函数
  看名字大概都知道是什么意思,不过这里还是做简要说明
  函数名
  含义
  drawBranches
  绘制branch
  drawRow
  绘制行
  drawTree
  绘制树
  indexRowSizeHint
  默认行高
  rowHeight
  获取行高
  前边提到我们要自己绘制branch线条,但是其余的东西还是要走Qt默认的绘制风格,因此在重写绘制函数时,千万不要忘记了调用原有的绘制方法。
  表格中前3个函数就是绘制树控件的具体方法,这3个函数搭配起来完成了树控件内容格子的绘制。下面我们来重写这3个函数,分别完成我们的需求 2、函数重写
  a、绘制行drawRow
  drawRow顾名思义就是绘制一行的意思,这里也确实如此。为什么要重写这个函数呢?答案也很简单。
  树控件本身是不具有垂直分割线的,既然我们要模拟表格的样式,那么垂直分割线必然是需要的。
  实现代码可能像下面这样,是不是很简单。 void FrozenTreeView::drawRow(QPainter * painter, const QStyleOptionViewItem & options, const QModelIndex & index) const { 	QTreeView::drawRow(painter, options, index);  	//绘制网格线 	QPen pen; 	pen.setWidth(m_iWidth); 	pen.setColor(m_gridLineColor);  	painter->save(); 	painter->setPen(pen); 	painter->drawRect(options.rect); 	painter->restore(); }
  b、绘制branch
  绘制行函数主要是添加了单元格边框绘制,接下来就是第一列的branch绘制。
  绘制branch时一定不要忘记调用原有的绘制函数,否则界面显示会异常。 { 	painter->save(); 	QTreeView::drawBranches(painter, rect, index); 	painter->restore(); }
  绘制branch时主要是根据当前节点是否展开、是否有孩子节点、是否有兄弟节点等状态来联合判断并进行绘制
  如下是绘制代码,可能有些长,但是应该比较好理解。
  点击领取Qt学习资料+视频教程~ 「链接」
  需要注意的点 除根节点外,每个节点都需要绘制文字前边的水平线 有父亲的节点需要绘制垂直线。绘制的竖线是否绘制到底,取决于是否有向下的兄弟 有爷爷的节点可能需要额外绘制向下的竖线。是否绘制取决于自己的父亲是否有向下的兄弟 规则3其实是一个循环的处理,也就是说爷爷如果有爸爸,也就是说节点如果有祖爷爷,那么可能还需要绘制更多的向下竖线。是否绘制取决于节点的爷爷是否有向下的兄弟
  代码这里就不细说了,有兴趣的可以自己研究研究。绘制规则就是上述4点 //绘制branch { 	DataNode * node = static_cast(index.internalPointer()); 	bool hasChild = node->children().size() != 0;//是否有孩子  	QList & children = node->parent()->children(); 	bool has_next_siblings = children.indexOf(node) != (children.size() - 1);//是否有向后的兄弟 	bool has_pre_siblings = children.indexOf(node) != 0;//是否有向前的兄弟  	int level = node->level(); 	int indentaion = indentation();//缩进 	int indentaions = indentaion * (level - 1);//缩进距离  	QRect r = rect; 	r.setLeft(r.left() + indentaions);//图标绘制位置  	painter->save(); 	painter->setPen(m_branchLine);  	bool expaned = isExpanded(index);//节点是否展开  	QLine line(r.center() + QPoint(0, r.top() - r.center().y()), r.center() + QPoint(0, r.bottom() - r.center().y())); 	line.translate(-indentaion, 0); 	//QLine line(r.topLeft(), r.bottomLeft()); 	//循环绘制(具有兄弟节点的)父节点向下的竖线 	DataNode * parent_node = node->parent(); 	DataNode * sub_node = node; 	bool isNeed = node->children().size() == 0; 	for (int i = level - 1; i >= 0; --i) 	{ 		QList & children = parent_node->children(); 		bool has_next_siblings = children.indexOf(sub_node) != (children.size() - 1);//父节点是否有(向后的)兄弟  		if (has_next_siblings) 		{ 			painter->drawLine(line); 		} 		  		if (level - 1 == i) 		{ 			QPoint pos = (line.p1() + line.p2()) / 2; 			QPoint pos2 = pos + QPoint(indentaion / 2, 0);  			painter->drawLine(pos, pos2);  			if (!has_next_siblings) 			{ 				painter->drawLine(line.p1(), (line.p1() + line.p2()) / 2); 			} 		}  		sub_node = parent_node; 		parent_node = parent_node->parent(); 		line.translate(-indentaion, 0); 	}  	QPixmap pix; 	if (expaned) 	{ 		if (hasChild) 		{ 			pix = QPixmap(":/branch-expand.png"); 		} 	} 	else 	{ 		if (hasChild) 		{ 			pix = QPixmap(":/branch-collapse.png"); 		} 	} 	if (pix.isNull() == false) 	{ 		QRect pixRect = QRect(QPoint(0, 0), pix.size()); 		pixRect.moveCenter(r.center());  		if (expaned) 		{ 			QLine line(r.center(), r.center() + QPoint(0, r.bottom() - r.center().y())); 			painter->drawLine(line); 		}  		painter->drawPixmap(pixRect, pix); 	}  	painter->restore(); } 3、同步左侧表头
  上一篇文章Qt实现表格树控件-支持多级表头 中已经说了,我们的表格控件是使用QTableView+QTreeView来实现的,那么我们操作树控件时必然要对表格中的表头进行同步操作了。
  点击领取Qt学习资料+视频教程~ 「链接」
  树控件折叠时隐藏垂直表头指定行 void collapsed_p(DataNode * node) { 	QList childNodeList = node->children(); 	//DataManager::getInstance()->allChildNode(node, childNodeList);  	int size = childNodeList.size(); 	for (int i = 0; i < size; ++i) 	{ 		int serial = DataManager::getInstance()->serialNoOfNode(childNodeList.at(i)); 		VHeaderView::instance->SetRowHide(serial, true);  		QModelIndex subIndex = FrozenTreeView::instance->rowIndex(serial);  		collapsed_p(childNodeList.at(i)); 	} }  void FrozenTreeView::onCollapsed(const QModelIndex & index) { 	if (!index.isValid()) 		return;  	DataNode * node = static_cast(index.internalPointer()); 	if (nullptr == node) 		return;  	collapsed_p(node); 	VHeaderView::instance->UpdateCache();  	//要对水平头的最后一列进行重设大小,引起水平头自己的更新操作,从而使整个界面显示正确 	HHeaderView::instance->resizeLastSection(true); }
  树控件展开时显示垂直表头指定行 void expanded_p(DataNode * node) { 	QList childNodeList = node->children();  	int size = childNodeList.size(); 	for (int i = 0; i < size; ++i) 	{ 		int serial = DataManager::getInstance()->serialNoOfNode(childNodeList.at(i)); 		VHeaderView::instance->SetRowHide(serial, false);  		QModelIndex subIndex = FrozenTreeView::instance->rowIndex(serial);  		if (FrozenTreeView::instance->isExpanded(subIndex)) 		{ 			expanded_p(childNodeList.at(i)); 		} 	} }  void FrozenTreeView::onExpanded(const QModelIndex & index) { 	DataNode * node = static_cast(index.internalPointer()); 	if (nullptr == node) 		return;  	VHeaderView::instance->blockSignals(true); 	expanded_p(node); 	VHeaderView::instance->UpdateCache(); 	VHeaderView::instance->blockSignals(false);  	//要对水平头的最后一列进行重设大小,引起水平头自己的更新操作,从而使整个界面显示正确 	HHeaderView::instance->resizeLastSection(false); }

晋江草庵寺姑嫂塔战地公园草庵寺我国唯一的摩尼光佛摩尼教寺庙遗存,也是世界现存唯一摩尼教寺庙遗址。被列为全国重点文物保护单位,位于福建省晋江市华表山南麓。草庵始于宋绍兴年间,初为草筑故名。元顺帝至元五年(公贺兰山丁香沟登贺兰矿头条创作挑战赛贺兰山丁香沟登贺兰矿摄影文字阳光脚步贺兰矿,是贺兰山网红打卡点贺兰矿,是贺兰山网红打卡点也是贺兰山滚钟口附近标志性山峰是驴友们日常登山锻炼喜欢去的地方在银川户外界,走祭月礼燃花灯,来南京莫愁湖祈福中秋现代快报讯(记者张然)还原祭月古礼,点燃祈福花灯。9月10日是中秋佳节,在南京莫愁湖公园抱月楼前,一场中秋节祭月仪式给公园增添了浓厚的古典气息。随后,市民游客月下放灯泛舟游湖提灯游元宇宙漫游,海派源打卡,这个中秋来体验一场线上游园又逢八月十五月圆夜,一年一度的唐韵中秋也如约而至。这个中秋活动的主会场一直在沪上海派古典名园桂林公园,丰富多彩的游园活动成为很多市民的美好回忆。今年,因桂林公园要进行全面修缮,不对两天一晚,爬完五岳最险的华山(多图)西安火车站广场乘坐游1路,两个小时左右到华山脚下的玉泉院。我们到的时候已经是晚上七点多了,在提前订好的宾馆放下行李,出去吃了点东西,顺便熟悉一下环境。玉泉院晚上很热闹,选择晚上上山在瑞金怎么找月子会所如果家里人不会照顾或者没人照顾月子的话,是可以去月子中心的。月子中心的服务员都是受专业培训的,不仅可以为产妇调理饮食。还可以护理宝宝。月子中心的护理方法,一般都是比较科学的,可以按家中有人坐月子的,切记最好别让3种人进月子房老人家常叮嘱,坐月子的时候,千万别让外人进月子房,不然对产妇不好。或许很多人会不以为然,觉得是老人家太迷信。其实这真的不是迷信,是有真实科学依据的。最好别让以下三种人进月子房,关系怎么判断一个孩子聪不聪明?个人看法,不喜勿喷。孩子聪不聪明,大体上可以通过6个方向判断。1,记忆力,花多久时间记住,记住时间多长。2,发散思维能力,能不能扩散联想,举一反三。3,热情与好奇,对周围事物是不是某粉的表现证明,孩子小不懂事,长大了会变好肯定是伪命题不少人听说过一句话孩子是自己的好。不管第二辈第三辈,很多人看自己家的孩子,越看越顺眼,做什么都是对的。有人跟他们探讨孩子教育问题,指出惯孩子是不对的,他们往往用孩子还小,大了自然就LCK夏季赛战况T1统治力不复存在,3队已晋级季后赛仅剩3个名额随着LPL夏季赛进入第九周,季后赛名额争夺已经进入白热化阶段,排名前6的队伍,已经锁定了季后赛资格,而前4名的TESRNGJDGV5,也已经确定了常规赛前4的成绩,4支战队将展开复estar23GK,大魔王状态波动,清融被限制就难打,鹏鹏状态爆棚KPL夏季赛常规赛继续进行,武汉estarpro和佛山GK上演了强强对决。这场比赛对于双方来说都很关键,毕竟常规赛已经到了第三阶段,各支队伍都需要努力冲击胜者组。Estar每次打G
微信这3个开关要尽快关闭,不然内存会越来越小,手机越用越卡本文编辑今日头条作者维权骑士签约用户小俊技术分享独家原创制作未经授权严禁转载,发现抄袭者将进行全网维权投诉分享生活小妙招,享受科技新生活!大家好,欢迎来到今天的知识分享!我是你们的物联网商机无限物联网创业和项目也有坑物联网避坑指南之1物联网是通过约定的协议将原本独立存在的设备相互连接起来,并最终实现智能识别定位跟踪监测控制和管理的一种网络,在户外露天野外郊外地下矿井海洋水域田间地头山河森林道路桥梁城市街头巷尾默iPhone要装中国芯片专家批是对美国的背叛但苹果并不违法苹果公司计划向中国长江存储订购装载于新款iPhone14智能手机的芯片后,美国国会反华议员鲁比奥警告该公司若执意与中国芯片企业合作,将面临美国政府的严格审查。就在美国政府对中国采取疯狂一夜!8笔新签约达成,篮网签勇士旧将,湖人签回施罗德北京时间9月17日,NBA自由市场迎来疯狂一夜,又有2笔新签约达成,其中篮网连签2人,包括勇士旧将切奥扎步行者则一口气连签4人,阵容名单已达20人湖人则正式签回旧将施罗德,后者在欧刺痛惨遭129段路人王零封输掉对局却赢了理解,几千元白亏了?最近,刺痛所举办的发育路SOLO挑战赛在网络上引起了不少玩家的关注,作为狼队功勋发育路选手,刺痛的后羿孙尚香等英雄都给观众留下了深刻的印象。这次挑战赛,刺痛邀请到全网各大顶级发育路AiFA体育阿莱格里遭球迷厌恶期盼齐达内接过教鞭阿莱格里遭球迷厌恶期盼齐达内接过教鞭去年5月份二进宫执教尤文图斯的阿莱格里在他1年多的执教中战绩不佳,他们在周中的欧冠小组赛中被本菲卡21逆转取得欧冠2连败。根据意大利媒体都灵体育如何看待当前经济形势文任泽平团队1以稳为主,空中加油当前的经济形势概括讲以稳为主。经济稳主要体现在78月数据窄幅波动,7月略降,8月略升,没有明显回落,也没有明显回升政策稳主要体现在财政货币政策表态不85分钟绝杀,10!亚洲第2晋级,创4大纪录,中国队出线形势出炉U20亚洲杯预选赛继续进行,日本队以10的比分战胜了也门男足,而伊朗队以20的比分战胜了阿联酋队,这样的话,日本队锁定了小组第一名,伊朗队同样是拿到榜首,两支亚洲强队携手晋级U20维尼修斯跳舞庆祝进球被批,这真的算挑衅对手吗?近期关于维尼修斯进球后跳舞的话题引起了诸多讨论,有声音认为这是在挑衅对手,西班牙经纪人协会主席佩德罗布拉沃公开批评了维尼修斯进球后跳舞的行为,也有越来越多的人对前锋维尼修斯发表了种短短7年,辗转8支球队!球员身份只为遮掩,全联盟都在等他退役如果联盟中有人能拿到四双,那毫无疑问是拉简隆多。担任教练的控球后卫我觉得我是全联盟最好的控球后卫。隆多说这句话时脸上充满自信,在当时隆多确实有这个实力。作为凯尔特人时期三巨头的带刀四大冠军中单打冒泡赛,令人感叹如果按照荣誉给LPL的中单们排个位置的话,那么前4名应该是ScoutRookieDoinbXiaohu。这四位都拥有国际赛事的冠军,前面三个各有一个S赛冠军,Scout拥有1个S赛