You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PowerShell已激活窗体更新:动态增删PictureBox方案问询

无需重启窗体实现动态更新地图红点的方案

我完全懂你现在的糟心体验——每次改完TXT坐标都得重启窗体太折腾了。其实咱们可以用FileSystemWatcher监听文件变化,再结合UI线程安全的控件更新逻辑,就能实现不用关窗体就动态增删红点的效果。

下面是修改后的完整代码,我会拆解关键改动帮你理解:

function MakeForm {
    [void][reflection.assembly]::LoadWithPartialName("System.Windows.Forms")
    [void][reflection.assembly]::LoadWithPartialName("System.Drawing")
    [System.Windows.Forms.Application]::EnableVisualStyles()

    $form = New-Object Windows.Forms.Form
    $form.Text = "Image Viewer"
    $form.Width = 300
    $form.Height = 270

    # 替换成你的实际路径
    $mapImagePath = "Insert Map Image Path here"
    $redDotImagePath = "Insert Red Dot Image Path here"
    $coordsTxtPath = "Insert Coordinates TXT Path here"

    $imgMap = [System.Drawing.Image]::FromFile($mapImagePath)
    $imgRedDot = [System.Drawing.Image]::FromFile($redDotImagePath)

    # 存储红点控件的列表,方便批量操作
    $redDotBoxes = New-Object 'System.Collections.Generic.List[Windows.Forms.PictureBox]'

    # --- 核心函数:加载/更新红点 ---
    function UpdateRedDots {
        # 先清理所有旧红点,避免重复叠加
        foreach ($box in $redDotBoxes) {
            $form.Controls.Remove($box)
            $box.Dispose() # 释放资源防止内存泄漏
        }
        $redDotBoxes.Clear()

        # 读取最新坐标文件
        if (-not (Test-Path $coordsTxtPath)) { return }
        $coordLines = Get-Content -Path $coordsTxtPath

        foreach ($Line in $coordLines) {
            if ($Line -like "*in 2*") {
                $Split1 = $Line.Split(" ")
                $x = [int]$Split1[5]
                $y = [int]$Split1[6]

                $pictureBox = New-Object Windows.Forms.PictureBox
                $pictureBox.Width = $imgRedDot.Size.Width
                $pictureBox.Height = $imgRedDot.Size.Height
                $pictureBox.Location = New-Object System.Drawing.Point($x, $y)
                $pictureBox.Image = $imgRedDot

                $form.Controls.Add($pictureBox)
                $redDotBoxes.Add($pictureBox)
            }
        }
        $form.Refresh() # 刷新窗体显示新控件
    }

    # --- 创建背景地图控件 ---
    $mapBox = New-Object Windows.Forms.PictureBox
    $mapBox.Width = $imgMap.Size.Width
    $mapBox.Height = $imgMap.Size.Height
    $mapBox.Image = $imgMap
    $form.Controls.Add($mapBox)
    $mapBox.SendToBack() # 确保红点显示在地图上方

    # --- 测试按钮:移除指定红点 ---
    $btnRemoveTest = New-Object System.Windows.Forms.Button
    $btnRemoveTest.Width = 25
    $btnRemoveTest.Height = 100
    $btnRemoveTest.Location = New-Object System.Drawing.Point(223, 0)
    $btnRemoveTest.Text = "移除测试"
    $form.Controls.Add($btnRemoveTest)
    $btnRemoveTest.Add_Click({
        if ($redDotBoxes.Count -ge 3) {
            $form.Controls.Remove($redDotBoxes[2])
            $redDotBoxes[2].Dispose()
            $redDotBoxes.RemoveAt(2)
        }
    })

    # --- 手动刷新按钮 ---
    $btnRefreshManual = New-Object System.Windows.Forms.Button
    $btnRefreshManual.Width = 25
    $btnRefreshManual.Height = 100
    $btnRefreshManual.Location = New-Object System.Drawing.Point(260, 0)
    $btnRefreshManual.Text = "手动刷新"
    $form.Controls.Add($btnRefreshManual)
    $btnRefreshManual.Add_Click({
        UpdateRedDots
    })

    # --- 自动监听文件变化 ---
    $fileWatcher = New-Object System.IO.FileSystemWatcher
    $fileWatcher.Path = Split-Path $coordsTxtPath -Parent
    $fileWatcher.Filter = Split-Path $coordsTxtPath -Leaf
    $fileWatcher.EnableRaisingEvents = $true

    # 文件修改/创建/删除时触发更新
    $fileWatcher.Add_Changed({
        # 注意:文件监听事件在后台线程,必须用Invoke切回UI线程操作控件
        $form.Invoke({
            Start-Sleep -Milliseconds 200 # 等待文件写入完成,避免读取不完整
            UpdateRedDots
        })
    })
    $fileWatcher.Add_Created({
        $form.Invoke({ UpdateRedDots })
    })
    $fileWatcher.Add_Deleted({
        $form.Invoke({ UpdateRedDots })
    })

    # 窗体显示时加载初始红点
    $form.Add_Shown({
        $form.Activate()
        UpdateRedDots
    })

    # 窗体关闭时释放所有资源
    $form.Add_FormClosed({
        $fileWatcher.Dispose()
        $imgMap.Dispose()
        $imgRedDot.Dispose()
        foreach ($box in $redDotBoxes) { $box.Dispose() }
    })

    $form.ShowDialog()
}

MakeForm

关键优化点说明:

  1. 封装UpdateRedDots函数:把读取坐标、创建/清理红点的逻辑抽成独立函数,不管是手动刷新还是自动更新都能复用。
  2. 自动文件监听:用FileSystemWatcher实时监测TXT文件的修改、创建、删除,不用手动触发刷新。加了200毫秒延迟是为了等文件完全写入,避免读取到不完整的内容。
  3. UI线程安全:文件监听事件是在后台线程跑的,WinForms控件只能在UI线程修改,所以用$form.Invoke把更新逻辑切回UI线程,防止跨线程异常。
  4. 资源管理:在窗体关闭时主动释放图片、监听器和控件资源,避免内存泄漏。
  5. 控件层级调整:把地图控件放到最底层,确保红点能正常显示在地图上面。

现在你替换好路径运行后,修改TXT里的坐标,窗体就会自动更新红点,再也不用重启啦!

内容的提问来源于stack exchange,提问作者Hoesl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 21:22:52