Tuesday, April 27, 2010

Create CheckBox Controls Inside A GroupBox Programmatically

I'm working on a WinForms app to interface with SQL server to grab parameters and other info for various objects. It uses a custom control I discovered on CodeProject to create a collapsible GroupBox control.

Say that I want to create a bunch of new controls based on the output of some SQL function or stored procedure. For example, the system stored procedure sp_databases returns a list of all databases on a given SQL server. 

In my collapsible GroupBox, I might want to create a CheckBox control for each database so that I can let the user choose which database to work on in the current session of the application.

To facilitate this, some pseudocode might be helpful:
  • Instantiate a new CheckBox object.
  • Does my GroupBox contain any other CheckBoxes?
    • NO: Set the CheckBox location so that it appears in the upper-left corner of the GroupBox
    • YES: Grab the X and Y coordinates of the last CheckBox contained in the GroupBox
  • Would the width of an additional CheckBox exceed that of the GroupBox?
    • YES: Set the new CheckBox X coordinate so that it aligns with the first CheckBox in the GroupBox, then bump the Y coordinate down by a set value.
    • NO: Place the new CheckBox to the right of the previous one.
  • Set the Text property of the newly-added CheckBox to a given input string value.

Along these lines, I created the method below, which takes a string as input representing the Text property of the newly-created CheckBox.

       
/// <summary>
        /// Create a new CheckBox control within a collapsible GroupBox, assigning input sName
        /// to the Text property.
        /// </summary>
        /// <param name="sName"></param>
        /// <returns></returns>
        private CheckBox CreateNewCheckBox(string sName)
        {
            int iExistingCheckBoxX = 0;
            int iExistingCheckBoxY = 0;

            int iIncrementX = 100;
            int iIncrementY = 20;

            CheckBox cbNew = new CheckBox();

            cbNew.Width = iIncrementX;

            if (cgbDatabases.Controls.Count == 0)
            {
                cbNew.Location = new Point(cgbDatabases.Location.X + 15, cgbDatabases.Location.Y - 50);
            }
            else
            {
                // Existing checkboxes, so get the Location of the last one.
                iExistingCheckBoxX = cgbDatabases.Controls[cgbDatabases.Controls.Count - 1].Location.X;
                iExistingCheckBoxY = cgbDatabases.Controls[cgbDatabases.Controls.Count - 1].Location.Y;

                // If the new control would overshoot the end of the container, bump it down.
                if ((iExistingCheckBoxX + iIncrementX) + cbNew.Width >= cgbDatabases.Width)
                {
                    iExistingCheckBoxX = cgbDatabases.Location.X + 15;
                    iExistingCheckBoxY = iExistingCheckBoxY + iIncrementY;

                    cbNew.Location = new Point(iExistingCheckBoxX, iExistingCheckBoxY);
                }
                else
                {
                    cbNew.Location = new Point(iExistingCheckBoxX + iIncrementX, iExistingCheckBoxY);
                }
            }

            // Set the Text property according to the input.
            cbNew.Text = sName;

            return cbNew;
        }


In the constructor of my WinForm app, as a test I used the collapsible GroupBox control's Add method in conjunction with the new method to insert a bunch of child CheckBox controls into parent GroupBox. 

        public frmMain()
        {
            InitializeComponent();

            cgbDatabases.Controls.Add(CreateNewCheckBox("CheckBox1"));
            cgbDatabases.Controls.Add(CreateNewCheckBox("CheckBox2"));
            cgbDatabases.Controls.Add(CreateNewCheckBox("CheckBox3"));
            cgbDatabases.Controls.Add(CreateNewCheckBox("CheckBox4"));
            cgbDatabases.Controls.Add(CreateNewCheckBox("Checkbox5"));
            cgbDatabases.Controls.Add(CreateNewCheckBox("Checkbox6"));
            cgbDatabases.Controls.Add(CreateNewCheckBox("Checkbox7"));
            cgbDatabases.Controls.Add(CreateNewCheckBox("Checkbox8"));
            cgbDatabases.Controls.Add(CreateNewCheckBox("Checkbox9"));
            cgbDatabases.Controls.Add(CreateNewCheckBox("Checkbox10"));
            cgbDatabases.Controls.Add(CreateNewCheckBox("Checkbox11"));
        }


The results are as I expect:




Advantages of this method include the ability to tweak the variables within the CreateNewCheckBox method to determine what the starting X and Y coordinates will be based on the Location of the GroupBox; if I move the GroupBox somewhere else in my form's design view, the code won't care, it will simply churn out the CheckBox objects based on the parent control's current position at runtime. Also, it prevents new objects from being created outside the visible width of the GroupBox.

Shortcomings include a lack of checking the height of the GroupBox; if a zillion controls are created within it, there's currently no logic to prevent them from being placed in the nonvisible area of the control. Also, I'm currently not analyzing the incoming string parameter to see whether I want to constrain the resulting object to a uniform height or width, which means a CheckBox with a huge label likely will not display its Text value correctly.

Speaking of dimensions, the method is currently not "smart" enough to roll with the punches in terms of variations in height or width of the resulting controls; it doesn't offer an easy way to make the child objects conform to specific patterns (e.g. the objects appear one after the next from left to right, not up to down or diagonally or some other order). These would need to be tweaked and tested manually to ensure the object labels remain intact, and the objects themselves remain visible and usable. A more elegant solution would be to have the method scrutinize the control to be created and its attributes and compensate.

Baby steps, but nonetheless I found this a helpful exercise in creating CheckBox controls at will within a parent GroupBox, and already am seeing ways in which I can improve this implementation. I wish to thank Jordan Hammond, creator of the CollapsibleGroupBox control from the article I cited above, and also Manoli's code formatter, which was used here to make the C# excerpts presentable.

Tuesday, March 23, 2010

Monday, March 8, 2010

Faith is Flawed

H. L. Mencken wrote, "It is not materialism that is the chief curse of the world, as pastors teach, but idealism. Men get into trouble by taking their visions and hallucinations too seriously."

When 11-year-old Madeline Neumann began suffering acutely from runaway ketoacidosis as a result of untreated diabetes, her parents, devout followers of the Bible, did what they thought was right. They prayed. Ultimately, Madeline died a painful, miserable death. This poor child suffered for over thirty days with extreme thirst, nausea, and weakness, all caused by an easily treatable condition.

David Koresh, the late leader of the Branch Davidians, claimed he not only possessed the gift of prophecy, but also claimed to have a vision that he was Cyrus, a reincarnation of the first Zoroastrian Persian emperor and founder of the Persian Empire. Ultimately Koresh and many of his followers perished in flame following the tragic Waco siege, paying the ultimate price for their deep commitment to their beliefs.

These people all share a common thread, they believed in what they were doing. The Neumann parents, fervent believers in the Scripture, convinced themselves that prayer would bring their daughter free and clear of suffering, and indeed following Madeline's death they dejectedly claimed that it was their own lack of faith which failed to bring their daughter back from the brink. Koresh, a fanatical believer in prophecy and his place as a new messiah appointed by God, led himself and dozens of devoted followers willingly into the sights of brutally effective government firepower.

William James, the pioneering psychologist and philosopher, defined true beliefs as those that prove useful to the believer. Certainly, believing that prayer will heal and that prophecy is truth served the people described above who embraced these beliefs. It gave them a sense of power, a sense of purpose, reassurance that they could apply the force of faith to their respective situations and prevail against evil.

The problem, however, is that beliefs do not counteract brutal reality. I don't claim knowledge of a "soul" or any intangible, nebulous definition of human existence that persists beyond the physical realm, but at the same time I do not discount this possibility.

I simply refuse to define and decide, within the confines of my merely human mind, that spectacularly serendipitous events like an ailing child healing or a band of followers providing the boon of their fealty to me are realistic expectations of fervent belief in a thing which, for all intents and purposes, is a product of my own imagination.

God exists in countless forms to countless people. Mencken, in his Treatise on the Gods, suggested that mysticism is the purest form of religion because it demands no tithe, no steeple, no trappings of religious doctrine, but merely an intimate, personal relationship of devotion and contemplation. This seems to me a more sensible system of belief than almost any form of organized religion in existence today, since God is not presented like some new car, a flagship ride to salvation, by bands of Its followers. Rather, God makes Itself known to the believer in a manner It deems fit, without outside influence and without mindlessly embracing scriptural doctrine maintained by human beings.

The aforementioned danger, of course, exists in the faith of mystic as well as maniac believer in religion, that they will be compelled to transform visions and compulsions into reality, in their mind purely for their God, but in essence either good or evil depending upon the impact to themselves or others.

Perhaps, in the end, it is safer and wiser to simply adhere to the New Commandment of Jesus Christ, "A new commandment I give unto you, that you love one another." Love is simple and true and in its purest forms leads to happiness for all involved. Better yet, love among creatures with intelligence, like dogs, is reciprocated in ways that are clear and meaningful, though they, like faith, are ultimately intangible.

___

Constructive commentary is always welcome!