• DrGraph软件升级:工程优化1


    1. 起因

    在DrGraph中,共分三个层次文件:工程、库、图。这是N久以前的处理方式及实现方式。现在看来,这种划分方式倒是很经典,多个IDE都采用这种模式,比如PROTEL。

    只是现在,越来越发现,工程实现的最终结果不尽如人意。每次运行,它时不时的要刷新多遍,尤其是工程中文件比较多的时候。仔细看一下代码,原来以前是用TreeView实现的,为了达到界面效果,采用了较多的自画处理:

    void __fastcall TProjectViewForm::TreeView1CustomDraw(

    TCustomTreeView *Sender, const TRect &ARect, bool &DefaultDraw)

    {

    DrawBackgound(Sender->Canvas, Sender, GlobalBrushData, false);

    }

     

    const int FButtonSize = 5;

    void __fastcall DrawButton(TTreeView * TV, TRect* ARect, TTreeNode* Node)

    {

    int cx, cy;

    cx = ARect -> Left + (TV -> Indent) / 2;

    cy = ARect -> Top + (ARect -> Bottom - ARect -> Top) / 2;

    // TV -> Canvas -> Pen -> Color = ButtonColorDialog -> Color;

    // draw horizontal line.

    if (Node -> HasChildren) {

    TV -> Canvas -> PenPos = Point(cx, cy);

    TV -> Canvas -> LineTo(ARect -> Left + TV -> Indent + FButtonSize, cy);

    }

    else {

    TV -> Canvas -> PenPos = Point(cx, cy);

    TV -> Canvas -> LineTo(ARect -> Left + TV -> Indent + FButtonSize, cy);

    }

    // draw half vertical line, top portion.

    TV -> Canvas -> PenPos = Point(cx, cy);

    TV -> Canvas -> LineTo(cx, (ARect -> Top) - 1);

    if ( ((Node -> GetNextVisible() != NULL) && (Node -> GetNextVisible() -> Level == Node -> Level))

    || (Node -> getNextSibling() != NULL) ) {

    // draw bottom portion of half vertical line.

    TV -> Canvas -> PenPos = Point(cx, cy);

    TV -> Canvas -> LineTo(cx, ARect -> Bottom + 1);

    }

    if (Node -> HasChildren) {

    // Let's try a circular button instead

    TV -> Canvas -> Ellipse(cx - FButtonSize, cy - FButtonSize, cx + FButtonSize, cy + FButtonSize);

    // draw the horizontal indicator.

    TV -> Canvas -> PenPos = Point(cx - FButtonSize + 2, cy);

    TV -> Canvas -> LineTo(cx + FButtonSize - 2, cy);

    }

    // draw the vertical indicator if the node is collapsed

    if ( !(Node -> Expanded) ) {

    TV -> Canvas -> PenPos = Point(cx, cy - FButtonSize + 2);

    TV -> Canvas -> LineTo(cx, cy + FButtonSize - 2);

    // now connect vertical lines of higher level nodes.

    Node = Node -> Parent;

    }

    while (Node != NULL) {

    cx -= TV -> Indent;

    if (Node -> getNextSibling() != NULL) {

    TV -> Canvas -> PenPos = Point(cx, ARect -> Top);

    TV -> Canvas -> LineTo(cx, ARect -> Bottom);

    }

    Node = Node -> Parent;

    }

    }

     

    void __fastcall DrawImage(TTreeView * TV, TRect* NodeRect, int ImageIndex)

    {

    TCustomImageList * ImageList = TV->Images;

    if(!ImageList) return;

    int cy;

    cy = NodeRect -> Top + (NodeRect -> Bottom - NodeRect -> Top) / 2;

    // center image in NodeRect.

    ImageList -> Draw(TV -> Canvas, NodeRect -> Left, cy - TV -> Images -> Height / 2, ImageIndex, true);

    }

     

    void __fastcall TProjectViewForm::TreeView1CustomDrawItem(

    TCustomTreeView *Sender, TTreeNode *Node, TCustomDrawState State,

    bool &DefaultDraw)

    {

    TTreeView * TV = dynamic_cast<TTreeView *>(Sender);

    if(!TV) return;

    TRect NodeRect;

    DefaultDraw = false;

    if (State.Contains(cdsSelected))

    NodeRect = Node -> DisplayRect(true);

    NodeRect = Node -> DisplayRect(false);

    TV->Canvas->Brush->Style = bsClear;

    TV->Canvas->Pen->Color = clBlack;

     

    NodeRect.Left = NodeRect.Left + ((Node->Level) * (TV->Indent));

    DrawButton(TV, &NodeRect, Node);

    NodeRect.Left = NodeRect.Left + TV -> Indent + FButtonSize;

    // NodeRect.Left is now the leftmost portion of the image.

    DrawImage(TV, &NodeRect, Node -> ImageIndex);

    NodeRect.Left = NodeRect.Left + TV->Images -> Width;

    // Now we are finally in a position to draw the text.

    TV -> Canvas -> TextOut(NodeRect.Left, NodeRect.Top, Node -> Text);

    }

    自画中,画出按钮与图标,相当费时。

    并且,为了达到另一种效果,即在TreeView中只显示文件名称,而在右侧可显示路径,再另维护了一个TStringList,各种处理均会相应更新。

    这一来二回的,那个刷新频率是相当的高,而速度还不快,给用户体验造成极大的不爽感觉。

    看看CB的实现效果,应该是比较清爽的。

    之前的工程效果是3、5年前实现的,现在有新的控件,可以改进下的了。

     

    稍加感受,即选定TcxTreeView控件。加入之:

    object TreeView_Project: TcxTreeView

    Left = 7

    Top = 20

    Width = 385

    Height = 412

    Anchors = [akLeft, akTop, akBottom]

    TabOrder = 4

    ExplicitHeight = 429

    End

    1. 打开工程

    首先处理打开工程,即工程内容要加入到该树形控件中,这样也便于看看实现效果:

            CbwXML * xml = new CbwXML(FProjectName, "");

            xml->Read();

            CbwXmlNode * RootNode = xml->RootNode;

            if (RootNode->ElementNumber) {

                ProjectBasePath = ExtractFilePath(FProjectName);

                UnicodeString projectName = ExtractFileName(FProjectName);

                TTreeNode * firstcxTreeNode = FTreeView_Project->Items->AddChild(NULL, projectName);

                CbwXmlNode * firstXmlNode = RootNode->Elements(0);

                LoadTreeNodeFromXmlNodeInFileFormat(firstcxTreeNode, firstXmlNode);

     

    其中,将XML对应的工程结构递归方式保存到树形节点中:

    void __fastcall LoadTreeNodeFromXmlNodeInFileFormat(TTreeNode * node, CbwXmlNode * xmlNode, //bool beginFlag = true,

        bool refreshProjectFlag = false) {

        QA_LOG_FUNCTION("__fastcall LoadTreeNodeFromXmlNodeInFileFormat");

        TTreeView * view = dynamic_cast<TTreeView*>(node->TreeView);

        if (!view)

            return;

     

        for (int i = 0; i < xmlNode->ElementNumber; ++i) {

            CbwXmlNode * childNode = xmlNode->Elements(i);

            UnicodeString tag = childNode->Name;

            UnicodeString fileName = childNode->Value;

            if (childNode->ContainAttribute("name"))

                fileName = childNode->AttributeValueByName("name");

            if (SameText(tag, "File"))

                view->Items->AddChild(node, fileName);

            else if (SameText(tag, "Directory")) {

                CbwXmlNode * destNode = childNode;

                if (!refreshProjectFlag) {

                    fileName = childNode->Elements(0)->Value;

                    destNode = childNode->Elements(1);

                }

                TTreeNode * subNode = view->Items->AddChild(node, fileName);

                LoadTreeNodeFromXmlNodeInFileFormat(subNode, destNode, refreshProjectFlag);

            }

        }

    }

     

    这段代码是以前经过千锤百炼的,应该没有问题。运行后,打开工程,界面OK。

    速度确实快多了,界面也清爽,看来这个选择没错。

    好象有点不足,TcxTreeView中,节点数目较多时,也不显示滚动条?

    在ObjectInspector中找了半天没找到相应的设置地方,转向GOOGLE搜索内容:tcxtreeview 滚动条 devexpress

    结果GOOGLE出来两条结果!!!

    尝试了一下百度,居然找到102个。这好象是我第一次用百度超过GOOGLE!!

    找到一条有用的信息:

    TreeView 控件没有内置的滚动。 若要添加滚动,请将 TreeView 控件放置在 Panel 控件中,并将滚动条添加到 Panel 控件。 有关更多信息,请参见 Panel Web 服务器控件概述。 

    暂且不管它,以后再说。

    1. 图标

    最简单的办法是查帮助

    Provides state images to be displayed within tree nodes. Syntax

    property StateImages: TCustomImageList;

    Description cxTreeView enables you to display up to two images within each node. By default, no images are displayed. If you need additional images to be displayed within nodes, assign the TImageList component storing the desired images to the StateImages property. You can then choose an image from the list to be displayed within the node by setting the node's StateIndex property.
    The following is a handler for the form's OnCreate event. It is used to create an image list, add two images corresponding to checked and unchecked states and assign the unchecked image to every item.

    [Delphi]

    procedure TForm1.FormCreate(Sender: TObject);

    var

    ImageList: TImageList;

    Image: TBitmap;

    I: Integer;

    begin

    ImageList := TImageList.Create(Self);

    ImageList.AddMasked(nil, $000000);

    Image := TBitmap.Create;

    Image.LoadFromFile('c:\Images\checked.bmp');

    ImageList.AddMasked(Image, $FF00FF);

    Image.LoadFromFile('c:\Images\unchecked.bmp');

    ImageList.AddMasked(Image, $FF00FF);

    cxTreeView1.StateImages := ImageList;

    for I := 0 to cxTreeView1.Items.Count - 1 do

    cxTreeView1.Items[I].StateIndex := 2;

    end;


    The OnClick event of the tree view control must be handled in the following manner to perform image toggling.

    [Delphi]

    procedure TForm1.cxTreeView1Click(Sender: TObject);

    var

    MousePos: TPoint;

    Node: TTreeNode;

    begin

    MousePos := Mouse.CursorPos;

    MousePos := cxTreeView1.ScreenToClient(MousePos);

    Node := cxTreeView1.GetNodeAt(MousePos.X, MousePos.Y);

    if Node <> nil then

    if htOnStateIcon in cxTreeView1.GetHitTestInfoAt(MousePos.X, MousePos.Y) then

    begin

    if Node.StateIndex = 2 then

    Node.StateIndex := 1

    else

    Node.StateIndex := 2;

    end;

    end;


    The image below shows the appearance of the control.


    Please refer to the Displaying Images within Tree View Nodes topic for a complete list of ways in which to assign images to nodes.

     

    Displaying Images within Tree View Nodes

    By default (if the tree view is not custom painted) two images can be displayed within each node.
    If you need a single image to be displayed within nodes, you first need to create the image source and then assign them to nodes in the desired manner. The image source is specified by the Images property of the tree view control. Assign an image list (the TImageList component) containing the desired images to this property. Images can be associated with nodes using the nodes' ImageIndex and SelectedIndex properties. These properties specify images that will be displayed within the node when it is in its normal state and selected respectively. Note that images are specified by indexes in the source collection.
    There are three methods to specify values of the ImageIndex and SelectedIndex properties. The first is to use the TreeView Items Editor dialog. This dialog can be invoked by clicking the ellipsis button corresponding to the Items property of the control.


    Use the edit boxes corresponding to the Image Index and Selected Index properties to specify image indexes. The edit box corresponding to the State Index property is used to assign a second image to a node (discussed below).
    At runtime, you can choose two ways of specifying images. The first is to assign desired values to the ImageIndex and SelectedIndex properties directly. If, however, you have a common logic for node image assignment, it is most appropriate to use the OnGetImageIndex and OnGetSelectedIndex events. These events fire each time an image must be obtained for the node (when the application starts, when the expanded state of a node is changed and when a node is selected).
    Note that you can also use overlay images. These are the images displayed over the ones specified by methods described above. Displaying such images is useful, for instance, if you need a red X over node images that are no longer available. Use the OverlayIndex node property to specify its overlay image.
    You can also display additional images within nodes. The source of these images is specified by the StateImages property of the control. Images are associated with nodes using the nodes' StateIndex property. Please refer to the StateImages property description for an example of using additional images within nodes to imitate check boxes.
    Note that you can custom paint nodes or the entire tree view. In this instance, you are free to display anything you like within nodes. Please refer to the OnCustomDraw, OnAdvancedCustomDraw, OnCustomDrawItem and OnAdvancedCustomDrawItem event descriptions for details.

     

    查了半天,还是用ImageIndex,先到www.easyicon.cn下载几个图标。PNG格式,透明哈。

    代码就不写了,不过是设置Node的ImageIndex属性值而已。

    运行结果,不由小吃一惊:

    PNG格式居然为黑底,这可不行。继续查:

    PNG在Delphi中显示有黑色背景的问题解决

    前一段时间写一个程序,ImageList中添加PNG图片,Toolbar引用ImageList中的PNG图片时,图片背景是黑色,

    其实只要设置ImageList的一个属性:ColorDepth设置成cd32Bit就可以了。

    兴致勃勃回到IDE,设置ImageList的ColorDepth,却是傻眼了,ImageList被清空了

    之前的

    设置之后:

    赶紧关闭文件,不保存,不然重加图标,可要累死个人了。

    看来,在Inspector中设置ColorDepth属性,会调用该属性的写方法。另辟蹊径吧,这个难不倒我。

    直接修改DFM文件,这总可以了吧。居然进不去!!

    而用文本编辑器打开DFM文件,还有乱码!

    我今天倒不信搞不定这个小东东。关闭工程,直接打开该CPP文件,然后…,这世界太平了。

    object SmallImages: TImageList

    ColorDepth = cd32Bit

    Left = 549

    Top = 65520

    Bitmap = {

    494C010195000801640010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600

    0000000000003600000028000000400000006002000001002000000000000060

         …

        }

    这下回眸一笑百媚生哈。运行一下,看上帝哈:

    1分钟后,感叹一下:唉,没用的

    还是用BMP图片吧。用PS处理一下就好了。

    留下一个疑问:为什么同样是PNG,同样在ImageList中,在别的地方是透明的,在TreeView中就是黑底的了呢?

    这个问题,折腾了一个小时,晕菜。

    1. 关闭工程

    关闭工程也太简单了吧。

    bool __fastcall TCbwFileModule::CloseProject() {

        QA_LOG_FUNCTION("TCbwFileModule::CloseProject"); // 关闭工程

        FProjectName = "";

        if (CanCloseProject() == false)

            return false;

        TreeView_Project->Items->Clear();

        FFile = NULL;

        FlushVector(FFileMaps, true);

        FOwnerForm->EnableAllControlsInMainForm();

        return true;

    }

    关闭后,回到初始状态,为空而已。

  • 相关阅读:
    接口开发
    操作Excel
    操作mongodb
    sys模块
    操作redis
    操作数据库
    日志生成、发送邮件
    Codeforces Round #487 (Div. 2)
    bitset学习
    Training for 分块&莫队
  • 原文地址:https://www.cnblogs.com/drgraph/p/3023608.html
Copyright © 2020-2023  润新知