精华内容
下载资源
问答
  • 简 述: 目录树组件QTreeWidget和停靠区域组件QDockWidget的和QScrollArea用法;然后写的一个小的相册查看器例子 文章目录QTreeWidget组件:QDockWidget组件:**allowedAreas**属性,设置允许停靠区域**feat**属性...

    简 述: 目录树组件QTreeWidget和停靠区域组件QDockWidget的和QScrollArea用法;然后写的一个小的相册查看器例子

    本篇的csdn/github.io同步博文: 目录树组件QTreeWidget和停靠区域组件QDockWidget的用法


    QTreeWidget组件:

    QTreeWidget目录树组件 控件,用来创建和管理树形结构的类的


    QDockWidget组件:

    QDockWidget是可以在QMainWindow窗口停靠,或者在桌面最上层浮动的界面组件;在本文里面的例子里面,将QTreeWidget控件存放在QDockWidget上面,设置其可以在主窗口的左或右侧,也是可以浮动的,还可以浮动;还可以设置其为隐藏/显示不显示窗体的效果

    allowedAreas属性,设置允许停靠区域

    使用setAllowedAreas()设置允许停靠区域(上下左右的区域)

    feat属性,设置停靠区组件的特性

    setFeatures()函数来设置停靠区域组件的特性,其参数是如下的枚举类型的组合值的使用

    ConstantDescription
    QDockWidget::DockWidgetClosable停靠区域可关闭
    QDockWidget::DockWidgetMovable停靠区域可移动
    QDockWidget::DockWidgetFloatable停靠区域可浮动
    QDockWidget::DockWidgetVerticalTitleBar在停靠区域左侧显示垂直标题栏
    QDockWidget::AllDockWidgetFeatures使用以上所有特征
    QDockWidget::NoDockWidgetFeatures不能停靠,移动和关闭

    QScrollArea组件:

    QScrollArea是一个自动滚区域组件的控件,可以用来实现有比较长的显示内容。


    运行效果:

    这种gif录制了一下午(N多次,就是没有特别满意,要么太大要么不清晰),但是gif好像录制的并不算太好,录制这张图,但是总是体积太大或者不清晰,在mac上面暂时没有找到比较好的录制和压缩gif的软件来代替win10上面的(ScreenGif + FSREsizer + FSCapture)这三个软件,有合适的话,可以知道的可以留言推荐一下,合适和录gif工具也在尝试中;


    实现代码:

    编程环境: MacOS 10.14.6 (18G103) 编程软件: Qt 5.9.8Qt Creator 4.8.2;

    在**.h**头文件里面,实现非部分代码:

    #ifndef EXQTREEWIDGET_H
    #define EXQTREEWIDGET_H
    
    #include <QMainWindow>
    #include <QLabel>
    #include <QTreeWidgetItem>
    #include <QFileDialog>
    
    namespace Ui {
    class ExQTreeWidget;
    }
    
    class ExQTreeWidget : public QMainWindow
    {
        Q_OBJECT
    
    public:
    
        enum treeItemType {         //枚举,节点类型
            itemRoot,
            itemFile,
            itemImage
        };
    
        enum treeColNum {           //目录树列表的编号
            colItem = 0,
            colItemType = 1
        };
    
        explicit ExQTreeWidget(QWidget *parent = nullptr);
        ~ExQTreeWidget();
    
        void initTree();                                                //初始化根节点(唯一)
        void addFolderItem(QTreeWidgetItem *parItem, QString dirName);  //添加目录
        void addImageItem(QTreeWidgetItem *parItem, QString fileName);  //添加图片文件
        QString getFinalFolderName(const QString &pathName);            //从完整的路径里面,获取最后的文件夹名称
        void changeItemCaption(QTreeWidgetItem* parItem);               //遍历item下面的所有节点
        void displayImage(QTreeWidgetItem* item);                       //显示当前item的图片(默认以适配高度)
    
    private slots:
        void on_actAddFolder_triggered();                               //增加文件夹
        void on_actAddFile_triggered();                                 //添加图片文件
        void on_actDeleFile_triggered();                                //删除节点
        void on_actScanItems_triggered();                               //遍历所有的顶层节点(本处只有一个root顶层节点)
        void on_actAdaptiveHeight_triggered();                          //图片自动适应高度
        void on_actAdaptiveWidth_triggered();                           //图片自动适应宽度
        void on_actAmplification_triggered();                           //放大
        void on_actShrink_triggered();                                  //缩小
        void on_actZoomRealSize_triggered();                            //还原
        void on_actDockFloating_triggered(bool check);                  //设置Dock窗口是否浮动
        void on_actDockVisible_triggered(bool checked);                 //设置Dock窗口是否隐藏不显示
        void on_actQiut_triggered();                                    //退出
        void on_treeFiles_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous);  //当前节点变化的时候,自动加载当前图片
        void on_dockWidget_visibilityChanged(bool visible);             //单击DockWidget组件的标题栏的关闭按钮时候,会隐藏在停靠区域,并且发射信号visibilityChanged;  停靠区域可见性变化
        void on_dockWidget_topLevelChanged(bool topLevel);              //当拖动DockWidget组件,使其浮动或者停靠时候,会发射信号topLevelChanged;  更新其Action的状态
    
    private:
        Ui::ExQTreeWidget *ui;
    
        QLabel *m_labFlie;      //状态栏显示当前文件路径
        QPixmap m_curPixmap;    //显示当前文件图片
        float   m_ratio;        //图片缩放比例
    
    };
    
    #endif // EXQTREEWIDGET_H
    

    对应的**.cpp**文件:

    #include "ExQTreeWidget.h"
    #include "ui_ExQTreeWidget.h"
    
    ExQTreeWidget::ExQTreeWidget(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::ExQTreeWidget)
    {
        ui->setupUi(this);
        setWindowTitle(QObject::tr("QTreeWidget和QDockWidget的讲解和使用"));
    
        setCentralWidget(ui->scrollArea);                //设置scrollArea为中心控件
        initTree();
    
        m_labFlie = new QLabel("当前文件的路径:", this);
        ui->statusBar->addWidget(m_labFlie);
    }
    
    ExQTreeWidget::~ExQTreeWidget()
    {
        delete ui;
    }
    
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    //初始化根节点(只能够有唯一)
    void ExQTreeWidget::initTree()
    {
        //准备工作
        ui->treeFiles->clear();
        QString dataStr = "";
        QIcon icon;
        icon.addFile(":/image/Image001.jpg");
    
        //创建唯一root的节点
        QTreeWidgetItem* root = new QTreeWidgetItem(treeItemType::itemRoot);
        root->setIcon(treeColNum::colItem, icon);
        root->setText(treeColNum::colItem, QString("相簿"));
        root->setText(treeColNum::colItemType, QString("treeItemType"));
        root->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsAutoTristate);
        root->setCheckState(treeColNum::colItem, Qt::Unchecked);
        root->setData(treeColNum::colItem, Qt::UserRole, QVariant(dataStr));
    
        //添加顶层节点
        ui->treeFiles->addTopLevelItem(root);
    }
    
    //添加目录节点
    void ExQTreeWidget::addFolderItem(QTreeWidgetItem *parItem, QString dirName)
    {
        QIcon icon;
        icon.addFile(":/image/Image006.jpg");
    
        //添加一个新的节点
        QTreeWidgetItem* item = new QTreeWidgetItem(treeItemType::itemFile);
        QString folderName = getFinalFolderName(dirName);
        item->setIcon(treeColNum::colItem, icon);
        item->setText(treeColNum::colItem, folderName);
        item->setText(treeColNum::colItemType, QString("treeItemType"));
        item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsAutoTristate);
        item->setCheckState(treeColNum::colItem, Qt::Unchecked);
        item->setData(treeColNum::colItem, Qt::UserRole, QVariant(dirName));
    
        //添加子节点
        if (parItem->type() == treeItemType::itemFile) {                 //若是文件节点
            parItem->addChild(item);
        } else if (parItem->type() == treeItemType::itemRoot) {          //若是唯一root节点
            QTreeWidgetItem *root = ui->treeFiles->topLevelItem(0);
            root->addChild(item);
        }
    
    }
    
    //添加图片节点
    void ExQTreeWidget::addImageItem(QTreeWidgetItem *parItem, QString fileName)
    {
        if (parItem == nullptr)
            return;
    
        QIcon icon;
        icon.addFile(":/image/Image014.jpg");
    
        //添加一个新的节点
        QTreeWidgetItem* item = new QTreeWidgetItem(treeItemType::itemImage);
        QString folderName = getFinalFolderName(fileName);
        item->setIcon(treeColNum::colItem, icon);
        item->setText(treeColNum::colItem, folderName);
        item->setText(treeColNum::colItemType, QString("treeItemType"));
        item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsAutoTristate);
        item->setCheckState(treeColNum::colItem, Qt::Unchecked);
        item->setData(treeColNum::colItem, Qt::UserRole, QVariant(fileName));
    
        //添加子节点
        if (parItem->type() == treeItemType::itemFile) {                 //若是文件节点
            parItem->addChild(item);
        } else if (parItem->type() == treeItemType::itemRoot) {          //若是唯一root节点
            QTreeWidgetItem *root = ui->treeFiles->topLevelItem(0);
            root->addChild(item);
        }
    }
    
    //从完整的路径里面,获取最后的文件夹名称
    QString ExQTreeWidget::getFinalFolderName(const QString &pathName)
    {
        QString path = pathName;
        int cnt = pathName.count();
        int i = pathName.lastIndexOf("/");
        QString str = pathName.right(cnt - i - 1);
        return str;
    }
    
    //遍历传进来的父节点下的所有子节点;每遍历过该节点,就在其节点的信息加一个#
    void ExQTreeWidget::changeItemCaption(QTreeWidgetItem *parItem)
    {
        QString str = "# " + parItem->text(treeColNum::colItem);
        parItem->setText(treeColNum::colItem, str);
    
        if (parItem->childCount() < 0)
            return;
    
        for (int i = 0; i < parItem->childCount(); i++) {
            changeItemCaption(parItem->child(i));                       //回调,调用自己
        }
    }
    
    //显示当前item的图片(默认以适配高度)
    void ExQTreeWidget::displayImage(QTreeWidgetItem *item)
    {
        QString fileName = item->data(treeColNum::colItem, Qt::UserRole).toString();
        m_labFlie->setText(fileName);
        m_curPixmap.load(fileName);                                     //从文件载入图片
        on_actAdaptiveHeight_triggered();                               //自动适应高度显示
    
        ui->actAmplification->setEnabled(true);
        ui->actShrink->setEnabled(true);
        ui->actZoomRealSize->setEnabled(true);
        ui->actAdaptiveHeight->setEnabled(true);
        ui->actAdaptiveWidth->setEnabled(true);
    }
    
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    //增加文件夹
    void ExQTreeWidget::on_actAddFolder_triggered()
    {
        QString path = QFileDialog::getExistingDirectory();             //选择目录
    
        if (! path.isEmpty()) {
            QTreeWidgetItem* item = ui->treeFiles->currentItem();       //获取当前节点
    
            if(item != nullptr)
                addFolderItem(item, path);
        }
    }
    
    //添加图片
    void ExQTreeWidget::on_actAddFile_triggered()
    {
        QStringList list = QFileDialog::getOpenFileNames(this, "选择多个将要加载的图片", "", "Images(*.jpg, *.png, *.*)");         //选择目录
    
        if (! list.isEmpty()) {
            QTreeWidgetItem* parItem = nullptr;
            QTreeWidgetItem* item = ui->treeFiles->currentItem();       //获取当前节点
    
            if (item == nullptr)
                return;
    
            if (item->type() == treeItemType::itemImage) {              //获得父节点
                parItem = item->parent();
            } else {
                parItem = item;
            }
    
            for (int i = 0; i < list.size(); i++) {
                QString strName = list.at(i);                          //获得文件名称
                addImageItem(parItem, strName);                        //添加图片文件到文件节点
            }
        }
    }
    
    //删除节点
    void ExQTreeWidget::on_actDeleFile_triggered()
    {
        QTreeWidgetItem* parItem = nullptr;
        QTreeWidgetItem* currItem = ui->treeFiles->currentItem();
    
        if (currItem->type() != treeItemType::itemRoot)
            parItem = currItem->parent();                              //只能够由其父节点删除
    //    else
    //        ui->treeFiles->takeTopLevelItem(0);                      //删除顶层节点使用这个
    
        if (currItem == nullptr || parItem == nullptr)
            return;
    
        parItem->removeChild(currItem);                                //移除没有从内存中删除,所以delete删除
        delete currItem;
    }
    
    //遍历所有的顶层节点(本处只有一个root顶层节点)
    void ExQTreeWidget::on_actScanItems_triggered()
    {
        for (int i = 0; i < ui->treeFiles->topLevelItemCount(); i++) {
            QTreeWidgetItem* currItem = ui->treeFiles->topLevelItem(i); //顶层item
            changeItemCaption(currItem);
        }
    }
    
    //图片自动适应高度
    void ExQTreeWidget::on_actAdaptiveHeight_triggered()
    {
        int height = ui->scrollArea->height();                        //得到scrollArea的高度
        int realHeight = m_curPixmap.height();                        //原始图片的实际高度
        m_ratio = height * 1.0 / realHeight;                          //当前显示比例,必须转换为浮点数
    
        QPixmap pixmap = m_curPixmap.scaledToHeight(height - 50);     //图片缩放到指定高度
        ui->labDisplay->setPixmap(pixmap);                            //设置Label的PixMap
    }
    
    //图片自动适应宽度
    void ExQTreeWidget::on_actAdaptiveWidth_triggered()
    {
        int width = ui->scrollArea->width();
        int realWidth = m_curPixmap.width();
        m_ratio = width * 1.0 / realWidth;
    
        QPixmap pixmap = m_curPixmap.scaledToHeight(width - 50);
        ui->labDisplay->setPixmap(pixmap);
    }
    
    //当前节点变化的时候,自动加载当前图片
    void ExQTreeWidget::on_treeFiles_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous)
    {
        if (current != nullptr && previous != nullptr) {
            displayImage(current);
        }
    }
    
    
    //放大
    void ExQTreeWidget::on_actAmplification_triggered()
    {
        m_ratio *= 1.2;                                             //在当前比例基础上乘以0.8
        int height = m_curPixmap.height() * m_ratio;                // 显示宽度
        int widht = m_curPixmap.width() * m_ratio;                  // 显示宽度
    
        QPixmap pix = m_curPixmap.scaled(widht, height);            //图片缩放到指定高度和宽度,保持长宽比例
        ui->labDisplay->setPixmap(pix);
    
    }
    
    //缩小
    void ExQTreeWidget::on_actShrink_triggered()
    {
        m_ratio *= 0.8;
        int height = m_curPixmap.height() * m_ratio;
        int widht = m_curPixmap.width() * m_ratio;
    
        QPixmap pix = m_curPixmap.scaled(widht, height);
        ui->labDisplay->setPixmap(pix);
    }
    
    //还原
    void ExQTreeWidget::on_actZoomRealSize_triggered()
    {
        m_ratio = 1;
        int height = m_curPixmap.height();
        int widht = m_curPixmap.width();
    
        QPixmap pix = m_curPixmap.scaled(widht, height);
        ui->labDisplay->setPixmap(pix);
    }
    
    //设置Dock窗口是否浮动
    void ExQTreeWidget::on_actDockFloating_triggered(bool check)
    {
        ui->dockWidget->setFloating(check);
    }
    
    //设置Dock窗口是否隐藏不显示
    void ExQTreeWidget::on_actDockVisible_triggered(bool checked)
    {
        ui->dockWidget->setVisible(!checked);
    }
    
    //退出
    void ExQTreeWidget::on_actQiut_triggered()
    {
        close();
    }
    
    //单击DockWidget组件的标题栏的关闭按钮时候,会隐藏在停靠区域,并且发射信号visibilityChanged;  停靠区域可见性变化
    void ExQTreeWidget::on_dockWidget_visibilityChanged(bool visible)
    {
        ui->actDockVisible->setChecked(visible);
    }
    
    //当拖动DockWidget组件,使其浮动或者停靠时候,会发射信号topLevelChanged;  更新其Action的状态
    void ExQTreeWidget::on_dockWidget_topLevelChanged(bool topLevel)
    {
        ui->actDockFloating->setChecked(topLevel);
    }
    

    源码下载:

    https://github.com/xmuli/QtExamples【QtQTreeWidgetEx】

    展开全文
  • 文章目录6.4 滚动区域6.5 停靠窗口和工具栏 6.4 滚动区域 QScrollArea类提供了一个可以滚动的视口和两个滚动条。如果想给一个窗口部件添加一个滚动条,则可以使用一一个QScrollArea类来实现,这可能要比我们自己通过...

    6.4 滚动区域

    QScrollArea类提供了一个可以滚动的视口和两个滚动条。如果想给一个窗口部件添加一个滚动条,则可以使用一一个QScrollArea类来实现,这可能要比我们自己通过初始化QScrollBar,然后再实现它的滚动等功能简单得多。

    QScrollArea的使用方法,就是以我们想要添加滚动条的窗口部件为参数调用setWidget()。如果这个窗口部件的父对象不是视口,QSrollArea会自动把这个窗口部件的父对象重定义为该视口(可以通过QSrollArea::viewport( )来访问) ,并且让它成为视口的子对象。例如,如果想在第5章中开发的IconEditor 窗口部件的周围添加滚动条(如图6. 11所示),则可以编写如下代码:


    在QT中 WIdget在构建并显示以后会有一 个默认的大小,而此时其实已经存在窗口和视口,只是这两者在没有人为改变时大小是一样的,所以你可以忽略二者的存在;QT在绘图时是先在窗口中绘制然后再映射到视口上去的。 视口就是代表我们的物理窗口,窗口是代表绘图区(QT的画板)使用的逻辑坐标。 在两者相同的情况下也是一一映射关系,所以你会看到所画即所得。 但是当两者不同时,如果不理解就会觉得莫名其妙。
    原文链接:https://blog.csdn.net/qjclinux/article/details/82864316


    int main(int argc, char *argv[])
    {
        QApplication app(argc, argv);
        IconEditor iconEditor;
        iconEditor.setWindowTitle(QObject::tr("Icon Editor"));
        iconEditor.setIconImage(QImage(":/images/mouse.png"));
        //iconEditor.show();
        QScrollArea scrollArea;
        //error: C2664: “void QScrollArea::setWidget(QWidget *)”: 无法将参数 1 从“IconEditor”转换为“QWidget *”没有可用于执行该转换的用户定义的转换运算符,或者无法调用该运算符
        scrollArea.setWidget(iconEditor);
        scrollArea.viewport()->setBackgroundRole(QPalette::Dark);
        scrollArea.viewport()->setAutoFillBackground(true) ;
        scrollArea.setWindowTitle(QObject::tr("Icon Editor"));
        scrollArea.show();
    
        return app.exec();
    }
    

    图6.12给出了QSrollArea的原理图,它会以窗口部件的当前大小来显示它,或者在没有重新改变窗口部件大小的时候以它的大小提示来显示它。通过调用setWidgetResizable( true),可以告诉QSrollArea要自动重新改变该窗口部件的大小,以利用超过它的大小提示之外的任何多余空间。

    在这里插入图片描述

    默认情况下,只有在视口的大小小于子窗口部件的大小时,才会把滚动条显示出来。但通过设置滚动条的策略,可以强制滚动条总是可见:
    scrollArea. setHorizontalScrollBarPolicy(Qt: :ScrollBarAlways0n) ;
    scrollArea. setVerticalScrollBarPolicy(Qt: :Scro.llBarAlivays0n);
    QScrollArea从QAbstractSCrollArea继承了它的许多功能。像QTextEdit和QAbstractItemView(Qt
    项视图类的基类)这样的一些类,由于它们是从QAbstractSrollArea中派生出来的,所以为了获得滚
    动条,就没有必要再把它们封装在QScrollArea 中。

    6.5 停靠窗口和工具栏

    停靠窗口(dockwindow)是指一些可以停靠在QMainWindow中或是浮动为独立窗口的窗口。QMainWindow提供了4个停靠窗口区域;分别在中央窗口部件的上部、下部、左侧和右侧。诸如像Microsoft Visual Studio和Qt Linguist这样的应用程序都广泛使用了停靠窗口,以提供一种非常灵活的用户接口方式。在Qt中,各个停靠窗口都是QDockWidget的实例。图6.13给出了一个带有工具栏和停靠窗口的Qt应用程序。

    每一个停靠窗口都有自己的标题栏,即使它处于停靠时也是如此。通过拖拽这一标题栏,用户可以把停靠窗口从一个停靠区域移动到另外一个停靠区域。通过把这个停靠窗口拖动到其他停靠区域的外面,就可以把停靠窗口从一个停靠区域中分离出来,让它成为一个独立的窗口。自由浮动的停靠窗口总是显示在它们的主窗口的上面。通过点击窗口部件标题栏上的“关闭”按钮,就可以关闭QDockWidget。通过调用QDockWidget::setFeatures() ,就可以禁用所有这些特性以及它们的任意组合。

    在这里插入图片描述

    在Qt的早期版本中,工具栏采用与停靠窗口一样的处理方式,并且共享同一停靠区域。从Qt 4开始,工具栏围绕中央窗口部件,占有它们自己的区域(如图6.14所示),并且不能取消停靠(undock)。如果需要一个浮动工具栏,只需把它放进QDockWidget即可。

    在这里插入图片描述

    用虚线显示的四个角可以属于两个相邻停靠区域中的任何一个。例如,假定我们需要让左上角属于左侧的停靠区域,则只需调用QMainWindow::setCorner(Qt: : TopLeftCorner, Qt::LeftDockWidgetArea)即可。

    以下程序片段说明了如何对QDockWidget中已经存在的窗口部件(在这个例子中,就是一个QTreeWidget)进行封装,并把它插人到右侧的停靠区域:

    QDockWidget *shapesDockWidget = new QDockWidget(tr( "Shapes"));
    shapesDockWidget->set0bjectName("shapesDockwidget");
    shapesDockWidget->setWidget(treeWidget);
    shapesDockWidget->setAllowedAreas(Qt::LeftDockWidgetArea.|Qt::RightDockWidgetArea);
    addDockWidget (Qt::RightDockWidgetArea, shapesDockWidget);
    

    setAllowedAreas()调用说明对停靠区域加以限定即可以接受停靠窗口。在此给出的代码中,只允许把停靠窗口拖拽到左侧和右侧的停靠区域,这两个地方都有显示它的足够垂直空间,因而可以合理地把它显示出来。如果没有明确地设置所允许的区域,那么用户就可能把该停靠窗口拖动到这四个可停靠区域中的任何一个地方。

    每个QObject都可以给定一一个“对象名”。在进行程序调试时,这个名字会非常有用,并且一些测试工具也会用到它。通常,我们不必费劲地给定窗口部件的名字,但是在创建一些停靠窗口和工具栏时,如果希望使用QMainWindow::saveState( )和QMainWindow::restoreState()来保存、恢复停靠窗口和工具栏的几何形状及状态的话,给定窗口部件的名字就很有必要了。

    下面的代码显示了如何创建一个工具栏的过程,该工具栏包含一个QComboBox、一个QSpinBox和一些QToolButton。其中的这些QToolButton来自QMainWindow子类的构造函数:

    QToolBar *fontToolBar = new QToolBar(tr ("Font"));
    fontToolBar->set0bjectName ("fontToolBar");
    fontToolBar->addWidget (familyComboBox);
    fontToolBar->addWidget(sizeSpinBox);
    fontToolBar->addAction(boldAction);
    fontToolBar->addAction(italicAction);
    fontToolBar->addAction(underlineAction); 
    fontToolBar->setAllowedAreas(Qt::TopToolBarArea|Qt::BottomToolBarArea);
    addToolBar(fontToolBar);
    

    如果想保存所有停靠窗口和工具栏的位置,以使下一次运行应用程序时能够恢复它们的值,那么可以像以前在保存一个QSplitter的状态值时所使用的代码一样来编写类似的代码,也就是使用QMainWindow的saveState( )和restoreState()函数:

    void MainWindow::writeSettings()
    {
        QSettings settings("Software Inc.", "Icon Editor");
    
        settings.beginGroup("mainWindow");
        settings.setValue("geometry", saveGeometry());
        settings.setValue("state"saveState());
        settings.endGroup();
    }
    
    void MainWindow::readSettings()
    {
        QSettings settings("Software Inc.", "Icon Editor");
    
        settings.beginGroup("mainWindow");
        restoreGeometry(settings.value("geometry").toByteArray());
        restoreState(settings.value("state").toByteArray());
        settings.endGroup();
    }
    

    最后,QMainWindow提供了一个上下文菜单,其中列出了所有的停靠窗口和工具栏。图6.15给出了这个上下文菜单。用户可以使用这个菜单关闭和恢复停靠窗口,也可以用它隐藏和恢复工具栏。

    展开全文
  • 通过按钮触发,而不是鼠标拖拽,使一个处于停靠状态的CDockablePane变为浮动状态,同时设置它的size。或者让它停靠在一个设定的区域
  • qml dockwidget窗口停靠

    2021-06-09 19:32:20
    前面一篇文章介绍了KDDockWidgets的使用(文章在这里),其实主要目的就是为了用KDDockWidgets提供的Qt quick 下的窗口停靠功能。Qt原生部并没有提供Qt quick的dockwidget,也不知道为啥。其实窗口停靠功能其实是...

    前言

    前面一篇文章介绍了KDDockWidgets的使用(文章在这里),其实主要目的就是为了用KDDockWidgets提供的Qt quick 下的窗口停靠功能。Qt原生部并没有提供Qt quick的dockwidget,也不知道为啥。其实窗口停靠功能其实是非常常见的,但是Qt只支持QWidget的。
    KDDockWidgets刚好可以解决这个问题,详细介绍在之前的文章已经介绍过了,其功能比QDockWidget更加丰富。

    那么,今天就来看一下如何用KDDockWidgets做自己的在qml 下的窗口停靠功能

    修改文件

    KDDockWidgets的源码编译和demo演示具体可以参照上一篇文章,编译后默认安装位置是在C盘下:C:\KDAB\KDDockWidgets-1.4.0 ,在源码中定义了一个宏KDDOCKWIDGETS_QTQUICK,要使用Qt quick,我们需要修改一下头文件:
    打开C:\KDAB\KDDockWidgets-1.4.0_debug\include\kddockwidgets\Config.h,找到:

    #ifdef KDDOCKWIDGETS_QTQUICK
        ///@brief Sets the QQmlEngine to use. Applicable only when using QtQuick.
        void setQmlEngine(QQmlEngine *);
        QQmlEngine* qmlEngine() const;
    #endif
    

    将这个宏判断注释掉。

    //#ifdef KDDOCKWIDGETS_QTQUICK
        ///@brief Sets the QQmlEngine to use. Applicable only when using QtQuick.
        void setQmlEngine(QQmlEngine *);
        QQmlEngine* qmlEngine() const;
    //#endif
    
    

    然后再打开 C:\KDAB\KDDockWidgets-1.4.0_debug\include\kddockwidgets\QWidgetAdapter.h
    找到

    #if !defined(KDDOCKWIDGETS_QTWIDGETS) && !defined(KDDOCKWIDGETS_QTQUICK)
    # define KDDOCKWIDGETS_QTWIDGETS
    #endif
    

    修改为:

    #if !defined(KDDOCKWIDGETS_QTWIDGETS) && !defined(KDDOCKWIDGETS_QTQUICK)
    # define KDDOCKWIDGETS_QTQUICK
    #endif
    

    创建工程

    ok,接下来就可以创建我们自己的工程了,新建一个QML工程,写个简单的qml程序

    在pro工程文件中, CONFIG添加KDDockWidgets

    CONFIG += c++11 KDDockWidgets
    

    添加库引用:

    win32:CONFIG(release, debug|release): LIBS += -LC:/KDAB/KDDockWidgets-1.4.0/lib/ -lkddockwidgets1
    else:win32:CONFIG(debug, debug|release): LIBS += -LC:/KDAB/KDDockWidgets-1.4.0/lib/ -lkddockwidgets1d
    
    INCLUDEPATH += C:/KDAB/KDDockWidgets-1.4.0/include
    DEPENDPATH += C:/KDAB/KDDockWidgets-1.4.0/include
    

    写个简单的qml文件:

    import QtQuick 2.15
    import QtQuick.Window 2.15
    import com.kdab.dockwidgets 1.0 as KDDW
    
    Window {
        width: 1000
        height: 800
        visible: true
        title: qsTr("Hello World")
    
    
        Rectangle{
            id:rect
            width: parent.width
            height: 200
            color: "cyan"
        }
    
    
        KDDW.MainWindowLayout {
            width: parent.width
            height:parent.height - rect.height
            anchors.top:rect.bottom
    
            // Each main layout needs a unique id
            uniqueName: "MainLayout-1"
    
    
            KDDW.DockWidget {
                id: dock1
                uniqueName: "dock1" // Each dock widget needs a unique id
                Rectangle {
                    color: "pink"
                }
            }
    
            KDDW.DockWidget {
                id: dock2
                uniqueName: "dock2"
                Rectangle {
                    color: "yellow"
                }
            }
            KDDW.DockWidget {
                id: dock3
                uniqueName: "dock3"
                Rectangle {
                    color: "red"
                }
            }
    
            Component.onCompleted: {
                // Add dock4 to the Bottom location
                addDockWidget(dock1, KDDW.KDDockWidgets.Location_OnBottom);
                // Add dock5 to the left of dock4
                addDockWidget(dock2, KDDW.KDDockWidgets.Location_OnRight, dock1);
                addDockWidget(dock3, KDDW.KDDockWidgets.Location_OnTop);
            }
        }
    }
    
    

    main文件

    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    
    #include <kddockwidgets/Config.h>
    
    int main(int argc, char *argv[])
    {
    #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    #endif
    
        QGuiApplication app(argc, argv);
        auto flags = KDDockWidgets::Config::self().flags();
        KDDockWidgets::Config::self().setFlags(flags);
    
        QQmlApplicationEngine engine;
    
        KDDockWidgets::Config::self().setQmlEngine(&engine);
    
        const QUrl url(QStringLiteral("qrc:/main.qml"));
        QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                         &app, [url](QObject *obj, const QUrl &objUrl) {
            if (!obj && url == objUrl)
                QCoreApplication::exit(-1);
        }, Qt::QueuedConnection);
        engine.load(url);
    
        return app.exec();
    }
    
    

    然后将kddockwidgets1d.dll 库文件拷贝到程序输出目录后运行代码,效果如下:
    在这里插入图片描述

    注意,qml代码中只有包含在KDDW.MainWindowLayout区域下的KDDW.DockWidget 才可以实现dock效果,为了测试,我故意在顶部放了一个Rectangle,其实MainWindowLayout是一个QQuickItem,可以简单理解成一个qml中的Item,所以用法其实是一样的。在此基础上进行拓展就行了。

    外部库

    以上示例是在编译完源码并安装后直接引用,所以在工程文件中,CONFIG添加KDDockWidget就可以使用了,那如果没有安装KDDockWidget怎么用呢,这就需要直接添加外部库的方式来实现。为方便移植,我们直接在源码下新建一个文件夹,然后将相关的lib include 等都拷贝进去,然后创建一个pri文件:
    在这里插入图片描述

    !contains(INCLUDEDFIES, KDDockWidgets.pri) {
    INCLUDEDFIES += KDDockWidgets.pri
    
    win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -lkddockwidgets1
    else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -lkddockwidgets1d
    
    INCLUDEPATH += $$PWD/include
    DEPENDPATH += $$PWD/include
    
    }
    

    然后在主工程文件pro中添加:

    include(KDDockWidgets/KDDockWidgets.pri)
    

    ok,直接编译运行就可以了。

    自定义

    以上窗口的效果是KDDockWidget默认的,如果想自定义窗口样式,比如修改边距、标题栏等,就需要修改源码了,在前面的文章中讲到的源码,找到:KDDockWidgets\src\private\quick\qml
    在这里插入图片描述
    可以修改这里对应的qml文件,然后重新编译源码后生成动态库,就可以直接在自己的项目中使用了。

    展开全文
  • Windows 窗口停靠测试

    2021-03-05 12:52:52
    窗口设置停靠属性,当悬浮框拖入具有停靠属性的窗口内时,窗口显示停靠图标,当拖拽悬浮框的光标进入停靠图标内是,窗口动态显示停靠区域。当释放悬浮框时,悬浮框调整属性,变成停靠窗口的子窗口,并被放置于指定...

    窗口停靠的简单尝试

    窗口设置停靠属性,当悬浮框拖入具有停靠属性的窗口内时,窗口显示停靠图标,当拖拽悬浮框的光标进入停靠图标内是,窗口动态显示停靠区域。当释放悬浮框时,悬浮框调整属性,变成停靠窗口的子窗口,并被放置于指定区域。

    窗口停靠的尝试思路

    测试中,将创建三个窗口

    1、容器窗口:当拖拽独立窗口时,独立窗口停靠的容器,主窗口;

    2、拖拽窗口:未停靠时,它是一个前端窗口,没有WS_CHILD属性;停靠之后,将变成容器的一个子窗口

    3、停靠提示:停靠提示用于指示停靠信息,即当拖拽窗口处于浮动状态且行拖拽动作时,在容器窗口的中心会显示一个停靠的UI提示,这不一定非得是一个窗口,但为了UI方便,这里做了一个前置窗口。

    窗口停靠的几个问题

    1、拖拽窗口的拖拽动作捕捉:按照其达到的效果,需要在开始拖拽时,停靠提示需要前端显示,当停止拖拽的时候,停靠提示需要隐藏(不可见),目前只有一个WM_MOVE消息,该消息确实能够捕捉到拖拽动作,但是停止拖拽的动作(即鼠标弹起,释放capture)尚无法有效捕捉,目前通过切换Focus, 以触发WM_CAPTURECHANGED, 效果不佳。(经过测试,捕捉WM_EXITSIZEMOVE 更加有效)

    2、停靠效果预览:当拖拽鼠标位于某个停靠区域时,如果不释放capture(左键不释放),应该在对应的停靠客户区高亮或者区域填充显示,或者浮动窗口遮罩显示停靠效果,目前未实现。

    3、拖拽释放,停靠:目前依据WM_MOVE来处理,但是由于拖拽过程中鼠标不停在移动,导致窗口为表达效果不断重绘,闪烁严重。

    窗口停靠效果

     

    测试代码

    #include<windows.h>
    #include<windowsx.h>
    #include<math.h>
    #include<stdio.h>
    #include<commctrl.h>
    #include<Richedit.h>
    #include<gdiplus.h>
    using namespace Gdiplus; //not use yet.
     
    #pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
    
    #pragma comment(lib,"user32.lib")
    #pragma comment(lib,"gdi32.lib")
    #pragma comment(lib,"kernel32.lib")
    #pragma comment(lib,"comctl32.lib")
    #pragma comment(lib,"gdiplus.lib")
    
    #define WINDOW_CLASS_NAME "MENUBAR NOT WORK WELL"
    #define RWIDTH(A) abs(A.right - A.left)   
    #define RHEIGHT(A) abs(A.bottom - A.top)  
    
    HINSTANCE instance;
    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    
    #define STEP_COLOR(C1,C2,LEN,IDX) \
    RGB(GetRValue(C1)+(BYTE)((double)(GetRValue(C2)-GetRValue(C1))*1.0/(LEN)*(IDX)),\
        GetGValue(C1)+(BYTE)((double)(GetGValue(C2)-GetGValue(C1))*1.0/(LEN)*(IDX)),\
        GetBValue(C1)+(BYTE)((double)(GetBValue(C2)-GetBValue(C1))*1.0/(LEN)*(IDX)))
    
    LRESULT CALLBACK WindowProc(HWND, UINT, WPARAM, LPARAM);
    int Frame_Test(HWND parent);
    
    #define ICONMARGIN 5 //icon margin
    #define ICONPIXLS 25 //icon pixls
    #define BTNMARGIN 5 //btn margin
    #define BTNPIXLSX 20 //btn pixls
    #define BTNPIXLSY 20
    #define MENUBARY 20 //menubar height
    #define BORDERPIXLS 1//border pixls
    #define MENUBARMARGIN 5
    
    typedef enum FRAME_AREA_TYPE {
        ZCLOSE,
        ZMAX,
        ZMIN,
        ZICON,
        ZMENUBAR,
        ZCAPTION,
        ZTEXTTITLE,
        ZCONFIG,
        ZMSG,
        ZNOCARE
    } EFNCZone;
    typedef struct _STRUCT_FRAME_STYLE_ {
       EFNCZone czone;
       HFONT font;
       COLORREF color_mibk;//menu item back color
       HBRUSH brush_mibk;
       COLORREF color_border;
       HBRUSH brush_border;
       
       COLORREF color_active;
       COLORREF color_deactive;
       HBRUSH brush_cap_active;
       HBRUSH brush_cap_deactive;
       
       COLORREF color_title;
       COLORREF color_text;
       COLORREF color_bk;
       
       HBRUSH brush_btnclose;
       HBRUSH brush_btn;
       
       HDC memdc;//mem dc double buffering flicker.
       HDC hdc;
       HBITMAP bmp;
       HPEN pen;
       
       WNDPROC proc;
       WNDPROC pre_proc;
    }RFrameStyle,*pFrameStyle;
    int Frame_InitialSettings(HWND hwnd);
    int Frame_ClearSettings(HWND hwnd);
    pFrameStyle Frame_GetSettings(HWND hwnd);
    
    int Frame_PopMenu(HWND hwnd,POINT pt);
    BOOL Frame_IsMenuBarRect(HWND hwnd,POINT pt);
    int Frame_GetMenuItemRect(HWND hwnd,int index,LPRECT prc);
    int Frame_DrawMenuItem(LPDRAWITEMSTRUCT draw);
    int Frame_NCDraw(HWND hwnd,LPVOID param);
    int Frame_CopyBtnRect(HWND hwnd,LPRECT pbtn_rc,int btn_count);
    int Frame_GetNCZoneRect(HWND hwnd,EFNCZone type,LPRECT prc,BOOL allign_topleft);
    int Frame_NCCalcSize(HWND hwnd,WPARAM wParam,LPARAM lParam);
    int Frame_InitialMenuPopup(HWND hwnd,WPARAM wParam,LPARAM lParam);
    int Frame_NCHitTest(HWND hwnd,WPARAM wParam,LPARAM lParam);
    int Frame_SetIcons(HWND hwnd);
    
    void gradient_rect(HDC hdc,RECT rect,COLORREF rgb_1,COLORREF rgb_2,int verical_or_horizen);
    
    //docker属性
    //停靠模式
    
    #define WM_DOCKINGONTHEWAY (UINT)(WM_USER+0x1001)
    typedef enum DOCKER_MODE {
        DOCKER_UNKNOW, //未实现
        DOCKER_LEFT,
        DOCKER_TOP,
        DOCKER_RIGHT,
        DOCKER_BOTTOM,
        DOCKER_CENTER
    }EDockerMode;
    typedef struct _STRUCT_DOCKER_STYLE_ {
        HWND container;//docker 容器,当docker移动的时候,会向容器发送消息,容器会绘制停靠图标
        EDockerMode mode;
        
    }RDockerStyle,*pDockerStyle;
    HWND btn;
    HWND main;
    HWND hint;
    BOOL docked=FALSE;
    EDockerMode docker_mode=DOCKER_LEFT;
    
    int Docker_Move(HWND hwnd);
    pDockerStyle Docker_GetSettings(HWND hwnd);
    HWND Docker_CreateHintWindow(HWND container);
    int Docker_GetPtArray(HWND hint,LPPOINT pt,int* pcc);
    BOOL Docker_PtInPolygon(LPPOINT lpt,int count,POINT pt);
    LRESULT CALLBACK HintWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
    
    int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, PSTR szcmdLine, int icmdshow)
    {
    	HWND hwnd;
    	MSG msg;
    	WNDCLASSEX winclass;
    	InitCommonControls();
    	instance = hinstance;
    
    	winclass.cbSize = sizeof(WNDCLASSEX);
    	winclass.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
    	winclass.lpfnWndProc = WindowProc;
    	winclass.cbClsExtra = 0;
    	winclass.cbWndExtra = 0;
    	winclass.hInstance = hinstance;
    	winclass.hIcon = LoadIcon(hinstance,"IDC_ICON_FRM2");//LoadIcon(NULL, IDI_APPLICATION);
    	winclass.hCursor = LoadCursor(NULL, IDC_ARROW);
    	winclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
    	winclass.lpszMenuName = NULL;
    	winclass.lpszClassName = WINDOW_CLASS_NAME;
    	winclass.hIconSm = LoadIcon(hinstance,"IDC_ICON_FRM");//LoadIcon(NULL, IDI_APPLICATION);
    
    	if (!RegisterClassEx(&winclass)) return 0;
    
    	if (!(hwnd = CreateWindowEx(NULL,
    								WINDOW_CLASS_NAME,
    								"Docker Frame Capture",
    								WS_OVERLAPPEDWINDOW | WS_VISIBLE,
    								240, 262,
    								780,400,
    								NULL,
    								LoadMenu(hinstance,"IDR_FRMENU"),
    								hinstance,
    								NULL)))
    		return 0;
        main=hwnd;
        Frame_Test(hwnd);
    
    	while (GetMessage(&msg, NULL, 0, 0)) {
    	    if(!IsDialogMessage(hwnd,&msg)) { //tabstop
    		    TranslateMessage(&msg);
    		    DispatchMessage(&msg);
    	    }
    	}
    
    	return(msg.wParam);
    }
    
    LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
    	switch (msg)
    	{
    	case WM_CREATE: {
    	    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
    	    InitCommonControls();
    	} break;
    	case WM_NCCALCSIZE: {
            return Frame_NCCalcSize(hwnd,wParam,lParam);
    	} break;
    	case WM_NCACTIVATE:
    	case WM_NCPAINT: {
            BOOL active_flag=(BOOL)wParam;
            Frame_NCDraw(hwnd,&active_flag);
            
            //将窗口置于底层
            SetWindowPos(hwnd,btn,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW);
            
            return !active_flag;	    
    	} break;
        case WM_NCMOUSEMOVE: {
            UINT HITPOS = wParam;
            POINT pt={GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam)};
            BOOL active_flag=(GetActiveWindow()==hwnd)||
                             (GetFocus()==hwnd)&&((WS_CHILD&GetWindowLongPtr(hwnd,GWL_STYLE))==WS_CHILD);
            Frame_NCDraw(hwnd,&active_flag);
            
            TRACKMOUSEEVENT tme;
            tme.cbSize=sizeof(TRACKMOUSEEVENT);
            tme.dwFlags=TME_NONCLIENT|TME_LEAVE;
            tme.hwndTrack=hwnd;
            tme.dwHoverTime=HOVER_DEFAULT;
            TrackMouseEvent(&tme);
            return 0;
        } break;
        case WM_NCMOUSELEAVE: {
            BOOL active_flag=(GetActiveWindow()==hwnd)||
                             (GetFocus()==hwnd)&&((WS_CHILD&GetWindowLongPtr(hwnd,GWL_STYLE))==WS_CHILD);
            Frame_NCDraw(hwnd,&active_flag);
            TRACKMOUSEEVENT tme;
            tme.cbSize=sizeof(TRACKMOUSEEVENT);
            tme.dwFlags=TME_CANCEL;
            tme.hwndTrack=hwnd;
            tme.dwHoverTime=HOVER_DEFAULT;
            TrackMouseEvent(&tme);
        } break;
        case WM_CAPTURECHANGED: {
            if(hwnd==btn) {
                RECT rcc;
                
                GetClientRect(main,&rcc);
                SetWindowLongPtr(hint,GWL_STYLE,(~WS_VISIBLE)&GetWindowLongPtr(hint,GWL_STYLE)); 
                if(docker_mode==DOCKER_LEFT) {
                    SetWindowLongPtr(hwnd,GWL_STYLE,WS_CHILD|GetWindowLongPtr(hwnd,GWL_STYLE));
                    SetParent(hwnd,main);
                    SetWindowPos(hwnd,NULL,0,0,300,rcc.bottom-rcc.top,SWP_FRAMECHANGED|SWP_SHOWWINDOW);
                }
                else if(docker_mode==DOCKER_RIGHT) {
                    SetWindowLongPtr(hwnd,GWL_STYLE,WS_CHILD|GetWindowLongPtr(hwnd,GWL_STYLE));
                    SetParent(hwnd,main);
                    SetWindowPos(hwnd,NULL,rcc.right-300,0,300,rcc.bottom-rcc.top,SWP_FRAMECHANGED|SWP_SHOWWINDOW);
                }
                else if(docker_mode==DOCKER_TOP) {
                    SetWindowLongPtr(hwnd,GWL_STYLE,WS_CHILD|GetWindowLongPtr(hwnd,GWL_STYLE));
                    SetParent(hwnd,main);
                    SetWindowPos(hwnd,NULL,0,0,rcc.right-rcc.left,300,SWP_FRAMECHANGED|SWP_SHOWWINDOW);
                }
                else if(docker_mode==DOCKER_BOTTOM) {
                    SetWindowLongPtr(hwnd,GWL_STYLE,WS_CHILD|GetWindowLongPtr(hwnd,GWL_STYLE));
                    SetParent(hwnd,main);
                    SetWindowPos(hwnd,NULL,0,rcc.bottom-300,rcc.right-rcc.left,300,SWP_FRAMECHANGED|SWP_SHOWWINDOW);
                }
            }
        } break;
        case WM_MOVE: {
            POINT pt;
            if(hwnd==btn) {
                RECT rc,rc_hint,rcc;
                POINT ct;
                
                SendMessage(hint,WM_DOCKINGONTHEWAY,0,0);
                //获取光标坐标
                GetCursorPos(&pt);
                GetClientRect(main,&rcc);
                //设置hint窗口位置
                GetWindowRect(main,&rc);
                GetWindowRect(hint,&rc_hint);
                ct.x=((rc.left+rc.right)>>1)-((rc_hint.right-rc_hint.left)>>1);
                ct.y=((rc.top+rc.bottom)>>1)-((rc_hint.bottom-rc_hint.top)>>1);
    
                if(!PtInRect(&rc,pt)) SetWindowLongPtr(hint,GWL_STYLE,(~WS_VISIBLE)&GetWindowLongPtr(hint,GWL_STYLE));
                else SetWindowPos(hint,NULL,ct.x,ct.y,(rc_hint.right-rc_hint.left),rc_hint.bottom-rc_hint.top,SWP_FRAMECHANGED|SWP_SHOWWINDOW);
                
                InflateRect(&rc_hint,-20,-20);
                //拖拽光标处于hint窗口,且拖拽窗口为浮动模式 : 执行停靠,并隐藏 hint 窗口
                if(PtInRect(&rc_hint,pt)&&((GetWindowLongPtr(hwnd,GWL_STYLE)&WS_CHILD)!=WS_CHILD)) {
                    docked=TRUE;
                    SetFocus(hint);
                    SetFocus(main);
                }
                else if(docked&&PtInRect(&rc_hint,pt)) {
                    RECT rcc;
                    
                    GetClientRect(main,&rcc);
                    SetWindowLongPtr(hint,GWL_STYLE,(~WS_VISIBLE)&GetWindowLongPtr(hint,GWL_STYLE)); 
                    if(docker_mode==DOCKER_LEFT) {
                        SetWindowLongPtr(hwnd,GWL_STYLE,WS_CHILD|GetWindowLongPtr(hwnd,GWL_STYLE));
                        SetParent(hwnd,main);
                        SetWindowPos(hwnd,NULL,0,0,300,rcc.bottom-rcc.top,SWP_FRAMECHANGED|SWP_SHOWWINDOW);
                    }
                    else if(docker_mode==DOCKER_RIGHT) {
                        SetWindowLongPtr(hwnd,GWL_STYLE,WS_CHILD|GetWindowLongPtr(hwnd,GWL_STYLE));
                        SetParent(hwnd,main);
                        SetWindowPos(hwnd,NULL,rcc.right-300,0,300,rcc.bottom-rcc.top,SWP_FRAMECHANGED|SWP_SHOWWINDOW);
                    }
                    else if(docker_mode==DOCKER_TOP) {
                        SetWindowLongPtr(hwnd,GWL_STYLE,WS_CHILD|GetWindowLongPtr(hwnd,GWL_STYLE));
                        SetParent(hwnd,main);
                        SetWindowPos(hwnd,NULL,0,0,rcc.right-rcc.left,300,SWP_FRAMECHANGED|SWP_SHOWWINDOW);
                    }
                    else if(docker_mode==DOCKER_BOTTOM) {
                        SetWindowLongPtr(hwnd,GWL_STYLE,WS_CHILD|GetWindowLongPtr(hwnd,GWL_STYLE));
                        SetParent(hwnd,main);
                        SetWindowPos(hwnd,NULL,0,rcc.bottom-300,rcc.right-rcc.left,300,SWP_FRAMECHANGED|SWP_SHOWWINDOW);
                    }
                    SetFocus(hint);
                    SetFocus(main);
                }
                else if(((GetWindowLongPtr(hwnd,GWL_STYLE)&WS_CHILD)==WS_CHILD)&&!PtInRect(&rc_hint,pt)) {//拽出来了
                    SetWindowLongPtr(hwnd,GWL_STYLE,~WS_CHILD&GetWindowLongPtr(hwnd,GWL_STYLE));
                    SetParent(hwnd,NULL);
                    docked=FALSE;
                }
                
            }
        } break;/*
        case WM_MOVE: {
            POINT pt;
            
            if(hwnd==btn) {
                RECT rc,rc_hint;
                POINT ct;
    
                GetCursorPos(&pt);
                            
                GetWindowRect(main,&rc);
                GetWindowRect(hint,&rc_hint);
                ct.x=((rc.left+rc.right)>>1)-((rc_hint.right-rc_hint.left)>>1);
                ct.y=((rc.top+rc.bottom)>>1)-((rc_hint.bottom-rc_hint.top)>>1);
                SetWindowPos(hint,NULL,ct.x,ct.y,(rc_hint.right-rc_hint.left),rc_hint.bottom-rc_hint.top,SWP_FRAMECHANGED|SWP_SHOWWINDOW);
                           
                if(PtInRect(&rc_hint,pt)&&((GetWindowLongPtr(hwnd,GWL_STYLE)&WS_CHILD)!=WS_CHILD)) {
                    SetWindowLongPtr(hwnd,GWL_STYLE,WS_CHILD|GetWindowLongPtr(hwnd,GWL_STYLE));
                    SetWindowLongPtr(hwnd,GWL_EXSTYLE,WS_EX_TOOLWINDOW|GetWindowLongPtr(hwnd,GWL_EXSTYLE));//不在任务栏显示条目
                    SetParent(hwnd,main);
                    SetWindowPos(hwnd,NULL,0,0,300,rc.bottom-rc.top,SWP_FRAMECHANGED|SWP_SHOWWINDOW);
                    docked=TRUE;
                    ReleaseCapture();
                }
                else if(docked&&PtInRect(&rc_hint,pt)) {
                    SetWindowPos(hwnd,NULL,0,0,300,rc.bottom-rc.top,SWP_FRAMECHANGED|SWP_SHOWWINDOW);
                }
                else if(docked&&!PtInRect(&rc_hint,pt)) {
                    SetWindowLongPtr(hwnd,GWL_STYLE,~WS_CHILD&GetWindowLongPtr(hwnd,GWL_STYLE));
                    SetParent(hwnd,NULL);
                    docked=FALSE;
                }
            }
        } break;*/
        case WM_INITMENUPOPUP: {
            Frame_InitialMenuPopup(hwnd,wParam,lParam);
        } break;    
        case WM_NCHITTEST: {
            return Frame_NCHitTest(hwnd,wParam,lParam);
        } break;
        case WM_SYSCOMMAND: {
            if(wParam==SC_KEYMENU) {
                BOOL active_flag=(GetActiveWindow()==hwnd)||
                                 (GetFocus()==hwnd)&&((WS_CHILD&GetWindowLongPtr(hwnd,GWL_STYLE))==WS_CHILD);
                Frame_NCDraw(hwnd,&active_flag);
                switch(lParam) { //加速键
                case 0: {//menubar activate. F10 与 Alt触发
                    
                } break;
                case 'f': {
                    //快捷键F
                } break;
                }
                
                SetWindowPos(hwnd,btn,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW);
                return 0;
            }
        } break;
        case WM_NCLBUTTONDOWN: {
            UINT HITPOS = wParam;
            POINT pt={GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam)};
            
            if(HITPOS==HTMENU) {
                Frame_PopMenu(hwnd,pt);
                return 0;
            }
            else if(HITPOS==HTMINBUTTON||HITPOS==HTMAXBUTTON||HITPOS==HTCLOSE) return 0;
        } break;
        case WM_NCLBUTTONUP: {
            UINT HITPOS = wParam;
            
            //写得有点别扭
            if(HITPOS==HTMINBUTTON) ShowWindow(hwnd,SW_MINIMIZE);
            else if(HITPOS==HTMAXBUTTON) {
                if(IsZoomed(hwnd)) ShowWindow(hwnd,SW_RESTORE);
                else ShowWindow(hwnd,SW_MAXIMIZE);
            }
            else if(HITPOS==HTCLOSE) SendMessage(hwnd,WM_CLOSE,0,0);
        } break;
        case WM_SIZE: {		
            int height = HIWORD(lParam);
    	    int width = LOWORD(lParam);
            
            RECT window_rect;
            HRGN window_rgn;
            
            //Rectangle the window      
            GetWindowRect(hwnd,&window_rect);
            window_rgn=CreateRectRgn(0,0,window_rect.right-window_rect.left,window_rect.bottom-window_rect.top);
            SetWindowRgn(hwnd,window_rgn,TRUE);
            DeleteObject(window_rgn);
            
            if(GetParent(btn)==hwnd) {
    		    int ctrl_h,ctrl_w;
    		    RECT rc_ctl;
    		    GetWindowRect(btn,&rc_ctl);
    		    
    		    ctrl_w=rc_ctl.right-rc_ctl.left;
    		    MoveWindow(btn,0,0,ctrl_w,height,TRUE);
    		}
    		
    		if(hwnd==main) {
    		    POINT ct;
    		    RECT rc_hint,rc;
                GetWindowRect(hint,&rc_hint);
                GetWindowRect(main,&rc);
                ct.x=((rc.left+rc.right)>>1)-((rc_hint.right-rc_hint.left)>>1);
                ct.y=((rc.top+rc.bottom)>>1)-((rc_hint.bottom-rc_hint.top)>>1);
                SetWindowPos(hint,NULL,ct.x,ct.y,(rc_hint.right-rc_hint.left),rc_hint.bottom-rc_hint.top,SWP_FRAMECHANGED);
    		}
        } break;
        case WM_NCDESTROY: {
            Frame_ClearSettings(hwnd);
        } break;
    	case WM_DESTROY: {
    	    GdiplusShutdown(gdiplusToken);
    		PostQuitMessage(0);
    		return (0);
    	} break;
    	case WM_COMMAND: {
    	    HWND ctrl=(HWND)lParam;
    	    UINT code=HIWORD(wParam);
    	    UINT id=LOWORD(wParam);
    	    
    	    if(code==0) {//菜单
        	    switch(id) {
        	    case 0x0001:
        	        MessageBox(hwnd,"","",MB_OK);
        	    break;
        	    }
    	    }
    	} break;
    	case WM_NOTIFY: {
    	    LPNMHDR phdr=(LPNMHDR)lParam;
    	    UINT ctrlid=wParam;
    	    
    	    if(phdr->code==DTN_DATETIMECHANGE) {
    	        //DateTimePicker Alter Notify.
    	    }
    	} break;
        case WM_MEASUREITEM: {
            LPMEASUREITEMSTRUCT lpmis;
            lpmis=(LPMEASUREITEMSTRUCT)lParam;
            
            if(lpmis->CtlType==ODT_MENU) {
                UINT menu_item_id=lpmis->itemID;
                lpmis->itemWidth=200;
                lpmis->itemHeight=((menu_item_id==0x0)?5:28);//menu item & menu spliter
            }
        } break;
    	case WM_DRAWITEM: {
    	    UINT ctrl_id=(UINT)wParam;
    	    LPDRAWITEMSTRUCT pDraw=(LPDRAWITEMSTRUCT)lParam;
    	    
    	    if(pDraw->CtlType==ODT_MENU) {
    	        Frame_DrawMenuItem(pDraw);
    	    }
    	} break;
        case WM_CTLCOLORLISTBOX:
        {
            HDC dc=(HDC)wParam;
            HWND ctrl=(HWND)lParam;
        } break;
        case WM_CTLCOLOREDIT:
        {
            HDC dc=(HDC)wParam;
            HWND ctrl=(HWND)lParam;
        } break;
    	default:
    		break;
    	}
    	return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    
    
    int Frame_ClearSettings(HWND hwnd)
    {
        pFrameStyle fs=Frame_GetSettings(hwnd);
        if(!fs) return -1;
        
        DeleteObject(fs->font);
        DeleteObject(fs->brush_mibk);
        DeleteObject(fs->brush_cap_active);
        DeleteObject(fs->brush_cap_deactive);
        DeleteObject(fs->brush_border);
        DeleteObject(fs->pen);
        DeleteObject(fs->bmp);
        DeleteObject(fs->brush_btnclose);
        DeleteObject(fs->brush_btn);
        DeleteDC(fs->memdc);
        ReleaseDC(hwnd,fs->hdc);
        
        free(fs);
        
        return 0;
    }
    
    pFrameStyle Frame_GetSettings(HWND hwnd)
    {
        return (pFrameStyle)GetWindowLongPtr(hwnd,GWLP_USERDATA);
    }
    
    int Frame_InitialSettings(HWND hwnd)
    {
        pFrameStyle fs=(pFrameStyle)calloc(sizeof(RFrameStyle),1);
        if(!fs) return -1;
        
        fs->font=CreateFont(17,0,0,0,
                            FW_MEDIUM,//FW_SEMIBOLD,
                            FALSE,FALSE,FALSE,
                            DEFAULT_CHARSET,
                            OUT_OUTLINE_PRECIS,
                            CLIP_DEFAULT_PRECIS,
                            CLEARTYPE_QUALITY, 
                            VARIABLE_PITCH,
                            "Courier New");
        SendMessage(hwnd,WM_SETFONT,(WPARAM)fs->font,0);
        SetWindowLongPtr(hwnd,GWLP_USERDATA,(LONG_PTR)fs);
        
        fs->color_mibk=RGB(43,43,43);
        fs->brush_mibk=CreateSolidBrush(fs->color_mibk);
        
        fs->color_active=RGB(30,30,30);
        fs->brush_cap_active=CreateSolidBrush(fs->color_active);
        fs->color_deactive=RGB(40,40,40);
        fs->brush_cap_deactive=CreateSolidBrush(fs->color_deactive);
        
        fs->color_border=RGB(53,53,53);
        fs->brush_border=CreateSolidBrush(fs->color_border);
        
        fs->color_text=RGB(255,255,255);
        fs->color_bk=RGB(16,16,16);
        
        fs->pen=CreatePen(PS_SOLID,BORDERPIXLS,fs->color_border);
        
        fs->brush_btnclose=CreateSolidBrush(RGB(255,0,0));
        fs->brush_btn=CreateSolidBrush(RGB(200,200,200));
        
        fs->hdc=GetWindowDC(hwnd);
        fs->memdc=CreateCompatibleDC(fs->hdc);
        fs->bmp=CreateCompatibleBitmap(fs->hdc,2500,1500);//GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_CYSCREEN));//when full screen , something was wrong.
        SelectObject(fs->memdc,fs->bmp);
        SelectObject(fs->memdc,fs->font);
        SelectObject(fs->memdc,fs->pen);
        
        return 0;
    }
    
    int Frame_Test(HWND frame)
    {
        Frame_InitialSettings(frame);
        btn=CreateWindowEx(WS_EX_TOOLWINDOW,
                 		   WINDOW_CLASS_NAME, "Docker window",
                 		   WS_OVERLAPPEDWINDOW|WS_VISIBLE,//WS_TABSTOP|WS_VISIBLE,
                 		   15,15,350,170,
                 		   NULL, (HMENU)NULL,//0x0001,
                 		   (HINSTANCE)GetWindowLongPtr(frame, GWLP_HINSTANCE), NULL);
        Frame_InitialSettings(btn);
        SendMessage(btn,WM_SETICON,(WPARAM)ICON_SMALL,(LPARAM)LoadIcon((HINSTANCE)GetWindowLongPtr(btn,GWLP_HINSTANCE),"IDC_ICON_DOCKER"));
        hint=Docker_CreateHintWindow(frame);
        return 0;
    }
    
    int Frame_PopMenu(HWND hwnd,POINT pt)
    {
        int item_count;
        HMENU menu;
        HMENU sub_menu;
        RECT mi_rc,win_rc;
        POINT pos;
    
        GetWindowRect(hwnd,&win_rc);
        pos=pt;
        pt.x=pt.x-win_rc.left;
        pt.y=pt.y-win_rc.top;
        
        menu=GetMenu(hwnd);
        item_count=GetMenuItemCount(menu);
        for(int index=0;index<item_count;index++) {
            Frame_GetMenuItemRect(hwnd,index,&mi_rc);
            if(PtInRect(&mi_rc,pt)) {
                sub_menu=GetSubMenu(menu,index);
                TrackPopupMenu(sub_menu,TPM_LEFTALIGN|TPM_TOPALIGN,mi_rc.left+win_rc.left,mi_rc.bottom+win_rc.top,0,hwnd,NULL);                                
                return 0;
            }
        }
        return 0;
    }
    
    BOOL Frame_IsMenuBarRect(HWND hwnd,POINT pt)
    {
        int item_count;
        RECT mb_rc;
        MENUBARINFO mb_if;
        
        Frame_GetMenuItemRect(hwnd,0,&mb_rc);
        mb_if.cbSize=sizeof(mb_if);
        GetMenuBarInfo(hwnd,OBJID_MENU,0,&mb_if);
        OffsetRect(&(mb_if.rcBar),-mb_if.rcBar.left,-mb_if.rcBar.top);
        mb_rc.left=mb_if.rcBar.left;
        mb_rc.right=mb_if.rcBar.right;
        
        return PtInRect(&mb_rc,pt);
    }
    
    int Frame_GetMenuItemRect(HWND hwnd,int index,LPRECT prc)
    {
        HMENU menu;
        MENUBARINFO mb_if;
        POINT pt_offset;
        RECT rc_bar;
        
        Frame_GetNCZoneRect(hwnd,ZMENUBAR,&rc_bar,TRUE);
        menu=GetMenu(hwnd);
        mb_if.cbSize=sizeof(mb_if);
        GetMenuBarInfo(hwnd,OBJID_MENU,1,&mb_if);
        pt_offset={rc_bar.left-mb_if.rcBar.left,rc_bar.top-mb_if.rcBar.top};
        
        GetMenuBarInfo(hwnd,OBJID_MENU,index+1,&mb_if);
        CopyRect(prc,&(mb_if.rcBar));
        OffsetRect(prc,pt_offset.x+index*BTNMARGIN+BORDERPIXLS,pt_offset.y);
        
        return 0;
    }
    
    int Frame_NCDraw(HWND hwnd,LPVOID param)//BOOL active_flag)
    {
        BOOL active_flag=*(BOOL*)param;
        pFrameStyle fs=Frame_GetSettings(hwnd);
        HICON icon;
        RECT rc={0},rc_mem={0},rc_cap,rc_ico,rc_title,rc_bar,rc_min,rc_max,rc_x;
        POINT pt_cursor;
        char text[256]="";
        COLORREF color_trans=RGB(0,0,1);
        HBRUSH brush_trans=CreateSolidBrush(color_trans),pre_brush;
        
        if(!fs) return 1;
        
        GetWindowRect(hwnd,&rc);
        CopyRect(&rc_mem,&rc);
        OffsetRect(&rc_mem,-rc_mem.left,-rc_mem.top);
        
        //获取鼠标位置
        GetCursorPos(&pt_cursor);
        pt_cursor.x-=rc.left;
        pt_cursor.y-=rc.top;
        
        //刷新画板
        pre_brush=(HBRUSH)SelectObject(fs->memdc,brush_trans);
        SelectObject(fs->memdc,fs->pen);
        Rectangle(fs->memdc,rc_mem.left,rc_mem.top,rc_mem.right,rc_mem.bottom);
        DeleteObject(SelectObject(fs->memdc,pre_brush));
        
        //填充标题
        Frame_GetNCZoneRect(hwnd,ZCAPTION,&rc_cap,TRUE);
        FillRect(fs->memdc,&rc_cap,active_flag?fs->brush_cap_active:fs->brush_cap_deactive);
        
        //绘制图标
        Frame_GetNCZoneRect(hwnd,ZICON,&rc_ico,TRUE);
        icon=(HICON)SendMessage(hwnd,WM_GETICON,(WPARAM)ICON_SMALL,0);//ICON_BIG 大图标
        if(icon==NULL) icon=(HICON)GetClassLongPtrW(hwnd, GCLP_HICONSM);
        if(icon == NULL) {
            HWND hwnd_owner=GetWindow(hwnd,GW_OWNER);
            if(hwnd_owner) icon=(HICON)GetClassLongPtrW(hwnd_owner, GCLP_HICONSM);
            if(icon==NULL) icon=(HICON)LoadIcon(NULL,IDI_APPLICATION);
        }
        DrawIconEx(fs->memdc,rc_ico.left,rc_ico.top,icon,ICONPIXLS,ICONPIXLS,0,0,DI_NORMAL);//是否需要释放?
        
        //绘制标题文本
        Frame_GetNCZoneRect(hwnd,ZTEXTTITLE,&rc_title,TRUE);
        GetWindowText(hwnd,text,sizeof(text));
        SetBkMode(fs->memdc,TRANSPARENT);
        SetTextColor(fs->memdc,fs->color_text);
        DrawText(fs->memdc,text,-1,&rc_title,DT_SINGLELINE|DT_VCENTER|DT_END_ELLIPSIS);
        
        //绘制MenuBar
        if(Frame_GetNCZoneRect(hwnd,ZMENUBAR,&rc_bar,TRUE)>0) {
            HMENU menu;
            MENUBARINFO mb_if;
            MENUITEMINFO mi_if;
            int count;
            char menu_text[256]="";
            RECT rc_mi;//菜单项区域
            POINT pt_offset;
            
            gradient_rect(fs->memdc,rc_bar,active_flag?fs->color_active:fs->color_deactive,fs->color_bk,1);
            //绘制菜单项.
            menu=GetMenu(hwnd);
            count=GetMenuItemCount(menu);
            
            mb_if.cbSize=sizeof(mb_if);
            for(int index=1;index<=count;index++) {
                GetMenuBarInfo(hwnd,OBJID_MENU,index,&mb_if);//菜单项的index从1开始
                
                mi_if.cbSize=sizeof(mi_if);
                mi_if.fMask=MIIM_STRING|MIIM_STATE;
                mi_if.dwTypeData=menu_text;
                mi_if.cch=sizeof(menu_text);
                GetMenuItemInfo(menu,index-1,TRUE,&mi_if);
                
                if(index==1) pt_offset={rc_bar.left-mb_if.rcBar.left,rc_bar.top-mb_if.rcBar.top};
                
                CopyRect(&rc_mi,&(mb_if.rcBar));
                OffsetRect(&rc_mi,pt_offset.x+index*BTNMARGIN+BORDERPIXLS,pt_offset.y);
                rc_mi.right+=8;
                if(PtInRect(&rc_mi,pt_cursor)) {
                    gradient_rect(fs->memdc,rc_mi,RGB(15,15,15),RGB(55,55,55),1);
                    FrameRect(fs->memdc,&rc_mi,fs->brush_border);
                }
                DrawText(fs->memdc,menu_text,-1,&rc_mi,DT_SINGLELINE|DT_VCENTER|DT_CENTER);
            }
        }
        
        //绘制关闭
        Frame_GetNCZoneRect(hwnd,ZCLOSE,&rc_x,TRUE);
        if(PtInRect(&rc_x,pt_cursor)) FillRect(fs->memdc,&rc_x,fs->brush_btnclose);//关闭
        DrawText(fs->memdc,"×",-1,&rc_x,DT_SINGLELINE|DT_VCENTER|DT_CENTER);
        
        //绘制最大化
        Frame_GetNCZoneRect(hwnd,ZMAX,&rc_max,TRUE);
        if(PtInRect(&rc_max,pt_cursor)) FillRect(fs->memdc,&rc_max,fs->brush_btn);
        if(IsZoomed(hwnd)) {
            //最大化 
            DrawText(fs->memdc,"□",-1,&rc_max,DT_SINGLELINE|DT_VCENTER|DT_CENTER);
            OffsetRect(&rc_max,2,-2);
            DrawText(fs->memdc,"□",-1,&rc_max,DT_SINGLELINE|DT_VCENTER|DT_CENTER);
        }
        else {
            //恢复
            DrawText(fs->memdc,"□",-1,&rc_max,DT_SINGLELINE|DT_VCENTER|DT_CENTER);
        }
        
        //绘制最小化
        if(Frame_GetNCZoneRect(hwnd,ZMIN,&rc_min,TRUE)>0) {
            if(PtInRect(&rc_min,pt_cursor)) FillRect(fs->memdc,&rc_min,fs->brush_btn);
            DrawText(fs->memdc,"-",-1,&rc_min,DT_SINGLELINE|DT_VCENTER|DT_CENTER);
        }
        
        //绘制config
        RECT rc_cfg;
        HICON icon_cfg;
        Frame_GetNCZoneRect(hwnd,ZCONFIG,&rc_cfg,TRUE);
        if(PtInRect(&rc_cfg,pt_cursor)) {
            icon_cfg=LoadIcon((HINSTANCE)GetWindowLongPtr(hwnd,GWLP_HINSTANCE),"IDC_ICON_CFG2");
        }
        else icon_cfg=LoadIcon((HINSTANCE)GetWindowLongPtr(hwnd,GWLP_HINSTANCE),"IDC_ICON_CFG");
        InflateRect(&rc_cfg,-2,-2);
        DrawIconEx(fs->memdc,rc_cfg.left,rc_cfg.top,icon_cfg,(rc_cfg.right-rc_cfg.left),(rc_cfg.bottom-rc_cfg.top),0,0,DI_NORMAL);
    
        //绘制msg
        RECT rc_msg;
        HICON icon_msg;
        Frame_GetNCZoneRect(hwnd,ZMSG,&rc_msg,TRUE);
        if(PtInRect(&rc_msg,pt_cursor)) {
            icon_msg=LoadIcon((HINSTANCE)GetWindowLongPtr(hwnd,GWLP_HINSTANCE),"IDC_ICON_MSG");
        }
        else icon_msg=LoadIcon((HINSTANCE)GetWindowLongPtr(hwnd,GWLP_HINSTANCE),"IDC_ICON_MSG2");
        InflateRect(&rc_msg,-2,-3);
        DrawIconEx(fs->memdc,rc_msg.left,rc_msg.top,icon_msg,(rc_msg.right-rc_msg.left),(rc_msg.bottom-rc_msg.top),0,0,DI_NORMAL);
    
        for(int index=0;index<BORDERPIXLS;index++) {
             FrameRect(fs->memdc,&rc_mem,fs->brush_border);
             InflateRect(&rc_mem,-1,-1);
        }
        
        OffsetRect(&rc,-rc.left,-rc.top);
        TransparentBlt(fs->hdc,rc.left,rc.top,(rc.right-rc.left),(rc.bottom-rc.top),
                       fs->memdc,0,0,(rc.right-rc.left),(rc.bottom-rc.top),color_trans);
                       
        return 0;
    }
    
    int Frame_CopyBtnRect(HWND hwnd,LPRECT pbtn_rc,int btn_count)
    {
        RECT rc_frame;
        int rc_length;
        int btn_height=20,btn_width=25;
        int btn_margin=10;//最按钮距离右侧边框的pixs
        
        if(hwnd==NULL) return -1;
        if(pbtn_rc==NULL) return -1;
        
        GetWindowRect(hwnd,&rc_frame);
        OffsetRect(&rc_frame,-rc_frame.left,-rc_frame.top);
        rc_length=rc_frame.right-rc_frame.left;
        
        for(int index=btn_count;index>0;index--) {
            pbtn_rc[index-1]={rc_length-btn_margin-btn_width*index,btn_margin,rc_length-btn_margin-btn_width*(index-1),btn_margin+btn_height};
        }
        
        return 0;
    }
    
    void gradient_rect(HDC hdc,RECT rect,COLORREF rgb_1,COLORREF rgb_2,int verical_or_horizen)
    {
        int length_pixs;
        int index_pixs = 0;
        COLORREF step_color;
        HPEN step_pen=NULL,pre_pen=NULL,tmp_pen=NULL;
        POINT pre_point;
        
        if(verical_or_horizen == 0) {
            length_pixs = rect.right - rect.left;
        }
        else length_pixs = rect.bottom - rect.top;
        
        //最好在memdc上操作
        while(index_pixs < length_pixs) {
            step_color = STEP_COLOR(rgb_1,rgb_2,length_pixs,index_pixs);
            step_pen = CreatePen(PS_SOLID,1,step_color);
            tmp_pen=(HPEN)SelectObject(hdc,step_pen);
            if(index_pixs == 0) pre_pen = tmp_pen;
            
            if(verical_or_horizen == 0) {
                MoveToEx(hdc,rect.left+index_pixs,rect.top,&pre_point);
                LineTo(hdc,rect.left+index_pixs,rect.bottom);
            }
            else {
                MoveToEx(hdc,rect.left,rect.top+index_pixs,&pre_point);
                LineTo(hdc,rect.right,rect.top+index_pixs);
            }
            
            DeleteObject(step_pen);
            index_pixs++;
        }
        SelectObject(hdc,pre_pen);
    }
    
    
    int Frame_DrawMenuItem(LPDRAWITEMSTRUCT draw)
    {
        UINT menu_item_id=draw->itemID;
        char text[256]="";
        RECT rect;
        HDC hdc;
        HMENU menu;
        HWND menu_hwnd;
        MENUITEMINFO mi_if={0}/*,itemtype={0}*/;
        COLORREF rgb_bk=RGB(43,43,43);//RGB(70,70,70);
        COLORREF rgb_disabled=RGB(150,150,150);
        COLORREF rgb_text_disabled=RGB(100,100,100);
        COLORREF rgb_check=RGB(65,65,65);
        COLORREF rgb_text_check=RGB(0,128,255);
        COLORREF rgb_text=RGB(255,255,255);
        HBRUSH brush,pre_brush;
        HPEN pen,pre_pen;
        
        hdc=draw->hDC;
        InflateRect(&(draw->rcItem),1,1);
        CopyRect(&rect,&(draw->rcItem));
        menu=(HMENU)draw->hwndItem;
        menu_hwnd=draw->hwndItem;
        
        mi_if.cbSize=sizeof(mi_if);
        mi_if.fMask=MIIM_STRING|MIIM_STATE|MIIM_ID;
        mi_if.dwTypeData=text;
        mi_if.cch=sizeof(text);
        GetMenuItemInfo(menu,menu_item_id,FALSE,&mi_if);
        
        if(draw->itemState&ODS_CHECKED==ODS_CHECKED) {
            if(mi_if.fState&MFS_DISABLED==MFS_DISABLED) {
                brush=CreateSolidBrush(rgb_bk);
                pre_brush=(HBRUSH)SelectObject(hdc,brush);
                SetTextColor(hdc,rgb_text_disabled);
                pen=CreatePen(PS_SOLID,1,rgb_text_disabled);
                pre_pen=(HPEN)SelectObject(hdc,pen);
            }
            else {
                brush=CreateSolidBrush(rgb_check);
                pre_brush=(HBRUSH)SelectObject(hdc,brush);
                SetTextColor(hdc,rgb_text_check);
                pen=CreatePen(PS_SOLID,1,rgb_check);
                pre_pen=(HPEN)SelectObject(hdc,pen);
            }
        }
        else {
            brush=CreateSolidBrush(rgb_bk);
            pre_brush=(HBRUSH)SelectObject(hdc,brush);
            if(mi_if.fState&MFS_DISABLED==MFS_DISABLED) {
                SetTextColor(hdc,rgb_text_disabled);
                pen=CreatePen(PS_SOLID,1,rgb_text_disabled);
                pre_pen=(HPEN)SelectObject(hdc,pen);
            }
            else {
                SetTextColor(hdc,rgb_text);
                pen=CreatePen(PS_SOLID,1,rgb_bk);
                pre_pen=(HPEN)SelectObject(hdc,pen);
            }
        }
    
        SetBkMode(hdc,TRANSPARENT);
        FillRect(hdc,&rect,brush);
        if(strlen(text)>0) {
            RECT check_rect;
            CopyRect(&check_rect,&rect);
            check_rect.right=rect.left+(rect.bottom-rect.top);
    
            if((UINT)(mi_if.fState&MFS_CHECKED)==(UINT)MFS_CHECKED) {
                DrawText(hdc,"√",-1,&check_rect,DT_SINGLELINE|DT_VCENTER|DT_CENTER);
            }
            rect.left = rect.left+(rect.bottom-rect.top);
            DrawText(hdc,text,-1,&rect,DT_SINGLELINE|DT_VCENTER|DT_EXPANDTABS);//DT_EXPANDTABS识别\t
        }
        else {
            //绘制菜单分隔条
            POINT pt[5]={{rect.left+5,(rect.top+rect.bottom)/2},
                         {rect.right-5,(rect.top+rect.bottom)/2},
                         {rect.left+5,(rect.top+rect.bottom)/2+1},
                         {rect.right-5,(rect.top+rect.bottom)/2+1}};
            
            COLORREF color_1=RGB(19,19,19),color_2=RGB(68,68,68);
            HPEN sp_line1=CreatePen(PS_SOLID,1,color_1);
            HPEN sp_line2=CreatePen(PS_SOLID,1,color_2);
            HPEN pre_sp;
            
            pre_sp=(HPEN)SelectObject(hdc,sp_line1);
            MoveToEx(hdc,pt[0].x,pt[0].y,&(pt[4]));
            LineTo(hdc,pt[1].x,pt[1].y);
            
            SelectObject(hdc,sp_line2);
            MoveToEx(hdc,pt[2].x,pt[2].y,&(pt[4]));
            LineTo(hdc,pt[3].x,pt[3].y);
            SelectObject(hdc,pre_sp);
            DeleteObject(sp_line1);
            DeleteObject(sp_line2);
        }
        
        DeleteObject(SelectObject(hdc,pre_brush));
        DeleteObject(SelectObject(hdc,pre_pen));
        return 0;
    }
    
    /*
    allign_topleft:TRUE 相对于窗口左上角的坐标
                   FALSE 屏幕坐标
     */
    int Frame_GetNCZoneRect(HWND hwnd,EFNCZone type,LPRECT prc,BOOL allign_topleft)
    {
        RECT rc={0};
        BOOL menubar_exist=(NULL!=GetMenu(hwnd));
        int assign_flag=-1;
        GetWindowRect(hwnd,&rc);
        
        switch(type) {
        case ZCLOSE: {
            prc->top=rc.top+BTNMARGIN;
            prc->bottom=prc->top+BTNPIXLSY;
            prc->right=rc.right-BTNMARGIN;
            prc->left=prc->right-BTNPIXLSX;
            assign_flag=1;
        } break;
        case ZMAX: {
            BOOL IsMaxButton=((GetWindowLongPtr(hwnd,GWL_STYLE)&WS_MAXIMIZEBOX)==WS_MAXIMIZEBOX);
            if(!IsMaxButton) break;
            prc->top=rc.top+BTNMARGIN;
            prc->bottom=prc->top+BTNPIXLSY;
            prc->right=rc.right-BTNMARGIN-BTNPIXLSX;
            prc->left=prc->right-BTNPIXLSX;
            assign_flag=1;
        } break;
        case ZMIN: {
            BOOL IsMinButton=((GetWindowLongPtr(hwnd,GWL_STYLE)&WS_MINIMIZEBOX)==WS_MINIMIZEBOX);
            if(!IsMinButton) break;
            prc->top=rc.top+BTNMARGIN;
            prc->bottom=prc->top+BTNPIXLSY;
            prc->right=rc.right-BTNMARGIN-BTNPIXLSX*2;
            prc->left=prc->right-BTNPIXLSX;
            assign_flag=1;
        } break;
        case ZICON: {
            prc->top=rc.top+ICONMARGIN;
            prc->bottom=prc->top+ICONPIXLS;
            prc->left=rc.left+ICONMARGIN;
            prc->right=prc->left+ICONPIXLS;
            assign_flag=1;
        } break;
        case ZMENUBAR: {
            if(!menubar_exist) break;
            prc->top=rc.top+ICONMARGIN*2+ICONPIXLS;
            prc->bottom=prc->top+MENUBARY;
            prc->left=rc.left;
            prc->right=rc.right;
            assign_flag=1;
        } break;
        case ZCAPTION: {
            prc->top=rc.top+BORDERPIXLS;
            prc->bottom=rc.top+ICONMARGIN*2+ICONPIXLS;
            prc->left=rc.left+BORDERPIXLS;
            prc->right=rc.right-BORDERPIXLS;
            assign_flag=1;
        } break;
        case ZTEXTTITLE: {
            prc->left=rc.left+ICONMARGIN*2+ICONPIXLS;
            prc->right=rc.right-BTNMARGIN-BTNPIXLSX*3;
            prc->top=rc.top;
            prc->bottom=rc.top+ICONMARGIN*2+ICONPIXLS;
            assign_flag=1;
        } break;
        case ZCONFIG: {
            prc->top=rc.top+ICONMARGIN;
            prc->bottom=prc->top+BTNPIXLSY;
            prc->right=rc.right-BTNMARGIN*2-BTNPIXLSX*3;
            prc->left=prc->right-BTNPIXLSX;
            assign_flag=1;
        } break;
        case ZMSG: {
            prc->top=rc.top+ICONMARGIN;
            prc->bottom=prc->top+BTNPIXLSY;
            prc->right=rc.right-BTNMARGIN*3-BTNPIXLSX*4;
            prc->left=prc->right-BTNPIXLSX;
            assign_flag=1;
        } break;
        }
        
        if(assign_flag==1&&allign_topleft) {
            OffsetRect(prc,-rc.left,-rc.top);
        }
        return assign_flag;
    }
    
    int Frame_NCCalcSize(HWND hwnd,WPARAM wParam,LPARAM lParam)
    {
        RECT rect_new;
        RECT rect_old;
        RECT client_rect_new;
        RECT client_rect_old;
        BOOL HasMenu=(GetMenu(hwnd)!=NULL);//失效原因应该与WM_NCCALCSIZE的触发时机有关.在创建时触发
    
        if(wParam == TRUE) {
            LPNCCALCSIZE_PARAMS calc_param = (LPNCCALCSIZE_PARAMS)lParam;
            
            CopyRect(&rect_new,&(calc_param->rgrc[0]));
            CopyRect(&rect_old,&(calc_param->rgrc[1]));
            CopyRect(&client_rect_old,&(calc_param->rgrc[2]));
            
            client_rect_new = {rect_new.left+BORDERPIXLS,
                               rect_new.top+ICONMARGIN*2+ICONPIXLS+(HasMenu?MENUBARY:0),
                               rect_new.right-BORDERPIXLS,
                               rect_new.bottom-BORDERPIXLS};
            CopyRect(&(calc_param->rgrc[0]),&client_rect_new);
            CopyRect(&(calc_param->rgrc[1]),&rect_new);
            CopyRect(&(calc_param->rgrc[2]),&rect_old);
            
            return WVR_VALIDRECTS;
        }
        else {
            RECT* prect = (RECT*)lParam;
            
            prect->left+=BORDERPIXLS; 
            prect->right-=BORDERPIXLS; 
            prect->top+=ICONMARGIN*2+ICONPIXLS+(HasMenu?MENUBARY:0); 
            prect->bottom-=BORDERPIXLS;
            return 0;
        }
    }
    
    int Frame_InitialMenuPopup(HWND hwnd,WPARAM wParam,LPARAM lParam)
    {
        HMENU menu=(HMENU)wParam;
        int pos=(UINT)LOWORD(lParam);
        BOOL sysmenu_flag=(BOOL)HIWORD(lParam);
        int item_count;
        MENUINFO mif={0};
        MENUITEMINFO miif={0};
        
        pFrameStyle fs=Frame_GetSettings(hwnd);
        if(!fs) return 0;
        
        item_count=GetMenuItemCount(menu);
        for(int index=0;index<item_count;index++) {
            miif.cbSize=sizeof(miif);
            miif.fMask=MIIM_STATE|MIIM_ID;
            GetMenuItemInfo(menu,index,TRUE,&miif);
            
            miif.cbSize=sizeof(miif);
            miif.fMask=MIIM_ID|MIIM_FTYPE;
            miif.fType=MFT_OWNERDRAW;//Menu Item Owner drawing
            SetMenuItemInfo(menu,index,TRUE,&miif);
        }
        //menu item backgnd color settings.
        mif.cbSize=sizeof(MENUINFO);
        mif.fMask=MIM_BACKGROUND;
        mif.hbrBack=fs->brush_mibk;
        SetMenuInfo(menu,&mif);
        return 0;
    }
    
    int Frame_NCHitTest(HWND hwnd,WPARAM wParam,LPARAM lParam)
    {
        RECT rc,rc_cap,rc_bar;
        RECT rc_min,rc_max,rc_x,rc_ico;
        char text[512]="";
        POINT hit={GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam)};
        LRESULT result=DefWindowProc(hwnd,WM_NCHITTEST,wParam,lParam);
        
        Frame_GetNCZoneRect(hwnd,ZCAPTION,&rc_cap,FALSE);
        Frame_GetNCZoneRect(hwnd,ZMENUBAR,&rc_bar,FALSE);
        Frame_GetNCZoneRect(hwnd,ZCLOSE,&rc_x,FALSE);
        Frame_GetNCZoneRect(hwnd,ZMAX,&rc_max,FALSE);
        Frame_GetNCZoneRect(hwnd,ZMIN,&rc_min,FALSE);
        Frame_GetNCZoneRect(hwnd,ZICON,&rc_ico,FALSE);
        
        if(PtInRect(&rc_bar,hit)) return HTMENU;
        else if(result==HTMENU) return HTCAPTION;
        else if(PtInRect(&rc_min,hit)) result=HTMINBUTTON;
        else if(PtInRect(&rc_max,hit)) result=HTMAXBUTTON;
        else if(PtInRect(&rc_x,hit)) result=HTCLOSE;
        else if(PtInRect(&rc_cap,hit)) result=HTCAPTION;
        
        return result;
    }
    
    HWND Docker_CreateHintWindow(HWND container)
    {
        HWND lbl=CreateWindowEx(WS_EX_TOOLWINDOW|WS_EX_LAYERED,
                 		   WC_STATIC,"",
                 		   NULL,//WS_TABSTOP|WS_VISIBLE,
                 		   0,0,150,150,
                 		   NULL, (HMENU)NULL,//0x0001,
                 		   (HINSTANCE)GetWindowLongPtr(container, GWLP_HINSTANCE), NULL);
        SetLayeredWindowAttributes(lbl,NULL,200,LWA_ALPHA); 
        SetWindowLongPtr(lbl,GWL_STYLE,(~WS_CAPTION)&GetWindowLongPtr(lbl,GWL_STYLE));
        SetWindowLongPtr(lbl,GWLP_USERDATA,(LONG_PTR)SetWindowLongPtr(lbl,GWLP_WNDPROC,(LONG_PTR)HintWindowProc));
    
        POINT pt[32];
        int psize[5];
        int pcc=Docker_GetPtArray(lbl,pt,psize);
           
        HRGN rgn=CreatePolyPolygonRgn(pt,psize,pcc,WINDING);
        SetWindowRgn(lbl,rgn,TRUE);
        DeleteObject(rgn);
        
        return lbl;
    }
    
    LRESULT CALLBACK HintWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
        WNDPROC pre_prc=(WNDPROC)GetWindowLongPtr(hwnd,GWLP_USERDATA);
    	switch (msg)
    	{
    	case WM_PAINT: {
    	    POINT pt,pl[32];
    	    int carray[5];
            RECT rect;
            PAINTSTRUCT ps;
            BeginPaint(hwnd,&ps);
            GetClientRect(hwnd,&rect);
            HBRUSH brush=CreateSolidBrush(RGB(30,30,30));
            
            Docker_GetPtArray(hwnd,pl,carray);
            for(int index=0;index<32;index++) ScreenToClient(hwnd,&pl[index]);
            SelectObject(ps.hdc,brush);
            SetPolyFillMode(ps.hdc,WINDING);
            PolyPolygon(ps.hdc,pl,carray,5);
            DeleteObject(brush);
            
            HBRUSH brush_checked=CreateSolidBrush(RGB(0,128,250));
            if(docker_mode==DOCKER_CENTER) {
                SelectObject(ps.hdc,brush_checked);
                SetPolyFillMode(ps.hdc,WINDING);
                Polygon(ps.hdc,pl,carray[0]);
            }
            else if(docker_mode==DOCKER_TOP) {
                SelectObject(ps.hdc,brush_checked);
                SetPolyFillMode(ps.hdc,WINDING);
                Polygon(ps.hdc,&pl[4],carray[1]);
            }
            else if(docker_mode==DOCKER_BOTTOM) {
                SelectObject(ps.hdc,brush_checked);
                SetPolyFillMode(ps.hdc,WINDING);
                Polygon(ps.hdc,&pl[11],carray[2]);
            }
            else if(docker_mode==DOCKER_RIGHT) {
                SelectObject(ps.hdc,brush_checked);
                SetPolyFillMode(ps.hdc,WINDING);
                Polygon(ps.hdc,&pl[18],carray[3]);
            }
            else if(docker_mode==DOCKER_LEFT) {
                SelectObject(ps.hdc,brush_checked);
                SetPolyFillMode(ps.hdc,WINDING);
                Polygon(ps.hdc,&pl[25],carray[4]);
            }/*
            else {
                SelectObject(ps.hdc,brush_checked);
                SetPolyFillMode(ps.hdc,WINDING);
                Polygon(ps.hdc,pl,carray[0]);
            }*/
            
            DeleteObject(brush_checked);
            EndPaint(hwnd,&ps);
            return 0;
    	} break;
    	case WM_DOCKINGONTHEWAY: {
    	    POINT pt,pl[32];
    	    int carray[5];
    	    
    	    GetCursorPos(&pt);
    	    Docker_GetPtArray(hwnd,pl,carray);
    	    docker_mode=DOCKER_CENTER;
    	    
    	    if(Docker_PtInPolygon(pl,4,pt)) {docker_mode=DOCKER_CENTER;}
    	    else if(Docker_PtInPolygon(&pl[4],7,pt)) {docker_mode=DOCKER_TOP;}
    	    else if(Docker_PtInPolygon(&pl[11],7,pt)) {docker_mode=DOCKER_BOTTOM;}
    	    else if(Docker_PtInPolygon(&pl[18],7,pt)) {docker_mode=DOCKER_RIGHT;}
    	    else if(Docker_PtInPolygon(&pl[25],7,pt)) {docker_mode=DOCKER_LEFT;}
    	    else docker_mode=DOCKER_UNKNOW;
    	    
    	    InvalidateRect(hwnd,NULL,TRUE);
    	} break;
    	}
    	
    	return CallWindowProc(pre_prc,hwnd,msg,wParam,lParam);
    }
    
    int Docker_GetPtArray(HWND hint,LPPOINT pt,int* pcc)
    {
        RECT rc;
        POINT ct;
    
        pcc[0]=4;
        pcc[1]=pcc[2]=pcc[3]=pcc[4]=7;
        GetWindowRect(hint,&rc);
        ct.x=(rc.left+rc.right)>>1;
        ct.y=(rc.top+rc.bottom)>>1;
        pt[0].x=ct.x-15;
        pt[0].y=ct.y-15;
        pt[1].x=ct.x+15;
        pt[1].y=ct.y-15;
    #define POINTSWITCH(p,c,t) (t)->x=(c)->x*2-(p)->x;(t)->y=(c)->y*2-(p)->y    
        POINTSWITCH(&pt[0],&ct,&pt[2]);
        POINTSWITCH(&pt[1],&ct,&pt[3]);
        
        //4,5,6,7,8,9,10
        pt[4].x=ct.x;
        pt[4].y=ct.y-50;
        pt[5].x=pt[1].x;
        pt[5].y=pt[4].y+20;
        pt[6].x=pt[1].x-10;
        pt[6].y=pt[5].y;
        pt[7].x=pt[6].x;
        pt[7].y=pt[1].y-10;
        pt[8].x=pt[0].x+10;
        pt[8].y=pt[0].y-10;
        pt[9].x=pt[0].x+10;
        pt[9].y=pt[6].y;
        pt[10].x=pt[0].x;
        pt[10].y=pt[9].y;
        
        POINTSWITCH(&pt[4],&ct,&pt[11]);
        POINTSWITCH(&pt[5],&ct,&pt[12]);
        POINTSWITCH(&pt[6],&ct,&pt[13]);
        POINTSWITCH(&pt[7],&ct,&pt[14]);
        POINTSWITCH(&pt[8],&ct,&pt[15]);
        POINTSWITCH(&pt[9],&ct,&pt[16]);
        POINTSWITCH(&pt[10],&ct,&pt[17]);
        
        pt[18].x=ct.x+50;
        pt[18].y=ct.y;
        pt[19].x=pt[18].x-20;
        pt[19].y=pt[2].y;
        pt[20].x=pt[19].x;
        pt[20].y=pt[2].y-10;
        pt[21].x=pt[2].x+10;
        pt[21].y=pt[20].y;
        pt[22].x=pt[21].x;
        pt[22].y=pt[1].y+10;
        pt[23].x=pt[19].x;
        pt[23].y=pt[22].y;
        pt[24].x=pt[23].x;
        pt[24].y=pt[1].y;
        POINTSWITCH(&pt[18],&ct,&pt[25]);
        POINTSWITCH(&pt[19],&ct,&pt[26]);
        POINTSWITCH(&pt[20],&ct,&pt[27]);
        POINTSWITCH(&pt[21],&ct,&pt[28]);
        POINTSWITCH(&pt[22],&ct,&pt[29]);
        POINTSWITCH(&pt[23],&ct,&pt[30]);
        POINTSWITCH(&pt[24],&ct,&pt[31]);
        
        return 5;
    }
    
    BOOL Docker_PtInPolygon(LPPOINT pl,int nvert,POINT pt)
    {
      int i,j;
      BOOL c=FALSE;
      for(i=0,j=nvert-1;i<nvert;j=i++) {
        if(((pl[i].y>pt.y)!=(pl[j].y>pt.y)) &&
           (pt.x<(pl[j].x-pl[i].x)*(pt.y-pl[i].y)*1.0/(pl[j].y-pl[i].y)+pl[i].x))
           c=!c;
      }
      return c;
    }

     

    展开全文
  • 停靠窗口QDockWidget

    2018-07-15 20:42:00
    停靠窗口QDockWidget类是应用程序中经常用到的,设置停靠窗口的一般流程如下 (1)创建一个QDockWidget对象的停靠窗口 (2)设置此停靠窗口的属性,通常调用setFeatures()及setAllowedAreas()两种方法 (3)新建一个要插入...
  • 上图红色方框中的客户区区域光标不停靠时的效果 [img=https://img-bbs.csdn.net/upload/201312/31/1388484871_13770.png][/img] 红色方框中光标停靠时的效果 请问这种效果是如何实现的?虽然考虑过用WM_...
  • qt 停靠窗口

    2019-07-22 21:07:17
    //停靠窗口1 //QDockWidget *dw1 = new QDockWidget("停靠窗口1",ui->screenView);//构建停靠窗口,指定父类 //dw1->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetCl...
  • CFormView侧栏停靠

    2016-08-05 12:48:16
    (MFC)Vs2010制作Visual Studio风格的停靠侧栏窗口(CDockablePane里嵌套FormView表单视图) 时间 2013-02-19 08:49:16 CSDN博客 原文 http://blog.csdn.net/k_linux_man/article/details/8587923 主题 Visual...
  • wpf停靠Download control - 238.1 KB 下载控件-238.1 KB 介绍 (Introduction) Some years ago, I created a commercial application with a large number of documents windows and tool windows. I wanted the user...
  • Qt4_停靠窗口

    2021-03-31 16:13:11
    QMainWindow提供了4个停靠窗口区域;分别在中央窗口部件的上部、下部、左侧和右侧。诸如像Microsoft Visual Studio和Qt Linguist这样的应用程序都广泛使用了停靠窗口,以提供一种非常灵活的用户接口方式。在Qt中,...
  • 停靠窗口

    2015-05-30 14:52:00
    参数 Qt.DockWidgetAreas 指定了停靠窗体可停靠区域,包括以下几种。  Qt.LeftDockWidgetArea:可在主窗口的左侧停靠。  Qt.RightDockWidgetArea:可在主窗口的右侧停靠。  Qt.TopDockWidgetArea:可在主窗口的...
  • 停靠窗口

    2013-04-23 11:02:34
    关于停靠窗口,现在我们所见的许多软件都存在停靠窗口,如Visual Studio软件的类视图、属性视图和资源视图都是停靠窗口的实际案例;停靠窗口作为主窗口的一部分,可以停靠、浮动、显示隐藏等; 该博文主要讲解在Qt...
  • Qt创建停靠悬浮窗口

    2021-03-10 19:32:04
    1.Qt实现窗口停靠和悬浮使用类QDockWidget,它有两个重要方法用来设置停靠特性以及停靠区域, dw1->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetClosable);//设置停靠窗口特性,可...
  • [摘要]DockWidget类继承与QWidget类,用于停靠窗口的管理,...在主窗口中,先设置中心控件,然后实例化 QDockWidget对象,通过setFeatures( )设置停靠窗口的窗体特性,通过setAllowedAreas( )设置窗体可停靠区域
  • QDockWidget的allowedAreas属性用于控制停靠部件在QMainWindow的停靠区域中可停靠的范围,其类型为枚举类型Qt.DockWidgetArea或其值的组合,分别控制可以停靠在主窗口停靠区域的左边(LeftDockWidgetArea)、右边...
  • 控制停靠行为

    2010-07-16 11:03:00
     当使用停靠功能时,将控件添加到窗体时所使用的顺序可影响屏幕上控件的布局...如果试图将两个控件停靠在一个父控件中的同一区域以便将一个控件置于另一个控件旁边,则 Z 顺序中更靠后的控件在得到的布局中靠前
  • 题外话:QT使用起来真是很方便,这是相对于 MFC 而言的,很多接口都封装得很清晰,当初写MFC的时候感觉有点散的感觉,而QT就比较完整和规整和... allowedAreas:允许停靠区域 dockWidgetArea:初始化显示区域 OK
  • QT 停靠窗简单使用

    2015-10-01 15:11:41
    QDockWidget类继承与QWidget类,用于停靠窗口的管理。在主窗口中,先设置中心控件,然后实例化...setAllowedAreas( )设置窗体可停靠区域。具体如下: void setFeatures(DockWidgetFeatures features ) QD
  • Qt中停靠窗口的实现

    2014-09-04 22:09:16
    停靠窗口作为主窗口的一部分,可以停靠、浮动、显示隐藏等。现在很多软件都具有可停靠窗口  可停靠位置:     [cpp] view plaincopyprint? //mydockwidget.h  #ifndef...
  •  在TWinControl类中有一个DockSite属性(boolean),它的作用是是否允许别的控件停靠在它的上面;在TControl类中有一个DragKind属性,如果要这个控件能停靠在别的控件上,就把DragKind属性设成dkDock。就这么简单,...
  • QT中窗体的停靠

    2017-02-06 11:28:25
    停靠窗口作为主窗口的一部分,可以停靠、浮动、显示隐藏等。现在很多软件都具有可停靠窗口  可停靠位置:     [cpp] view plain copy  print? //mydockwidget.h  #...
  • 在 Qt 中,停靠窗口 (dock window) 都是QDockWidget 的实例,可以停靠在 QMainWindow 的中央部件 (central widget) 的上下左右四个区域停靠的 QDockWidget 没有框架,有一个较小的标题栏;也可浮动出来作为独立...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 6,373
精华内容 2,549
关键字:

区域停靠