Powershell GUI based on Forms + Panels - Flickers on Update - powershell

Before we begin, let me aside: I am not THAT familiar with Powershell. I know more than a lot of people around me by virtue of experimentation in a VM environment and Googlefu, which is why this has landed on me.
Here's my problem. I've created a small Powershell GUI. I've built a form, and in that form I've embedded four panels. IndexPanel, ScreenSelectionPanel, OptionsPanel, and ThemePanel.
The form itself has an 'OK' and 'CANCEL' button.
Each Panel has either a NEXT, PREVIOUS or both buttons depending on placement.
ScreenSelect only has NEXT
Options has NEXT and PREVIOUS
Theme has PREVIOUS
Index floats off to the side in the same form, letting you jump around as there'll be more panels later.
I've gotten to the point where I can have the panels - all the same size - slide from one to the next via add_click call on the individually named buttons, with my panel function sending the argument called to all panels at once. If the argument is '1', for instance, SelectScreen calls method .show(), while the others call method .hide().
And for the first few clicks, it works great. My problem is that after three or four clicks back and forth, the app starts flickering. And then starts lagging. And then begins doing both. I suspect the problem is in the way paint is being handled, as all I'm calling is 'Refresh' or 'Update'.
Has anyone found a smooth way to swap from panel to panel in a single form in Powershell? Yes, I realize VB or even C would have been a better solution as I'm rather pushing what Powershell is supposed to handle, but neither of those are available to me via the nature of the project. It MUST be done in Powershell, with .NET support.
Example code, because my current is a mess of reminders and hashes for mistakes I've made in writing. I'll clean it all up once I jot down the roadblocks I've hit. I load all my variable at the top of the script so they're considered in scope for every function that calls them. It also helps me keep track of all the variables I've got, so don't be concerned by my lack of loading here. Also, I'm leaving out the definitions for the boxes, buttons, and so forth - I'll add it if it's important to the scope of the problem. Just to cut down on so much spam.
function GUIPanels {
function ScreenSelectPanel{
$objScreenSelectPanel.Size = New-Object System.Drawing.Size(500,600)
$objScreenSelectPanel.BorderStyle = "FixedSingle"
$objScreenSelectPanel.AutoScroll = "True"
$objScreenSelectPanel.AutoSize = "True"
$objScreenSelectPanel.Width = 400
if ($Args[0] -eq 1) {$objScreenSelectPanel.Show()}
else {$objScreenSelectPanel.Hide()}
$SelectionPanelNEXTButton.Add_Click({
GUIPanels 2
$objMainForm.Update()
})
}
function OptionsPanel {
$objOptionsPanel.Size = New-Object System.Drawing.Size(500,600)
$objOptionsPanel.BorderStyle = "FixedSingle"
$objOptionsPanel.AutoScroll = "True"
$objOptionsPanel.AutoSize = "True"
$objOptionsPanel.Width = 400
if ($Args[0] -eq 2) {$objOptionsPanel.Show()}
else {$objOptionsPanel.Hide()}
$OptionsPanelNEXTButton.Add_Click({
GUIPanels 3
$objMainForm.Update()
})
$OptionsPanelPREVIOUSButton.Add_Click({
GUIPanels 1
$objMainform.Update()
})
}
function ThemePanel {
$objThemePanel.Size = New-Object System.Drawing.Size(500,600)
$objThemePanel.BorderStyle = "FixedSingle"
$objThemePanel.AutoScroll = "True"
$objThemePanel.AutoSize = "True"
$objThemePanel.Width = 400
if ($Args[0] -eq 3) {$objThemePanel.Show()}
else {$objThemePanel.Hide()}
$ThemePanelPREVIOUSButton.Add_Click({
GUIPanels 1
$objMainform.Update()
})
}
}
function GUIMainForm {
$objMainForm.Size = New-Object System.Drawing.Size(680,700)
$objMainForm.AutoScroll = "True"
$objMainForm.KeyPreview = $True
#Location setups.
$objMainForm.StartPosition = "CenterScreen"
#Key captures. Adding in activity for button presses.
#Letting panels handle the ENTER Key for now.
#$objMainForm.Add_KeyDown({
# if ($_.KeyCode -eq "Enter") {
# $x=$objMainScreenBox.SelectedItem
# $objMainForm.Close()
# }
# })
$objMainForm.Add_KeyDown({
if ($_.KeyCode -eq "Escape") {
$objMainForm.Close()
}
})
#Button Locations.
$OKButton.Location = New-Object System.Drawing.Size(175,620)
$CloseButton.Location = New-Object System.Drawing.Size(320,620)
#Panel Locations.
$objScreenSelectPanel.Location = New-Object System.Drawing.Size(220,10)
$objOptionsPanel.Location = New-Object System.Drawing.Size(220,10)
$objThemePanel.Location = New-Object System.Drawing.Size(220,10)
$objIndexPanel.Location = New-Object System.Drawing.Size(10,10)
$objMainForm.Controls.add($objIndexPanel)
$objMainForm.Controls.add($objScreenSelectPanel)
$objMainForm.Controls.add($objThemePanel)
$objMainForm.Controls.add($objOptionsPanel)
$objMainForm.Controls.add($OKButton)
$objMainForm.Controls.add($CloseButton)
$objMainForm.Topmost = $True
#$objMainForm.DoubleBuffered = "True"
}
function GUISetup {
#1 - main screen, 2 - optionals, 3 - theme, 4 - Slipdata
#for ($i=1; $i -le 4; $i++) {Write-Host (4%$i)} -- Doesn't feed $i properly.
GUIBoxes
GUIButtons
GUILabels
GUIMainForm
GUIPanels $Args[0]
#$objMainForm.Add_Shown({$objMainForm.Activate()})
#[void] $objMainForm.ShowDialog()
#$objMainForm.hide()
#timeout 5 > $null
#$objMainForm.show()
#timeout 4 > $null
#$objMainForm.Update()
#$objMainForm.hide()
#$objMainForm.Refresh()
#$InitialFormWindowState = $objMainForm.WindowState
#Init the OnLoad event to correct the initial state of the form
#$objMainForm.add_Load($Form_StateCorrection_Load)
#Handling Refresh in the actual button press.
return $objMainForm.ShowDialog()
#$objMainForm.Dispose()
#$objApplicationClass.run($objMainForm)
}
#DEBUG
GUIsetup 1 | Out-Null
$x

I actually figured out what I did wrong. Namely, I'm calling every panel to create with every next or previous. So four panels, eight panels, twelve panels, sixteen panels (flicker), twenty panels (Flicker flicker slow down) and so forth. I was so focused on this being a problem with Powershell I didn't stop to think about the logic I was using.
So I'm going to call the .hide() and .show() in a separate function.

Related

Hide and disable maximize button and disable double-clicking bar to maximize window

I have the following Frame Settings in Powershell for my GUI.
$frmMainframe = New-Object system.Windows.Forms.Form
$frmMainframe.ClientSize = New-Object System.Drawing.Point(449,385)
$frmMainframe.text = "Yannicks Administration Tools"
$frmMainframe.TopMost = $false
$frmMainframe.FormBorderStyle = "FixedSingle"
$frmMainframe.startposition = "CenterScreen"
$frmMainframe.BackColor = [System.Drawing.ColorTranslator]::FromHtml("#ffffff")
Can someone help me disabling aswell as hiding the maximize button?
And is it possible to disable the double-clicking function on the Window bar to maximize the window?
Thank you for your time!
You can disable the Maximize button like this:
$frmMainframe.MaximizeBox = $false
You can do the same for the MinimizeBox. To not show any of the Minimize, Maximize and Close boxes, you can do $frmMainframe.ControlBox = $false. In that case, you need to have a button so the form can be closed.
To prevent changing the size when the user double-clicks the window bar, setting the MinimumSize and MaximumSize properties of the form might help:
$frmMainframe.MaximumSize = $frmMainframe.Size
$frmMainframe.MinimumSize = $frmMainframe.Size

How to Add a PictureBox to Multiple Tabs?

Having some issues with a program I'm creating for our organisations IT Service Desk.
Basically it's a troubleshooting tool, and it has multiple tabs.
I want each tab page to have our company logo on the top of the tabpage.
However, when I create the picturebox and then add it to the tab, then try and add it to another tab, it removes from the first.
Some code example below:
$LogoBox = New-Object Windows.Forms.PictureBox
$LogoBox.Image = $CompanyImage
$LogoBox.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::StretchImage
$LogoBox.Size = New-Object System.Drawing.Size(300,100)
$LogoBox.Location = (($Form.Width / 2) - ($LogoBox.Width / 2))
$EmailGeneralTab.Controls.Add($LogoBox)
$UserTab.Controls.Add($LogoBox)
In this example, the LogoBox will only end up on the UserTab, and it will not show up on the EmailGeneral Tab.
Thanks in advance.

PowerShell Studio WebBrowser ProgressBarOverlay

I'm creating a web browser in PowerShell Studio, which works with no issues. I'm trying to use a loading bar when using the search functionality, but it has been to no avail. Below is what my browser looks like. The ideas is to only show the loading bar (using the marquee animation) only while it's loading.
This is what I currently have for the loading functionality:
$Search_Click={
#TODO: Place custom script here
$url = $txtSearch.Text
$webbrowser1.Navigate($url)
while ($webbrowser1.IsBusy)
{
$loadingBar.MarqueeAnimationSpeed(50)
$loadingBar.Visible = $true
}
}
Below is how I have the loading bar setup in the designer.
If you cant see the progress bar try to bring it to front using
$progressBar.BringToFront()
If you need to set the style as Marquee
$progressBar = New-Object System.Windows.Forms.ProgressBar
$progressBar.Width = 389
$progressBar.Height = 20
$progressBar.Location = new-object system.drawing.point(5,51)
$progressBar.Style = [System.Windows.Forms.ProgressBarStyle]::Marquee
$Form.controls.Add($progressBar)

How to close the form on mouse click?

I'm creating a Graphical Date Picker in PowerShell, based on this article. The following part of the code in the article helps to close the form after the date selection and pressing Enter key:
$objForm.Add_KeyDown({
if ($_.KeyCode -eq "Enter")
{
$dtmDate=$objCalendar.SelectionStart
$objForm.Close()
}
})
I also want to add mouse event for the date selection and to close the form. So the question is, how do we close the form once the date has been selected and on MouseUp event?
Thanks.
Instead of registering an event handler for all Click/MouseDown/MouseUp events, you could use the DateSelected event instead. From the description:
Occurs when the user makes an explicit date selection using the mouse.
$objForm.Add_DateSelected({
$dtmDate=$objCalendar.SelectionStart
$objForm.Close()
})
In PowerShell 3.0 or newer, you may have to change the scope of $dtmDate variable in order for it to work:
$script:dtmDate = $objCalendar.SelectionStart
or (-Scope 1 means "direct parent scope" or "1 step up the call stack")
Set-Variable -Scope 1 -Name dtmDate -Value $objCalendar.SelectionStart

Update status bar tooltip in Powershell

I am creating a GUI with status bar using PowerShell. Here is code:
$StatusBar = New-Object System.Windows.Forms.StatusBar
$StatusBarPanel = New-Object System.Windows.Forms.StatusBarPanel
$StatusBarPanel.AutoSize = [System.Windows.Forms.StatusBarPanelAutoSize]::Contents
$StatusBarPanel.text = "Ready.."
$StatusBarPanel.ToolTipText = $StatusBarPanel.text
$StatusBar.showpanels = $True
$StatusBar.Panels.Add($StatusBarPanel)
Initially, I am setting Ready.. as tooltip content. Later I have to display some path in status bar which be calculated at runtime. Status bar shows correct path but tooltip doesn't get updated.
It keeps showing Ready... Small code snippet is here:
$StatusBarPanel.text = "Hotfix successfully created at -" + $hotfixFolder
$StatusBarPanel.ToolTiptext = $StatusBarPanel.text
Can anybody guide what am I missimg to update tooltip?
I couldn't figure out exact problem but got a workaround. I stoted value is a temp variable and assigned same as mentioned here:
$StatusBarPanel.text = "Hotfix successfully created at -" + $hotfixFolder
$temp = $StatusBarPanel.text
$StatusBarPanel.ToolTiptext = $temp
I am not sure how this is working but it worked for me...