I'm building an application with treeview in windows form. I would like to change the background color/highlight individual items in the treeview based on some criteria. Does anyone have any suggestions on how to accomplish this?
Thank you very much!
Jason
void HighlightNodes(TreeNodeCollection nodes)
{
if (nodes != null)
{
foreach (TreeNode node in nodes)
{
// Process sub-nodes
if (node.Nodes.Count > 0)
{
HighlightNodes(node.Nodes);
}
if (criteriaIsMet)
{
node.BackColor = SystemColors.Highlight;
}
else
{
node.BackColor = Color.Empty;
}
}
}
}
Related
I have a tree of family members. I am attempting to provide a SEARCH facility which will allow me to select all the tree items where person name contains the SEARCH name. See this screen shot, though the first item matches RAJA it is not selected.
Now when I click on the LOCATE button again, the selections are correct as you can see.
This is the code for LOCATE BUTTON CLICKED.
#FXML
void onLocateClicked(MouseEvent event) {
childrenTreeView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
childrenTreeView.getSelectionModel().clearSelection();
String tmpLocateString = txtLocate.getText().toLowerCase();
TreeItem<APerson> item = childrenTreeView.getRoot();
item.setExpanded(true);
System.out.println("Locate ->"+tmpLocateString+" Root value = "+item.getValue().getPersonName());
if (item == null) {
// Don't do anything
return;
}
if (item.getValue().getPersonName().toLowerCase().contains(tmpLocateString)){
System.out.println("Item ->"+item+" MATCHES (LocateClicked)");
childrenTreeView.getSelectionModel().select(item);
}
doSearch(item, tmpLocateString);
}
private void doSearch(TreeItem<APerson> item, String tmpLocateString) {
System.out.println("Current Parent :" + item.getValue());
if (item != childrenTreeView.getRoot()) {
if (item.getValue().getPersonName().toLowerCase().contains(tmpLocateString)){
System.out.println("Item ->"+item+" MATCHES (in doSearch)");
childrenTreeView.getSelectionModel().select(item);
}
}
for(TreeItem<APerson> child: item.getChildren()){
String personName = child.getValue().getPersonName();
if (personName.toLowerCase().contains(tmpLocateString)) {
childrenTreeView.getSelectionModel().select(child);
}
if(child.getChildren().isEmpty()){
System.out.println(" No Children for this node : "+personName);
} else {
doSearch(child, tmpLocateString);
}
}
}
After the first error, the selections work correctly for all other searches..... Can anyone guess what is wrong? "doSearch" function is recursive to walk thru entire tree.
Thanks for your help, in advance.
Hornigold
This is the change I did to onLocateClicked but it did not work.
void onLocateClicked(MouseEvent event) {
TreeItem<APerson> item = childrenTreeView.getRoot();
if (item == null) {
// Don't do anything
return;
}
String tmpLocateString = txtLocate.getText().toLowerCase();
childrenTreeView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
childrenTreeView.getSelectionModel().clearSelection();
item.setExpanded(true);
System.out.println("Locate ->"+tmpLocateString+" Root value = "+item.getValue().getPersonName());
if (item.getValue().getPersonName().toLowerCase().contains(tmpLocateString)){
System.out.println("Item ->"+item+" MATCHES (LocateClicked)");
childrenTreeView.getSelectionModel().select(item);
}
doSearch(item, tmpLocateString);
}
I am new to JavaFX and, therefore, also to TornadoFX so please bear with me.
I have a simple app in Java but want to move it to Kotlin and am running into problems finding the corresponding mechanisms in TornadoFX. I have a ListView holding implementations of IStoryItem representing Stories and Chapters. I want to be able to move the chapters around and even from one story to another. The TreeView in Java has the following implementation in its setCellFactory call:
tv.setCellFactory(new Callback<TreeView<IStoryItem>, TreeCell<IStoryItem>>() {
#Override
public TreeCell<IStoryItem> call(TreeView<IStoryItem> siTreeView) {
TreeCell<IStoryItem> cell = new TreeCellStoryEditor();
cell.setOnDragDetected((MouseEvent event) -> {
// Don't drag Story nodes.
if (cell.getItem() instanceof Story) return;
Dragboard db = cell.startDragAndDrop(TransferMode.MOVE);
// Put the Part on the dragboard
// From: https://stackoverflow.com/a/30916660/780350
ClipboardContent content = new ClipboardContent();
content.put(objectDataFormat, cell.getItem());
db.setContent(content);
event.consume();
});
cell.setOnDragOver((DragEvent event) -> {
if (event.getGestureSource() != cell && event.getDragboard().hasContent(objectDataFormat)) {
/* allow for moving */
event.acceptTransferModes(TransferMode.MOVE);
}
event.consume();
});
cell.setOnDragEntered((DragEvent event) -> {
IStoryItem item = cell.getItem();
if (item instanceof Story &&
event.getGestureSource() != cell &&
event.getDragboard().hasContent(objectDataFormat)) {
cell.setUnderline(true);
}
event.consume();
});
cell.setOnDragExited((DragEvent event) -> {
cell.setUnderline(false);
event.consume();
});
cell.setOnDragDropped((DragEvent event) -> {
try {
Dragboard db = event.getDragboard();
boolean success = false;
if (db.hasContent(objectDataFormat)) {
Part droppedPart = (Part)db.getContent(objectDataFormat);
IStoryItem targetStoryItem = cell.getItem();
// Question: How to handle drops between leaf items or
// before the initial leaf or after the final leaf.
if (targetStoryItem instanceof Story) {
Story story = (Story) targetStoryItem;
updateStoryWith(droppedPart, story);
addPartTo(cell.getTreeItem(), droppedPart);
success = true;
}
}
event.setDropCompleted(success);
event.consume();
} catch (Exception e) {
System.out.println(e.getMessage());
}
});
cell.setOnDragDone((DragEvent event) -> {
if (event.getTransferMode() == TransferMode.MOVE) {
IStoryItem item = cell.getItem();
TreeItem<IStoryItem> ti = cell.getTreeItem();
TreeItem<IStoryItem> pti = ti.getParent();
pti.getChildren().remove(ti);
IStoryItem psi = pti.getValue();
// Remove the Part/Chapter from its previous Story
boolean removed = removePartFrom(psi, item);
}
event.consume();
});
cell.setEditable(true);
return cell;
};
});
I have looked for something similar in TornadoFX but can't find anything that looks like it would work. I am already using the cellFormat builder but I can't figure out how to add the event handlers inside it. I see from IntelliJ's intellisense that there is also a cellFactory builder but I am not sure how to make use of it or how to add the event handlers to it.
You can use the exact same technique in TornadoFX. Remember, TornadoFX just applies a high level API on top of JavaFX. You can always still access the underlying JavaFX API's without issue.
tv.setCellFactory {
object : TreeCell<IStoryItem>() {
init {
setOnDragOver { event ->
}
setOnDragEntered { event ->
}
setOnDragExited { event ->
}
setOnDragDropped { event ->
}
}
}
}
I want extend an System.Windows.Forms.Panel(just inherit) and using a custom ControlDesigner.
I use a very minimalistic ControlDesigner implementation, just overwrite GetHitTest.
The problem is my custom panel instance is not ready to contains child controls any longer.
I play a little bit with AssociatedComponents but without effect. Remove custom designer attribute and it works great.
can someone help me to pin point whats wrong ???
[Designer(typeof(MyPanelDesigner)), ToolboxItem(true)]
public class MyPanel : System.Windows.Forms.Panel
{
// empty except for OnPaint
}
internal class DrawPanelDesigner : ControlDesigner
{
private MyPanel ParentControl
{
get
{
return Control as MyPanel;
}
}
public override System.Collections.ICollection AssociatedComponents
{
get
{
return ParentControl.Controls;
}
}
protected override bool GetHitTest(System.Drawing.Point point)
{
// hit detection for some owner drawed items in OnPaint
point = ParentControl.PointToClient(point);
var item = ParentControl.View.GetItemFromViewPoint(point.X, point.Y, true);
return null != item;
}
You are using the wrong designer. Try inheriting from the ScrollableControlDesigner instead:
internal class DrawPanelDesigner : ScrollableControlDesigner {
public DrawPanelDesigner() {
AutoResizeHandles = true;
}
private MyPanel ParentControl {
get {
return Control as MyPanel;
}
}
protected Pen BorderPen {
get {
Color penColor = Control.BackColor.GetBrightness() < .5 ?
ControlPaint.Light(Control.BackColor) :
ControlPaint.Dark(Control.BackColor);
Pen pen = new Pen(penColor);
pen.DashStyle = DashStyle.Dash;
return pen;
}
}
protected virtual void DrawBorder(Graphics graphics) {
Panel panel = (Panel)Component;
if (panel == null || !panel.Visible) {
return;
}
Pen pen = BorderPen;
Rectangle rc = Control.ClientRectangle;
rc.Width--;
rc.Height--;
graphics.DrawRectangle(pen, rc);
pen.Dispose();
}
protected override void OnPaintAdornments(PaintEventArgs pe) {
Panel panel = (Panel)Component;
if (panel.BorderStyle == BorderStyle.None) {
DrawBorder(pe.Graphics);
}
base.OnPaintAdornments(pe);
}
}
I have a radTreeListView with multiple parent nodes,which can contain multiple child nodes which can also contain multiple sub-child nodes.
I want to make sure only 8 items are selected and no more than that. Those 8 selections MUST also be under the same parent node.
You could try something like that:
private RadTreeNode GetParentNode(RadTreeNode currentNode) {
if (currentNode.Parent!=null) {
return GetParentNode(currentNode.Parent);
}
return currentNode;
}
private void CountSelectedNodes(RadTreeNode firstNode, ref int selectedCount) {
if (firstNode.Nodes!=null) {
foreach(RadTreeNode node in firstNode.Nodes) {
CountSelectedNodes(node, ref selectedCount);
}
if (firstNode.IsSelected) {
selectedCount+=1;
}
}
}
private bool SelectionAllowed(RadTreeNode currentNode) {
RadTreeNode treeNode=GetParentNode(currentNode);
int selectedCount;
CountSelectedNodes(treeNode, ref selectedCount);
return selectedCount<=8;
}
(this code is not tested so there could be some bugs)
Call selectionAllowed() with the Node currently clicked
I'm looking for a simple way to loop through all buttons onscreen for a given tag. Eg "foo". I'm using WP7, using C#. I'm very new to the platform so go easy on me :P
Googling this sort of thing isn't really working out for me either - I think I have my terminology wrong, so any tips on that too would be appreciated.
You should probably loop through all the controls on your page, check whether each one is a button, and if so check its Tag property.
Something like this...
foreach (UIElement ctrl in ContentPanel.Children)
{
if (ctrl.GetType() == typeof(Button))
{
Button potentialButton = ((Button)ctrl);
if (potentialButton.Tag = Tag)
return (Button)ctrl;
}
}
Bear in mind, though, that if you have nested controls on the page, you will need to think about recursing into any item with children to make sure you catch all the controls.
First, create a method to enumerate recursively the controls in your page:
public static IEnumerable<FrameworkElement> FindVisualChildren(FrameworkElement control)
{
if (control == null)
{
yield break;
}
for (int i = 0; i < System.Windows.Media.VisualTreeHelper.GetChildrenCount(control); i++)
{
var child = System.Windows.Media.VisualTreeHelper.GetChild(control, i) as FrameworkElement;
if (child != null)
{
yield return child;
foreach (var grandChild in FindVisualChildren(child))
{
yield return grandChild;
}
}
}
}
Then call it and keep only the controls you want:
var buttons = FindVisualChildren(this.ContentPanel)
.OfType<Button>()
.Where(b => b.Tag is string && (string)b.Tag == "foo");
(where ContentPanel is the root element of your page)