簡體   English   中英

根據事件更改托盤圖標

[英]change tray icon based on event

我有將在托盤(任務欄)中啟動進程的代碼。 右鍵單擊托盤圖標后,它將顯示菜單。 單擊第一個菜單項 winform 窗口啟動后。 此 winform 顯示有關記事本進程的狀態。 我的目標是根據記事本的狀態更改托盤圖標(如果記事本正在運行,則顯示online.ico否則顯示offline.ico )。 如果我理解正確,那么每次打開/關閉 winform 窗口時我的代碼都會啟動/停止System.Windows.Forms.Timer ,我不確定這是否是最好的方法。 我的猜測是我需要以某種方式在OnMenuItem1ClickEventFn “外部”啟動計時器,以便它可以以某種方式重新加載*.ico文件。 以下腳本深受網站的啟發:

Add-Type -AssemblyName System.Windows.Forms    
Add-Type -AssemblyName System.Drawing

function Test-Notepad {
    [bool](Get-Process -Name 'notepad' -ErrorAction SilentlyContinue)
}


function OnMenuItem1ClickEventFn () {
    # Build Label object
    $Label = New-Object System.Windows.Forms.Label
        $Label.Name = "labelName"
        $Label.AutoSize = $True

    # Set and start timer
    $timer = New-Object System.Windows.Forms.Timer
    $timer.Interval = 1000
    $timer.Add_Tick({
        if ($Label){
            $Label.Text = if (Test-Notepad) { "Notepad is running" } else { "Notepad is NOT running" }
        }
    })
    $timer.Start()


    # Build Form object
    $Form = New-Object System.Windows.Forms.Form
        $Form.Text = "My Form"
        $Form.Size = New-Object System.Drawing.Size(200,200)
        $Form.StartPosition = "CenterScreen"
        $Form.Topmost = $True
        $Form.Add_Closing({ $timer.Dispose() })  # Dispose() also stops the timer.
        $Form.Controls.Add($Label)               # Add label to form
        $form.ShowDialog()| Out-Null             # Show the Form
}


function OnMenuItem4ClickEventFn () {
    $Main_Tool_Icon.Visible = $false
    $window.Close()
    Stop-Process $pid
}


function create_taskbar_menu{
    # Create menu items
    $Main_Tool_Icon = New-Object System.Windows.Forms.NotifyIcon
    $Main_Tool_Icon.Text = "Icon Text"
    $Main_Tool_Icon.Icon = $icon
    $Main_Tool_Icon.Visible = $true

    $MenuItem1 = New-Object System.Windows.Forms.MenuItem
    $MenuItem1.Text = "Menu Item 1"

    $MenuItem2 = New-Object System.Windows.Forms.MenuItem
    $MenuItem2.Text = "Menu Item 2"

    $MenuItem3 = New-Object System.Windows.Forms.MenuItem
    $MenuItem3.Text = "Menu Item 3"

    $MenuItem4 = New-Object System.Windows.Forms.MenuItem
    $MenuItem4.Text = "Exit"


    # Add menu items to context menu
    $contextmenu = New-Object System.Windows.Forms.ContextMenu
    $Main_Tool_Icon.ContextMenu = $contextmenu
    $Main_Tool_Icon.contextMenu.MenuItems.AddRange($MenuItem1)
    $Main_Tool_Icon.contextMenu.MenuItems.AddRange($MenuItem2)
    $Main_Tool_Icon.contextMenu.MenuItems.AddRange($MenuItem3)
    $Main_Tool_Icon.contextMenu.MenuItems.AddRange($MenuItem4)


    $MenuItem4.add_Click({OnMenuItem4ClickEventFn})
    $MenuItem1.add_Click({OnMenuItem1ClickEventFn})
}


$Current_Folder = split-path $MyInvocation.MyCommand.Path

# Add assemblies for WPF and Mahapps
[System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms')    | out-null
[System.Reflection.Assembly]::LoadWithPartialName('presentationframework')   | out-null
[System.Reflection.Assembly]::LoadWithPartialName('System.Drawing')          | out-null
[System.Reflection.Assembly]::LoadWithPartialName('WindowsFormsIntegration') | out-null
# [System.Reflection.Assembly]::LoadFrom("Current_Folder\assembly\MahApps.Metro.dll")  | out-null

# Choose an icon to display in the systray
$icon = [System.Drawing.Icon]::ExtractAssociatedIcon("$Current_Folder/icons/online.ico")
# use this icon when notepad is not running
# $icon = [System.Drawing.Icon]::ExtractAssociatedIcon("$Current_Folder/icons/offline.ico")


create_taskbar_menu

# Make PowerShell Disappear - Thanks Chrissy
$windowcode = '[DllImport("user32.dll")] public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);'
$asyncwindow = Add-Type -MemberDefinition $windowcode -name Win32ShowWindowAsync -namespace Win32Functions -PassThru
$null = $asyncwindow::ShowWindowAsync((Get-Process -PID $pid).MainWindowHandle, 0)




# Use a Garbage colection to reduce Memory RAM
# https://dmitrysotnikov.wordpress.com/2012/02/24/freeing-up-memory-in-powershell-using-garbage-collector/
# https://docs.microsoft.com/fr-fr/dotnet/api/system.gc.collect?view=netframework-4.7.2
[System.GC]::Collect()

# Create an application context for it to all run within - Thanks Chrissy
# This helps with responsiveness, especially when clicking Exit - Thanks Chrissy
$appContext = New-Object System.Windows.Forms.ApplicationContext
[void][System.Windows.Forms.Application]::Run($appContext)

編輯:基於@BACON 答案的工作解決方案

# Toggle following two lines
Set-StrictMode -Version Latest
# Set-StrictMode -Off

Add-Type -AssemblyName System.Windows.Forms    
Add-Type -AssemblyName System.Drawing

function Test-Notepad {
    [bool](Get-Process -Name 'notepad' -ErrorAction SilentlyContinue)
}


function OnMenuItem1ClickEventFn () {
    # Build Form object
    $Form = New-Object System.Windows.Forms.Form
        $Form.Text = "My Form"
        $Form.Size = New-Object System.Drawing.Size(200,200)
        $Form.StartPosition = "CenterScreen"
        $Form.Topmost = $True
        $Form.Controls.Add($Label)               # Add label to form
        $form.ShowDialog()| Out-Null             # Show the Form
}


function OnMenuItem4ClickEventFn () {
    $Main_Tool_Icon.Visible = $false

    [System.Windows.Forms.Application]::Exit()
}


function create_taskbar_menu{
    # Create menu items
    $MenuItem1 = New-Object System.Windows.Forms.MenuItem
    $MenuItem1.Text = "Menu Item 1"

    $MenuItem2 = New-Object System.Windows.Forms.MenuItem
    $MenuItem2.Text = "Menu Item 2"

    $MenuItem3 = New-Object System.Windows.Forms.MenuItem
    $MenuItem3.Text = "Menu Item 3"

    $MenuItem4 = New-Object System.Windows.Forms.MenuItem
    $MenuItem4.Text = "Exit"


    # Add menu items to context menu
    $contextmenu = New-Object System.Windows.Forms.ContextMenu
    $Main_Tool_Icon.ContextMenu = $contextmenu
    $Main_Tool_Icon.contextMenu.MenuItems.AddRange($MenuItem1)
    $Main_Tool_Icon.contextMenu.MenuItems.AddRange($MenuItem2)
    $Main_Tool_Icon.contextMenu.MenuItems.AddRange($MenuItem3)
    $Main_Tool_Icon.contextMenu.MenuItems.AddRange($MenuItem4)


    $MenuItem4.add_Click({OnMenuItem4ClickEventFn})
    $MenuItem1.add_Click({OnMenuItem1ClickEventFn})
}


$Current_Folder = split-path $MyInvocation.MyCommand.Path

# Add assemblies for WPF and Mahapps
[System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms')    | out-null
[System.Reflection.Assembly]::LoadWithPartialName('presentationframework')   | out-null
[System.Reflection.Assembly]::LoadWithPartialName('System.Drawing')          | out-null
[System.Reflection.Assembly]::LoadWithPartialName('WindowsFormsIntegration') | out-null
# [System.Reflection.Assembly]::LoadFrom("Current_Folder\assembly\MahApps.Metro.dll")  | out-null

# Choose an icon to display in the systray
$onlineIcon = [System.Drawing.Icon]::ExtractAssociatedIcon("$Current_Folder/icons/online.ico")
# use this icon when notepad is not running
$offlineIcon = [System.Drawing.Icon]::ExtractAssociatedIcon("$Current_Folder/icons/offline.ico")

$Main_Tool_Icon = New-Object System.Windows.Forms.NotifyIcon
$Main_Tool_Icon.Text = "Icon Text"
$Main_Tool_Icon.Icon = if (Test-Notepad) { $onlineIcon } else { $offlineIcon }
$Main_Tool_Icon.Visible = $true

# Build Label object
$Label = New-Object System.Windows.Forms.Label
    $Label.Name = "labelName"
    $Label.AutoSize = $True

# Initialize the timer
$timer = New-Object System.Windows.Forms.Timer
$timer.Interval = 1000
$timer.Add_Tick({
    if ($Label){
        $Label.Text, $Main_Tool_Icon.Icon = if (Test-Notepad) {
            "Notepad is running", $onlineIcon
        } else {
            "Notepad is NOT running", $offlineIcon
        }
    }
})
$timer.Start()

create_taskbar_menu

# Make PowerShell Disappear - Thanks Chrissy
$windowcode = '[DllImport("user32.dll")] public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);'
$asyncwindow = Add-Type -MemberDefinition $windowcode -name Win32ShowWindowAsync -namespace Win32Functions -PassThru
$null = $asyncwindow::ShowWindowAsync((Get-Process -PID $pid).MainWindowHandle, 0)

# Use a Garbage colection to reduce Memory RAM
# https://dmitrysotnikov.wordpress.com/2012/02/24/freeing-up-memory-in-powershell-using-garbage-collector/
# https://docs.microsoft.com/fr-fr/dotnet/api/system.gc.collect?view=netframework-4.7.2
[System.GC]::Collect()

# Create an application context for it to all run within - Thanks Chrissy
# This helps with responsiveness, especially when clicking Exit - Thanks Chrissy
$appContext = New-Object System.Windows.Forms.ApplicationContext
try
{
    [System.Windows.Forms.Application]::Run($appContext)    
}
finally
{
    foreach ($component in $timer, $Main_Tool_Icon, $offlineIcon, $onlineIcon, $appContext)
    {
        # The following test returns $false if $component is
        # $null, which is really what we're concerned about
        if ($component -is [System.IDisposable])
        {
            $component.Dispose()
        }
    }

    Stop-Process -Id $PID
}

您已經有代碼來設置NotifyIcon使用的圖標...

$Main_Tool_Icon.Icon = $icon

...並定義要使用的圖標...

# Choose an icon to display in the systray
$icon = [System.Drawing.Icon]::ExtractAssociatedIcon("$Current_Folder/icons/online.ico")
# use this icon when notepad is not running
# $icon = [System.Drawing.Icon]::ExtractAssociatedIcon("$Current_Folder/icons/offline.ico")

...並定期測試Notepad是否正在運行並做出適當的響應...

$timer.Add_Tick({
    if ($Label){
        $Label.Text = if (Test-Notepad) { "Notepad is running" } else { "Notepad is NOT running" }
    }
})

你只需要將它們與一些額外的調整結合起來......

  • 使用描述性名稱將每個圖標存儲在自己的變量中,以便在它們之間輕松切換。
  • $Main_Tool_Icon需要在create_taskbar_menu范圍之外定義,以便它可以在OnMenuItem1ClickEventFn內部訪問。 我將創建和初始化移動到調用create_taskbar_menu之前,但您也可以在create_taskbar_menu或其他一些函數內部對其進行初始化。

最終看起來像這樣......

# Choose an icon to display in the systray
$onlineIcon = [System.Drawing.Icon]::ExtractAssociatedIcon("$Current_Folder/icons/online.ico")
# use this icon when notepad is not running
$offlineIcon = [System.Drawing.Icon]::ExtractAssociatedIcon("$Current_Folder/icons/offline.ico")

$Main_Tool_Icon = New-Object System.Windows.Forms.NotifyIcon
$Main_Tool_Icon.Text = "Icon Text"
$Main_Tool_Icon.Icon = if (Test-Notepad) { $onlineIcon } else { $offlineIcon }
$Main_Tool_Icon.Visible = $true

create_taskbar_menu

...和這個...

$timer.Add_Tick({
    if ($Label){
        # Change the text and icon with one test
        $Label.Text, $Main_Tool_Icon.Icon = if (Test-Notepad) {
            "Notepad is running", $onlineIcon
        } else {
            "Notepad is NOT running", $offlineIcon
        }
    }
})

您將看到在初始化$Main_Tool_Icon和引發Tick事件時根據Test-Notepad的結果選擇了一個圖標。

至於在$Form關閉時處理$timer ......

$Form.Add_Closing({ $timer.Dispose() })

......這幾乎是一個合適的地方,但是......

  • Closing事件本質Closing是在表單被請求關閉時引發的; 它為取消該請求提供了機會。 Closed事件更合適,因為它是在表單實際關閉時引發的。
  • 文檔指出ClosingClosed事件都已過時。 請改用FormClosed事件

此外,在OnMenuItem4ClickEventFn ,即使未定義$window ,您也正在調用$window.Close() 我想你的意思是$Form.Close() 我認為更簡潔的另一種方法是單擊“ Exit菜單項僅退出 Windows 窗體應用程序循環......

function OnMenuItem4ClickEventFn () {
    $Main_Tool_Icon.Visible = $false

    [System.Windows.Forms.Application]::Exit()
}

...然后您可以將清理/拆卸代碼放在腳本末尾的finally塊中...

try
{
    # This call returns when [System.Windows.Forms.Application]::Exit() is called
    [System.Windows.Forms.Application]::Run($appContext)
}
finally
{
    # $timer would also have to be defined at the script scope
    # (outside of OnMenuItem1ClickEventFn) for this to work
    $timer.Dispose()

    # $Form, $Label, $Main_Tool_Icon, $onlineIcon, etc. would all be candidates for disposal...

    # Exit the entire PowerShell process
    Stop-Process $pid
}

以下是包含上述更改並適用於我的完整代碼...

Add-Type -AssemblyName System.Windows.Forms    
Add-Type -AssemblyName System.Drawing

function Test-Notepad {
    [bool](Get-Process -Name 'notepad' -ErrorAction SilentlyContinue)
}


function OnMenuItem1ClickEventFn () {
    $timer.Start()

    # Build Form object
    $Form = New-Object System.Windows.Forms.Form
        $Form.Text = "My Form"
        $Form.Size = New-Object System.Drawing.Size(200,200)
        $Form.StartPosition = "CenterScreen"
        $Form.Topmost = $True
        $Form.Add_Closing({ $timer.Dispose() })  # Dispose() also stops the timer.
        $Form.Controls.Add($Label)               # Add label to form
        $form.ShowDialog()| Out-Null             # Show the Form
}


function OnMenuItem4ClickEventFn () {
    $Main_Tool_Icon.Visible = $false

    [System.Windows.Forms.Application]::Exit()
}


function create_taskbar_menu{
    # Create menu items
    $MenuItem1 = New-Object System.Windows.Forms.MenuItem
    $MenuItem1.Text = "Menu Item 1"

    $MenuItem2 = New-Object System.Windows.Forms.MenuItem
    $MenuItem2.Text = "Menu Item 2"

    $MenuItem3 = New-Object System.Windows.Forms.MenuItem
    $MenuItem3.Text = "Menu Item 3"

    $MenuItem4 = New-Object System.Windows.Forms.MenuItem
    $MenuItem4.Text = "Exit"


    # Add menu items to context menu
    $contextmenu = New-Object System.Windows.Forms.ContextMenu
    $Main_Tool_Icon.ContextMenu = $contextmenu
    $Main_Tool_Icon.contextMenu.MenuItems.AddRange($MenuItem1)
    $Main_Tool_Icon.contextMenu.MenuItems.AddRange($MenuItem2)
    $Main_Tool_Icon.contextMenu.MenuItems.AddRange($MenuItem3)
    $Main_Tool_Icon.contextMenu.MenuItems.AddRange($MenuItem4)


    $MenuItem4.add_Click({OnMenuItem4ClickEventFn})
    $MenuItem1.add_Click({OnMenuItem1ClickEventFn})
}


$Current_Folder = split-path $MyInvocation.MyCommand.Path

# Add assemblies for WPF and Mahapps
[System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms')    | out-null
[System.Reflection.Assembly]::LoadWithPartialName('presentationframework')   | out-null
[System.Reflection.Assembly]::LoadWithPartialName('System.Drawing')          | out-null
[System.Reflection.Assembly]::LoadWithPartialName('WindowsFormsIntegration') | out-null
# [System.Reflection.Assembly]::LoadFrom("Current_Folder\assembly\MahApps.Metro.dll")  | out-null

# Choose an icon to display in the systray
$onlineIcon = [System.Drawing.Icon]::ExtractAssociatedIcon("$Current_Folder/icons/online.ico")
# use this icon when notepad is not running
$offlineIcon = [System.Drawing.Icon]::ExtractAssociatedIcon("$Current_Folder/icons/offline.ico")

$Main_Tool_Icon = New-Object System.Windows.Forms.NotifyIcon
$Main_Tool_Icon.Text = "Icon Text"
$Main_Tool_Icon.Icon = if (Test-Notepad) { $onlineIcon } else { $offlineIcon }
$Main_Tool_Icon.Visible = $true

# Build Label object
$Label = New-Object System.Windows.Forms.Label
    $Label.Name = "labelName"
    $Label.AutoSize = $True

# Initialize the timer
$timer = New-Object System.Windows.Forms.Timer
$timer.Interval = 1000
$timer.Add_Tick({
    if ($Label){
        $Label.Text, $Main_Tool_Icon.Icon = if (Test-Notepad) {
            "Notepad is running", $onlineIcon
        } else {
            "Notepad is NOT running", $offlineIcon
        }
    }
})

create_taskbar_menu

# Make PowerShell Disappear - Thanks Chrissy
$windowcode = '[DllImport("user32.dll")] public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);'
$asyncwindow = Add-Type -MemberDefinition $windowcode -name Win32ShowWindowAsync -namespace Win32Functions -PassThru
$null = $asyncwindow::ShowWindowAsync((Get-Process -PID $pid).MainWindowHandle, 0)

# Use a Garbage colection to reduce Memory RAM
# https://dmitrysotnikov.wordpress.com/2012/02/24/freeing-up-memory-in-powershell-using-garbage-collector/
# https://docs.microsoft.com/fr-fr/dotnet/api/system.gc.collect?view=netframework-4.7.2
[System.GC]::Collect()

# Create an application context for it to all run within - Thanks Chrissy
# This helps with responsiveness, especially when clicking Exit - Thanks Chrissy
$appContext = New-Object System.Windows.Forms.ApplicationContext
try
{
    [System.Windows.Forms.Application]::Run($appContext)    
}
finally
{
    foreach ($component in $timer, $form, $Main_Tool_Icon, $offlineIcon, $onlineIcon, $appContext)
    {
        # The following test returns $false if $component is
        # $null, which is really what we're concerned about
        if ($component -is [System.IDisposable])
        {
            $component.Dispose()
        }
    }

    Stop-Process -Id $PID
}

嗨,我知道在這里提出更多問題是違反規則的,因此我提出了與此相關的后續問題。 也許知識淵博的蘭斯先生也為我解答了..謝謝

我的問題鏈接

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM