设计要求树中节点内容是动态变化的。所以程序在Timer1中会用到以下两句:
TreeView1.Nodes(i).Image = 1
TreeView1.Nodes(i).Text = "aaa"
每次更新都会引起整个控件闪烁一下,有什么办法只让该节点的内容刷新,而不让整个控件刷新,避免闪烁。本想结合ValidateRect和InvalidateRect来做的,可是又没办法获得该节点的坐标。

解决方案 »

  1.   

    你不是刷新一次,而是 n 多次吧。
    在循环外将整个 TreeView 的刷新禁止,循环结束后再一次性刷新。
      

  2.   

    一秒更新一次,那还是要一秒种闪一次的呀?时间太长了又达不到设计要求了。
    每次赋值,整个树都会先擦除,再重绘,从而闪烁。而我仅仅只是改变了一个节点的image和text属性,没必要整个树重绘吧,是我没用好treeview吗?
      

  3.   

    这是我每秒对 10000 个节点进行更新,也没有闪烁
    Private Sub Timer1_Timer()
        Static b As Boolean
        Dim nd As Node
        
        b = Not b
        For Each nd In TreeView1.Nodes
            nd.Image = IIf(b, 1, 2)
            nd.Text = Left$(nd.Text, 1) & IIf(b, "1", "0")
        Next
    End Sub
      

  4.   

    感谢Tiger_Zhao提供的代码,跟我差不多。
    用你的代码试了,可是确实是闪的呀。你仔细感觉就能发现,它其实是先擦除再更新的。
    可能所有节点都在变,你感觉不出闪的现象了。我只需要更改节点1的状态,这样闪的状态会更明显,
    用以下代码你试一下:
    Private Sub Timer1_Timer()   '1秒一次
        Static b As Boolean
        Dim nd As Node
        
        b = Not b
        Set nd = TreeView1.Nodes(1)
        nd.Image = IIf(b, 1, 2)
        nd.Text = left$(nd.Text, 1) & IIf(b, "1", "0")
    End Sub
      

  5.   

    treeview1.visible=false
    treeview1.visible=true 
      

  6.   

    HOHO..你太注重细节了..我发个绘目录结果的代码..嘿嘿:'第二次真正列一个只列了一个子目录的目录时会提示key的唯一性问题
    '用它跳过这个跳(我们知道的正常的错):
    On Error Resume Next
    '将选定位置的图片加入Lst
       Dim flecount As Long
       Dim i As Long, j As Long, tmpEndN1 As Long, tmpEndN2 As Long
       Dim TmpStr As String, DirGetMsg As String, DirNextDirMsg As String
       Dim LstItm As ListItem, NowAddedDir() As String
    '选定的每一个目录都要列举。定义动态数组,动态记录点过的目录,列过了就不列了。
       tmpEndN1 = UBound(DirRecordCache())
       ReDim Preserve NowAddedDir(0) As String '初始化监时数组。   For i = 0 To tmpEndN1
           If InStr(DirRecordCache(i), TreeLst_NetPC.SelectedItem.Key) <> 0 Then Exit For
       Next
       If i > tmpEndN1 Then '一级缓存中没有访问痕迹
          tmpEndN2 = UBound(DirRecord())
          For i = tmpEndN2 To 0 Step -1
              If InStr(DirRecord(i), TreeLst_NetPC.SelectedItem.Key) <> 0 Then Exit For
          Next i
       End If
       If i < 0 Then '没有被访问记录,需要列举
          '列举当前选中目录(盘符)下的一级子目录
          '并记录在当选择目录
          DirRecordCache(tmpEndN1) = TreeLst_NetPC.SelectedItem.Key
          DirRecord(tmpEndN2) = TreeLst_NetPC.SelectedItem.Key
          ReDim Preserve DirRecord(tmpEndN2 + 1) As String
          If (tmpEndN1 + 1) <= 21 Then
             ReDim Preserve DirRecordCache(tmpEndN1 + 1) As String
          Else
             ReDim Preserve DirRecordCache(0) As String
             DirRecordCache(0) = ""
          End If
          '用dir()函数列出该机共享目录下的所有打印机录
          DirGetMsg = Dir(CheckPath(TreeLst_NetPC.SelectedItem.Key), vbHidden + vbReadOnly + vbDirectory) ' 找寻第一项。
          Do While DirGetMsg <> ""   ' 开始循环。
             ' 跳过当前的目录及上层目录。
             If DirGetMsg <> "." And DirGetMsg <> ".." Then
                ' 使用位比较来确定 MyName 代表一目录。
                If (GetAttr(CheckPath(TreeLst_NetPC.SelectedItem.Key) & DirGetMsg) And vbDirectory) = vbDirectory Then
                   ' 如果它是一个目录,将其名称显示出来。
                   For i = 0 To UBound(NowAddedDir())
                       If InStr(NowAddedDir(i), CheckPath(TreeLst_NetPC.SelectedItem.Key) & DirGetMsg) <> 0 Then
                          Exit For
                       End If
                   Next i
                   If i > UBound(NowAddedDir()) Then
                      ' 如果它是一个目录,将其名称显示出来。
                      Me.TreeLst_NetPC.Nodes.Add TreeLst_NetPC.SelectedItem.Key, tvwChild, CheckPath(TreeLst_NetPC.SelectedItem.Key) & DirGetMsg, DirGetMsg
                      '让有下级目录的显示+号。列一个出来。省时间
                      DirNextDirMsg = Dir(CheckPath(CheckPath(TreeLst_NetPC.SelectedItem.Key) & DirGetMsg), vbHidden + vbReadOnly + vbDirectory)
                      ReDim Preserve NowAddedDir(j) As String
                      NowAddedDir(j) = CheckPath(TreeLst_NetPC.SelectedItem.Key) & DirGetMsg
                      j = j + 1
                      Do While DirNextDirMsg <> ""
                         If DirNextDirMsg <> "." And DirNextDirMsg <> ".." Then
                           ' 使用位比较来确定 MyName 代表一目录。
                           If (GetAttr(CheckPath(CheckPath(TreeLst_NetPC.SelectedItem.Key) & DirGetMsg) & DirNextDirMsg) And vbDirectory) = vbDirectory Then
                           ' 如果它是一个目录,将其名称显示出来。
                              Me.TreeLst_NetPC.Nodes.Add CheckPath(TreeLst_NetPC.SelectedItem.Key) & DirGetMsg, tvwChild, CheckPath(CheckPath(TreeLst_NetPC.SelectedItem.Key) & DirGetMsg) & DirNextDirMsg, DirNextDirMsg
                              DirGetMsg = Dir(CheckPath(TreeLst_NetPC.SelectedItem.Key), vbHidden + vbReadOnly + vbDirectory) ' 找寻第一项。
                              Exit Do
                           End If
                         End If
                         DirNextDirMsg = Dir ' 查找下一个目录。
                         If DirNextDirMsg = "" Then
                            DirGetMsg = Dir(CheckPath(TreeLst_NetPC.SelectedItem.Key), vbHidden + vbReadOnly + vbDirectory) ' 找寻第一项。
                         End If
                      Loop
                   End If
                End If
             End If
             DirGetMsg = Dir   ' 查找下一个目录。
          Loop
       End If
       'Me.Text2.Text = CheckPath(Me.TreeLst_NetPC.SelectedItem.Key)直接用会有好些问题..HOHO..
      

  7.   

    ykwang,这样更闪,一关一开本身就是一个闪烁。
      

  8.   

    rjzhangjun(RJ),你的程序不适合我,我不是要建树或是往树中添加节点。
    树已建好,只是节点上显示的图像和文字要变化。如果只是变化image,我改成这样倒是可以忍受:
    Private Sub Timer1_Timer()   '1秒一次
        Static b As Boolean
        Dim nd As Node
        b = Not b
        Set nd = TreeView1.Nodes(1)
        nd.Image = IIf(b, 1, 2)
        'nd.Text = left$(nd.Text, 1) & IIf(b, "1", "0")
        ValidateRectBynum TreeView1.hWnd, 0
        InvalidateRecBynum TreeView1.hWnd, 0, 0
        UpdateWindow TreeView1.hwnd
    End Sub但如果变化的是Text属性,就不行了:
    Private Sub Timer1_Timer()   '1秒一次
        Static b As Boolean
        Dim nd As Node
        b = Not b
        Set nd = TreeView1.Nodes(1)
        'nd.Image = IIf(b, 1, 2)
        nd.Text = left$(nd.Text, 1) & IIf(b, "1", "0")
        ValidateRectBynum TreeView1.hWnd, 0
        InvalidateRecBynum TreeView1.hWnd, 0, 0
        UpdateWindow TreeView1.hwnd
    End Sub
    为什么ValidateRectBynum会来不及屏蔽text属性的变化呢?
    欢迎大家继续探讨。
      

  9.   

    经调试发现:赋值image属性,会向控件发WM_PAINT消息(整棵树无效,都要重绘);如果无效区域只是图片范围就好了。但是无法知晓图片的坐标位置,上面的程序我把无效区域改成了整个显示区域,效果上已经好了不少。赋值text属性,会向控件发WM_SETREDRAW消息。水平有限,这个苦思冥想都想不出解决办法了。
      

  10.   

    方法一: LockWindowUpdate treeview.hwnd/LockWindowUpdate 0, 可以减轻闪烁.方法二: 在WM_PAINT消息内利用BeginPaint/EndPaint获得无效区域的hdc及rcRect,进行更新。(ValidateRect/InvalidateRect本身不能确定无效区域)