April 18, 2024, 07:11:37 PM

News:

Own IWBasic 2.x ? -----> Get your free upgrade to 3.x now.........


Images in Tree View Control

Started by Bruce Peaslee, January 05, 2007, 10:22:02 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Bruce Peaslee

I've gotten to the point where an image appears on my tree view, but it is only the second one I load - it doesn't change as expected. Here are some code fragments:


MainDialog::MainDialog()
{
   m_TreeImageList.Create(16, 16, ILC_COLOR, 2);
   m_TreeImageList.AddBitmap(m_TreeImageList.LoadBitMap(GetModuleHandleA(0), "ClosedFolder", 16));
   m_TreeImageList.AddBitMap(m_TreeImageList.LoadBitMap(GetModuleHandleA(0), "OpenFolder",   16)); // THIS IS THE ONLY ONE I SEE
   return;
}
...
MainDialog::OnInitDialog(),int
{
   unsigned int root1, root2;
   unsigned int child1;

   /* Initialize any controls here */
   CTreeView *tree = GetControl(DLG_TREEVIEW);
   //insert items in the treeview
   root1 = tree->InsertItem("Item 1",0);
   child1 = tree->InsertItem("child 1",root1);
   tree->InsertItem("Child of child1",child1);
   tree->InsertItem("child 2",root1);

   root2 = tree->InsertItem("Item 2",0);
   tree->InsertItem("child 1",root2);
   tree->InsertItem("child 2",root2);

   SendMessage(tree->m_hwnd,TVM_SETIMAGELIST,TVSIL_NORMAL,m_TreeImageList.m_himl);
   CenterWindow();
   return true;
}
Bruce Peaslee
"Born too loose."
iTired (There's a nap for that.)
Well, I headed for Las Vegas
Only made it out to Needles

Ionic Wind Support Team

The TreeView class needs a few more methods to use the image list.  Specifically InsertItem doesn't set the index into the image list.

You can do it with SendMessage though.  Derive a class from CTreeView, add the method below.  Or just use it directly.  You will need the handle to the item you want to set the image index to.  It is returned when you call the InsertItem method.

The index is the zero based index into the image list.


struct TV_ITEM
{
    UINT       mask;
    UINT     hItem;
    UINT       state;
    UINT       stateMask;
    POINTER    pszText;
    int        cchTextMax;
    int        iImage;
    int        iSelectedImage;
    int        cChildren;
    UINT       lParam;
}
#define TV_FIRST 0x1100
#define TVIF_IMAGE              0x0002
#define TVM_SETITEMA            (TV_FIRST + 13)

MyTreeView::SetItemImage(handle as unsigned int,index as int),unsigned int
{
TV_ITEM tvi;
IF(m_hWnd)
{
ZeroMemory(tvi,LEN(TV_ITEM));
tvi.mask = TVIF_IMAGE;
tvi.pszText = NULL;
tvi.cchTextMax = 0;
tvi.hitem = handle;
                tvi.iImage = index
RETURN SendMessageA(m_hWnd,TVM_SETITEMA,0,&tvi);
}
RETURN 0;
}

Ionic Wind Support Team

Bruce Peaslee

Thanks. I now have images. It wasn't easy. The tree control doesn't want to do anything automatically.

I now want to change the image to an open folder when the item is expanded, but I'm not able to figure out how to detect the item that was.

I'm trying this:


TreeDialog::OnNotify(int code, int  nID, NMHDR  *pnmhdr), int
{

   select code
   {
      case TVN_ITEMEXPANDED:
         NMTREEVIEW *pTreeView = *(NMTREEVIEW)pnmhdr;
         if  pTreeView->action == 2
         {
            MessageBox(this,"Item expanded","",0);
         }
   }

   return 0;
}


Thanks in advance.
Bruce Peaslee
"Born too loose."
iTired (There's a nap for that.)
Well, I headed for Las Vegas
Only made it out to Needles

Ionic Wind Support Team

Give me a bit and I will figure it out ;)
Ionic Wind Support Team

Ionic Wind Support Team

OK here is a modifiction of the treeview sample that comes with Aurora.  I got you as far as using the notification and retrieving the handle to the item that is expanded or collapsed.  Send that handle to the SetItemImage method I gave you before and you should be all set.


#define TREEVIEW_1 1
#define STATIC_2 2
#define STATIC_3 3

struct TVITEM
{
    UINT       mask;
    UINT     hItem;
    UINT       state;
    UINT       stateMask;
    POINTER    pszText;
    int        cchTextMax;
    int        iImage;
    int        iSelectedImage;
    int        cChildren;
    UINT       lParam;
}

struct NMTREEVIEW {
    NMHDR hdr;
    UINT action;
    TVITEM itemOld;
    TVITEM itemNew;
    POINT ptDrag;
}

class TreeViewDialog:CDialog
{
declare OnInitDialog(),int;
declare OnClose(),int;
declare OnControl(int nID, int nNotifyCode, unsigned int hControl),int;
declare OnNotify(int code,int nID,NMHDR *pnmhdr),int;

}

global sub main()
{
TreeViewDialog dlg1;
dlg1.Create(0,0,300,202,0x80C80080,0,"TreeView demo",0);
dlg1.AddControl(CTTREEVIEW,"Static",32,24,107,150,0x50800007,0x200,TREEVIEW_1);
dlg1.AddControl(CTSTATIC,"Selected Item:",147,24,70,20,0x5000010B,0x0,STATIC_2);
dlg1.AddControl(CTSTATIC,"Item 1",218,24,70,20,0x50000000,0x0,STATIC_3);

dlg1.DoModal();
return 0;
}

TreeViewDialog::OnClose(),int
{
CloseDialog(1);
return true;
}

TreeViewDialog::OnInitDialog(),int
{
/* Initialize any controls here */
CTreeView *tree = GetControl(TREEVIEW_1);
//insert items in the treeview
root1 = tree->InsertItem("Item 1",0);
child1 = tree->InsertItem("child 1",root1);
tree->InsertItem("Child of child1",child1);
tree->InsertItem("child 2",root1);

root2 = tree->InsertItem("Item 2",0);
tree->InsertItem("child 1",root2);
tree->InsertItem("child 2",root2);
CenterWindow();
return true;
}

TreeViewDialog::OnControl(int nID, int nNotifyCode, unsigned int hControl),int
{
CTreeView *tree = GetControl(TREEVIEW_1);
CStatic *s = GetControl(STATIC_3);
string text;
select nID
{
case TREEVIEW_1:
select(nNotifyCode)
{
case TVNSELCHANGEDA:
hSel = tree->GetSelectedItem();
tree->GetItemText(hSel,text,255);
s->SetText(text);
}
}
return true;
}

TreeViewDialog::OnNotify(int code,int nID,NMHDR *pnmhdr),int
{
select nID
{
case TREEVIEW_1:
select(code)
{
case TVNITEMEXPANDEDA:
if(*(NMTREEVIEW)pnmhdr.action == 2)
{
MessageBox(this,"Item Expanded " + str$(*(NMTREEVIEW)pnmhdr.itemold.hitem),"");
}
else
{
MessageBox(this,"Item Collapsed " + str$(*(NMTREEVIEW)pnmhdr.itemold.hitem),"");

}
}
}
//remember to call the base class
return CDialog!!OnNotify(code,nID,pnmhdr);
}

Ionic Wind Support Team

Bruce Peaslee

This is better  ;)

*(NMTREEVIEW)pnmhdr.itemnew.hitem

Also, I previously screwed up the struct definition for NMTREEVIEW which didn't help.

But now it works like a charm. I'll post the results here for others when it's cleaned up a bit.

Thanks, Paul.
Bruce Peaslee
"Born too loose."
iTired (There's a nap for that.)
Well, I headed for Las Vegas
Only made it out to Needles

Ionic Wind Support Team

You are most welcome.  On the "little too late" front, Microsoft added an iExpandedImage field to TVITEM for Vista.  It is probably part of the common control update for IE7 as well.  But then it would only work for Vista or greater anyway.  Handling the notification works for all windows versions.

Paul.
Ionic Wind Support Team

Bruce Peaslee

Here is the result of our efforts. I never have the best of luck uploading projects, but I think all of the pieces are there. Be sure to check to see if the bitmaps are loaded into the project and are named correctly. Click FILE|OPEN to display the control.
Bruce Peaslee
"Born too loose."
iTired (There's a nap for that.)
Well, I headed for Las Vegas
Only made it out to Needles

Bruce Peaslee

Everything is humming with my TreeView control with one nagging little bit.

I have created a context menu that works correctly and causes action on the selected item. My problem is that I must left click on an item to select it, then right click (actually anywhere in the control) to see the context menu. If I right click on an item in the tree, the selection does not change, although it is highlighted while the button is down. The highlighting returns to the previous item when the mouse button is released and the context menu appears.
Bruce Peaslee
"Born too loose."
iTired (There's a nap for that.)
Well, I headed for Las Vegas
Only made it out to Needles

Ionic Wind Support Team

Try setting the focus on right button down. 
Ionic Wind Support Team

Bruce Peaslee

Quote from: Paul Turley on January 15, 2007, 12:48:47 PM
Try setting the focus on right button down. 

I couldn't get the item to accept the focus, but this got me thinking that what we want is to make the right click select the item in the tree. After spending a lovely afternoon with MSDN, I came up with this:


TreeDialog::OnControl(int nID, int nNotifyCode, unsigned int hControl), int
{
   point location;
   TVHITTESTINFO *hitInfo;
   CONST TVHT_ONITEMICON   = 0x2;
   CONST TVHT_ONITEMLABEL = 0x4;
   CONST TVM_HITTEST          = 4369;

   select nID
   {
      case TD_tv_Tree:
         if(nNotifyCode == NM_RCLICK)
         {
            hitInfo = new(TVHITTESTINFO,1);
            GetCursorPos(location);
            ScreenToClient(this->m_hwnd,location);
            hitInfo->pt.x = location.x - 46; // adjust for location of control in dialog
            hitInfo->pt.y = location.y - 56;
            hitInfo->flags = TVHT_ONITEMLABEL | TVHT_ONITEMICON;
            CTreeView *pTree = GetControl(TD_tv_Tree);
            SendMessage(pTree->m_hwnd,TVM_HITTEST,0,hitInfo);
            if(hitInfo->hItem <> null)
            {
               pTree->SelectItem(hitInfo->hItem);
               ShowContextMenu(m.m_hMenu, location.x, location.y);
            }
               Delete(hitInfo);
         }
   }
}
Bruce Peaslee
"Born too loose."
iTired (There's a nap for that.)
Well, I headed for Las Vegas
Only made it out to Needles

Ionic Wind Support Team

You should be able to call ScreenToClient on the hitInfo->pt structure.
Ionic Wind Support Team

Bruce Peaslee

Quote from: Paul Turley on January 15, 2007, 08:11:29 PM
You should be able to call ScreenToClient on the hitInfo->pt structure.

Nice touch.

ScreenToClient(pTree->m_hwnd,hitInfo->pt);


TreeDialog::OnControl(int nID, int nNotifyCode, unsigned int hControl), int
{
   point location;
   TVHITTESTINFO *hitInfo;
   CONST TVHT_ONITEMICON  = 0x2;
   CONST TVHT_ONITEMLABEL= 0x4;
   CONST TVM_HITTEST         = 4369;

   select nID
   {
      case TD_tv_Tree:
         if(nNotifyCode == NM_RCLICK)
         {
            CTreeView *pTree = GetControl(TD_tv_Tree);
            hitInfo = new(TVHITTESTINFO,1);
            GetCursorPos(location);
            hitInfo->pt = location;
            ScreenToClient(this->m_hwnd,location); // adjust for dialog
            ScreenToClient(pTree->m_hwnd,hitInfo->pt);  // adjust for control
            hitInfo->flags = TVHT_ONITEMLABEL | TVHT_ONITEMICON;
            SendMessage(pTree->m_hwnd,TVM_HITTEST,0,hitInfo);
            if(hitInfo->hItem <> null) // hit an item
            {
               pTree->SelectItem(hitInfo->hItem);
               ShowContextMenu(m.m_hMenu, location.x, location.y);
            }
            else // didn't hit an item
            {
               ShowContextMenu(m2.m_hMenu, location.x, location.y);
            }
            Delete(hitInfo);
         }
   }
}
Bruce Peaslee
"Born too loose."
iTired (There's a nap for that.)
Well, I headed for Las Vegas
Only made it out to Needles

Ionic Wind Support Team

Thats better ;).   It is almost the same code that I use for right clicking on items in the resource view of the IDE.
Ionic Wind Support Team

Bruce Peaslee

Quote from: Paul Turley on January 16, 2007, 06:19:57 AM
Thats better ;).   It is almost the same code that I use for right clicking on items in the resource view of the IDE.

Feel free to use any efficiencies I have found.  ;)

Here is the code to date. A final product, if I get one, will be part of the Programmers Toolkit.
Bruce Peaslee
"Born too loose."
iTired (There's a nap for that.)
Well, I headed for Las Vegas
Only made it out to Needles

Bruce Peaslee

Things have been humming with my tree view. Additions, deletions, and edits are all fairly simple, especially now that I have replaced the array with a linked list. However, trying to get the control to drag and drop is driving me crazy  :P . There appears to be comands in the CImageList class that might help, but I am getting nowhere fast. Any advice on how to approach this would be appreciated.
Bruce Peaslee
"Born too loose."
iTired (There's a nap for that.)
Well, I headed for Las Vegas
Only made it out to Needles

Bruce Peaslee

March 01, 2007, 09:06:53 AM #16 Last Edit: March 01, 2007, 04:35:57 PM by peaslee
I have been working, on and off, for over a month on the tree control and have not been able to successfully implement the drag part.

If anyone can share code to do this in Aurora, EBasic, or IBasic, I would sure appreciate it.

EDIT:  Never mind. I finally got it to work. I found an assembly language program on the net that was easy to convert to Aurora.  8)
Bruce Peaslee
"Born too loose."
iTired (There's a nap for that.)
Well, I headed for Las Vegas
Only made it out to Needles