Windows Forms resizable dialog with filterable ListView and multi-select checkboxes

From a clue in another thread, Claude 2, Bard, and finally the awesome paid version of GPT-4, I produced this sweet function:



GPT-4 summary: The code defines a Python function, multi_select_dialog, which creates a custom Windows Forms dialog. This dialog features a filterable ListView with multi-select checkboxes. The dialog is resizable, and it includes “Select All” and “Select None” buttons for easy manipulation of the checkboxes. The ListView and buttons are anchored to dynamically adjust their positions when the form is resized. The function returns a list of selected items when the user clicks “OK” and an empty list if “Cancel” is clicked. The dialog also includes a separator line for visual separation of the action buttons. The code leverages the .NET framework through Python’s clr library.

Code:

import clr
clr.AddReference('System.Windows.Forms')
clr.AddReference('System.Drawing')
from System.Windows.Forms import Form, ListView, ListViewItem, TextBox, Button, DialogResult, CheckBox, View, AnchorStyles, Label, Panel
from System.Drawing import Point, Size, Color

def multi_select_dialog(options):
    frm = Form()
    frm.Width = 500
    frm.Height = 900
    lblFilter = Label()
    lblFilter.Text = "Filter:"
    lblFilter.Location = Point(10, 10)
    lblFilter.Size = Size(60, 20)
    frm.Controls.Add(lblFilter)
    txtFilter = TextBox()
    txtFilter.Width = 350
    txtFilter.Location = Point(lblFilter.Right + 5, 10)
    frm.Controls.Add(txtFilter)
    lstView = ListView()
    lstView.View = View.Details
    lstView.Height = frm.Height - 200
    lstView.Width = frm.ClientSize.Width - 20
    lstView.MultiSelect = True
    lstView.CheckBoxes = True
    lstView.Columns.Add("Options", lstView.Width - 25)
    lstView.Location = Point(10, txtFilter.Bottom + 10)
    lstView.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right
    for option in options:
        lstView.Items.Add(ListViewItem(option))
    frm.Controls.Add(lstView)
    btnSelectAll = Button()
    btnSelectAll.Text = "Select All"
    btnSelectAll.Size = Size(150, 25)
    btnSelectAll.Location = Point(10, lstView.Bottom + 5)
    btnSelectAll.Anchor = AnchorStyles.Bottom | AnchorStyles.Left
    frm.Controls.Add(btnSelectAll)
    btnSelectNone = Button()
    btnSelectNone.Text = "Select None"
    btnSelectNone.Size = Size(150, 25)
    btnSelectNone.Location = Point(btnSelectAll.Right + 10, lstView.Bottom + 5)
    btnSelectNone.Anchor = AnchorStyles.Bottom | AnchorStyles.Left
    frm.Controls.Add(btnSelectNone)
    separator = Panel()
    separator.BackColor = Color.Black
    separator.Height = 1
    separator.Width = frm.ClientSize.Width - 20
    separator.Location = Point(10, frm.ClientSize.Height - 45)
    frm.Controls.Add(separator)
    btnOK = Button()
    btnOK.Text = "OK"
    btnOK.Size = Size(75, 25)
    btnOK.Location = Point(frm.ClientSize.Width - 185, frm.ClientSize.Height - 40)
    btnOK.Anchor = AnchorStyles.Bottom | AnchorStyles.Right
    frm.Controls.Add(btnOK)
    btnCancel = Button()
    btnCancel.Text = "Cancel"
    btnCancel.Size = Size(100, 25)
    btnCancel.Location = Point(btnOK.Right + 10, frm.ClientSize.Height - 40)
    btnCancel.Anchor = AnchorStyles.Bottom | AnchorStyles.Right
    frm.Controls.Add(btnCancel)
    frm.AcceptButton = btnOK
    frm.CancelButton = btnCancel
    frm.Text = "Select Options"
    def btnOK_click(sender, e):
        frm.DialogResult = DialogResult.OK
        frm.Close()
    btnOK.Click += btnOK_click
    def btnCancel_click(sender, e):
        frm.DialogResult = DialogResult.Cancel
        frm.Close()
    btnCancel.Click += btnCancel_click
    def txtFilter_TextChanged(sender, e):
        lstView.Items.Clear()
        for option in options:
            if txtFilter.Text.lower() in option.lower():
                lstView.Items.Add(ListViewItem(option))
    txtFilter.TextChanged += txtFilter_TextChanged
    def btnSelectAll_click(sender, e):
        for item in lstView.Items:
            item.Checked = True
    btnSelectAll.Click += btnSelectAll_click
    def btnSelectNone_click(sender, e):
        for item in lstView.Items:
            item.Checked = False
    btnSelectNone.Click += btnSelectNone_click
    dialogResult = frm.ShowDialog()
    if dialogResult == DialogResult.OK:
        return [item.Text for item in lstView.CheckedItems]
    else:
        return []
options = IN[0]
OUT = multi_select_dialog(options)


With these fantastic AI tools, we can really get good at making great UX, etc.

5 Likes

Maybe I don’t have something else set appropriately, but I had to add this little tidbit of code for the “from System.Drawing import Point, Size, Color” part to work.

image

Good catch. Seems like that got done for me in another Python node that was frozen. (???)
Will update.
multi_select_dialog.dyn (7.8 KB)

1 Like

@truevis

gpt4 generated the correct code in one go, or you had to make corrections ? (just to be able to compare to gpt3.5)

'Twas Claude 2 that inspired me to pursue this:
Q: what are the other functions from .NET that can be used in python?

A: The .NET Framework provides a huge range of classes and functions that can be accessed from Python using the clr module and AddReference.

Here are some of the major functionality areas and useful classes:

  • System.IO - file/directory operations (Path, File, Directory etc)
  • System.Text - text processing (StringBuilder, Regex)
  • System.Collections - data structures (List, Dictionary, HashSet)
  • System.Linq - LINQ methods for queries
  • System.Net - network/web access (WebClient, HttpListener)
  • System.Data - database access (SqlClient, OleDb)
  • System.Drawing - 2D graphics (Bitmap, Graphics)
  • System.Windows.Forms - GUI framework (Form, Button, TextBox)
  • System.Threading - multithreading (Thread, Timer)
  • System.Media - audio/video (SoundPlayer, SpeechSynthesizer)

Additionally any .NET user-defined classes and methods can be accessed as well.

Some key functions include:

  • DateTime/TimeSpan - date and time manipulation
  • Math - math constants and methods
  • Convert - type conversions
  • Console - output console
  • Debug/Trace - debugging utils

So in summary, virtually anything in .NET is available to Python through the clr module. It opens up a massive amount of functionality.

What other awesome functionality might we add to Dynamo with all of that?

1 Like

Hahahahahaha no. Flat out nope.

GPT-4 corrected some code I already made in other LLMs and it ran in Dynamo. I started prompting it "CPython3 running inside Dynamo for Autodesk Revit" and then my code. I went back and forth many times with the UI, describing what was wrong and what I wanted different. I changed some of the size and location numbers myself. Lots of copy/pasting, saving, and running in Dynamo Python box.

"show whole code with no empty lines or comments" is a prompt I used often. Also "show whole function"

Nonetheless, I have low-level at Python language skills and I can do much higher-level things with these tools, now. I also learn Python as I work at it.

1 Like

If I can make all kinds of bespoke UI dialogs and not have to just use DataShapes, I am happy!

(Claude 2 was not writing about use within Dynamo.) What are the .NET major limitations within Dynamo?

Yes - Python works for WPF, WINForms, and some other content. It does not work for virtually anything in .NET.