全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:3737
推到 Plurk!
推到 Facebook!

TreeView如何做出像ListView多選的功能??

答題得分者是:axsoft
billlee
一般會員


發表:31
回覆:46
積分:15
註冊:2002-06-25

發送簡訊給我
#1 引用回覆 回覆 發表時間:2002-12-09 16:53:38 IP:61.56.xxx.xxx 未訂閱
各位好: 我想請問各位,TreeView如何做出像ListView多選的功能 ,如果現有的元件,無法做出,請問大家有沒有用過可以達到 我功能的元件,謝謝。
jessechan
版主


發表:109
回覆:394
積分:254
註冊:2002-04-05

發送簡訊給我
#2 引用回覆 回覆 發表時間:2002-12-09 19:21:53 IP:61.228.xxx.xxx 未訂閱
我不懂您的問題吔, 不是把 MultiSelect 的 property 設成 true 然後再以 MultiSelectStyle 去做出您想要的效果就好嗎? 請再說明您的問題是什麼好嗎? Jesse Chan
------
Jesse Chan
axsoft
版主


發表:681
回覆:1056
積分:969
註冊:2002-03-13

發送簡訊給我
#3 引用回覆 回覆 發表時間:2002-12-10 08:59:38 IP:61.218.xxx.xxx 未訂閱
引言: 各位好: 我想請問各位,TreeView如何做出像ListView多選的功能 ,如果現有的元件,無法做出,請問大家有沒有用過可以達到 我功能的元件,謝謝。
參考這個看看! 資料來源: http://www.bridgespublishing.com/

Creating a multiselect tree-view

by Damon Chandler Tree-views are great for displaying data in a compact, hierarchical format. Unfortunately, the standard tree-view control?and thus, the VCL TTreeView component?allows only a single node to be selected at any given time. In this article, I?ll show you how to overcome this limitation. I?ll first give a brief overview of the Custom Draw service and it?s applicability to tree-views; and then I?ll explain how to use this technology to easily implement basic multiple-selection functionality. Custom drawn tree-views A few months back, I explained how to use the Custom Draw service with the TTrackBar control. In that article, I mentioned that many common controls provide Custom Draw notification messages?the tree-view control is no exception. As it turns out, in newer version of C Builder, the TTreeView class exposes Custom-Draw-specific events (e.g., OnCustomDrawItem). I won?t cover these events for two reasons: (1) they?re not available in all versions of C Builder and (2) they?re a bit buggy. Instead, I?ll show you how to handle the NM_CUSTOMDRAW notification message directly. Recall that this notification message is sent to the tree-view?s parent window in the form of a WM_NOTIFY message. Next I?ll explain how to handle this latter message. Handling the WM_NOTIFY message Imagine a form that contains only one child control: a TTreeView object. Because the tree-view is a direct child of the form, the tree-view will send all of its notification messages to the form (i.e., to its parent window). So in this ideal setup, to handle the WM_NOTIFY message, all you need to do is augment the form?s Dispatch() method by using the message-mapping macros:
class TForm1 : public TForm
{
__published:
  TTreeView *TreeView1;
  TImageList *ImageList1;
private:
  MESSAGE void __fastcall WMNotify(
    TMessage& Msg);
public:
  __fastcall TForm1(TComponent* Owner);
 
BEGIN_MESSAGE_MAP
  MESSAGE_HANDLER(
    WM_NOTIFY, TMessage, WMNotify)
END_MESSAGE_MAP(TForm)
};
Let me remind you of what this code is doing. The WM_NOTIFY message, as its name suggests, is the tree-view?s way of notifying its parent window of specific events. In this case, because TreeView1?s parent window is Form1, I handle the WM_NOTIFY message by tapping into Form1?s window procedure via the Dispatch() method. The WMNotify() method can now be defined as follows:
void __fastcall TForm1::
  WMNotify(TMessage& Msg)
{
  // grab a pointer to the tree-view's 
  // notification structure
  const NM_TREEVIEW* pnmtv =
    reinterpret_cast
      (Msg.LParam);
 
  // if the notification is NM_CUSTOMDRAW
  // and its from the tree-view
  if (pnmtv->hdr.code == NM_CUSTOMDRAW &&
      pnmtv->hdr.hwndFrom ==
      TreeView1->Handle)
  {
    // Custom Draw stuff...
  }
 
  // pass everything else on
  TForm::Dispatch(&Msg);
}
Notice from this code that I look specifically for the NM_CUSTOMDRAW notification code. This step is necessary because I?m interested only in those events that correspond to the tree-view?s drawing cycle. Also, notice that the NMHDR::hwndFrom data member is tested for equality with the tree-view?s handle. This step ensures that only the notifications that are sent from TreeView1 are handled. (This test isn?t really needed in this ideal case because the form doesn?t contain any other child controls.) So far, so good, but, where?s the code to handle the "Custom Draw stuff"? Well, I didn?t provide that code because you?ll rarely handle the WM_NOTIFY message in this way. Remember, this implementation assumes?and will work only if?TreeView1 is a direct child of Form1. If you later decide that your tree-view will look better if it?s placed on, say, a TPanel object, then this code won?t work. Instead, you?d have to handle the WM_NOTIFY message that?s sent to the panel (i.e., to the tree-view?s new parent window). To avoid this hassle the VCL provides the CN_NOTIFY message, which is a reflected version of WM_NOTIFY that?s sent back to the tree-view itself. Because you handle this reflected message within the tree-view?s window procedure, you don?t have to worry about which window the tree-view is placed on. Handling the CN_NOTIFY message I just mentioned that the CN_NOTIFY message is a reflected version of the WM_NOTIFY message. Because of this fact, you handle the CN_NOTIFY message in the exact same way as you?d handle the WM_NOTIFY message. The only difference is where you handle the message?i.e., in which window procedure. In this case it is done within a descendant class, like so:
class TMyTreeView : public TTreeView
{
public:
  __fastcall TMyTreeView(
    TComponent* Owner);
 
private:
  MESSAGE void __fastcall CNNotify(
    TMessage& Msg);
 
public:
BEGIN_MESSAGE_MAP
  MESSAGE_HANDLER(
    CN_NOTIFY, TMessage, CNNotify)
END_MESSAGE_MAP(TTreeView)
};
And, here?s the definition of the TMyTreeView::CNNotify() method:
void __fastcall TMyTreeView::
  CNNotify(TMessage& Msg)
{
  // grab a pointer to the
  // tree-view's notification structure
  const NM_TREEVIEW* pnmtv =
    reinterpret_cast
      (Msg.LParam);
 
  // if the notification is NM_CUSTOMDRAW
  if (pnmtv->hdr.code == NM_CUSTOMDRAW)
  {
    // grab a pointer to the tree-view's
    // Custom Draw structure    
    NMTVCUSTOMDRAW* ptvcd =
      reinterpret_cast
        (Msg.LParam);
 
    switch(ptvcd->nmcd.dwDrawStage)
    {
      // prior to painting...
      case CDDS_PREPAINT:
      {
        // tell the tree-view we want
        // individual notification of
        // each item being drawn
        Msg.Result = CDRF_NOTIFYITEMDRAW;
        break;
      }
 
      // upon notification of
      // each item being drawn...
      case CDDS_ITEMPREPAINT:
      {
        // extract the handle to the node
        const HTREEITEM hItem =
          reinterpret_cast<
            const HTREEITEM>(
              ptvcd->nmcd.dwItemSpec
              );
              
        // grab a pointer to the node
        TTreeNode* Node =
          Items->GetNode(hItem);
 
        // extract the state of the node
        const UINT state =
          ptvcd->nmcd.uItemState;
 
        // if the node is selected
        // or at an odd ordinal position
        if ((state & CDIS_SELECTED) ||
            (Node->AbsoluteIndex % 2))
        {
          // change the background color
          ptvcd->clrTextBk =
            ColorToRGB(clHighlight);
 
          // change the text color
          ptvcd->clrText =
            ColorToRGB(clHighlightText);
 
          // tell the tree-view that
          // we changed an attribute
          Msg.Result = CDRF_NEWFONT;
        }
        // otherwise...
        else
        {
          // punt to the tree-view
          Msg.Result = CDRF_DODEFAULT;
        }
        break;
      }
 
      // let the tree-view
      // draw everything else
      default:
      {
        Msg.Result = CDRF_DODEFAULT;
        break;
      }
    }
  }
  else TTreeView::Dispatch(&Msg);
}
This code will render every other node in a selected state, regardless of whether the node is actually selected. You can begin to see here how multiselect functionality can be added to a standard tree-view control. At this point the code to render multiple nodes in a selected state is done; what is needed now is to add code to store and manage the selected state of each node. Adding multiselect functionality Listing A provides the definition of a TTreeView descendant class, which I?ve called TMultiTreeView. In the sections that follow, I?ll show you how to implement each of its methods. Getting and setting the selected state As I mentioned earlier, the selected state of each node must be stored; the TTreeNode::Data property can be used for this purpose. Accordingly, I will define a couple of methods to get and set the value of the Data property:
inline bool __fastcall
  TMultiTreeView::IsNodeSelected(
    TTreeNode* Node
  )
{
  if (Node) return Node->Data;
  return false;
}
 
inline void __fastcall
  TMultiTreeView::SelectNode(
    TTreeNode* Node, bool select,
    bool redraw
  )
{
  if (Node && Node->Data !=
      reinterpret_cast(select))
  {
    Node->Data =
      reinterpret_cast(select);
    if (redraw) RedrawNode(Node);
  }
}
The definition of the IsNodeSelected() method is fairly simple: it just returns the value that?s held in the specified node?s Data property (implicitly casting the result to a Boolean value). The SelectNode() method serves a similar role: instead of reading the Data property, it assigns the value that?s specified by the select parameter to the node?s Data property. Notice that the Data property is changed only if the select parameter indicates a different value than what?s currently indicated in the node?s Data property. Also notice that the redraw parameter governs whether the RedrawNode() method?which I will explain next?is called. Redrawing a node After you change the selected state of a node, you?ll need a way to incite the tree-view to redraw that node. Specifically, you?ll want the tree-view to send its parent (and thus itself) a Custom Draw notification so that the TMultiTreeView::CNNotify() method?which I?ll define shortly?can redraw the node to reflect its new state. The RedrawWindow() API function can be used to redraw a specific rectangular-based area of a window. In this case, to redraw a specific node, you simply pass the RedrawWindow() function the target node?s bounding rectangle, which you can retrieve by using the TTreeNode::DisplayRect() method. Here?s the code:
inline void __fastcall
  TMultiTreeView::RedrawNode(
    TTreeNode* Node
  )
{
  if (Node)
  {
    const RECT R =
      Node->DisplayRect(true);
    RedrawWindow(
      Handle, &R, NULL,
      RDW_INVALIDATE | RDW_UPDATENOW
      );  
  }
}
Note the use of the RDW_UPDATENOW flag in the call to RedrawWindow(). This specification ensures that the CNNotify() method will be called before RedrawWindow() returns. Now I?ll explain how the CNNotify() method is defined. Drawing the selected nodes I?ve already explained the mechanism to draw multiple nodes in a selected state. Here?s the definition of the TMultiTreeView::CNNotify() method:
void __fastcall TMultiTreeView::
  CNNotify(TMessage& Msg)
{
  // grab a pointer to the tree-view's 
  // notification structure
  const NM_TREEVIEW* pnmtv =
    reinterpret_cast
      (Msg.LParam);
 
  // if the notification is NM_CUSTOMDRAW
  if (pnmtv->hdr.code == NM_CUSTOMDRAW)
  {
    // grab a pointer to the tree-view's
    // Custom Draw structure
    NMTVCUSTOMDRAW* ptvcd =
      reinterpret_cast
        (Msg.LParam);
 
    switch(ptvcd->nmcd.dwDrawStage)
    {
      // prior to painting...
      case CDDS_PREPAINT:
      {
        // tell the tree-view we want
        // individual notification of
        // each item being drawn
        Msg.Result = CDRF_NOTIFYITEMDRAW;
        break;
      }
 
      // upon notification of
      // each item being drawn...
      case CDDS_ITEMPREPAINT:
      {
        // extract the handle to the node
        const HTREEITEM hItem =
           reinterpret_cast<
            const HTREEITEM>(
              ptvcd->nmcd.dwItemSpec
              );
 
        // grab a pointer to the node
        TTreeNode* Node =
          Items->GetNode(hItem);
 
        // extract the state of the node
        const UINT state =
          ptvcd->nmcd.uItemState;
 
        // if the node is selected
        // or pseudo-selected
        if ((state & CDIS_SELECTED) ||
            IsNodeSelected(Node))
        {
          // change the background color
          ptvcd->clrTextBk =
            ColorToRGB(clHighlight);
 
          // change the text color
          ptvcd->clrText =
            ColorToRGB(clHighlightText);
 
          // tell the tree-view that
          // we changed an attribute
          Msg.Result = CDRF_NEWFONT;
        }
        // otherwise...
        else
        {
          // punt to the tree-view
          Msg.Result = CDRF_DODEFAULT;
        }
        break;
      }
 
      // let the tree-view
      // draw everything else
      default:
      {
        Msg.Result = CDRF_DODEFAULT;
        break;
      }
    }
  }
  else TTreeView::Dispatch(&Msg);
}
Notice that this method is nearly identical to the previous CNNotify() method, which was defined for the TMyTreeView class. Here, instead of just drawing every other node selected, I use the IsNodeSelected() method to decide which nodes to highlight. Although I?ve now shown you how to toggle the selected state of each node, you?ll still need to know when to call the SelectNode() method. Because there are two ways in which a user can select nodes?via the mouse and via the keyboard?you need to provide code to handle both of these situations. Handling multiple selection via the mouse Notice from Listing A that I?ve mapped the WM_LBUTTONDOWN message to the WMLButtonDown() method. This method will be called immediately after the user presses the left mouse button while the cursor is within the tree-view. You can use this opportunity to strategically call the SelectNode() method. Here?s the code:
void __fastcall TMultiTreeView::
  WMLButtonDown(TMessage& Msg)
{
  // find the node that's hit
  const POINT PHit =
    {Msg.LParamLo, Msg.LParamHi};
  TTreeNode* HitNode =
    GetNodeAt(PHit.x, PHit.y);
 
  // if a node is hit
  if (HitNode)
  {
    // perform a hit test
    const TV_HITTESTINFO
      hit_info = {PHit.x, PHit.y};
    TreeView_HitTest(Handle, &hit_info);
 
    // if the node's label or icon is hit
    if (hit_info.flags & TVHT_ONITEM)
    {
      // extract the key-state flags
      const WPARAM keys = Msg.WParam;
 
      // if the control key is pressed
      if (keys & MK_CONTROL)
      {
        // if the node is selected
        if (HitNode->Selected ||
            IsNodeSelected(HitNode))
        {
          // deselect the node
          HitNode->Selected = false;
          SelectNode(HitNode, false);
          return;
        }
 
        // otherwise, select the
        // currently-selected node
        SelectNode(Selected, true);
      }
 
      // if the shift key is pressed
      else if (keys & MK_SHIFT)
      {     
        // deselect all but from
        // HitNode to PreviousNode_
        SelectAllExcept(
          HitNode, PreviousNode_, false);
 
        // select all nodes from
        // HitNode to PreviousNode_
        SelectNodes(
          HitNode, PreviousNode_, true);
      }
 
      // otherwise, deselect all nodes
      else SelectAll(false);
    }
    
    // otherwise, if the user clicks
    // to the right of the nodes...
    else if (
      hit_info.flags & TVHT_ONITEMRIGHT)
    {
      // if the tree-view has focus
      if (Handle == GetFocus())
      {
        // deselect all nodes
        SelectAll(false);
        Selected = NULL;
      }
    }
  }
  // pass the message on
  TTreeView::Dispatch(&Msg);
}
The logic behind this code is as follows: First use the TTreeView::GetNodeAt() method to identify the node that?s closest to the location that was clicked. Next, perform a hit test?by using the TreeView_HitTest() macro?to make sure that the node?s label or icon was hit. If this condition is satisfied, use the WParam value (that accompanies the WM_LBUTTONDOWN message) to determine if the control and/or shift keys were held down during the click. If the control key is held down, simply toggle HitNode?s selected status. Note that when you deselect HitNode, you?ll have to return immediately so that the tree-view doesn?t make the node editable. If the shift key is held down, select a range of nodes. Specifically, select the range from HitNode to the last node that was selected without using the shift key?i.e., to PreviousNode_. (I?ll show you how to set the PreviousNode_ member shortly.) If neither the control key nor the shift key is held down, deselect all nodes and then let the tree-view highlight its real selected node as usual. Finally, notice that?in addition to the SelectNode() method?the WMLButtonDown() method makes use of the SelectNodes(), SelectAllExcept(), and SelectAll() methods. I added these latter three methods to help keep things sane; they?re defined in Listing B. Handling multiple selection via the keyboard To handle the case in which the user selects nodes via the keyboard, you use the WM_KEYDOWN message. From Listing A, you can see that this message is mapped to the WMKeyDown() method, which is defined as follows:
void __fastcall TMultiTreeView::
  WMKeyDown(TMessage& Msg)
{
  switch (Msg.WParam)
  {
    // if the up-arrow key is pressed
    case VK_UP:
    {
      // if the shift key is down
      if (GetKeyState(VK_SHIFT) < 0)
      {
        // get the previous visible node
        TTreeNode* PrevNode =
          Selected->GetPrevVisible();
 
        // toggle the currently selected
        // node based on the selected
        // state of the previous node
        SelectNode(
          Selected,
          !IsNodeSelected(PrevNode)
          );
      }
      // otherwise, deselect all nodes
      else SelectAll(false);
      break;
    }
 
    // if the down-arrow key is pressed
    case VK_DOWN:
    {
      // if the shift key is down
      if (GetKeyState(VK_SHIFT) < 0)
      {
        // get the next visible node
        TTreeNode* NextNode =
          Selected->GetNextVisible();
 
        // toggle the currently selected
        // node based on the selected
        // state of the next node
        SelectNode(
          Selected,
          !IsNodeSelected(NextNode)
          );
      }
      // otherwise, deselect all nodes
      else SelectAll(false);
      break;
    }
  }
  // pass the messages on
  TTreeView::Dispatch(&Msg);
}
The logic behind this code is as follows: If the user holds down the shift key while navigating down (i.e., pressing the down arrow), grab a pointer to the next visible node, and then toggle the status of the currently-selected node based on the status of this next node. Why do you need to toggle the status of the currently selected node? Well, when the user holds down the shift key, this suggests that he or she intends to select a continuous range of nodes. If the next node isn?t selected, this means that the user has pressed the down arrow to add the next node to his or her current range. The tree-view will, by default, select the next node. But because the tree-view can have only one truly selected node, before it selects the next node, it will deselect the currently selected node. Therefore, when the user wants to add the next node to his or her range, you need to select the currently selected node (i.e., set the node?s Data property) because the tree-view will deselect it. On the other hand, if the user holds down the shift key while navigating down, but the next node isn?t selected, this means that the user wants to remove the currently selected from his or her range. In this case, you need to deselect the currently selected node. A similar argument can be made for the case in which the user has pressed the up arrow. Finally, notice that there?s no code to handle the case in which the user holds down the control key while pressing the arrows. For tree-views, the control key is used for scrolling via the keyboard. Keeping things in sync There?s one final step that needs to be addressed. You?ll want the Data property of tree-view?s truly selected node to always indicate true. This way, you can retrieve the selected nodes by using only the IsNodeSelected() method (within a while loop). Otherwise, you?d also have to test the tree-view?s Selected property. To keep the truly-selected node?s Data property updated, you can use the TTreeView::Change() method like so:
void __fastcall TMultiTreeView::
  Change(TTreeNode* Node)
{
  // store the previous node that
  // was selected without using
  // the shift key
  if (GetKeyState(VK_SHIFT) >= 0)
  {
    PreviousNode_ = Node;
  }
 
  // select the to-be-truly-selected node
  SelectNode(Node, true, false);
  TTreeView::Change(Node);
}
Note that in addition to setting the Data property of the truly selected node, this is where the PreviousNode_ member is set (when the shift key isn?t pressed). Conclusion I?ve shown how to add basic multiple-selection support to a standard tree-view control. You can download the source code for the TMultiTreeView class from www.bridgespublishing.com. I must warn you, however, that this code isn?t well suited for tree-views that contain numerous items (say, greater than 1000). The reason is that the SelectNodes() and SelectAllExcept() methods are relatively expensive because they use the AbsoluteIndex property. There are ways to speed things up (e.g., by using a TList object and/or comparing each node?s bounding rectangle instead of using its AbsoluteIndex property), but I?ll save that for another day. If you do have a large number of items, consider using a virtual-mode TListView object instead. Listing A: Definition of the TMultiTreeView class
class TMultiTreeView : public TTreeView
{
public:
  __fastcall TMultiTreeView(TComponent* Owner);
 
  virtual bool __fastcall IsNodeSelected(
    TTreeNode* Node);
  virtual void __fastcall RedrawNode(
    TTreeNode* Node);
  virtual void __fastcall SelectNode(
    TTreeNode* Node, bool select,
    bool redraw = true);
  virtual void __fastcall SelectNodes(
    TTreeNode* NodeA, TTreeNode* NodeB,
    bool select);
  virtual void __fastcall SelectAll(
    bool select);
  virtual void __fastcall SelectAllExcept(
    TTreeNode* NodeA, TTreeNode* NodeB,
    bool select);
 
protected:
  DYNAMIC void __fastcall Change(
    TTreeNode* Node);
 
private:
  TTreeNode* PreviousNode_;
  MESSAGE void __fastcall CNNotify(
    TMessage& Msg);
  MESSAGE void __fastcall WMKeyDown(
    TMessage& Msg);
  MESSAGE void __fastcall WMLButtonDown(
    TMessage& Msg);
 
public:
BEGIN_MESSAGE_MAP
  MESSAGE_HANDLER(
    CN_NOTIFY, TMessage, CNNotify)
  MESSAGE_HANDLER(
    WM_KEYDOWN, TMessage, WMKeyDown)
  MESSAGE_HANDLER(
    WM_LBUTTONDOWN, TMessage, WMLButtonDown)
END_MESSAGE_MAP(TTreeView)
};
Listing B: Definition of the TMultiTreeView::SelectNodes(), SelectAll(), and SelectAllExcept() methods
//-----------------------------------
// Selects all nodes that lie in 
// the range from NodeA to NodeB
// (or from NodeB to NodeA). 
//-----------------------------------
void __fastcall
  TMultiTreeView::SelectNodes(
    TTreeNode* NodeA,
    TTreeNode* NodeB,
    bool select
   )
{
  TTreeNode* FirstNode = NULL;
  TTreeNode* LastNode = NULL;
 
  if (NodeA && NodeB)
  {
    if (NodeA->AbsoluteIndex <
        NodeB->AbsoluteIndex)
    {
      FirstNode = NodeA;
      LastNode = NodeB;
    }
    else
    {
      FirstNode = NodeB;
      LastNode = NodeA;
    }
  }
  else if (NodeA && !NodeB)
  {
    FirstNode = NodeA;
  }
 
  SelectNode(FirstNode, select);
  while (FirstNode != LastNode)
  {
    FirstNode = FirstNode->GetNext();
    SelectNode(FirstNode, select);
  }
}
 
//-----------------------------------
// Selects all nodes.
//-----------------------------------
void __fastcall
  TMultiTreeView::SelectAll(bool select)
{
  SelectNodes(
    Items->GetFirstNode(), NULL, select);
}
 
//-----------------------------------
// Selects all nodes expect those in 
// the range from NodeA to NodeB.
//-----------------------------------
void __fastcall
  TMultiTreeView::SelectAllExcept(
    TTreeNode* NodeA,
    TTreeNode* NodeB,
    bool select
   )
{
  if (!NodeA || !NodeB) return;
 
  if (NodeA->AbsoluteIndex <
      NodeB->AbsoluteIndex)
  {
    if (NodeA->AbsoluteIndex > 0)
    {
      SelectNodes(
        Items->GetFirstNode(),
        NodeA->GetPrev(), select);
    }
    if (NodeB->AbsoluteIndex <
        Items->Count - 1)
    {
      SelectNodes(
        NodeB->GetNext(), NULL, select);
    }
  }
  else
  {
    if (NodeB->AbsoluteIndex > 0)
    {
      SelectNodes(
        Items->GetFirstNode(),
        NodeB->GetPrev(), select);
    }
    if (NodeA->AbsoluteIndex <
        Items->Count - 1)
    {
      SelectNodes(
        NodeA->GetNext(), NULL, select);
    }
  }
}
Copyright ? 2002, Bridges Publishing. All rights reserved. Reproduction in whole or in part in any form or medium without express written permission of Bridges Publishing is prohibited. All other product names and logos are trademarks or registered trademarks of their respective owners. 聯盟----Visita網站http://www.vista.org.tw ---[ 發問前請先找找舊文章 ]--- 發表人 - axsoft 於 2002/12/10 09:11:49
billlee
一般會員


發表:31
回覆:46
積分:15
註冊:2002-06-25

發送簡訊給我
#4 引用回覆 回覆 發表時間:2002-12-10 09:08:59 IP:61.56.xxx.xxx 未訂閱
axsoft謝謝你的資訊,我會去試試看的,很感激你。^_^ 發表人 - billlee 於 2002/12/11 11:29:47
billlee
一般會員


發表:31
回覆:46
積分:15
註冊:2002-06-25

發送簡訊給我
#5 引用回覆 回覆 發表時間:2002-12-11 11:38:58 IP:61.56.xxx.xxx 未訂閱
再請問一下 我有將axsoft給我的資料去看過,我也去compile過了 但是這是一個class,我不曉得要怎麼去使這個class生效, 是否有人有用過這個東西,可以教我一下,謝謝
axsoft
版主


發表:681
回覆:1056
積分:969
註冊:2002-03-13

發送簡訊給我
#6 引用回覆 回覆 發表時間:2002-12-11 14:46:27 IP:61.218.xxx.xxx 未訂閱
引言: 再請問一下 我有將axsoft給我的資料去看過,我也去compile過了 但是這是一個class,我不曉得要怎麼去使這個class生效, 是否有人有用過這個東西,可以教我一下,謝謝
這有個Source Code 參考一下,與上面的文章內容是同一個 http://www.bridgespublishing.com/articles/source/August02Code.zip 聯盟----Visita網站http://www.vista.org.tw ---[ 發問前請先找找舊文章 ]--- 發表人 - axsoft 於 2002/12/11 15:05:11
billlee
一般會員


發表:31
回覆:46
積分:15
註冊:2002-06-25

發送簡訊給我
#7 引用回覆 回覆 發表時間:2002-12-11 16:35:14 IP:61.56.xxx.xxx 未訂閱
引言:
引言: 再請問一下 我有將axsoft給我的資料去看過,我也去compile過了 但是這是一個class,我不曉得要怎麼去使這個class生效, 是否有人有用過這個東西,可以教我一下,謝謝
這有個Source Code 參考一下,與上面的文章內容是同一個 http://www.bridgespublishing.com/articles/source/August02Code.zip 聯盟----Visita網站http://www.vista.org.tw ---[ 發問前請先找找舊文章 ]--- 發表人 - axsoft 於 2002/12/11 15:05:11
axsoft你好 這個的程式碼我有下載過來看過了,只有看到你給我的資料一開始定義在Form上執行的方法,我想要知道的是後面不是有定義class嗎,我想知道要怎麼用TMultiTreeView這個Class,謝謝
系統時間:2024-03-29 18:21:02
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!