zoukankan      html  css  js  c++  java
  • Qt编写自定义控件55-手机通讯录

    一、前言

    前面几篇文章中的控件基本上难度系数接近0,甚至有凑控件数量的嫌疑,这次必须来一个强悍的控件,本控件难度系数在所有控件中排前五,代码量也不少,头文件都550行,实现文件1600行,为什么这么多呢,其实本控件是由好多个子控件组成的,字母高亮背景类、中间字母分隔类、右侧字母导航类、通讯录按钮类、自定义滚动条类,我在写比较复杂的控件的时候,一般都会逐个功能拆分,然后思考是否该功能可以做成独立的类,这样管理起来比较方便,也方便查看代码。
    最开始拿到这个控件需求的时候,也觉得不会简单,要求用纯QWidget实现,qml实现滑动等各种效果很方便,天生的优势,而QWidget就需要自己来实现了,需求主要是要求五点,能够批量和单个添加联系人信息(头像+姓名+标识)、能够滑动列表悬浮滚动条、能够自动按照字母分类、提供字母导航栏直接快速定位、单击联系人发出对应联系人的详细信息。

    二、实现的功能

    • 1:可设置信息集合(图标+姓名+类型+电话)以及添加单个联系人
    • 2:可设置背景图片+背景颜色
    • 3:可设置右侧导航字母的列表+默认颜色+高亮颜色
    • 4:可设置联系人按钮姓名颜色+姓名字体
    • 5:可设置联系人按钮类型颜色+姓名字体
    • 6:可设置联系人按钮选中背景颜色
    • 7:可设置字母导航的风格(背景颜色+线条)
    • 8:可设置字母导航的颜色+字体大小
    • 9:可设置各种边距+联系人列数+元素间隔等
    • 10:支持悬浮滚动条,可设置悬停时间
    • 11:可设置悬浮滚动条的正常颜色+高亮颜色
    • 12:支持滑动,可设置滑动的步长速度
    • 13:支持单击右侧字母导航定位+文本突出显示
    • 14:单击发出当前联系人的姓名+类型+电话等信息
    • 15:根据汉字字母排序从小到大排列联系人,自带汉字转拼音功能

    三、效果图

    四、头文件代码

    #ifdef quc
    #if (QT_VERSION < QT_VERSION_CHECK(5,7,0))
    #include <QtDesigner/QDesignerExportWidget>
    #else
    #include <QtUiPlugin/QDesignerExportWidget>
    #endif
    
    class QDESIGNER_WIDGET_EXPORT TelWidget : public QWidget
    #else
    class TelWidget : public QWidget
    #endif
    
    {
        Q_OBJECT
        Q_PROPERTY(QString names READ getNames WRITE setNames)
        Q_PROPERTY(QString types READ getTypes WRITE setTypes)
        Q_PROPERTY(QString tels READ getTels WRITE setTels)
    
        Q_PROPERTY(QPixmap bgImage READ getBgImage WRITE setBgImage)
        Q_PROPERTY(QColor bgColor READ getBgColor WRITE setBgColor)
    
        Q_PROPERTY(int telHighFontSize READ getTelHighFontSize WRITE setTelHighFontSize)
        Q_PROPERTY(QPixmap telHighBgImage READ getTelHighBgImage WRITE setTelHighBgImage)
        Q_PROPERTY(QColor telHighBgColor READ getTelHighBgColor WRITE setTelHighBgColor)
        Q_PROPERTY(QColor telHighTextColor READ getTelHighTextColor WRITE setTelHighTextColor)
    
        Q_PROPERTY(QColor telBannerBgColor READ getTelBannerBgColor WRITE setTelBannerBgColor)
        Q_PROPERTY(QColor telBannerTextColor READ getTelBannerTextColor WRITE setTelBannerTextColor)
        Q_PROPERTY(QColor telBannerLineColor READ getTelBannerLineColor WRITE setTelBannerLineColor)
    
        Q_PROPERTY(QColor telLetterNormalColor READ getTelLetterNormalColor WRITE setTelLetterNormalColor)
        Q_PROPERTY(QColor telLetterHighColor READ getTelLetterHighColor WRITE setTelLetterHighColor)
    
        Q_PROPERTY(QColor telButtonBgColor READ getTelButtonBgColor WRITE setTelButtonBgColor)
        Q_PROPERTY(QColor telButtonNameColor READ getTelButtonNameColor WRITE setTelButtonNameColor)
        Q_PROPERTY(QColor telButtonTypeColor READ getTelButtonTypeColor WRITE setTelButtonTypeColor)
    
        Q_PROPERTY(QColor telPanelNormalColor READ getTelPanelNormalColor WRITE setTelPanelNormalColor)
        Q_PROPERTY(QColor telPanelHighColor READ getTelPanelHighColor WRITE setTelPanelHighColor)
    
    public:
        //联系人结构体
        struct TelInfo {
            QString letter;
            QString name;
            QString type;
            QString tel;
            QPixmap pixmap;
    
            bool operator <(const TelInfo &telInfo)const
            {
                return letter < telInfo.letter;
                //return (letter == "#") ? false : (letter < telInfo.letter);
            }
    
            bool operator >(const TelInfo &telInfo)const
            {
                return letter > telInfo.letter;
                //return (letter == "#") ? true : (letter > telInfo.letter);
            }
        };
    
        explicit TelWidget(QWidget *parent = 0);
        ~TelWidget();
    
    protected:
        void resizeEvent(QResizeEvent *);
        void showEvent(QShowEvent *);
        void paintEvent(QPaintEvent *);
    
    private:
        QString names;                  //姓名集合
        QString types;                  //类型集合
        QString tels;                   //电话集合
    
        QPixmap bgImage;                //背景图片
        QColor bgColor;                 //背景颜色
    
        int telHighFontSize;            //高亮标签字体大小
        QPixmap telHighBgImage;         //高亮标签背景图片
        QColor telHighBgColor;          //高亮标签背景颜色
        QColor telHighTextColor;        //高亮标签文字颜色
    
        QColor telBannerBgColor;        //顶部字母导航背景颜色
        QColor telBannerTextColor;      //顶部字母导航文字颜色
        QColor telBannerLineColor;      //顶部字母导航线条颜色
    
        QColor telLetterNormalColor;    //右侧字母导航正常颜色
        QColor telLetterHighColor;      //右侧字母导航高亮颜色
    
        QColor telButtonBgColor;        //通讯录按钮背景颜色
        QColor telButtonNameColor;      //通讯录按钮姓名颜色
        QColor telButtonTypeColor;      //通讯录按钮类型颜色
    
        QColor telPanelNormalColor;     //滚动条正常颜色
        QColor telPanelHighColor;       //滚动条高亮颜色
    
        int lastPosition;               //最后滚动条位置
        TelHigh *telHigh;               //高亮字母标签
        TelBanner *telBanner;           //顶部间隔字母导航
        TelLetter *telLetter;           //右侧字母标签
        TelPanel *telPanel;             //通讯录面板
    
        QList<QWidget *> items;         //通讯录按钮集合
        QList<QWidget *> banners;       //通讯录字母分割集合
        QList<QPixmap> pixmaps;         //联系人图片集合
        QTimer *timer;                  //隐藏高亮标签定时器
    
    public:
        QString getNames()              const;
        QString getTypes()              const;
        QString getTels()               const;
    
        QPixmap getBgImage()            const;
        QColor getBgColor()             const;
    
        int getTelHighFontSize()        const;
        QPixmap getTelHighBgImage()     const;
        QColor getTelHighBgColor()      const;
        QColor getTelHighTextColor()    const;
    
        QColor getTelBannerBgColor()    const;
        QColor getTelBannerTextColor()  const;
        QColor getTelBannerLineColor()  const;
    
        QColor getTelLetterNormalColor()const;
        QColor getTelLetterHighColor()  const;
    
        QColor getTelButtonBgColor()    const;
        QColor getTelButtonNameColor()  const;
        QColor getTelButtonTypeColor()  const;
    
        QColor getTelPanelNormalColor() const;
        QColor getTelPanelHighColor()   const;
    
        QSize sizeHint()                const;
        QSize minimumSizeHint()         const;
    
    private slots:
        void initControl();
        void initForm();
        void btnPressed();
        void btnRelease();
        void positionChanged(int value);
        void letterClicked(const QString &letter, int letterY);
    
    public Q_SLOTS:
        //设置姓名+类型+电话集合
        void setNames(const QString &names);
        void setTypes(const QString &types);
        void setTels(const QString &tels);
        void setInfo(const QString &names, const QString &types, const QString &tels);
        void setInfo(const QStringList &names, const QStringList &types,
                     const QStringList &tels, const QList<QPixmap> &pixmaps);
    
        //添加单个联系人
        void addInfo(const QString &name, const QString &type,
                     const QString &tel, const QPixmap &pixmap);
    
        //设置背景图+背景颜色
        void setBgImage(const QPixmap &bgImage);
        void setBgColor(const QColor &bgColor);
    
        //设置高亮字母标签相关属性
        void setTelHighFontSize(int telHighFontSize);
        void setTelHighBgImage(const QPixmap &telHighBgImage);
        void setTelHighBgColor(const QColor &telHighBgColor);
        void setTelHighTextColor(const QColor &telHighTextColor);
    
        //设置顶部字母导航相关属性
        void setTelBannerBgColor(const QColor &telBannerBgColor);
        void setTelBannerTextColor(const QColor &telBannerTextColor);
        void setTelBannerLineColor(const QColor &telBannerLineColor);
    
        //设置右侧字母导航相关属性
        void setTelLetterNormalColor(const QColor &telLetterNormalColor);
        void setTelLetterHighColor(const QColor &telLetterHighColor);
    
        //设置通讯录按钮相关属性
        void setTelButtonBgColor(const QColor &telButtonBgColor);
        void setTelButtonNameColor(const QColor &telButtonNameColor);
        void setTelButtonTypeColor(const QColor &telButtonTypeColor);
    
        //设置滚动条相关属性
        void setTelPanelNormalColor(const QColor &telPanelNormalColor);
        void setTelPanelHighColor(const QColor &telPanelHighColor);
    
    Q_SIGNALS:
        void telClicked(const QString &name, const QString &type, const QString &tel);
    };
    
    

    五、核心代码

    void TelWidget::setInfo(const QStringList &names, const QStringList &types,
                            const QStringList &tels, const QList<QPixmap> &pixmaps)
    {
        this->names = names.join("|");
        this->types = types.join("|");
        this->tels = tels.join("|");
        this->pixmaps = pixmaps;
    
        if (names.isEmpty() || types.isEmpty() || tels.isEmpty()) {
            return;
        }
    
        //行标识符文字集合
        QList<QString> texts;
        texts << "A" << "B" << "C" << "D" << "E" << "F" << "G" << "H" << "I" << "J" << "K" << "L" << "M"
              << "N" << "O" << "P" << "Q" << "R" << "S" << "T" << "U" << "V" << "W" << "X" << "Y" << "Z" << "#";
    
        QList<QString> listName = names;
        QList<QString> listType = types;
        QList<QString> listTel = tels;
        QList<QPixmap> listPix = pixmaps;
        int countName = listName.count();
        int countType = listType.count();
        int countTel = listTel.count();
        int countPix = listPix.count();
    
        if (countName == countType && countType == countTel && countTel == countPix) {
            //取出对应汉字首字母,先对所有姓名按照字母从小到大排序
            QList<TelInfo> poundInfos, telInfos;
            for (int i = 0; i < countName; i++) {
                TelInfo telInfo;
                telInfo.name = listName.at(i);
                telInfo.type = listType.at(i);
                telInfo.tel = listTel.at(i);
                telInfo.pixmap = listPix.at(i);
    
                //如果首字母未找到字母则归结到 # 分类中
                QString letter = ZhToPY::Instance()->zhToZM(listName.at(i).at(0));
                if (texts.contains(letter)) {
                    telInfo.letter = ZhToPY::Instance()->zhToJP(listName.at(i));
                    telInfos << telInfo;
                } else {
                    telInfo.letter = "#";
                    poundInfos << telInfo;
                }
            }
    
            //对信息集合进行升序排序
            qSort(telInfos.begin(), telInfos.end());
    
            //对最后的 # 类别追加到末尾
            foreach (TelInfo telInfo, poundInfos) {
                telInfos << telInfo;
            }
    
            //先要清空所有元素
            qDeleteAll(items);
            qDeleteAll(banners);
            items.clear();
            banners.clear();
    
            //生成电话本按钮
            for (int i = 0; i < countName; i++) {
                TelInfo telInfo = telInfos.at(i);
                TelButton *btn = new TelButton;
                connect(btn, SIGNAL(btnPressed()), this, SLOT(btnPressed()));
                connect(btn, SIGNAL(btnRelease()), this, SLOT(btnRelease()));
    
                //设置字母属性
                QString letter = telInfo.letter.at(0);
                btn->setProperty("letter", letter);
    
                //设置头像+姓名+类型+电话
                btn->setPixmap(telInfo.pixmap);
                btn->setName(telInfo.name);
                btn->setType(telInfo.type);
                btn->setTel(telInfo.tel);
                items << btn;
            }
    
            //逐个计算字母对应的索引
            QList<int> tempIndex;
            int textCount = texts.count();
            for (int j = 0; j < textCount; j++) {
                QString text = texts.at(j);
                int index = -1;
                for (int k = 0; k < items.count(); k++) {
                    if (items.at(k)->property("letter").toString() == text) {
                        index = k;
                        break;
                    }
                }
    
                tempIndex << index;
            }
    
            //过滤索引,标识符索引>=0才算数
            QList<int> indexs;
            for (int j = 0; j < textCount; j++) {
                int index = tempIndex.at(j);
                if (index >= 0) {
                    TelBanner *banner = new TelBanner;
                    banner->setText(texts.at(j));
                    banners << banner;
                    indexs << index;
                }
            }
    
            //设置标识符+元素集合
            telPanel->setIndexs(indexs);
            telPanel->setBanners(banners);
            telPanel->setItems(items);
    
            //重新设置颜色
            setTelHighBgColor(telHighBgColor);
            setTelBannerBgColor(telBannerBgColor);
            setTelBannerTextColor(telBannerTextColor);
            setTelLetterNormalColor(telLetterNormalColor);
            setTelLetterHighColor(telLetterHighColor);
            setTelButtonNameColor(telButtonNameColor);
            setTelButtonTypeColor(telButtonTypeColor);
            setTelPanelNormalColor(telPanelNormalColor);
            setTelPanelHighColor(telPanelHighColor);
        }
    }
    
    void TelWidget::addInfo(const QString &name, const QString &type,
                            const QString &tel, const QPixmap &pixmap)
    {
        names = names + "|" + name;
        types = types + "|" + type;
        tels = tels + "|" + tel;
        pixmaps.append(pixmap);
        setInfo(names.split("|"), types.split("|"), tels.split("|"), pixmaps);
    }
    
    

    六、控件介绍

    1. 超过150个精美控件,涵盖了各种仪表盘、进度条、进度球、指南针、曲线图、标尺、温度计、导航条、导航栏,flatui、高亮按钮、滑动选择器、农历等。远超qwt集成的控件数量。
    2. 每个类都可以独立成一个单独的控件,零耦合,每个控件一个头文件和一个实现文件,不依赖其他文件,方便单个控件以源码形式集成到项目中,较少代码量。qwt的控件类环环相扣,高度耦合,想要使用其中一个控件,必须包含所有的代码。
    3. 全部纯Qt编写,QWidget+QPainter绘制,支持Qt4.6到Qt5.13的任何Qt版本,支持mingw、msvc、gcc等编译器,支持任意操作系统比如windows+linux+mac+嵌入式linux等,不乱码,可直接集成到Qt Creator中,和自带的控件一样使用,大部分效果只要设置几个属性即可,极为方便。
    4. 每个控件都有一个对应的单独的包含该控件源码的DEMO,方便参考使用。同时还提供一个所有控件使用的集成的DEMO。
    5. 每个控件的源代码都有详细中文注释,都按照统一设计规范编写,方便学习自定义控件的编写。
    6. 每个控件默认配色和demo对应的配色都非常精美。
    7. 超过130个可见控件,6个不可见控件。
    8. 部分控件提供多种样式风格选择,多种指示器样式选择。
    9. 所有控件自适应窗体拉伸变化。
    10. 集成自定义控件属性设计器,支持拖曳设计,所见即所得,支持导入导出xml格式。
    11. 自带activex控件demo,所有控件可以直接运行在ie浏览器中。
    12. 集成fontawesome图形字体+阿里巴巴iconfont收藏的几百个图形字体,享受图形字体带来的乐趣。
    13. 所有控件最后生成一个动态库文件(dll或者so等),可以直接集成到qtcreator中拖曳设计使用。
    14. 目前已经有qml版本,后期会考虑出pyqt版本,如果用户需求量很大的话。
    15. 自定义控件插件开放动态库使用(永久免费),无任何后门和限制,请放心使用。
    16. 目前已提供26个版本的dll,其中包括了qt5.12.3 msvc2017 32+64 mingw 32+64 的。
    17. 不定期增加控件和完善控件,不定期更新SDK,欢迎各位提出建议,谢谢!
    18. Qt入门书籍推荐霍亚飞的《Qt Creator快速入门》《Qt5编程入门》,Qt进阶书籍推荐官方的《C++ GUI Qt4编程》。
    19. 强烈推荐程序员自我修养和规划系列书《大话程序员》《程序员的成长课》《解忧程序员》,受益匪浅,受益终生!
    20. SDK下载链接:https://pan.baidu.com/s/1A5Gd77kExm8Co5ckT51vvQ 提取码:877p
  • 相关阅读:
    团队项目-第一阶段冲刺7
    团队项目-第一阶段冲刺6
    Spring Boot 揭秘与实战(七) 实用技术篇
    Spring Boot 揭秘与实战(七) 实用技术篇
    Spring Boot 揭秘与实战(六) 消息队列篇
    Spring Boot 揭秘与实战(五) 服务器篇
    Spring Boot 揭秘与实战(五) 服务器篇
    Spring Boot 揭秘与实战(五) 服务器篇
    Spring Boot 揭秘与实战(五) 服务器篇
    Spring Boot 揭秘与实战(四) 配置文件篇
  • 原文地址:https://www.cnblogs.com/feiyangqingyun/p/11560100.html
Copyright © 2011-2022 走看看