感受生活无聊

2016/9/5 无聊

Posted by WangXiaoDong on September 5, 2016

时间:2016年9月5日 天气:小雨:umbrella:


Author:冬之晓:angry:
Email: 347916416@qq.com
MyAppearance: MyAppearance

    今天又是周一了,下午快下班的时候,妈妈跟我聊天,说生活很没有意思,我回答
曰:确实没意思……无语了,终于明白为啥我自己比较消极了,原来我和我妈的想法都差
不多……

今天在进行Qt编程的时候,学习了一下如何自定义ui的样式,有时候,你在修改别人程序的时候,可能会发现别人程序中的某个控件ui设计是直接拖上去的。这种情况下如果你想增加该控件的事件处理,比如拖拽功能。不太好办,今天在书上找到一个方法,就是使用Qt设计师里面的提升,将需要增加事件响应的那个控件提升到一个类里面,然后自己实现里面相关的事件响应函数,今天我成功实现了一个QTreeWidget的提升,然后把里面的数据实现了拖拽功能,代码如下:

#ifndef NEW_QTREEWIDGET_H
#define NEW_QTREEWIDGET_H

#include <QTreeWidget>

#include <QDragEnterEvent>

class new_QTreeWidget:public QTreeWidget
{
    Q_OBJECT
public:
    new_QTreeWidget(QWidget *parent = 0);
protected:
    void dragEnterEvent(QDragEnterEvent *e);
    void dragMoveEvent(QDragMoveEvent *e);
    void dropEvent(QDropEvent *e);
    void mousePressEvent(QMouseEvent *e);
    void mouseMoveEvent(QMouseEvent *e);
private:
    QPoint _startPos;

    void performDrag();

};


#endif // NEW_QTREEWIDGET_H

#include "new_qtreewidget.h"

#include <QMimeData>
#include <QDragEnterEvent>
#include <QDragMoveEvent>
#include <QDropEvent>
#include <QMouseEvent>
#include <QApplication>
#include <QDrag>

#include <QDebug>

new_QTreeWidget::new_QTreeWidget(QWidget *parent):QTreeWidget(parent)
{
    setAcceptDrops(true);
}

void new_QTreeWidget::dragEnterEvent(QDragEnterEvent *e)
{
    new_QTreeWidget *source = qobject_cast<new_QTreeWidget *>(e->source());
    if(source)
    {
        e->setDropAction(Qt::MoveAction);
        e->accept();
    }
}

void new_QTreeWidget::dragMoveEvent(QDragMoveEvent *e)
{
    new_QTreeWidget *source = qobject_cast<new_QTreeWidget *>(e->source());
    if(source)
    {
        e->setDropAction(Qt::MoveAction);
        e->accept();
    }
}

void new_QTreeWidget::dropEvent(QDropEvent *e)
{
    new_QTreeWidget *source = qobject_cast<new_QTreeWidget *>(e->source());
    if(source)
    {
        new_QTreeWidget *source = qobject_cast<new_QTreeWidget *>(e->source());
        if(source)
        {
            QTreeWidgetItem *item = this->itemAt(e->pos()); //当前位置的item
            if( item == nullptr)   //如果放下的位置没有item,则退出,没有这句话死机!
                return;
            if( -1 == this->indexOfTopLevelItem(item) && (-1 == this->indexOfTopLevelItem(currentItem())) ||
                -1 != this->indexOfTopLevelItem(item) && (-1 != this->indexOfTopLevelItem(currentItem()))
               )  //如果“放下位置的item是顶层item,且原来的是顶层”或者“放下的不是顶层,且原来也不是顶层”
            {
                qDebug()<<"放下的文本是:"<<e->mimeData()->text();
                item->setText(currentColumn(),e->mimeData()->text());
                e->setDropAction(Qt::MoveAction);
                e->accept();
            }
        }
    }
}

void new_QTreeWidget::mousePressEvent(QMouseEvent *e)
{
    if(e->button() == Qt::LeftButton)
    {
        _startPos = e->pos();
    }
    QTreeWidget::mousePressEvent(e);
}

void new_QTreeWidget::mouseMoveEvent(QMouseEvent *e)
{
    if(e->buttons() & Qt::LeftButton)
    {
        int distance = (e->pos() - _startPos).manhattanLength();
        if(distance >= QApplication::startDragDistance())   //当拖动距离大于一个推荐抖动距离时,表示同意已经拖动操作了
            performDrag();
    }
    QTreeWidget::mouseMoveEvent(e);
}

void new_QTreeWidget::performDrag()
{
    QTreeWidgetItem *item = currentItem();
    int column = currentColumn();
    if(item)  //必须是非顶层item才可以移动数据
//    if(item)
    {
        QMimeData *mineData = new QMimeData;
        if(column != 4)   //只有第四列才可以移动数据
            return;
        mineData->setText(item->text(column));
        qDebug()<<item->text(column);

        QDrag *drag = new QDrag(this);
        drag->setMimeData(mineData);
        drag->exec(Qt::MoveAction);
    }
}

这样就解决了当界面已经设置好后如何添加功能的难题!

条款22 :将成员变量声明为private

为什么不采用public成员变量

首先,语法一致性考虑,客户唯一能访问对象的方法就是通过成员函数,客户不必考虑是否该记住使用小括号()。

其次,使用函数可以让你对成员变量的处理有更精确的控制。如果成员变量是public,每个人都可以读写它,但是如果你也函数。取得或设定其值,你就可以实现“不准访问”、“只读访问”,以及”读写访问”甚至”唯写访问“:

class AccessLevels 
{ 
public: 
    int getReadOnlay() const {return readOnly;} 
    void setReadWrite(int value){readWrite = value;} 
    int getReadWrite()const {return readWrite;} 
    void setWriteOnly(int value){writeOnly = value;} 
protected: 
private: 
    int noAccess; 
    int readOnly; 
    int readWrite; 
    int writeOnly; 
};

如此细微的访问控制颇为必要,因为许多成员变量应该被隐藏起来。

最后,还有封装性。如果通过函数访问成员变量,日后可改以某个计算替换这个成员变量,客户不会知道class内部实现已经起了变化。 如下面的测速程序,汽车通过,其速度被计算并填入一个速度收集器内:

class SpeedDataCollection 
{ 
public: 
    void addValue(int speed); //添加一笔新数据 
    double averageSoFar() const; //返回平均速度 
protected: 
private: 
};

考虑averageSoFar。做法之一是在class内设计一个成员变量,记录至今以来所有速度的平均值。当averageSoFar被调用,只返回那个成员变量就好。

另一个做法是令averageSoFar每次被调用时,重新计算平均值,此函数有权力调取收集器内的每一笔速度值。

哪一种做法更好,在内存吃紧的机器上,第一种做法会增加SpeedDataCollection对象的占用空间,在频繁需要平均值的应用程序中,内存不是重点。

所以,成员变量隐藏在函数接口的背后,可以为“所有可能的实现”提供弹性。例如这可使得成员变量被读或被写时轻松通知其他对象、可以验证class的约束条件及函数的前提和事后状态、可以在多线程环境中执行同步控制。。。等等。

封装性非常重要。如果对客户隐藏成员变量(也就是)封装,保留了日后变更实现的权力。public意味着不封装,不封装意味着不可改变

特别是被广泛使用的classes而言,因为他们最能够从“改采用一个较佳实现版本”中获益。

protected成员变量就像public成员变量一样缺乏封装性:

成员变量的封装性与“成员变量的内容改变时所破坏的代码数量”成反比,假设一个public成员变量,我们取消了它。所有使用它的客户码都会被破坏,那是一个不可知的大量。所以public成员函数完全没有封装性。假设一个protected成员变量,我们取消了它,所有使用它的derived classes都会被破坏,往往也是一个不可知的大量。

最后总结一下:

  • 切记将成员变量声明为private,这可赋予客户访问数据的一致性、可细微划分访问控制、允诺约束条件获得保证,并提供class作者以充分的实现弹性

  • protected并不比public更具封装性

设计模式(七)————工厂方法模式

使用一个例子是实现一个雷锋的例子,使用工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例延迟到其子类!

注意:它和简单工厂的区别是没有违背开放–封闭原则,简单工厂在工厂类里面通过逻辑实例话对应的类,违背了开放–封闭原则

雷锋和雷锋工厂的头文件是这样实现的:

#ifndef LEIFENG
#define LEIFENG
#include <QtDebug>

class LeiFeng
{
public:
    void Sweep()
    {
        qDebug() <<"扫地";
    }
    void Wash()
    {
        qDebug() <<"洗衣服";
    }
    void BuyRice()
    {
        qDebug() <<"买米";
    }
    virtual ~LeiFeng(){}
};

class Undergraduate final:public LeiFeng
{};
class Volunteer final:public LeiFeng
{};

#endif // LEIFENG


#ifndef LEIFENGFACTORY
#define LEIFENGFACTORY
#include "leifeng.h"

class LeiFenngInterface
{
public:
    virtual LeiFeng *CreateLeiFeng() = 0;
    virtual ~LeiFenngInterface(){}
};
class UndergraduateFactory final:public LeiFenngInterface
{
public:
    LeiFeng *CreateLeiFeng() override
    {
        return new Undergraduate();
    }
};
class VolunteerFactory final:public LeiFenngInterface
{
public:
    LeiFeng *CreateLeiFeng() override
    {
        return new Volunteer();
    }
};

#endif // LEIFENGFACTORY

然后就可以在主函数中这样测试工厂方法模式。

#include "leifengfactory.h"
#include "leifeng.h"
#include <QtDebug>

int main(int argc , char *argv[])
{
    LeiFenngInterface *factory = new UndergraduateFactory();
    LeiFeng *lf = factory->CreateLeiFeng();

    lf->BuyRice();
    lf->Sweep();
    lf->Wash();

    qDebug() <<"测试完毕!";
    return 0;
}