如何禁用TLabel自动绘制?解决跨显示器切换显示异常问题
问题与解决方案
问题详情
我有一个包含TTreeView和TPanel的TForm,Panel上关联了一个TLabel作为标题。TreeView中存在文本过长的节点,自动生成了滚动条。我通过TextOutA在TreeView位置变化时绘制Label标题,功能正常,但切换到第二显示器时,Label会自动重绘导致显示异常。已尝试在Form的OnPaint事件中调用HeadlineDrawing()但无效,也确认了绘制位置正确,寻求解决办法。
现有代码
void __fastcall TShortView2Form::HeadlineDrawing(void) { TRect LabelRect; LabelRect = TitelLabel->ClientRect; TitelLabel->Canvas->Brush->Color = Panel1->Color; LabelRect.Left = DefaultLeftPosition - 20; TitelLabel->Canvas->FillRect(LabelRect); // Fill the Pannel, with his Background Color, therefore it is blank LabelRect.Left = DefaultLeftPosition - 20; // -20, for the Correct Position of the Drawing TitelLabel->Canvas->Font->Color = clBlack; TitelLabel->Canvas->Font->Style += TitelLabel->Canvas->Font->Style << fsBold; TitelLabel->Canvas->TextOutA(LabelRect.Left, LabelRect.Top, TitelLabel->Caption); TitelLabel->Canvas->Font->Style -= TitelLabel->Canvas->Font->Style << fsBold; } void __fastcall TShortView2Form::TreeView1AdvancedCustomDrawItem(TCustomTreeView *Sender, TTreeNode *Node, TCustomDrawState State, TCustomDrawStage Stage, bool &PaintImages, bool &DefaultDraw) { bool bHeadlineDraw = true; if (Node->Level == 0) { TRect Rect; Rect = Node->DisplayRect(true); if (DefaultLeftPosition != Rect.Left) { DefaultLeftPosition = Rect.Left; if (Stage == cdPostPaint) { HeadlineDrawing(); bHeadlineDraw = false; } } } Sender->Canvas->Brush->Color = clWhite; Sender->Canvas->Font->Color = clBlack; bool bIsSelected = State.Contains(cdsFocused); if (bIsSelected && bHeadlineDraw && Stage == cdPostPaint) { HeadlineDrawing(); bHeadlineDraw = false; } }
效果对比
- 正常显示:标题文本与TreeView节点对齐,显示正常
- 切换显示器后异常:标题文本位置偏移或被默认Label内容覆盖
解决办法
问题根源
切换显示器时,Label会触发默认重绘逻辑,覆盖你通过TreeView事件执行的自定义绘制;Form的OnPaint事件无法阻止Label自身的重绘,导致自定义内容丢失。
具体修正步骤
接管Label的
OnPaint事件
将自定义绘制逻辑移到Label自己的Paint事件中,确保每次Label需要重绘时都执行你的绘制代码,避免被默认重绘覆盖。修正字体样式操作
原代码中字体样式的叠加逻辑错误,会导致样式重复累加,需先保存原有样式再修改,绘制完成后恢复。处理显示器切换时的位置更新
监听Form的OnDisplayChanged事件,在显示器切换时重新获取TreeView根节点的位置,更新DefaultLeftPosition并触发Label重绘。
修改后的代码示例
// 修正后的HeadlineDrawing函数 void __fastcall TShortView2Form::HeadlineDrawing(void) { TRect LabelRect = TitelLabel->ClientRect; // 保存Label原有字体样式 TFontStyles originalStyle = TitelLabel->Canvas->Font->Style; // 用Panel背景色填充Label区域,清除默认内容 TitelLabel->Canvas->Brush->Color = Panel1->Color; TitelLabel->Canvas->FillRect(LabelRect); // 计算正确的绘制位置 int drawLeft = DefaultLeftPosition - 20; // 设置绘制字体属性 TitelLabel->Canvas->Font->Color = clBlack; TitelLabel->Canvas->Font->Style = originalStyle << fsBold; // 绘制标题文本 TitelLabel->Canvas->TextOutA(drawLeft, LabelRect.Top, TitelLabel->Caption); // 恢复原有字体样式 TitelLabel->Canvas->Font->Style = originalStyle; } // 给TitelLabel添加OnPaint事件处理 void __fastcall TShortView2Form::TitelLabelPaint(TObject *Sender) { HeadlineDrawing(); } // Form的OnDisplayChanged事件(处理显示器切换) void __fastcall TShortView2Form::FormDisplayChanged(TObject *Sender) { // 重新获取根节点位置,更新DefaultLeftPosition if (TreeView1->Items->Count > 0) { TTreeNode* rootNode = TreeView1->Items->Item[0]; if (rootNode) { TRect nodeRect = rootNode->DisplayRect(true); DefaultLeftPosition = nodeRect.Left; } } // 强制Label重绘 TitelLabel->Invalidate(); }
额外注意事项
- 确保
DefaultLeftPosition初始值正确,可在Form的OnCreate事件中提前获取根节点位置初始化。 - 若TreeView节点动态变化,需在节点添加/删除后更新
DefaultLeftPosition并触发Label重绘。
内容的提问来源于stack exchange,提问作者killa
相关产品推荐
相关产品推荐

