Builder C++ : TTreeView with checkbox items - checkbox

I need to create a treeview with checkbox node like this image :
How to do that?
thx!

The TTreeView component does not natively support checkboxes, but the standard Windows TREEVIEW control does, via the TVS_CHECKBOXES style:
TVS_CHECKBOXES
Version 4.70. Enables check boxes for items in a tree-view control. A check box is displayed only if an image is associated with the item. When set to this style, the control effectively uses DrawFrameControl to create and set a state image list containing two images. State image 1 is the unchecked box and state image 2 is the checked box. Setting the state image to zero removes the check box altogether. For more information, see Working with state image indexes.
Version 5.80. Displays a check box even if no image is associated with the item.
Once a tree-view control is created with this style, the style cannot be removed. Instead, you must destroy the control and create a new one in its place. Destroying the tree-view control does not destroy the check box state image list. You must destroy it explicitly. Get the handle to the state image list by sending the tree-view control a TVM_GETIMAGELIST message. Then destroy the image list with ImageList_Destroy.
If you want to use this style, you must set the TVS_CHECKBOXES style with SetWindowLong after you create the treeview control, and before you populate the tree. Otherwise, the checkboxes might appear unchecked, depending on timing issues.
To apply the TVS_CHECKBOXES style to a TTreeView component, you should derive a new component and override the virtual CreateParams() method, eg:
class TMyTreeView : public TTreeView
{
protected:
virtual void __fastcall CreateParams(TCreateParams &Params);
};
void __fastcall TMyTreeView::CreateParams(TCreateParams &Params)
{
TTreeView::CreateParams(Params);
Params.Style |= TVS_CHECKBOXES;
}
To assign the checkbox states in code, you can then use the TreeView_GetItem()/TreeView_SetItem() macros to toggle a node's state image index as needed.
Alternatively, a more flexible approach is to simply assign your own TImageList to the TTreeView::StateImages property and fill it with whatever checkbox images you want, and then you can set the TTreeNode::StateIndex property as needed. To react to user input on the checkboxes, use the TTreeView::OnClick and TTreeView::OnKeyDown events to toggle the TTreeNode::StateIndex accordingly:
void __fastcall ToggleTreeNodeCheckBox(TTreeNode *Node)
{
if ((Node) && (Node->StateIndex != -1))
{
if (Node->StateIndex == MyCheckedStateImageIndex)
Node->StateIndex = MyUncheckedStateImageIndex;
else
Node->StateIndex = MyCheckedStateImageIndex;
}
}
void __fastcall TMyForm::TreeView1Click(TObject *Sender)
{
TPoint P;
::GetCursorPos(&P);
// or: P = Mouse->CursorPos;
// or: POINTS pts = MAKEPOINTS(::GetMessagePos()); P = Point(pts.x, pts.y);
P = TreeView1->ScreenToClient(P);
if (TreeView1->GetHitTestInfoAt(P.x, P.y).Contains(htOnStateIcon))
ToggleTreeNodeCheckBox(TreeView1->GetNodeAt(P.x, P.y));
}
void __fastcall TMyForm1::TreeView1KeyDown(TObject *Sender, WORD &Key, TShiftState Shift)
{
if (Key == VK_SPACE)
ToggleTreeNodeCheckBox(TreeView1->Selected);
}

Related

Event to fire after a System Windows Form element has been updated

I have a Windows form with a series of list boxes
The contents of subsequent lists change based on choices in earlier ones
All the boxes are bound to a BindingList with OnListChanged enabled
I use this to retain user-specified 'checked' items when elements are added or removed
However, I note that if I add an item to the list, it appears to update the UI only after all the other events have been fired
I've looked at the events I would expect to fire on the CheckedListBox, and in the related ViewModel, in order to catch the one which adds an item to the list, but so far without success
Can someone please advise me which event would allow me to call my 'CheckBoxes' method after the UI has been updated, otherwise they all get set to blank again until the form is closed and opened
private void OnPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
// I've removed the debug statements, but this event when the bound list updates is fired before the UI updates
}
private void teams_checked_list_box_SelectedIndexChanged(object sender, EventArgs e)
{
// same with this event, and the other events like SizeChanged
}
EDITED: On reflection, I realise that the problem occurs because I am not setting the true / false checked flag in the binding, because I couldn't figure out how to do it. If someone could point me in the right direction? Code currently looks like this:
teams_checked_list_box.DataSource = Globals.ThisAddIn.TFSTeamsViewModel.ListOfTeamsFromVM.value;
teams_checked_list_box.DisplayMember = "name";
So basically I am only updating the item name, and the check flag is handled on a later pass
How are you adding items to your list? Are you re-binding the listbox? There are basically two ways you can do this depending on your method of adding items:
If you are re-binding, capture the event BEFORE the item is added. Loop through the CheckedItems property of your list box. Save the values. Add your item. Loop through the NEW values and recheck.
OR
When the user checks the item in the listbox, capture that using the ItemChecked event and then store the value of the item somewhere. (Variable, hidden textbox -- ugly, but it works -- etc.) If you are only adding items to the BOTTOM of your list, you can store the index of the item. If you are re-sorting your list, you'll need to store a unique id to reference the item. (Note: you will also need to REMOVE the checked items from your stored value if the user UN-checks an item in your listbox.) Then, after you add your items to the listbox, loop back through and set the checked value on the appropriate listbox items.

How do we add Checkboxes for an ownerdrawn list control in MFC?

How can I make an owner-draw list control with checkboxes. What I need is:
I have data separate, each has a different color code. I need to add this to a list control with the format :
This allows multiple selection
[checkbox] [color code rectangle] Text_Item
I need to use checkboxes to select which I want selected.
I Should be able to select multiple items from listcontrol without having to use CTRL+Click.
I have tried using DrawFrameControl For getting the checkboxes.But using which we are able to select only one item at a time.Following is my code I have used in my drawitem method.
void OwnerdrawListCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
bool sel = (lpDrawItemStruct->itemState && ODS_SELECTED);
if
DrawFrameControl(*pDC, rcItem, DFC_BUTTON, DFCS_CHECKED);
else
DrawFrameControl(*pDC, rcItem, DFC_BUTTON, DFCS_INACTIVE);
}
This is how I am adding the checkboxes to my listCtrl.Im handling an NM_Click event in which Im setting the state of the ienter code heretem that is being clicked.

How to change content in the same form

I need to view new content in the same form (not to open a new form) when I click some button.
For exapmle this opera installer. When I click "Options" content changes in this window. And when I click "Back" I see previous components.
There is different ways to achive this easily :
You can use the TabControl control, which holds different pages you can design separatly in the vs designer.
Then you choose the initial one, hide the tabs selection bar on top, and control the TabPage selection with your buttons with SelectedTab or SelectedIndex properties.
Or you can simply wrap each section in a GroupBox control, set them all to Visible=false except the initial one and handle their visibility with your buttons with something like :
List<GroupBox> sections = new List<GroupBox>() { /* add your sections */ };
nextButton.OnClick += (o, e) =>
{
sections.ForEach(s => s.Visible = .../* condition to select the section you want displayed and hide others */);
};

How to impelment iPhone like Drag to Scroll Scrollviewer in WPF

I have a scrollviewer which contains number of buttons and forms. Now I want this application to scroll like in iPhone in touchscreen computers.
I have been trying to modify this tutorial:
Drag scrollable ListView
It implements double click to select the list item. However, I rather wanted to use single click so I changed the following code like this:
// initial source code values
// this registers the double click
isMouseDoubleClick = (e.ClickCount>1);
I changed it to..
// Get initial position of the mouse.
Point initialPos = e.GetPosition(this);
// initialize the isMouseDoubleClick;
isMouseDoubleClick = false
//if the button is pressed and hold (not released yet)..
if (e.ButtonState == MouseButtonState.Pressed) {
// if the hold position is same
if (e.GetPosition(this) == initialPose) {
//if mouse released
if (e.ButtonState == MouseButtonState.Released) {
// set isMouseDoubleClick true;
isMouseDoubleClick = true;
}
}
}
But it does not seems to work.
How does they made it work in iPhone.
The item does not gets selected when touched for a while and also while dragged but it gets selected in a single tap.
How can I make it happen similar in WPF application? A click will select the list item. Click and Hold will not select the list item.

Display the menu for a ToolStripDropDownButton as a context menu

I have a tool strip which contains a ToolStripDropDownButton. As an alternative access method, I would also like to be able to display this button's dropdown menu as a context menu, when the user right-clicks in the area below the tool strip.
I tried the following code, but it didn't work (it displayed the button's dropdown in the normal location, directly under the button):
Point contextMenuLocation = [get from WM_CONTEXTMENU]
myButton.DropDown.Show( contextMenuLocation );
The best idea I can think of would be to copy the toolstrip items from the button's dropdown into a ContextMenuStrip, but I don't see any simple way to do that (ToolStripItem does not implement ICloneable or a Clone method). Tool strip items store a reference to their Parent, so I can't just add the existing items to the context menu, as that would break the button.
Does anybody have a good idea on how to accomplish this?
A good way of populating two different dropdown with the same items is to extract the items creation into a function that builds the necessary drop down just before you open any instance of that dropdown. This also lets you enable a disable stuff if the application state changes.
class A
{
public A()
{
button = new ToolStripDropDownButton();
button.DropDown = new ToolStripDropDown();
ToolStripDropDown dropDown = new ToolStripDropDown();
dropDown.Opening += DropDownOpening;
menu.Items.DropDown = dropDown;
}
void DropDownOpening(object sender, EventArgs e)
{
ToolStripDropDown dropDown = sender as ToolStripDropDown;
if(dropDown != null)
{
dropDown.Items.Clear();
BuildMenu(dropDown);
}
else
{
// throw if you like
}
}
void BuildMenu(ToolStripDropDown dropDown)
{
// TODO : Add items to dropdown
// TODO : Take decisions depending on current application state
}
ToolStripDropDownButton button;
MenuStrip menu;
}

Resources