我想通过用鼠标左键单击文本“退出”来退出这个系统托盘程序。当我将鼠标悬停时,鼠标会显示一个旋转的蓝色图标,而我点击却什么也没做。脚本有什么问题?
# a systray program, that should be exited (but it doesn't)
# 2023-03-18
$iconPath = "H:\Dropbox\400 - Scriptprogrammierung\Powershell\Taskleiste mit Wochentag\icons\ico\Logo.ico" # icon path
Write-Host -ForegroundColor Yellow $iconPath
$tooltip = "This is a text."
# NotifyIcon-object
$notifyIcon = New-Object System.Windows.Forms.NotifyIcon
$notifyIcon.Icon = [System.Drawing.Icon]::ExtractAssociatedIcon($iconPath)
$notifyIcon.Text = $tooltip
########################
# Here seems to be the problem...
$contextMenu = New-Object System.Windows.Forms.ContextMenuStrip
$menuItemExit = New-Object System.Windows.Forms.ToolStripMenuItem
$menuItemExit.Text = "Quit."
$contextMenu.Items.Add($menuItemExit)
$notifyIcon.ContextMenuStrip = $contextMenu
$menuItemExit.add_Click({ $notifyIcon.Dispose(); exit })
########################
# Show icon in systray
$notifyIcon.Visible = $true
# Loop
while ($true) {
$notifyIcon.Text = $tooltip
Start-Sleep -Seconds 60 # wait 60 seconds
}
所需的关键变化是:
不要直接从
exit
事件处理程序脚本块调用 .add_Click()
:它会使您的脚本崩溃。
下面的代码还将
$notifyIcon.Dispose()
移出此脚本块,而是将其移动到包装 finally
循环的 try
语句的 while
块中,而是通过以下方式通知希望退出的循环脚本级 $done
变量,通过事件处理程序中的 $script:done = $true
设置(在脚本的 child 范围内运行)。
这确保使用 Ctrl-C 终止脚本也能正确处理图标并将其从通知区域中删除。
在您的
while
循环中,您必须定期调用 [System.Windows.Forms.Application]::DoEvents()
以允许 WinForms 处理其 UI 事件。在这些调用之间只休眠 short,以保持 UI 响应 - 长时间休眠会在该休眠期间阻止事件处理。
# Load the WinForms assembly.
Add-Type -AssemblyName System.Windows.Forms
$iconPath = "H:\Dropbox\400 - Scriptprogrammierung\Powershell\Taskleiste mit Wochentag\icons\ico\Logo.ico" # icon path
$tooltip = "This is a text."
# NotifyIcon-object
$notifyIcon = New-Object System.Windows.Forms.NotifyIcon
$notifyIcon.Icon = [System.Drawing.Icon]::ExtractAssociatedIcon($iconPath)
$notifyIcon.Text = $tooltip
# Define a script-level variable that indicates whether the
# script should be exited, to be set to $true from the .add_Click() event handler.
$done = $false
$contextMenu = New-Object System.Windows.Forms.ContextMenuStrip
$menuItemExit = New-Object System.Windows.Forms.ToolStripMenuItem
$menuItemExit.Text = "Quit."
$null = $contextMenu.Items.Add($menuItemExit)
$notifyIcon.ContextMenuStrip = $contextMenu
# Set the script-level $done variable to $true when the menu item is clicked.
$menuItemExit.add_Click({ $script:done = $true })
# Show icon in systray (notification area)
$notifyIcon.Visible = $true
Write-Verbose -Verbose @"
Adding icon to notification area (system tray).
Use the icon's context menu to quit this script or press Ctrl-C.
"@
# Loop
try {
while (-not $done) {
# IMPORTANT: Make WinForms process its events.
[System.Windows.Forms.Application]::DoEvents()
# Sleep just a little, to keep the UI responsive.
Start-Sleep -MilliSeconds 100
}
}
finally {
$notifyIcon.Dispose()
}