Search code examples
powershellwinformssystem.drawing

How to change the color of the tab each time its selected in a powershell Windows Form?


I'm looking to change the color of the tab on the currently active tabpage to make it stand out more.

I have set the DrawMode to OwnerDrawFixed and I was able to convert some c# code, found on another question here, to draw the tabs. I have enabled TabControl Selecting and Deselecting actions but those do not receive DrawItem events.

Here is my DrawItem code, if you think it could be optimized let me know, as I'm not the greatest at converting c# to powershell.

$TabControl_DrawItem = {
$CurrentTabPage = $TabControl1.TabPages[$_.Index]
$paddedBounds = New-Object Rectanglef ($_.Bounds.Location,$_.Bounds.Size)
$paddedBounds.Inflate(-2,-2)  
$_.Graphics.DrawString($CurrentTabPage.Text, $_.Font, [SolidBrush]::New([Color]::Black), $paddedBounds)}

I know how to change the background color of a tab at load time but how do you do it every time a new tab is selected?

$_.Graphics.FillRectangle([SolidBrush]::New([Color]::Yellow), $_.Bounds)

Here is my complete test form, thanks in advance.

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

$TabControl_DrawItem = {
$CurrentTabPage = $TabControl1.TabPages[$_.Index]
$paddedBounds = New-Object Rectanglef ($_.Bounds.Location,$_.Bounds.Size)
$paddedBounds.Inflate(-2,-2)  
$_.Graphics.DrawString($CurrentTabPage.Text, $_.Font, [SolidBrush]::New([Color]::Black), $paddedBounds)
}
$TabControl_Selecting = {
    #---Tab is selecting
}
$TabControl_Deselecting = {
    #---Tab is deselecting
}
$Form1 = New-Object -TypeName Form
$TabControl1 = New-Object -TypeName TabControl
$TabPage1 = New-Object -TypeName TabPage
$TabPage2 = New-Object -TypeName TabPage
$TabPage3 = New-Object -TypeName TabPage

$Form1.Text = "Test-TabControl-Form"
$Form1.ClientSize = (New-Object -TypeName Size -ArgumentList @(632,356))
$Form1.BackColor = [Color]::DimGray

$TabControl1.Name = "TabControl1"
$TabControl1.Size = (New-Object -TypeName Size -ArgumentList @(610,308))
$TabControl1.Location = (New-Object -TypeName Point -ArgumentList @(12,36))
$TabControl1.Multiline = $true
$TabControl1.HotTrack = $true
$TabControl1.SelectedIndex = 0
$TabControl1.TabIndex = 0
$TabControl1.DrawMode = [TabDrawMode]::OwnerDrawFixed
$TabControl1.add_DrawItem($TabControl_DrawItem)
$TabControl1.add_Selecting($TabControl_Selecting)
$TabControl1.add_Deselecting($TabControl_Deselecting)

$TabPage1.Name = "TabPage1"
$TabPage1.Text = "TabPage1"
$TabPage1.Location = (New-Object -TypeName Point -ArgumentList @(4,22))
$TabPage1.Padding = (New-Object -TypeName Padding -ArgumentList @(3))
$TabPage1.Size = (New-Object -TypeName Size -ArgumentList @(391,282))
$TabPage1.TabIndex = 0
$TabPage1.BackColor = [Color]::DimGray

$TabPage2.Name = "TabPage2"
$TabPage2.Text = "TabPage2"
$TabPage2.Location = (New-Object -TypeName Point -ArgumentList @(4,22))
$TabPage2.Padding = (New-Object -TypeName Padding -ArgumentList @(3))
$TabPage2.Size = (New-Object -TypeName Size -ArgumentList @(602,282))
$TabPage2.TabIndex = 1
$TabPage2.BackColor = [Color]::DimGray

$TabPage3.Name = "TabPage3"
$TabPage3.Text = "TabPage3"
$TabPage3.Location = (New-Object -TypeName Point -ArgumentList @(4,22))
$TabPage3.Size = (New-Object -TypeName Size -ArgumentList @(391,282))
$TabPage3.TabIndex = 2
$TabPage3.BackColor = [Color]::DimGray

$Form1.Controls.Add($TabControl1)
$TabControl1.Controls.Add($TabPage1)
$TabControl1.Controls.Add($TabPage2)
$TabControl1.Controls.Add($TabPage3)

$Form1.ShowDialog()

Solution

  • You'd have to implement the FillRectangle() method before you write the tabs name based on if the tab (Index) is being drawn:

    $TabControl_DrawItem = {
        $CurrentTabPage = $TabControl1.TabPages[$_.Index]
        $paddedBounds = New-Object Rectanglef ($_.Bounds.Location,$_.Bounds.Size)
        $paddedBounds.Inflate(-2,-2)
    
        # If the tab being drawn is the currently selected tab, color it; otherwise, use a default color
        $tabColor = if ($_.Index -eq $TabControl1.SelectedIndex) 
        {
            switch ($CurrentTabPage.Name) 
            {
                "TabPage1" { [Color]::Red }
                "TabPage2" { [Color]::Green }
                "TabPage3" { [Color]::Blue }
            }
        } 
        else 
        {
            [Color]::White  # Default color for non-selected tabs
        }
    
        $_.Graphics.FillRectangle([SolidBrush]::New($tabColor), $_.Bounds) # Fill tab background
        $_.Graphics.DrawString($CurrentTabPage.Text, $_.Font, [SolidBrush]::New([Color]::Black), $paddedBounds)
    }
    

    So, $_.Index represents the index of the tab currently being drawn (or looked at), while $TabControl1.SelectedIndex represents the index of the tab that's currently selected or clicked on.

    I specified some basic colors for each tab to change to when selected as an example, but it can easily be modified to fit your needs.